/* * BP Size in bytes Description * 1 1 Name size * 2 1 Extended Attribute record length * 3 4 Directory block address * 7 2 Parent Directory number * 9 n Directory file name */ public static List <CDIPathNode> ParsePathTable(Stream s, int PathTableSize) { EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; // Read the entire structure s.Read(buffer, 0, ISOFile.SECTOR_SIZE); int startCursor = 0; List <CDIPathNode> pathNodes = new List <CDIPathNode>(); int pad = 0; do { CDIPathNode node = new CDIPathNode(); byte[] data = bc.ReadBytes(buffer, startCursor, ISOFile.SECTOR_SIZE - startCursor); node.NameLength = data[0]; node.ExtendedAttribRecordLength = data[1]; node.DirectoryBlockAddress = bcBig.ReadIntValue(data, 2, 4); node.ParentDirectoryNumber = bcBig.ReadIntValue(data, 6, 2); node.Name = Encoding.ASCII.GetString(bc.ReadBytes(data, 8, data[0])); // if nameLength is odd a padding byte must be added if (node.NameLength % 2 != 0) { pad = 1; } pathNodes.Add(node); startCursor += node.NameLength + 8; } while (startCursor < PathTableSize + pad); return(pathNodes); }
public void ParseCDInteractive(Stream s) { /* From the Green Book Spec * BP (byte position) obviously is n+1 * * BP Size in Bytes Description * 1 1 Disc Label Record Type * 2 5 Volume Structure Standard ID * 7 1 Volume Structure Version number * 8 1 Volume flags * 9 32 System identifier * 41 32 Volume identifier * 73 12 Reserved * 85 4 Volume space size * 89 32 Coded Character Set identifier * 121 2 Reserved * 123 2 Number of Volumes in Album * 125 2 Reserved * 127 2 Album Set Sequence number * 129 2 Reserved * 131 2 Logical Block size * 133 4 Reserved * 137 4 Path Table size * 141 8 Reserved * 149 4 Address of Path Table * 153 38 Reserved * 191 128 Album identifier * 319 128 Publisher identifier * 447 128 Data Preparer identifier * 575 128 Application identifier * 703 32 Copyright file name * 735 5 Reserved * 740 32 Abstract file name * 772 5 Reserved * 777 32 Bibliographic file name * 809 5 Reserved * 814 16 Creation date and time * 830 1 Reserved * 831 16 Modification date and time * 847 1 Reserved * 848 16 Expiration date and time * 864 1 Reserved * 865 16 Effective date and time * 881 1 Reserved * 882 1 File Structure Standard Version number * 883 1 Reserved * 884 512 Application use * 1396 653 Reserved */ long startPosition = s.Position; byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; s.Position = startPosition - ISOFile.SECTOR_SIZE; // Read the entire structure s.Read(buffer, 0, ISOFile.SECTOR_SIZE); // Get the type this.Type = buffer[0]; // Handle the primary volume information if (this.Type == 1) { this.VolumeFlags = buffer[7]; this.SystemIdentifier = bc.ReadBytes(buffer, 8, LENGTH_SHORT_IDENTIFIER); this.VolumeIdentifier = bc.ReadBytes(buffer, 40, LENGTH_SHORT_IDENTIFIER); this.NumberOfSectors = bcBig.ReadIntValue(buffer, 84, 4); this.CodedCharSetIdent = bc.ReadBytes(buffer, 88, LENGTH_SHORT_IDENTIFIER); this.VolumeSetSize = bcBig.ReadIntValue(buffer, 122, 2); this.VolumeSequenceNumber = bcBig.ReadIntValue(buffer, 126, 2); this.SectorSize = bcBig.ReadIntValue(buffer, 130, 2); this.PathTableSize = bcBig.ReadIntValue(buffer, 136, 4); this.AddressOfPathTable = bcBig.ReadIntValue(buffer, 148, 4); this.VolumeSetIdentifier = bc.ReadBytes(buffer, 190, LENGTH_LONG_IDENTIFIER); this.PublisherIdentifier = bc.ReadBytes(buffer, 318, LENGTH_LONG_IDENTIFIER); this.DataPreparerIdentifier = bc.ReadBytes(buffer, 446, LENGTH_LONG_IDENTIFIER); this.ApplicationIdentifier = bc.ReadBytes(buffer, 574, LENGTH_LONG_IDENTIFIER); this.CopyrightFileIdentifier = bc.ReadBytes(buffer, 702, LENGTH_SHORT_IDENTIFIER); this.AbstractFileIdentifier = bc.ReadBytes(buffer, 739, LENGTH_SHORT_IDENTIFIER); this.BibliographicalFileIdentifier = bc.ReadBytes(buffer, 776, LENGTH_SHORT_IDENTIFIER); this.VolumeCreationDateTime = bc.ReadBytes(buffer, 813, 16); this.LastModifiedDateTime = bc.ReadBytes(buffer, 830, 16); this.ExpirationDateTime = bc.ReadBytes(buffer, 847, 16); this.EffectiveDateTime = bc.ReadBytes(buffer, 864, 16); // save current position long pos = s.Position; // get path table records s.Position = ISOFile.SECTOR_SIZE * this.AddressOfPathTable; ISOFile.CDIPathTable = CDIPathNode.ParsePathTable(s, this.PathTableSize); // read the root dir record s.Position = ISOFile.SECTOR_SIZE * ISOFile.CDIPathTable[0].DirectoryBlockAddress; s.Read(buffer, 0, ISOFile.SECTOR_SIZE); this.RootDirectoryRecord.Parse(buffer, 0); // go back to where we were s.Position = pos; } }
/// <summary> /// Parse the node record from the given CD-I stream. /// </summary> /// <param name="s">The stream to parse from.</param> public void ParseCDInteractive(Stream s) { /* * BP Size in bytes Description * 1 1 Record length * 2 1 Extended Attribute record length * 3 4 Reserved * 7 4 File beginning LBN * 11 4 Reserved * 15 4 File size * 19 6 Creation date * 25 1 Reserved * 26 1 File flags * 27 2 Interleave * 29 2 Reserved * 31 2 Album Set Sequence number * 33 1 File name size * 34 (n) File name * 34+n 4 Owner ID * 38+n 2 Attributes * 40+n 2 Reserved * 42+n 1 File number * 43+n 1 Reserved * 43+n Total */ EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); long startPosition = s.Position; byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; // Read the entire structure s.Read(buffer, 0, ISOFile.SECTOR_SIZE); s.Position -= ISOFile.SECTOR_SIZE; // Get the record length this.Length = buffer[0]; // extended attribute record length this.ExtendedAttribRecordLength = buffer[1]; // Read Data Offset this.OffsetOfData = bcBig.ReadIntValue(buffer, 6, 4); // Read Data Length this.LengthOfData = bcBig.ReadIntValue(buffer, 14, 4); // Read the time var ti = bc.ReadBytes(buffer, 18, 6); this.Year = ti[0]; this.Month = ti[1]; this.Day = ti[2]; this.Hour = ti[3]; this.Minute = ti[4]; this.Second = ti[5]; // read interleave - still to do // read album (volume) set sequence number (we are ignoring this) // Read the name length this.NameLength = buffer[32]; // Read the file/directory name var name = bc.ReadBytes(buffer, 33, this.NameLength); if (this.NameLength == 1 && (name[0] == 0 || name[0] == 1)) { if (name[0] == 0) { this.Name = ISONodeRecord.CURRENT_DIRECTORY; } else { this.Name = ISONodeRecord.PARENT_DIRECTORY; } } else { this.Name = ASCIIEncoding.ASCII.GetString(name, 0, this.NameLength); } // skip ownerID for now // read the flags - only really interested in the directory attribute (bit 15) // (confusingly these are called 'attributes' in CD-I. the CD-I 'File Flags' entry is something else entirely) this.Flags = buffer[37 + this.NameLength]; // skip filenumber //this.FileNumber = buffer[41 + this.NameLength]; // Seek to end s.Seek(startPosition + this.Length, SeekOrigin.Begin); }