public static void UpdateBootstrapTableOfContents(byte[] bootstrapData, List <GDTrack> tracks) { //Tracks 03 to 99, 1 and 2 were in the low density area for (int t = 0; t < 97; t++) { uint dcLBA = 0xFFFFFF; byte dcType = 0xFF; if (t < tracks.Count) { GDTrack track = tracks[t]; dcLBA = track.LBA + 150; dcType = (byte)(((uint)track.Type << 4) | 0x1); } int offset = 0x104 + (t * 4); bootstrapData[offset++] = (byte)(dcLBA & 0xFF); bootstrapData[offset++] = (byte)((dcLBA >> 8) & 0xFF); bootstrapData[offset++] = (byte)((dcLBA >> 16) & 0xFF); bootstrapData[offset] = dcType; } // Update track count in bootsector (HDA + SDA tracks count) bootstrapData[0x28E] = (byte)(tracks.Count + 2); }
private List <GDTrack> ReadCDDA(List <string> gdda) { List <GDTrack> retval = new List <GDTrack>(); foreach (string path in gdda) { FileInfo fi = new FileInfo(path); if (!fi.Exists) { throw new FileNotFoundException("GDDA track " + fi.Name + " could not be accessed."); } GDTrack track = new GDTrack { FileName = fi.Name, Type = 0, FileSize = fi.Length }; retval.Add(track); } return(retval); }
private void WriteDataTrack(bool isSingleDensityArea, BuiltStream isoStream, byte[] bootstrapData, List <GDTrack> tracks) { // When starting this, tracks contains only GDDA tracks (for SDA: only 1 audio track, for HDA: all GDDA if any) long currentBytes = 0; long totalBytes = isoStream.Length; int skip = 0; int currentLBA = isSingleDensityArea ? SINGLE_DENSITY_AREA_LBA_START : HIGH_DENSITY_AREA_LBA_START; bool isHighDensityAreaMultiDataTrack = !isSingleDensityArea && HighDensityDataTrackSplitted; string dataTrackFileFirstPath = isSingleDensityArea ? _singleDensityAreaDataTrackPath : _highDensityAreaDataTrackFirstPath; // for SDA/HDA string dataTrackFileLastPath = isSingleDensityArea ? string.Empty : _highDensityAreaDataTrackLastPath; // for HDA only // Retrive the real space occuped on the data track long lastHeaderEnd = 0; long firstFileStart = 0; foreach (BuilderExtent extent in isoStream.BuilderExtents) { if (extent is FileExtent) { firstFileStart = extent.Start; break; } else { lastHeaderEnd = extent.Start + GDImageUtility.RoundUp(extent.Length, DATA_SECTOR_SIZE); } } lastHeaderEnd /= DATA_SECTOR_SIZE; firstFileStart /= DATA_SECTOR_SIZE; // HDA: Single track is filling all the available space by default, if only one data track in HDA (computed below if HDA has GDDA) int trackEnd = HIGH_DENSITY_AREA_LBA_END - HIGH_DENSITY_AREA_LBA_START; // SDA: Computing trackEnd for the data track if (isSingleDensityArea) { // SDA: Single data track (track01) is filling the available space... after taken into account the SDA audio track long singleDensityAreaAudioTrackFileSize = tracks[0].FileSize; // When SDA, tracks[0] = SDA Audio Track (only 1 track) // Computing the space filled by the SDA audio track int singleDensityAreaAudioTrackSectorsSize = (int)(GDImageUtility.RoundUp(singleDensityAreaAudioTrackFileSize, RAW_SECTOR_SIZE) / RAW_SECTOR_SIZE); // So the SDA data track will fill this space... trackEnd = SINGLE_DENSITY_AREA_LBA_END - singleDensityAreaAudioTrackSectorsSize - TRACK_GAP_SECTOR_COUNT; /* FIXME */ // Updating the SDA audio track in consequence tracks[0].LBA = (uint)trackEnd + TRACK_GAP_SECTOR_COUNT; } if (isHighDensityAreaMultiDataTrack) { trackEnd = RecomputeAudioTracksLogicalBlockAddresses(tracks, HIGH_DENSITY_AREA_LBA_START, firstFileStart); if (trackEnd < lastHeaderEnd) { throw new Exception("Not enough room to fit all of the CDDA after we added the data."); } // trackEnd: HDA when multi tracks: computed with GDDA } long firstTrackFileSize = trackEnd * DATA_SECTOR_SIZE; // Applied for SDA data track and HDA first data track if (TruncateData) { long firstTrackSectorSize = (lastHeaderEnd > TRACK_MINIMUM_SECTOR_COUNT ? lastHeaderEnd : TRACK_MINIMUM_SECTOR_COUNT); RecomputeAudioTracksLogicalBlockAddresses(tracks, (uint)currentLBA, firstTrackSectorSize); firstTrackFileSize = firstTrackSectorSize * DATA_SECTOR_SIZE; } // Handle data track (SDA is track01, HDA is track03) GDTrack firstTrack = new GDTrack { FileName = Path.GetFileName(dataTrackFileFirstPath), FileSize = firstTrackFileSize, LBA = (uint)currentLBA, Type = GDTrackType.Data }; tracks.Insert(0, firstTrack); // the first data track is at the beginning of the area // Handle last data track for HDA (if applicable) GDTrack lastTrack = null; if (isHighDensityAreaMultiDataTrack) { lastTrack = new GDTrack { FileName = Path.GetFileName(dataTrackFileLastPath), FileSize = (HIGH_DENSITY_AREA_LBA_END - HIGH_DENSITY_AREA_LBA_START - firstFileStart) * DATA_SECTOR_SIZE, LBA = (uint)(HIGH_DENSITY_AREA_LBA_START + firstFileStart), Type = GDTrackType.Data }; tracks.Add(lastTrack); } // Update the TOC in the IP.BIN for the HDA if (!isSingleDensityArea) { GDImageUtility.UpdateBootstrapTableOfContents(bootstrapData, tracks); } // Initialize stream variables byte[] buffer = new byte[DATA_SECTOR_SIZE]; int numRead = 0; long bytesWritten = 0; // Write first (or single) data track using (FileStream destStream = new FileStream(dataTrackFileFirstPath, FileMode.Create, FileAccess.Write)) { // Write Bootsector data in the first sector bytesWritten = GDImageWriteHelper.WriteBootSector(RawMode, isoStream, destStream, buffer, ref currentLBA, ref currentBytes, bootstrapData); numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0 && bytesWritten < firstTrack.FileSize) { GDImageWriteHelper.WriteSector(RawMode, isoStream, destStream, buffer, ref currentLBA, ref numRead); numRead = isoStream.Read(buffer, 0, buffer.Length); bytesWritten += numRead; currentBytes += numRead; skip = NotifyProgress(currentBytes, totalBytes, skip); } } // Write last data track (if any) if (isHighDensityAreaMultiDataTrack) { currentLBA = (int)lastTrack.LBA; using (FileStream destStream = new FileStream(dataTrackFileLastPath, FileMode.Create, FileAccess.Write)) { currentBytes = firstFileStart * DATA_SECTOR_SIZE; isoStream.Seek(currentBytes, SeekOrigin.Begin); numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0) { GDImageWriteHelper.WriteSector(RawMode, isoStream, destStream, buffer, ref currentLBA, ref numRead); numRead = isoStream.Read(buffer, 0, buffer.Length); currentBytes += numRead; skip = NotifyProgress(currentBytes, totalBytes, skip); } } } }