private void GenPathTableEx(IsoFolder parentFolder, IsoFolder thisFolder, bool lsb)
        {
            var di = new FieldValidator(this.generator);

            // Path table record ( ECMA-119 section 9.4 )
            byte[] b_di = this.generator.IsoName(thisFolder.Name, true);
            di.Byte((byte)b_di.Length, 1);
            di.Byte(0, 2);             // Extended Attribute Record Length
            if (lsb)
            {
                di.IntLSB(thisFolder.DataBlock, 3, 6);                 // Location of Extent
                di.ShortLSB(parentFolder.PathTableEntry, 7, 8);        // Parent Directory Number
            }
            else
            {
                di.IntMSB(thisFolder.DataBlock, 3, 6);          // Location of Extent
                di.ShortMSB(parentFolder.PathTableEntry, 7, 8); // Parent Directory Number
            }
            di.Bytes(b_di, 9, 8 + b_di.Length);                 // Directory Identifier
            if ((b_di.Length & 1) != 0)
            {
                di.Byte(0, 9 + b_di.Length);                 // optional padding if LEN_DI is odd
            }
            foreach (KeyValuePair <string, IsoEntry> it in thisFolder.entries)
            {
                if (it.Value.IsFolder)
                {
                    GenPathTableEx(thisFolder, (IsoFolder)it.Value, lsb);
                }
            }
        }
        private void GenVolumeDescriptorTerminator()         // ISO 9660 - 8.3
        {
            var vdt = new FieldValidator(this.generator);

            vdt.Byte(255, 1);           // Volume Descriptor Type ( 8.3.1 )
            vdt.AString("CD001", 2, 6); // Standard Identifier ( 8.4.2 )
            vdt.Byte(1, 7);             // Volume Descriptor Version ( 8.4.3 )
            this.generator.FinishBlock();
        }
        private void GenBootRecordDescriptor()         // ( ISO 9660 - 8.2, El Torito Figure 7 )
        {
            var br = new FieldValidator(this.generator);

            br.Byte(0, 1);                                // Volume Descriptor Type ( 8.2.1 ), Boot Record Indicator - must be 0 ( offset 0x00 )
            br.AString("CD001", 2, 6);                    // Standard Identifier ( 8.2.2 ), ( offset 0x01-0x05 )
            br.Byte(1, 7);                                // Volume Descriptor Version ( 8.2.3 ), must be 1 for El Torito also ( offset 0x06 )
            br.AString("EL TORITO SPECIFICATION", 8, 39); // Boot System Identifier ( 8.2.4 ), ( offset 0x07-0x26 )
            br.Zero(40, 71);                              // Boot Identifier ( 8.2.5 ), Unused - must be 0 ( offset 0x27-0x46 )
            br.IntLSB(BootCatalog, 72, 75);               // Boot System Use ( 8.2.6 ), Absolute Pointer to first sector of Boot Catalog ( offset 0x47-0x4A )
            this.generator.FinishBlock();
        }
        private void GenContinuationBlock()
        {
            ContinuationBlock  = this.generator.Index / LogicalBlockSize;
            ContinuationLength = -this.generator.Index;             // HACK ALERT: we will add the final offset when done, and that will give us the length

            // ER - Extensions Reference - see P1281 section 5.5
            byte[] b_id  = this.generator.Ascii.GetBytes("RRIP_1991A");            // I can't find documentation anywhere for these values, but they came from an ISO I analyzed.
            byte[] b_des = this.generator.Ascii.GetBytes("THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS");
            byte[] b_src = this.generator.Ascii.GetBytes("PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.");
            var    er    = new FieldValidator(this.generator);

            er.Byte((byte)'E', 1);
            er.Byte((byte)'R', 2);
            System.Diagnostics.Debug.Assert((9 + b_id.Length + b_des.Length + b_src.Length) < 256);
            er.Byte((byte)(8 + b_id.Length + b_des.Length + b_src.Length), 3);
            er.Byte(1, 4);             // version
            er.Byte((byte)b_id.Length, 5);
            er.Byte((byte)b_des.Length, 6);
            er.Byte((byte)b_src.Length, 7);
            er.Byte(1, 8);             // extension version ( got this value from peeking at another ISO file )
            er.Bytes(b_id, 9, 9 + b_id.Length - 1);
            er.Bytes(b_des, 9 + b_id.Length, 9 + b_id.Length + b_des.Length - 1);
            er.Bytes(b_src, 9 + b_id.Length + b_des.Length, 9 + b_id.Length + b_des.Length + b_src.Length - 1);

            ContinuationLength += this.generator.Index;
            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();
        }
        private void GenPrimaryVolumeDescriptor()         // ( 8.4 )
        {
            PrimaryVolumeDescriptor = this.generator.Index / LogicalBlockSize;
            var pvd = new FieldValidator(this.generator);

            pvd.Byte(1, 1);                                                               // Volume Descriptor Type ( 8.4.1 )
            pvd.AString("CD001", 2, 6);                                                   // Standard Identifier ( 8.4.2 )
            pvd.Byte(1, 7);                                                               // Volume Descriptor Version ( 8.4.3 )
            pvd.Zero(8, 8);                                                               // Unused Field ( 8.4.4 )
            pvd.AString("?", 9, 40);                                                      // System Identifier ( 8.4.5 )
            pvd.DString(this.volumeLabel, 41, 72);                                        // Volume Identifier ( 8.4.6 )
            pvd.Zero(73, 80);                                                             // Unused Field ( 8.4.7 )
            pvd.IntLSBMSB((TotalSize + LogicalBlockSize - 1) / LogicalBlockSize, 81, 88); // Volume Space Size ( 8.4.8 )
            pvd.Zero(89, 120);                                                            // Unused Field ( 8.4.9 )
            pvd.ShortLSBMSB(1, 121, 124);                                                 // Volume Set Size ( 8.4.10 )
            pvd.ShortLSBMSB(1, 125, 128);                                                 // Volume Sequence Number ( 8.4.11 )
            pvd.ShortLSBMSB(LogicalBlockSize, 129, 132);                                  // Logical Block Size ( 8.4.12 )
            pvd.IntLSBMSB(PathTableSize, 133, 140);                                       // Path Table Size ( 8.4.13 )
            pvd.IntLSB(LPathTable, 141, 144);                                             // L Path Table ( 8.4.14 )
            pvd.IntLSB(0, 145, 148);                                                      // Optional L Path Table ( 8.4.15 )
            pvd.IntMSB(MPathTable, 149, 152);                                             // M Path Table ( 8.4.16 )
            pvd.IntMSB(0, 153, 156);                                                      // Optional M Path Table ( 8.4.17 )
            pvd.BeginField(157);
            DirectoryRecord(".", this.isoRoot, 1);                                        // Directory Record for Root Directory ( 8.4.18 )
            pvd.EndField(190);
            pvd.DupByte(0x20, 191, 318);                                                  // Volume Set Identifier ( 8.4.19 )
            pvd.DupByte(0x20, 319, 446);                                                  // Publisher Identifier ( 8.4.20 )
            pvd.DupByte(0x20, 447, 574);                                                  // Data Preparer ( 8.4.21 )
            pvd.DupByte(0x20, 575, 702);                                                  // Application Identifier ( 8.4.22 )
            pvd.DupByte(0x20, 703, 739);                                                  // Copyright File Identifier ( 8.4.23 )
            pvd.DupByte(0x20, 740, 776);                                                  // Abstract File Identifier ( 8.4.24 )
            pvd.DupByte(0x20, 777, 813);                                                  // Bibliographic File Identifier ( 8.4.25 )
            System.DateTime now = System.DateTime.Now;
            pvd.AnsiDateTime(now, 814, 830);                                              // Volume Creation Date and Time ( 8.4.26 )
            pvd.AnsiDateTime(now, 831, 847);                                              // Volume Modification Date and Time ( 8.4.27 )
            pvd.Zero(848, 864);                                                           // Volume Expiration Date and Time ( 8.4.28 )
            pvd.Zero(865, 881);                                                           // Volume Effective Date and Time ( 8.4.29 )
            pvd.Byte(1, 882);                                                             // File Structure Version ( 8.4.30 )
            pvd.Zero(883, 883);                                                           // Reserved ( 8.4.31 )
            pvd.Zero(884, 1395);                                                          // Application Use ( 8.4.32 )
            pvd.Zero(1396, 2048);                                                         // Reserved for Future Standardization ( 8.4.33 )
        }
