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); } } } }