/* * 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); }
/// <summary> /// Start parsing the volume descriptor header. /// </summary> /// <param name="s">The stream to parse from.</param> public bool Parse(Stream s) { long startPosition = s.Position; byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; // Read the entire structure s.Read(buffer, 0, ISOFile.SECTOR_SIZE); // Parse based on format byte[] header = bc.ReadBytes(buffer, 0, ISOFile.SECTOR_SIZE); if (GetISO9660(header)) { ParseISO9660(s); return(true); } if (GetCDI(header)) { ParseCDInteractive(s); return(true); } return(false); }
/// <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); }