Beispiel #7
0
        public void BinaryDateTime(System.DateTime d, int start, int end)         // ( 9.1.5 )
        {
            BeginField(start);
            var dt = new FieldValidator(this.generator);

            dt.Byte((byte)(d.Year - 1900), 1);
            dt.Byte((byte)d.Month, 2);
            dt.Byte((byte)d.Day, 3);
            dt.Byte((byte)d.Hour, 4);
            dt.Byte((byte)d.Minute, 5);
            dt.Byte((byte)d.Second, 6);
            dt.Byte(0, 7);             // TODO FIXME - unsure about how to encode time zone exactly... :(
            EndField(end);
        }
Beispiel #8
0
		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;
		}
Beispiel #9
0
		private void GenContinuationBlock()
		{
			ContinuationBlock = this.generator.Index / LogicalBlockSize;
			ContinuationLength = -this.generator.Index; // HACK ALERT: we will add the final offset when done, and that will give us the length

			// ER - Extensions Reference - see P1281 section 5.5
			byte[] b_id = this.generator.Ascii.GetBytes("RRIP_1991A"); // I can't find documentation anywhere for these values, but they came from an ISO I analyzed.
			byte[] b_des = this.generator.Ascii.GetBytes("THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS");
			byte[] b_src = this.generator.Ascii.GetBytes("PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.");
			var er = new FieldValidator(this.generator);
			er.Byte((byte)'E', 1);
			er.Byte((byte)'R', 2);
			System.Diagnostics.Debug.Assert((9 + b_id.Length + b_des.Length + b_src.Length) < 256);
			er.Byte((byte)(8 + b_id.Length + b_des.Length + b_src.Length), 3);
			er.Byte(1, 4); // version
			er.Byte((byte)b_id.Length, 5);
			er.Byte((byte)b_des.Length, 6);
			er.Byte((byte)b_src.Length, 7);
			er.Byte(1, 8); // extension version ( got this value from peeking at another ISO file )
			er.Bytes(b_id, 9, 9 + b_id.Length - 1);
			er.Bytes(b_des, 9 + b_id.Length, 9 + b_id.Length + b_des.Length - 1);
			er.Bytes(b_src, 9 + b_id.Length + b_des.Length, 9 + b_id.Length + b_des.Length + b_src.Length - 1);

			ContinuationLength += this.generator.Index;
			this.generator.FinishBlock();
		}
