public static void WriteSector(bool isRawMode, BuiltStream isoStream, FileStream destStream, byte[] buffer, ref int currentLBA, ref int numRead) { if (isRawMode) { byte[] resultSector; while (numRead != 0 && numRead < buffer.Length) { // We need all 2048 bytes for a complete sector! int localRead = isoStream.Read(buffer, numRead, buffer.Length - numRead); numRead += localRead; if (localRead == 0) { for (int i = numRead; i < buffer.Length; i++) { buffer[i] = 0; } break; // Prevent infinite loop } } resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); } else { destStream.Write(buffer, 0, numRead); } }
private void BuildSingleDensityArea() { CDBuilder builder = NewCDBuilderInstance(SINGLE_DENSITY_AREA_LBA_START, SINGLE_DENSITY_AREA_LBA_END); byte[] ip0000Data = GDImageUtility.LoadBootstrapInMemory(SingleDensityArea.BootstrapFilePath); _singleDensityAreaBootstrapFileName = GDImageUtility.GetBootBinaryFileName(ip0000Data); // Handle track02 List <string> cdda = new List <string> { _singleDensityAreaAudioTrackPath }; _singleDensityAreaTracks.AddRange(ReadCDDA(cdda)); // Handle track01 DirectoryInfo di = new DirectoryInfo(SingleDensityArea.SourceDataDirectory); PopulateFromDirectory(builder, di, di.FullName, null, SINGLE_DENSITY_AREA_LBA_END); using (BuiltStream isoStream = (BuiltStream)builder.Build()) { _lastProgress = 0; WriteDataTrack(true, isoStream, ip0000Data, _singleDensityAreaTracks); } }
public void BuildStreamLengthIsRespected() { int length = 1024; var extent = new BuilderSparseStreamExtent(0, new ZeroStream(2 * length)); using (var stream = new BuiltStream(length, new List <BuilderExtent> { extent })) { Assert.Equal(0, stream.Position); Assert.Equal(length, stream.Length); var content = new byte[2 * length]; var read = stream.Read(content, 0, content.Length); Assert.Equal(length, read); Assert.Equal(stream.Length, stream.Position); } }
private void ExportSingleTrack(BuiltStream isoStream, byte[] ipbinData, List <DiscTrack> tracks) { long currentBytes = 0; long totalBytes = isoStream.Length; int skip = 0; DiscTrack track3 = new DiscTrack(); track3.FileName = Path.GetFileName(Track03Path); track3.LBA = GD_START_LBA; track3.Type = 4; track3.FileSize = (GD_END_LBA - GD_START_LBA) * DATA_SECTOR_SIZE; tracks.Add(track3); UpdateIPBIN(ipbinData, tracks); using (FileStream destStream = new FileStream(Track03Path, FileMode.Create, FileAccess.Write)) { destStream.Write(ipbinData, 0, ipbinData.Length); isoStream.Seek(ipbinData.Length, SeekOrigin.Begin); currentBytes += ipbinData.Length; byte[] buffer = new byte[64 * 1024]; int numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0) { destStream.Write(buffer, 0, numRead); numRead = isoStream.Read(buffer, 0, buffer.Length); currentBytes += numRead; skip++; if (skip >= 10) { skip = 0; int percent = (int)((currentBytes * 100) / totalBytes); if (percent > _lastProgress) { _lastProgress = percent; if (ReportProgress != null) { ReportProgress(_lastProgress); } } } } } }
private void BuildHighDensityArea() { CDBuilder builder = NewCDBuilderInstance(HIGH_DENSITY_AREA_LBA_START, HIGH_DENSITY_AREA_LBA_END); byte[] ipbinData = GDImageUtility.LoadBootstrapInMemory(HighDensityArea.BootstrapFilePath); _highDensityAreaBootstrapFileName = GDImageUtility.GetBootBinaryFileName(ipbinData); DirectoryInfo di = new DirectoryInfo(HighDensityArea.SourceDataDirectory); PopulateFromDirectory(builder, di, di.FullName, _highDensityAreaBootstrapFileName, HIGH_DENSITY_AREA_LBA_END); // Handle GDDA _highDensityAreaTracks.AddRange(ReadCDDA(_gddaTrackPaths)); // Handle Data Tracks using (BuiltStream isoStream = (BuiltStream)builder.Build()) { _lastProgress = 0; WriteDataTrack(false, isoStream, ipbinData, _highDensityAreaTracks); } }
public static long WriteBootSector(bool isRawMode, BuiltStream isoStream, FileStream destStream, byte[] buffer, ref int currentLBA, ref long currentBytes, byte[] bootstrapData) { if (isRawMode) { byte[] resultSector; for (int i = 0; i < bootstrapData.Length; i += buffer.Length) { Array.Copy(bootstrapData, i, buffer, 0, buffer.Length); resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); currentBytes += buffer.Length; } } else { destStream.Write(bootstrapData, 0, bootstrapData.Length); } isoStream.Seek(bootstrapData.Length, SeekOrigin.Begin); return((long)bootstrapData.Length); // bytesWritten }
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); } } } }
public List <DiscTrack> BuildGDROM(string data, string ipbin, List <string> cdda) { string bootBin; byte[] ipbinData = new byte[0x8000]; CDBuilder builder = new CDBuilder(); builder.VolumeIdentifier = VolumeIdentifier; builder.SystemIdentifier = SystemIdentifier; builder.VolumeSetIdentifier = VolumeSetIdentifier; builder.PublisherIdentifier = PublisherIdentifier; builder.DataPreparerIdentifier = DataPreparerIdentifier; builder.ApplicationIdentifier = ApplicationIdentifier; builder.UseJoliet = false; //A stupid default, mkisofs won't do this by default. builder.LBAoffset = GD_START_LBA; builder.EndSector = GD_END_LBA; using (FileStream ipfs = new FileStream(ipbin, FileMode.Open, FileAccess.Read, FileShare.Read)) { if (ipfs.Length != ipbinData.Length) { throw new Exception("IP.BIN is the wrong size. Possibly the wrong file? Cannot continue."); } bootBin = GetBootBin(ipfs); ipfs.Seek(0, SeekOrigin.Begin); ipfs.Read(ipbinData, 0, ipbinData.Length); } List <DiscTrack> retval = new List <DiscTrack>(); if (cdda != null && cdda.Count > 0) { retval = ReadCDDA(cdda); } DirectoryInfo di = new DirectoryInfo(data); PopulateFromFolder(builder, di, di.FullName, bootBin); using (BuiltStream isoStream = (BuiltStream)builder.Build()) { _lastProgress = 0; if (retval.Count > 0 || (TruncateData && !string.IsNullOrEmpty(LastTrackPath))) { if (RawMode) { ExportMultiTrackRaw(isoStream, ipbinData, retval); } else { ExportMultiTrack(isoStream, ipbinData, retval); } } else { if (RawMode) { ExportSingleTrackRaw(isoStream, ipbinData, retval); } else { ExportSingleTrack(isoStream, ipbinData, retval); } } } return(retval); }
private void ExportMultiTrackRaw(BuiltStream isoStream, byte[] ipbinData, List <DiscTrack> tracks) { //There is a 150 sector gap before and after the CDDA long lastHeaderEnd = 0; long firstFileStart = 0; foreach (BuilderExtent extent in isoStream.BuilderExtents) { if (extent is FileExtent) { firstFileStart = extent.Start; break; } else { lastHeaderEnd = extent.Start + RoundUp(extent.Length, DATA_SECTOR_SIZE); } } lastHeaderEnd = lastHeaderEnd / DATA_SECTOR_SIZE; firstFileStart = firstFileStart / DATA_SECTOR_SIZE; int trackEnd = (int)(firstFileStart - 150); for (int i = tracks.Count - 1; i >= 0; i--) { trackEnd = trackEnd - (int)(RoundUp(tracks[i].FileSize, RAW_SECTOR_SIZE) / RAW_SECTOR_SIZE); //Track end is now the beginning of this track and the end of the previous tracks[i].LBA = (uint)(trackEnd + GD_START_LBA); } trackEnd = trackEnd - 150; if (trackEnd < lastHeaderEnd) { throw new Exception("Not enough room to fit all of the CDDA after we added the data."); } if (TruncateData) { trackEnd = (int)lastHeaderEnd; } DiscTrack track3 = new DiscTrack(); track3.FileName = Path.GetFileName(Track03Path); track3.LBA = GD_START_LBA; track3.Type = 4; track3.FileSize = trackEnd * DATA_SECTOR_SIZE; tracks.Insert(0, track3); DiscTrack lastTrack = new DiscTrack(); lastTrack.FileName = GetLastTrackName(tracks.Count - 1); lastTrack.FileSize = (GD_END_LBA - GD_START_LBA - firstFileStart) * DATA_SECTOR_SIZE; lastTrack.LBA = (uint)(GD_START_LBA + firstFileStart); lastTrack.Type = 4; tracks.Add(lastTrack); UpdateIPBIN(ipbinData, tracks); long currentBytes = 0; long totalBytes = isoStream.Length; int skip = 0; int currentLBA = GD_START_LBA; using (FileStream destStream = new FileStream(Track03Path, FileMode.Create, FileAccess.Write)) { byte[] buffer = new byte[DATA_SECTOR_SIZE]; byte[] resultSector; for (int i = 0; i < ipbinData.Length; i += buffer.Length) { Array.Copy(ipbinData, i, buffer, 0, buffer.Length); resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); currentBytes += 2048; } isoStream.Seek(ipbinData.Length, SeekOrigin.Begin); long bytesWritten = (long)ipbinData.Length; int numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0 && bytesWritten < track3.FileSize) { while (numRead != 0 && numRead < buffer.Length) { //We need all 2048 bytes for a complete sector! int localRead = isoStream.Read(buffer, numRead, buffer.Length - numRead); numRead += localRead; if (localRead == 0) { for (int i = numRead; i < buffer.Length; i++) { buffer[i] = 0; } break; //Prevent infinite loop } } resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); numRead = isoStream.Read(buffer, 0, buffer.Length); bytesWritten += numRead; currentBytes += numRead; skip++; if (skip >= 50) { skip = 0; int percent = (int)((currentBytes * 100) / totalBytes); if (percent > _lastProgress) { _lastProgress = percent; if (ReportProgress != null) { ReportProgress(_lastProgress); } } } } } currentLBA = (int)lastTrack.LBA; using (FileStream destStream = new FileStream(LastTrackPath, FileMode.Create, FileAccess.Write)) { byte[] buffer = new byte[DATA_SECTOR_SIZE]; byte[] resultSector; currentBytes = firstFileStart * DATA_SECTOR_SIZE; isoStream.Seek(currentBytes, SeekOrigin.Begin); int numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0) { while (numRead != 0 && numRead < buffer.Length) { //We need all 2048 bytes for a complete sector! int localRead = isoStream.Read(buffer, numRead, buffer.Length - numRead); numRead += localRead; if (localRead == 0) { for (int i = numRead; i < buffer.Length; i++) { buffer[i] = 0; } break; //Prevent infinite loop } } resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); numRead = isoStream.Read(buffer, 0, buffer.Length); currentBytes += numRead; skip++; if (skip >= 10) { skip = 0; int percent = (int)((currentBytes * 100) / totalBytes); if (percent > _lastProgress) { _lastProgress = percent; if (ReportProgress != null) { ReportProgress(_lastProgress); } } } } } }
/// <summary> /// Separate raw logic to maintain performance of the 2048 version /// </summary> private void ExportSingleTrackRaw(BuiltStream isoStream, byte[] ipbinData, List <DiscTrack> tracks) { long currentBytes = 0; long totalBytes = isoStream.Length; int skip = 0; DiscTrack track3 = new DiscTrack(); track3.FileName = Path.GetFileName(Track03Path); track3.LBA = GD_START_LBA; track3.Type = 4; track3.FileSize = (GD_END_LBA - GD_START_LBA) * DATA_SECTOR_SIZE; tracks.Add(track3); UpdateIPBIN(ipbinData, tracks); using (FileStream destStream = new FileStream(Track03Path, FileMode.Create, FileAccess.Write)) { int currentLBA = GD_START_LBA; byte[] buffer = new byte[DATA_SECTOR_SIZE]; byte[] resultSector; for (int i = 0; i < ipbinData.Length; i += buffer.Length) { Array.Copy(ipbinData, i, buffer, 0, buffer.Length); resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); currentBytes += 2048; } isoStream.Seek(ipbinData.Length, SeekOrigin.Begin); int numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0) { while (numRead != 0 && numRead < buffer.Length) { //We need all 2048 bytes for a complete sector! int localRead = isoStream.Read(buffer, numRead, buffer.Length - numRead); numRead += localRead; if (localRead == 0) { for (int i = numRead; i < buffer.Length; i++) { buffer[i] = 0; } break; //Prevent infinite loop } } resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); numRead = isoStream.Read(buffer, 0, buffer.Length); currentBytes += numRead; skip++; if (skip >= 10) { skip = 0; int percent = (int)((currentBytes * 100) / totalBytes); if (percent > _lastProgress) { _lastProgress = percent; if (ReportProgress != null) { ReportProgress(_lastProgress); } } } } } }
/// <summary> /// Separate raw logic to maintain performance of the 2048 version /// </summary> private void ExportSingleTrackRaw(BuiltStream isoStream, byte[] ipbinData, List<DiscTrack> tracks) { long currentBytes = 0; long totalBytes = isoStream.Length; int skip = 0; DiscTrack track3 = new DiscTrack(); track3.FileName = Path.GetFileName(Track03Path); track3.LBA = GD_START_LBA; track3.Type = 4; track3.FileSize = (GD_END_LBA - GD_START_LBA) * DATA_SECTOR_SIZE; tracks.Add(track3); UpdateIPBIN(ipbinData, tracks); using (FileStream destStream = new FileStream(Track03Path, FileMode.Create, FileAccess.Write)) { int currentLBA = GD_START_LBA; byte[] buffer = new byte[DATA_SECTOR_SIZE]; byte[] resultSector; for (int i = 0; i < ipbinData.Length; i += buffer.Length) { Array.Copy(ipbinData, i, buffer, 0, buffer.Length); resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); currentBytes += 2048; } isoStream.Seek(ipbinData.Length, SeekOrigin.Begin); int numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0) { while (numRead != 0 && numRead < buffer.Length) { //We need all 2048 bytes for a complete sector! int localRead = isoStream.Read(buffer, numRead, buffer.Length - numRead); numRead += localRead; if (localRead == 0) { for (int i = numRead; i < buffer.Length; i++) { buffer[i] = 0; } break; //Prevent infinite loop } } resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); numRead = isoStream.Read(buffer, 0, buffer.Length); currentBytes += numRead; skip++; if (skip >= 10) { skip = 0; int percent = (int)((currentBytes * 100) / totalBytes); if (percent > _lastProgress) { _lastProgress = percent; if (ReportProgress != null) { ReportProgress(_lastProgress); } } } } } }
private void ExportSingleTrack(BuiltStream isoStream, byte[] ipbinData, List<DiscTrack> tracks) { long currentBytes = 0; long totalBytes = isoStream.Length; int skip = 0; DiscTrack track3 = new DiscTrack(); track3.FileName = Path.GetFileName(Track03Path); track3.LBA = GD_START_LBA; track3.Type = 4; track3.FileSize = (GD_END_LBA - GD_START_LBA) * DATA_SECTOR_SIZE; tracks.Add(track3); UpdateIPBIN(ipbinData, tracks); using (FileStream destStream = new FileStream(Track03Path, FileMode.Create, FileAccess.Write)) { destStream.Write(ipbinData, 0, ipbinData.Length); isoStream.Seek(ipbinData.Length, SeekOrigin.Begin); currentBytes += ipbinData.Length; byte[] buffer = new byte[64 * 1024]; int numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0) { destStream.Write(buffer, 0, numRead); numRead = isoStream.Read(buffer, 0, buffer.Length); currentBytes += numRead; skip++; if (skip >= 10) { skip = 0; int percent = (int)((currentBytes*100) / totalBytes); if (percent > _lastProgress) { _lastProgress = percent; if(ReportProgress != null){ ReportProgress(_lastProgress); } } } } } }
private void ExportMultiTrackRaw(BuiltStream isoStream, byte[] ipbinData, List<DiscTrack> tracks) { //There is a 150 sector gap before and after the CDDA long lastHeaderEnd = 0; long firstFileStart = 0; foreach (BuilderExtent extent in isoStream.BuilderExtents) { if (extent is FileExtent) { firstFileStart = extent.Start; break; } else { lastHeaderEnd = extent.Start + RoundUp(extent.Length, DATA_SECTOR_SIZE); } } lastHeaderEnd = lastHeaderEnd / DATA_SECTOR_SIZE; firstFileStart = firstFileStart / DATA_SECTOR_SIZE; int trackEnd = (int)(firstFileStart - 150); for (int i = tracks.Count - 1; i >= 0; i--) { trackEnd = trackEnd - (int)(RoundUp(tracks[i].FileSize, RAW_SECTOR_SIZE) / RAW_SECTOR_SIZE); //Track end is now the beginning of this track and the end of the previous tracks[i].LBA = (uint)(trackEnd + GD_START_LBA); } trackEnd = trackEnd - 150; if (trackEnd < lastHeaderEnd) { throw new Exception("Not enough room to fit all of the CDDA after we added the data."); } if (TruncateData) { trackEnd = (int)lastHeaderEnd; } DiscTrack track3 = new DiscTrack(); track3.FileName = Path.GetFileName(Track03Path); track3.LBA = GD_START_LBA; track3.Type = 4; track3.FileSize = trackEnd * DATA_SECTOR_SIZE; tracks.Insert(0, track3); DiscTrack lastTrack = new DiscTrack(); lastTrack.FileName = GetLastTrackName(tracks.Count - 1); lastTrack.FileSize = (GD_END_LBA - GD_START_LBA - firstFileStart) * DATA_SECTOR_SIZE; lastTrack.LBA = (uint)(GD_START_LBA + firstFileStart); lastTrack.Type = 4; tracks.Add(lastTrack); UpdateIPBIN(ipbinData, tracks); long currentBytes = 0; long totalBytes = isoStream.Length; int skip = 0; int currentLBA = GD_START_LBA; using (FileStream destStream = new FileStream(Track03Path, FileMode.Create, FileAccess.Write)) { byte[] buffer = new byte[DATA_SECTOR_SIZE]; byte[] resultSector; for (int i = 0; i < ipbinData.Length; i += buffer.Length) { Array.Copy(ipbinData, i, buffer, 0, buffer.Length); resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); currentBytes += 2048; } isoStream.Seek(ipbinData.Length, SeekOrigin.Begin); long bytesWritten = (long)ipbinData.Length; int numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0 && bytesWritten < track3.FileSize) { while (numRead != 0 && numRead < buffer.Length) { //We need all 2048 bytes for a complete sector! int localRead = isoStream.Read(buffer, numRead, buffer.Length - numRead); numRead += localRead; if (localRead == 0) { for (int i = numRead; i < buffer.Length; i++) { buffer[i] = 0; } break; //Prevent infinite loop } } resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); numRead = isoStream.Read(buffer, 0, buffer.Length); bytesWritten += numRead; currentBytes += numRead; skip++; if (skip >= 50) { skip = 0; int percent = (int)((currentBytes * 100) / totalBytes); if (percent > _lastProgress) { _lastProgress = percent; if (ReportProgress != null) { ReportProgress(_lastProgress); } } } } } currentLBA = (int)lastTrack.LBA; using (FileStream destStream = new FileStream(LastTrackPath, FileMode.Create, FileAccess.Write)) { byte[] buffer = new byte[DATA_SECTOR_SIZE]; byte[] resultSector; currentBytes = firstFileStart * DATA_SECTOR_SIZE; isoStream.Seek(currentBytes, SeekOrigin.Begin); int numRead = isoStream.Read(buffer, 0, buffer.Length); while (numRead != 0) { while (numRead != 0 && numRead < buffer.Length) { //We need all 2048 bytes for a complete sector! int localRead = isoStream.Read(buffer, numRead, buffer.Length - numRead); numRead += localRead; if (localRead == 0) { for (int i = numRead; i < buffer.Length; i++) { buffer[i] = 0; } break; //Prevent infinite loop } } resultSector = SectorConversion.ConvertSectorToRawMode1(buffer, currentLBA++); destStream.Write(resultSector, 0, resultSector.Length); numRead = isoStream.Read(buffer, 0, buffer.Length); currentBytes += numRead; skip++; if (skip >= 10) { skip = 0; int percent = (int)((currentBytes * 100) / totalBytes); if (percent > _lastProgress) { _lastProgress = percent; if (ReportProgress != null) { ReportProgress(_lastProgress); } } } } } }