Ejemplo n.º 1
0
        // Read the table of contents of the ARC file
        private void ReadARCToC()
        {
            // Format of an ARC file
            // 0x08 - 4 bytes = # of files
            // 0x0C - 4 bytes = # of parts
            // 0x18 - 4 bytes = offset to directory structure
            //
            // Format of directory structure
            // 4-byte int = offset in file where this part begins
            // 4-byte int = size of compressed part
            // 4-byte int = size of uncompressed part
            // these triplets repeat for each part in the arc file
            // After these triplets are a bunch of null-terminated strings
            // which are the sub filenames.
            // After the subfilenames comes the subfile data:
            // 4-byte int = 3 == indicates start of subfile item  (maybe compressed flag??)
            //				1 == maybe uncompressed flag??
            // 4-byte int = offset in file where first part of this subfile begins
            // 4-byte int = compressed size of this file
            // 4-byte int = uncompressed size of this file
            // 4-byte crap
            // 4-byte crap
            // 4-byte crap
            // 4-byte int = numParts this file uses
            // 4-byte int = part# of first part for this file (starting at 0).
            // 4-byte int = length of filename string
            // 4-byte int = offset in directory structure for filename

            m_fileHasBeenRead = true;

            try {
                FileStream   arcFile = new FileStream(m_filename, FileMode.Open, FileAccess.Read);
                BinaryReader reader  = new BinaryReader(arcFile);
                try
                {
                    // check the file header
                    if (reader.ReadByte() != 0x41)
                    {
                        return;                                         // A
                    }
                    if (reader.ReadByte() != 0x52)
                    {
                        return;                                         // R
                    }
                    if (reader.ReadByte() != 0x43)
                    {
                        return;                                         // C
                    }
                    if (arcFile.Length < 0x21)
                    {
                        return;
                    }

                    reader.BaseStream.Seek(0x08, SeekOrigin.Begin);
                    int numEntries = reader.ReadInt32();
                    int numParts   = reader.ReadInt32();

                    ARCPartEntry[] parts   = new ARCPartEntry[numParts];
                    ARCDirEntry[]  records = new ARCDirEntry[numEntries];

                    reader.BaseStream.Seek(0x18, SeekOrigin.Begin);
                    int tocOffset = reader.ReadInt32();

                    if (arcFile.Length < (tocOffset + 4 * 3))
                    {
                        return;
                    }

                    // Read in all of the part data
                    reader.BaseStream.Seek(tocOffset, SeekOrigin.Begin);
                    int i;
                    for (i = 0; i < numParts; ++i)
                    {
                        parts[i]                = new ARCPartEntry();
                        parts[i].fileOffset     = reader.ReadInt32();
                        parts[i].compressedSize = reader.ReadInt32();
                        parts[i].realSize       = reader.ReadInt32();
                    }

                    // Now record this offset so we can come back and read in the filenames after we have
                    // read in the file records
                    int fileNamesOffset = (int)arcFile.Position;
                    // Now seek to the location where the file record data is
                    // This offset is from the end of the file.
                    int fileRecordOffset = 44 * numEntries;

                    arcFile.Seek(-1 * fileRecordOffset, SeekOrigin.End);
                    for (i = 0; i < numEntries; ++i)
                    {
                        records[i] = new ARCDirEntry();
                        int storageType = reader.ReadInt32();                     // storageType = 3 - compressed / 1- non compressed

                        // Added by VillageIdiot to support stored types
                        records[i].storageType    = storageType;
                        records[i].fileOffset     = reader.ReadInt32();
                        records[i].compressedSize = reader.ReadInt32();
                        records[i].realSize       = reader.ReadInt32();
                        int crap = reader.ReadInt32();             // crap

                        crap = reader.ReadInt32();                 // crap
                        crap = reader.ReadInt32();                 // crap

                        int np = reader.ReadInt32();
                        if (np < 1)
                        {
                            records[i].parts = null;
                        }
                        else
                        {
                            records[i].parts = new ARCPartEntry[np];
                        }

                        int firstPart = reader.ReadInt32();
                        crap = reader.ReadInt32();                 // filename length

                        crap = reader.ReadInt32();                 // filename offset

                        if (storageType != 1 && records[i].IsActive)
                        {
                            for (int ip = 0; ip < records[i].parts.Length; ++ip)
                            {
                                records[i].parts[ip] = parts[ip + firstPart];
                            }
                        }
                    }

                    // Now read in the record names
                    arcFile.Seek(fileNamesOffset, SeekOrigin.Begin);
                    byte[]        buffer = new byte[2048];
                    ASCIIEncoding ascii  = new ASCIIEncoding();
                    for (i = 0; i < numEntries; ++i)
                    {
                        // only Active files have a filename entry
                        if (records[i].IsActive)
                        {
                            // For each string, read bytes until I hit a 0x00 byte.
                            int bufSize = 0;

                            while ((buffer[bufSize++] = reader.ReadByte()) != 0x00)
                            {
                                if (buffer[bufSize - 1] == 0x03)
                                {                                         // god damn it
                                    arcFile.Seek(-1, SeekOrigin.Current); // backup
                                    bufSize--;
                                    buffer[bufSize] = 0x00;
                                    break;
                                }
                            }

                            string newfile;
                            if (bufSize >= 1)
                            {
                                // Now convert the buffer to a String
                                char[] chars = new char[ascii.GetCharCount(buffer, 0, bufSize - 1)];
                                ascii.GetChars(buffer, 0, bufSize - 1, chars, 0);
                                newfile = new string(chars);
                            }
                            else
                            {
                                newfile = string.Format("Null File {0}", i);
                            }

                            records[i].filename = NormalizeRecordPath(newfile);
                        }
                    }

                    // Now convert the array of records into a hash table.
                    Hashtable hash = new Hashtable(numEntries);

                    for (i = 0; i < numEntries; ++i)
                    {
                        if (records[i].IsActive)
                        {
                            hash.Add(records[i].filename, records[i]);
                        }
                    }
                    m_dir = hash;

                    BuildKeyTable();
                }
                finally
                {
                    reader.Close();
                }
            }
            catch (IOException)
            {
                // silently eat these errors
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Read the table of contents of the ARC file
        /// </summary>
        private void ReadARCToC()
        {
            // Format of an ARC file
            // 0x08 - 4 bytes = # of files
            // 0x0C - 4 bytes = # of parts
            // 0x18 - 4 bytes = offset to directory structure
            //
            // Format of directory structure
            // 4-byte int = offset in file where this part begins
            // 4-byte int = size of compressed part
            // 4-byte int = size of uncompressed part
            // these triplets repeat for each part in the arc file
            // After these triplets are a bunch of null-terminated strings
            // which are the sub filenames.
            // After the subfilenames comes the subfile data:
            // 4-byte int = 3 == indicates start of subfile item  (maybe compressed flag??)
            //          1 == maybe uncompressed flag??
            // 4-byte int = offset in file where first part of this subfile begins
            // 4-byte int = compressed size of this file
            // 4-byte int = uncompressed size of this file
            // 4-byte crap
            // 4-byte crap
            // 4-byte crap
            // 4-byte int = numParts this file uses
            // 4-byte int = part# of first part for this file (starting at 0).
            // 4-byte int = length of filename string
            // 4-byte int = offset in directory structure for filename
            this.fileHasBeenRead = true;

            if (TQDebug.ArcFileDebugLevel > 0)
            {
                TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "ARCFile.ReadARCToC({0})", this.FileName));
            }

            try
            {
                using (FileStream arcFile = new FileStream(this.FileName, FileMode.Open, FileAccess.Read))
                {
                    using (BinaryReader reader = new BinaryReader(arcFile))
                    {
                        if (TQDebug.ArcFileDebugLevel > 1)
                        {
                            TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "File Length={0}", arcFile.Length));
                        }

                        // check the file header
                        if (reader.ReadByte() != 0x41)
                        {
                            return;
                        }

                        if (reader.ReadByte() != 0x52)
                        {
                            return;
                        }

                        if (reader.ReadByte() != 0x43)
                        {
                            return;
                        }

                        if (arcFile.Length < 0x21)
                        {
                            return;
                        }

                        reader.BaseStream.Seek(0x08, SeekOrigin.Begin);
                        int numEntries = reader.ReadInt32();
                        int numParts   = reader.ReadInt32();

                        if (TQDebug.ArcFileDebugLevel > 1)
                        {
                            TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "numEntries={0}, numParts={1}", numEntries, numParts));
                        }

                        ARCPartEntry[] parts   = new ARCPartEntry[numParts];
                        ARCDirEntry[]  records = new ARCDirEntry[numEntries];

                        if (TQDebug.ArcFileDebugLevel > 2)
                        {
                            TQDebug.DebugWriteLine("Seeking to tocOffset location");
                        }

                        reader.BaseStream.Seek(0x18, SeekOrigin.Begin);
                        int tocOffset = reader.ReadInt32();

                        if (TQDebug.ArcFileDebugLevel > 1)
                        {
                            TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "tocOffset = {0}", tocOffset));
                        }

                        // Make sure all 3 entries exist for the toc entry.
                        if (arcFile.Length < (tocOffset + 12))
                        {
                            return;
                        }

                        // Read in all of the part data
                        reader.BaseStream.Seek(tocOffset, SeekOrigin.Begin);
                        int i;
                        for (i = 0; i < numParts; ++i)
                        {
                            parts[i]                = new ARCPartEntry();
                            parts[i].FileOffset     = reader.ReadInt32();
                            parts[i].CompressedSize = reader.ReadInt32();
                            parts[i].RealSize       = reader.ReadInt32();

                            if (TQDebug.ArcFileDebugLevel > 2)
                            {
                                TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "parts[{0}]", i));
                                TQDebug.DebugWriteLine(string.Format(
                                                           CultureInfo.InvariantCulture,
                                                           "  fileOffset={0}, compressedSize={1}, realSize={2}",
                                                           parts[i].FileOffset,
                                                           parts[i].CompressedSize,
                                                           parts[i].RealSize));
                            }
                        }

                        // Now record this offset so we can come back and read in the filenames
                        // after we have read in the file records
                        int fileNamesOffset = (int)arcFile.Position;

                        // Now seek to the location where the file record data is
                        // This offset is from the end of the file.
                        int fileRecordOffset = 44 * numEntries;

                        if (TQDebug.ArcFileDebugLevel > 1)
                        {
                            TQDebug.DebugWriteLine(string.Format(
                                                       CultureInfo.InvariantCulture,
                                                       "fileNamesOffset = {0}.  Seeking to {1} to read file record data.",
                                                       fileNamesOffset,
                                                       fileRecordOffset));
                        }

                        arcFile.Seek(-1 * fileRecordOffset, SeekOrigin.End);
                        for (i = 0; i < numEntries; ++i)
                        {
                            records[i] = new ARCDirEntry();

                            // storageType = 3 - compressed / 1- non compressed
                            int storageType = reader.ReadInt32();

                            if (TQDebug.ArcFileDebugLevel > 2)
                            {
                                TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "StorageType={0}", storageType));
                            }

                            // Added by VillageIdiot to support stored types
                            records[i].StorageType    = storageType;
                            records[i].FileOffset     = reader.ReadInt32();
                            records[i].CompressedSize = reader.ReadInt32();
                            records[i].RealSize       = reader.ReadInt32();
                            int crap = reader.ReadInt32();                             // crap
                            if (TQDebug.ArcFileDebugLevel > 2)
                            {
                                TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Crap2={0}", crap));
                            }

                            crap = reader.ReadInt32();                             // crap
                            if (TQDebug.ArcFileDebugLevel > 2)
                            {
                                TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Crap3={0}", crap));
                            }

                            crap = reader.ReadInt32();                             // crap
                            if (TQDebug.ArcFileDebugLevel > 2)
                            {
                                TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Crap4={0}", crap));
                            }

                            int numberOfParts = reader.ReadInt32();
                            if (numberOfParts < 1)
                            {
                                records[i].Parts = null;
                                if (TQDebug.ArcFileDebugLevel > 2)
                                {
                                    TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "File {0} is not compressed.", i));
                                }
                            }
                            else
                            {
                                records[i].Parts = new ARCPartEntry[numberOfParts];
                            }

                            int firstPart = reader.ReadInt32();
                            crap = reader.ReadInt32();                             // filename length
                            if (TQDebug.ArcFileDebugLevel > 2)
                            {
                                TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Filename Length={0}", crap));
                            }

                            crap = reader.ReadInt32();                             // filename offset
                            if (TQDebug.ArcFileDebugLevel > 2)
                            {
                                TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Filename Offset={0}", crap));

                                TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "record[{0}]", i));
                                TQDebug.DebugWriteLine(string.Format(
                                                           CultureInfo.InvariantCulture,
                                                           "  offset={0} compressedSize={1} realSize={2}",
                                                           records[i].FileOffset,
                                                           records[i].CompressedSize,
                                                           records[i].RealSize));

                                if (storageType != 1 && records[i].IsActive)
                                {
                                    TQDebug.DebugWriteLine(string.Format(
                                                               CultureInfo.InvariantCulture,
                                                               "  numParts={0} firstPart={1} lastPart={2}",
                                                               records[i].Parts.Length,
                                                               firstPart,
                                                               firstPart + records[i].Parts.Length - 1));
                                }
                                else
                                {
                                    TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "  INACTIVE firstPart={0}", firstPart));
                                }
                            }

                            if (storageType != 1 && records[i].IsActive)
                            {
                                for (int ip = 0; ip < records[i].Parts.Length; ++ip)
                                {
                                    records[i].Parts[ip] = parts[ip + firstPart];
                                }
                            }
                        }

                        // Now read in the record names
                        arcFile.Seek(fileNamesOffset, SeekOrigin.Begin);
                        byte[]        buffer = new byte[2048];
                        ASCIIEncoding ascii  = new ASCIIEncoding();
                        for (i = 0; i < numEntries; ++i)
                        {
                            // only Active files have a filename entry
                            if (records[i].IsActive)
                            {
                                // For each string, read bytes until I hit a 0x00 byte.
                                if (TQDebug.ArcFileDebugLevel > 2)
                                {
                                    TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Reading entry name {0:n0}", i));
                                }

                                int bufferSize = 0;

                                while ((buffer[bufferSize++] = reader.ReadByte()) != 0x00)
                                {
                                    if (buffer[bufferSize - 1] == 0x03)
                                    {
                                        // File is null?
                                        arcFile.Seek(-1, SeekOrigin.Current);                                         // backup
                                        bufferSize--;
                                        buffer[bufferSize] = 0x00;
                                        if (TQDebug.ArcFileDebugLevel > 2)
                                        {
                                            TQDebug.DebugWriteLine("Null file - inactive?");
                                        }

                                        break;
                                    }

                                    if (bufferSize >= buffer.Length)
                                    {
                                        TQDebug.DebugWriteLine("ARCFile.ReadARCToC() Error - Buffer size of 2048 has been exceeded.");
                                        if (TQDebug.ArcFileDebugLevel > 2)
                                        {
                                            TQDebug.DebugWriteLine("Buffer contents:\n");
                                            for (int j = 0; j < bufferSize; ++j)
                                            {
                                                TQDebug.DebugWrite(string.Format(CultureInfo.InvariantCulture, "0x{0:X}", buffer[j]));
                                            }

                                            TQDebug.DebugWriteLine(String.Empty);
                                        }
                                    }
                                }

                                if (TQDebug.ArcFileDebugLevel > 2)
                                {
                                    TQDebug.DebugWriteLine(string.Format(
                                                               CultureInfo.InvariantCulture,
                                                               "Read {0:n0} bytes for name.  Converting to string.",
                                                               bufferSize));
                                }

                                string newfile;
                                if (bufferSize >= 1)
                                {
                                    // Now convert the buffer to a string
                                    char[] chars = new char[ascii.GetCharCount(buffer, 0, bufferSize - 1)];
                                    ascii.GetChars(buffer, 0, bufferSize - 1, chars, 0);
                                    newfile = new string(chars);
                                }
                                else
                                {
                                    newfile = string.Format(CultureInfo.InvariantCulture, "Null File {0}", i);
                                }

                                records[i].FileName = TQData.NormalizeRecordPath(newfile);

                                if (TQDebug.ArcFileDebugLevel > 2)
                                {
                                    TQDebug.DebugWriteLine(string.Format(CultureInfo.InvariantCulture, "Name {0:n0} = '{1}'", i, records[i].FileName));
                                }
                            }
                        }

                        // Now convert the array of records into a Dictionary.
                        Dictionary <string, ARCDirEntry> dictionary = new Dictionary <string, ARCDirEntry>(numEntries);
                        if (TQDebug.ArcFileDebugLevel > 1)
                        {
                            TQDebug.DebugWriteLine("Creating Dictionary");
                        }

                        for (i = 0; i < numEntries; ++i)
                        {
                            if (records[i].IsActive)
                            {
                                dictionary.Add(records[i].FileName, records[i]);
                            }
                        }

                        this.directoryEntries = dictionary;

                        if (TQDebug.ArcFileDebugLevel > 0)
                        {
                            TQDebug.DebugWriteLine("Exiting ARCFile.ReadARCToC()");
                        }
                    }
                }
            }
            catch (IOException exception)
            {
                // Turn on debugging.
                if (!TQDebug.DebugEnabled)
                {
                    TQDebug.DebugEnabled = true;
                }

                // Write the errors to the debug log.
                TQDebug.DebugWriteLine("ARCFile.ReadARCToC() - Error reading arcfile");
                TQDebug.DebugWriteLine(exception.ToString());
            }
        }