Beispiel #10
0
		private void GenPathTableEx(IsoFolder parentFolder, IsoFolder thisFolder, bool lsb)
		{
			var di = new FieldValidator(this.generator);
			// Path table record ( ECMA-119 section 9.4 )
			byte[] b_di = this.generator.IsoName(thisFolder.Name, true);
			di.Byte((byte)b_di.Length, 1);
			di.Byte(0, 2); // Extended Attribute Record Length
			if (lsb) {
				di.IntLSB(thisFolder.DataBlock, 3, 6); // Location of Extent
				di.ShortLSB(parentFolder.PathTableEntry, 7, 8); // Parent Directory Number
			}
			else {
				di.IntMSB(thisFolder.DataBlock, 3, 6); // Location of Extent
				di.ShortMSB(parentFolder.PathTableEntry, 7, 8); // Parent Directory Number
			}
			di.Bytes(b_di, 9, 8 + b_di.Length); // Directory Identifier
			if ((b_di.Length & 1) != 0)
				di.Byte(0, 9 + b_di.Length); // optional padding if LEN_DI is odd

			foreach (KeyValuePair<string, IsoEntry> it in thisFolder.entries)
				if (it.Value.IsFolder)
					GenPathTableEx(thisFolder, (IsoFolder)it.Value, lsb);
		}
Beispiel #11
0
		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();
		}
Beispiel #12
0
		private void GenBootRecordDescriptor() // ( ISO 9660 - 8.2, El Torito Figure 7 )
		{
			var br = new FieldValidator(this.generator);
			br.Byte(0, 1); // Volume Descriptor Type ( 8.2.1 ), Boot Record Indicator - must be 0 ( offset 0x00 )
			br.AString("CD001", 2, 6); // Standard Identifier ( 8.2.2 ), ( offset 0x01-0x05 )
			br.Byte(1, 7); // Volume Descriptor Version ( 8.2.3 ), must be 1 for El Torito also ( offset 0x06 )
			br.AString("EL TORITO SPECIFICATION", 8, 39); // Boot System Identifier ( 8.2.4 ), ( offset 0x07-0x26 )
			br.Zero(40, 71); // Boot Identifier ( 8.2.5 ), Unused - must be 0 ( offset 0x27-0x46 )
			br.IntLSB(BootCatalog, 72, 75); // Boot System Use ( 8.2.6 ), Absolute Pointer to first sector of Boot Catalog ( offset 0x47-0x4A )
			this.generator.FinishBlock();
		}
