private void GenFile(IsoFile f) { f.DataBlock = this.generator.Index / LogicalBlockSize; f.DataLength = (int)f.fileInfo.Length; this.generator.WriteFile(f, PrimaryVolumeDescriptor); this.generator.FinishBlock(); }
private void GenBootCatalog(IsoFile f) { BootCatalog = this.generator.Index / LogicalBlockSize; // write validation entry first... see El Torito section 2.1 var ve = new FieldValidator(this.generator); ve.Byte(1, 1); // Header ID, must be 0x01 ve.Byte(0, 2); // 0 == x86 - TODO FIXME: 1 == PowerPC, 2 == Mac, see El Torito figure 2 ve.DupByte(0, 3, 4); // Reserved ve.DupByte(0, 5, 0x1C); // Manufacturer/Developer of CD-ROM, see El Torito figure 2 ve.ShortLSB(0x55AA, 0x1D, 0x1E); // checksum - TODO FIXME - allow custom Manufacturer string - calculate checksum dynamically ve.Byte(0x55, 0x1F); // 1st Key Byte ve.Byte(0xAA, 0x20); // 2nd Key Byte // initial/default entry... see El Torito section 2.2 and figure 3 var ide = new FieldValidator(this.generator); ide.Byte(0x88, 1); // 0x88 = bootable, 0x00 = not bootable // TODO FIXME - this is extremely hackish... fix me... ide.Byte(0, 2); // no emulation /*if ( f.fileInfo.Length <= 1182720 ) * ide.Byte(1, 2); // 1.2 meg diskette * else if ( f.fileInfo.Length <= 1440 * 1024 ) * ide.Byte(2,2); // 1.44 meg diskette * else if ( f.fileInfo.Length <= 2880 * 1024 ) * ide.Byte(3,2); // 2.88 meg diskette * else * ide.Byte(4,2);*/ // Hard Disk ( drive 80 ) ide.ShortLSB(0, 3, 4); // Load Segment - 0 == default of 0x7C0 ide.Byte(0, 5); // System Type, according to El Torito figure 3 this MUST be a copy of the "System Type" from the boot image. In practice this appears to not be the case. ide.Byte(0, 6); // Unused, must be 0 if (this.bootLoadSize == 0) { this.bootLoadSize = (short)((f.fileInfo.Length - 1) / 0x200 + 1); } ide.ShortLSB(this.bootLoadSize, 7, 8); // Sector Count ide.IntLSB(this.boot.DataBlock, 9, 12); // Logical Block of boot image ide.Zero(13, 32); // unused this.generator.FinishBlock(); }
/// <summary> /// writes a file out to cd. Generate the Boot Info Table if necessary /// </summary> /// <param Name="f">the file to write</param> /// <param Name="primaryVolumeDescriptor">the PVD block, passed in case we need to generate the Boot Info Table</param> public void WriteFile(IsoFile f, int primaryVolumeDescriptor) { if (f.fileInfo.Length > 0xffffffff) { throw new NotImplementedException(">4G files not implemented"); } int bytes = (int)f.fileInfo.Length; if (this.fs == null) { this.Index += bytes; return; } // TODO FIXME - create smaller reusable buffer and read fixed-size chunks at a time... byte[] b = new byte[bytes]; using (FileStream stream = f.fileInfo.OpenRead()) { if (bytes != stream.Read(b, 0, bytes)) { throw new Exception("number of bytes read from file != reported length of file: " + f.fileInfo.Name); } } if (f.BootInfoTable) { // TODO FIXME - this is TERRIBLE. This should be implemented at a higher level, and // doing it here requires passing the primaryVolumeDescriptor to every call of WriteFile() // The reason it is here is because this is the only place where the file actually gets // pulled into memory and I didn't want to modify the boot image on-disk like mkisofs does. Bytes(b, 0, 8); Bytes(ConvertTo.Int2LSB(primaryVolumeDescriptor)); Bytes(ConvertTo.Int2LSB(f.DataBlock)); Bytes(ConvertTo.Int2LSB((int)f.fileInfo.Length)); Bytes(ConvertTo.Int2LSB(0)); // TODO FIXME - checksum DupByte(0, 40); // reserved Bytes(b, 64, bytes - 64); } else { Bytes(b); } }
/// <summary> /// add a file to the ISO ( common implementation - called by AddFile() and AddBootFile() ) /// </summary> private IsoFile AddFileEx(string path, FileInfo fileInfo) { string key; string[] ar = NormalizePath(path).Split('/'); int i; IsoFolder f = this.isoRoot; for (i = 0; i < ar.Length - 1; i++) { key = ar[i].Trim().ToLower(); if (!f.entries.ContainsKey(key)) { var subf = new IsoFolder(); subf.Name = ar[i].Trim(); f.entries[key] = subf; } IsoEntry e = f.entries[key]; if (e.IsFile) { throw new Exception("cannot create directory \"" + ar[i].Trim() + "\", a file by that Name already exists"); //return; } f = (IsoFolder)e; } var x = new IsoFile(fileInfo); x.Name = ar[i].Trim(); key = ar[i].Trim().ToLower(); if (f.entries.ContainsKey(key)) { //throw new Exception("file or folder by that Name already exists"); return((IsoFile)f.entries[key]); // just don't add it for now... } f.entries[key] = x; return(x); }
private void GenFile(IsoFile f) { f.DataBlock = this.generator.Index / LogicalBlockSize; f.DataLength = (int)f.fileInfo.Length; this.generator.WriteFile(f, PrimaryVolumeDescriptor); this.generator.FinishBlock(); }
private void GenBootCatalog(IsoFile f) { BootCatalog = this.generator.Index / LogicalBlockSize; // write validation entry first... see El Torito section 2.1 var ve = new FieldValidator(this.generator); ve.Byte(1, 1); // Header ID, must be 0x01 ve.Byte(0, 2); // 0 == x86 - TODO FIXME: 1 == PowerPC, 2 == Mac, see El Torito figure 2 ve.DupByte(0, 3, 4); // Reserved ve.DupByte(0, 5, 0x1C); // Manufacturer/Developer of CD-ROM, see El Torito figure 2 ve.ShortLSB(0x55AA, 0x1D, 0x1E); // checksum - TODO FIXME - allow custom Manufacturer string - calculate checksum dynamically ve.Byte(0x55, 0x1F); // 1st Key Byte ve.Byte(0xAA, 0x20); // 2nd Key Byte // initial/default entry... see El Torito section 2.2 and figure 3 var ide = new FieldValidator(this.generator); ide.Byte(0x88, 1); // 0x88 = bootable, 0x00 = not bootable // TODO FIXME - this is extremely hackish... fix me... ide.Byte(0, 2); // no emulation /*if ( f.fileInfo.Length <= 1182720 ) ide.Byte(1, 2); // 1.2 meg diskette else if ( f.fileInfo.Length <= 1440 * 1024 ) ide.Byte(2,2); // 1.44 meg diskette else if ( f.fileInfo.Length <= 2880 * 1024 ) ide.Byte(3,2); // 2.88 meg diskette else ide.Byte(4,2);*/ // Hard Disk ( drive 80 ) ide.ShortLSB(0, 3, 4); // Load Segment - 0 == default of 0x7C0 ide.Byte(0, 5); // System Type, according to El Torito figure 3 this MUST be a copy of the "System Type" from the boot image. In practice this appears to not be the case. ide.Byte(0, 6); // Unused, must be 0 if (this.bootLoadSize == 0) this.bootLoadSize = (short)((f.fileInfo.Length - 1) / 0x200 + 1); ide.ShortLSB(this.bootLoadSize, 7, 8); // Sector Count ide.IntLSB(this.boot.DataBlock, 9, 12); // Logical Block of boot image ide.Zero(13, 32); // unused this.generator.FinishBlock(); }
/// <summary> /// add a file to the ISO ( common implementation - called by AddFile() and AddBootFile() ) /// </summary> private IsoFile AddFileEx(string path, FileInfo fileInfo) { string key; string[] ar = NormalizePath(path).Split('/'); int i; IsoFolder f = this.isoRoot; for (i = 0; i < ar.Length - 1; i++) { key = ar[i].Trim().ToLower(); if (!f.entries.ContainsKey(key)) { var subf = new IsoFolder(); subf.Name = ar[i].Trim(); f.entries[key] = subf; } IsoEntry e = f.entries[key]; if (e.IsFile) { throw new Exception("cannot create directory \"" + ar[i].Trim() + "\", a file by that Name already exists"); //return; } f = (IsoFolder)e; } var x = new IsoFile(fileInfo); x.Name = ar[i].Trim(); key = ar[i].Trim().ToLower(); if (f.entries.ContainsKey(key)) { //throw new Exception("file or folder by that Name already exists"); return (IsoFile)f.entries[key]; // just don't add it for now... } f.entries[key] = x; return x; }
/// <summary> /// writes a file out to cd. Generate the Boot Info Table if necessary /// </summary> /// <param Name="f">the file to write</param> /// <param Name="primaryVolumeDescriptor">the PVD block, passed in case we need to generate the Boot Info Table</param> public void WriteFile(IsoFile f, int primaryVolumeDescriptor) { if (f.fileInfo.Length > 0xffffffff) throw new NotImplementedException(">4G files not implemented"); int bytes = (int)f.fileInfo.Length; if (this.fs == null) { this.Index += bytes; return; } // TODO FIXME - create smaller reusable buffer and read fixed-size chunks at a time... byte[] b = new byte[bytes]; using (FileStream stream = f.fileInfo.OpenRead()) { if (bytes != stream.Read(b, 0, bytes)) throw new Exception("number of bytes read from file != reported length of file: " + f.fileInfo.Name); } if (f.BootInfoTable) { // TODO FIXME - this is TERRIBLE. This should be implemented at a higher level, and // doing it here requires passing the primaryVolumeDescriptor to every call of WriteFile() // The reason it is here is because this is the only place where the file actually gets // pulled into memory and I didn't want to modify the boot image on-disk like mkisofs does. Bytes(b, 0, 8); Bytes(ConvertTo.Int2LSB(primaryVolumeDescriptor)); Bytes(ConvertTo.Int2LSB(f.DataBlock)); Bytes(ConvertTo.Int2LSB((int)f.fileInfo.Length)); Bytes(ConvertTo.Int2LSB(0)); // TODO FIXME - checksum DupByte(0, 40); // reserved Bytes(b, 64, bytes - 64); } else Bytes(b); }
private string DirectoryRecordEx(byte[] fileName, string realName, IsoEntry e, byte root, bool secondPass) { byte[] /*b_fi,*/ b_su = null; /*if (fileName == ".") * { * b_fi = new byte[] { 0 }; * realName = ""; * } * else if (fileName == "..") * { * b_fi = new byte[] { 1 }; * realName = ""; * } * else * b_fi = generator.Ascii.GetBytes(fileName);*/ byte LEN_FI = (byte)fileName.Length; byte LEN_DR = (byte)(33 + LEN_FI); bool fi_padding = ((LEN_DR & 1) != 0); if (fi_padding) { LEN_DR++; } // as much as I HATE to do it, I have to generate this data in both passes for now. // I don't yet understand enough about what and how many DR entries have to be made to figure out how to do it "right" byte LEN_SU = 0; #if ROCKRIDGE if (root != 1) // don't generate susp on PVD's root entry... { b_su = Susp(ref realName, e, root == 2, secondPass, (byte)(255 - LEN_DR)); if (b_su.Length > 255) { throw new NotImplementedException("can't yet handle SUSP > 255 bytes"); } LEN_SU = (byte)b_su.Length; } else { realName = ""; } #endif LEN_DR += LEN_SU; var dr = new FieldValidator(this.generator); dr.Byte(LEN_DR, 1); // Length of Directory Record ( 9.1.1 ) dr.Byte(0, 2); // Extended Attribute Record Length ( 9.1.2 ) dr.IntLSBMSB(e.DataBlock, 3, 10); // Location of Extent ( 9.1.3 ) #if true // in this test - I round the data length up to the next multiple of 2048, didn't help fix my booting problem though... dr.IntLSBMSB(((e.DataLength - 1) / 2048 + 1) * 2048, 11, 18); // Data Length ( 9.1.4 ) #else dr.IntLSBMSB(e.DataLength, 11, 18); // Data Length ( 9.1.4 ) #endif dr.BinaryDateTime(System.DateTime.Now, 19, 25); // Recording Date and Time ( 9.1.5 ) byte flags = 0; if (e.IsFile) { IsoFile f = (IsoFile)e; if ((f.fileInfo.Attributes & FileAttributes.Hidden) != 0) { flags |= 1; // hidden } } else { // TODO FIXME - not supporting hidden folders right now //IsoFolder f = (IsoFolder)e; //if ((f.dirInfo.Attributes & DirectoryAttributes.Hidden) != 0) // flags |= 1; // hidden } if (e.IsFolder) { flags |= 2; // directory } #if false // I'm disabling this because analysing of a working ISO never sets this bit... if (real_name.Length == 0) { flags |= 128; // final } #endif dr.Byte(flags, 26); // flags ( 9.1.6 ) dr.Byte(0, 27); // File Unit Size ( 9.1.7 ) dr.Byte(0, 28); // Interleave Gap Size ( 9.1.8 ) dr.ShortLSBMSB(1, 29, 32); // Volume Sequence Number ( 9.1.9 ) dr.Byte(LEN_FI, 33); // Length of File Identifier ( 9.1.10 ) dr.Bytes(fileName, 34, 33 + LEN_FI); if (fi_padding) { dr.Zero(34 + LEN_FI, 34 + LEN_FI); } if (LEN_SU > 0) { dr.Bytes(b_su, LEN_DR - LEN_SU + 1, LEN_DR); } return(realName); }