Ejemplo n.º 1
0
        public void ParseToc(TocFileNotify notifyFn)
        {
            uint[] offsets = new uint[Files];
            // this merry dance is because unsigned things are second-class
            // citizens when it comes to marshalling
            byte[] offsetBytes = new byte[offsets.Length * sizeof(uint)];
            // offsets start at 0x10
            IntPtr offStart = new IntPtr(volMappingAddrAsNum + 0x10);

            Marshal.Copy(offStart, offsetBytes, 0, offsetBytes.Length);
            Buffer.BlockCopy(offsetBytes, 0, offsets, 0, offsetBytes.Length);

            // offsets[0] = offset of the offsets
            // offsets[1] = toc
            // offsets[2...n] = files
            uint unusedLastSectorBytes = 0;
            uint tocOffset             = SanitiseOffset(offsets[1], out unusedLastSectorBytes);

            uint notNeeded       = 0;
            uint firstFileOffset = SanitiseOffset(offsets[2], out notNeeded);

            uint tocLen = firstFileOffset - tocOffset - unusedLastSectorBytes;

            byte[] toc      = new byte[tocLen];
            IntPtr tocStart = new IntPtr(volMappingAddrAsNum + tocOffset);

            Marshal.Copy(tocStart, toc, 0, (int)tocLen);

            embeddedFiles.Capacity = TotalEntries;
            BinaryReader reader = new BinaryReader(new MemoryStream(toc, false));

            ReadEmbeddedFileData(embeddedFiles, TotalEntries, reader, offsets, notifyFn, volMappingAddrAsNum);
        }
Ejemplo n.º 2
0
        static void ReadEmbeddedFileData(
            List <EmbeddedFileInfo> files,
            short numFiles,
            BinaryReader src,
            uint[] fileOffsets,
            TocFileNotify notifyFn,
            long volStartAddress
            )
        {
            List <string>    directories = new List <string>();
            string           dirBeingParsed = String.Empty;
            EmbeddedFileInfo lastFile = null;
            int   dirIndex = 0, dirInsertIndex = 0;
            short i = 0;

            for (; i < numFiles; ++i)
            {
                EmbeddedFileInfo efi = new EmbeddedFileInfo();
                efi.dateTime = src.ReadInt32();
                int  offsetIndex = src.ReadInt16();
                byte flags       = src.ReadByte();

                uint bytesFromLastSector = 0;
                // flags
                // 0x00 = regular file
                // 0x01 = directory
                // 0x80 = last entry for this directory
                if (offsetIndex == 0 || (flags & 0x1) == 0x1)
                {
                    // '..' entries and directories don't have an offset
                    efi.fileAddress = 0;
                    efi.pFileStart  = IntPtr.Zero;
                }
                else
                {
                    efi.fileAddress = SanitiseOffset(fileOffsets[offsetIndex], out bytesFromLastSector);
                    efi.pFileStart  = new IntPtr(volStartAddress + efi.fileAddress);
                }

                // cache this here for now, it's not the actual size, but it's used in its calculation
                efi.size = bytesFromLastSector;
                efi.name = Path.Combine(dirBeingParsed, Encoding.ASCII.GetString(src.ReadBytes(25)).TrimEnd('\0'));

                if ((flags & 0x1) != 0)
                {
                    // '..' don't need saving
                    if (!efi.name.EndsWith(".."))
                    {
                        // if we're parsing one, this is a child directory
                        // its' contents are after the one being parsed, not at the end of the list
                        if (dirBeingParsed != String.Empty)
                        {
                            directories.Insert(dirInsertIndex++, efi.name);
                        }
                        else
                        {
                            directories.Add(efi.name);
                        }
                    }
                }
                else
                {
                    if (lastFile != null)
                    {
                        uint realSize = efi.fileAddress - lastFile.fileAddress - lastFile.size;
                        // realsize can be 0 if files are 0 bytes (everything in the replay dir)
                        lastFile.size = realSize;
                        if (notifyFn != null)
                        {
                            notifyFn(lastFile);
                        }
                    }
                    lastFile = efi;
                }
                // if this is the last entry for this directory
                // change which dir we use as the parent
                if ((flags & 0x80) != 0)
                {
                    // directories are listed in order of first encounter
                    // so a simple iteration will suffice
                    dirBeingParsed =
                        (dirIndex < directories.Count) ? directories[dirIndex++] : String.Empty;
                    dirInsertIndex = dirIndex;
                }
                // '..' entries don't need to be saved
                if (offsetIndex != 0)
                {
                    files.Add(efi);
                }
            }
            // the last fileOffset is the length of the whole file
            lastFile.size = fileOffsets[fileOffsets.Length - 1] - lastFile.fileAddress - lastFile.size;
            lastFile.size = (lastFile.size > 0) ? lastFile.size : 0x800;
            if (notifyFn != null)
            {
                notifyFn(lastFile);
            }
        }