Beispiel #13
0
		private void GenVolumeDescriptorTerminator() // ISO 9660 - 8.3
		{
			var vdt = new FieldValidator(this.generator);
			vdt.Byte(255, 1); // Volume Descriptor Type ( 8.3.1 )
			vdt.AString("CD001", 2, 6); // Standard Identifier ( 8.4.2 )
			vdt.Byte(1, 7); // Volume Descriptor Version ( 8.4.3 )
			this.generator.FinishBlock();
		}
Beispiel #14
0
		private void GenPrimaryVolumeDescriptor() // ( 8.4 )
		{
			PrimaryVolumeDescriptor = this.generator.Index / LogicalBlockSize;
			var pvd = new FieldValidator(this.generator);
			pvd.Byte(1, 1); // Volume Descriptor Type ( 8.4.1 )
			pvd.AString("CD001", 2, 6); // Standard Identifier ( 8.4.2 )
			pvd.Byte(1, 7); // Volume Descriptor Version ( 8.4.3 )
			pvd.Zero(8, 8); // Unused Field ( 8.4.4 )
			pvd.AString("?", 9, 40); // System Identifier ( 8.4.5 )
			pvd.DString(this.volumeLabel, 41, 72); // Volume Identifier ( 8.4.6 )
			pvd.Zero(73, 80); // Unused Field ( 8.4.7 )
			pvd.IntLSBMSB((TotalSize + LogicalBlockSize - 1) / LogicalBlockSize, 81, 88); // Volume Space Size ( 8.4.8 )
			pvd.Zero(89, 120); // Unused Field ( 8.4.9 )
			pvd.ShortLSBMSB(1, 121, 124); // Volume Set Size ( 8.4.10 )
			pvd.ShortLSBMSB(1, 125, 128); // Volume Sequence Number ( 8.4.11 )
			pvd.ShortLSBMSB(LogicalBlockSize, 129, 132); // Logical Block Size ( 8.4.12 )
			pvd.IntLSBMSB(PathTableSize, 133, 140); // Path Table Size ( 8.4.13 )
			pvd.IntLSB(LPathTable, 141, 144); // L Path Table ( 8.4.14 )
			pvd.IntLSB(0, 145, 148); // Optional L Path Table ( 8.4.15 )
			pvd.IntMSB(MPathTable, 149, 152); // M Path Table ( 8.4.16 )
			pvd.IntMSB(0, 153, 156); // Optional M Path Table ( 8.4.17 )
			pvd.BeginField(157);
			DirectoryRecord(".", this.isoRoot, 1); // Directory Record for Root Directory ( 8.4.18 )
			pvd.EndField(190);
			pvd.DupByte(0x20, 191, 318); // Volume Set Identifier ( 8.4.19 )
			pvd.DupByte(0x20, 319, 446); // Publisher Identifier ( 8.4.20 )
			pvd.DupByte(0x20, 447, 574); // Data Preparer ( 8.4.21 )
			pvd.DupByte(0x20, 575, 702); // Application Identifier ( 8.4.22 )
			pvd.DupByte(0x20, 703, 739); // Copyright File Identifier ( 8.4.23 )
			pvd.DupByte(0x20, 740, 776); // Abstract File Identifier ( 8.4.24 )
			pvd.DupByte(0x20, 777, 813); // Bibliographic File Identifier ( 8.4.25 )
			System.DateTime now = System.DateTime.Now;
			pvd.AnsiDateTime(now, 814, 830); // Volume Creation Date and Time ( 8.4.26 )
			pvd.AnsiDateTime(now, 831, 847); // Volume Modification Date and Time ( 8.4.27 )
			pvd.Zero(848, 864); // Volume Expiration Date and Time ( 8.4.28 )
			pvd.Zero(865, 881); // Volume Effective Date and Time ( 8.4.29 )
			pvd.Byte(1, 882); // File Structure Version ( 8.4.30 )
			pvd.Zero(883, 883); // Reserved ( 8.4.31 )
			pvd.Zero(884, 1395); // Application Use ( 8.4.32 )
			pvd.Zero(1396, 2048); // Reserved for Future Standardization ( 8.4.33 )
		}
        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);
        }
		public void BinaryDateTime(System.DateTime d, int start, int end) // ( 9.1.5 )
		{
			BeginField(start);
			var dt = new FieldValidator(this.generator);
			dt.Byte((byte)(d.Year - 1900), 1);
			dt.Byte((byte)d.Month, 2);
			dt.Byte((byte)d.Day, 3);
			dt.Byte((byte)d.Hour, 4);
			dt.Byte((byte)d.Minute, 5);
			dt.Byte((byte)d.Second, 6);
			dt.Byte(0, 7); // TODO FIXME - unsure about how to encode time zone exactly... :(
			EndField(end);
		}