Esempio n. 1
0
        /// <summary>
        /// Get the directory at the end of this path, or make it (and all
        /// intermediate dirs) if it doesn't exist.
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private ArkDirectory makeOrGetDir(string path)
        {
            if (path == null || path == "")
            {
                path = ".";
            }
            string[]   breadcrumbs = path.Split('/');
            IDirectory last        = root;
            IDirectory current;

            if (breadcrumbs[0] == "." && breadcrumbs.Length == 1)
            {
                return(root);
            }

            for (var idx = 0; idx < breadcrumbs.Length; idx++)
            {
                if (!last.TryGetDirectory(breadcrumbs[idx], out current))
                {
                    current = new ArkDirectory(last, breadcrumbs[idx]);
                    (last as ArkDirectory).AddDir(current as ArkDirectory);
                }
                last = current;
            }
            return(last as ArkDirectory);
        }
Esempio n. 2
0
        private void readOldArkHeader(IFile hdrFile, Stream header)
        {
            root            = new ArkDirectory(null, ROOT_DIR);
            contentFileMeta = hdrFile.GetStream();
            header.Position = 8;
            long fileTableOffset = header.ReadUInt32LE();
            uint numFiles        = header.ReadUInt32LE();
            long dirTableOffset  = header.ReadUInt32LE();

            string[] dirs = new string[header.ReadUInt32LE()];
            header.Position = 0x24;
            long blockSize = header.ReadUInt32LE();

            header.Position = dirTableOffset;
            for (int dir = 0; dir < dirs.Length; dir++)
            {
                header.Position = dirTableOffset + (8 * dir) + 4;
                header.Position = header.ReadUInt32LE();
                dirs[dir]       = header.ReadASCIINullTerminated();
            }
            for (int file = 0; file < numFiles; file++)
            {
                header.Position = fileTableOffset + (24 * file) + 4;
                long filenameOffset = header.ReadUInt32LE();
                int  dir            = header.ReadUInt16LE();
                uint blockOffset    = header.ReadUInt16LE();
                uint block          = header.ReadUInt32LE();
                uint compressedSize = header.ReadUInt32LE();
                header.Position = filenameOffset;
                string       filename = header.ReadASCIINullTerminated();
                ArkDirectory parent   = dir > 0 ? makeOrGetDir(dirs[dir]) : root;
                parent.AddFile(new OffsetFile(filename, parent, contentFileMeta, block * blockSize + blockOffset,
                                              compressedSize));
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Read the filename table, which is a blob of strings,
        /// then read the filename pointer table which links files to filenames
        /// </summary>
        private void readFileTable(Stream header, uint version, bool brokenv4)
        {
            string[] fileNames = readFileNames(header, version != 1);
            if (version > 2)
            {
                // Version 3+:
                // Go to end of the filename pointer table which we already read
                //               filename blob               filename pointer table
                header.Seek(fileNameTableOffset + fileNameTableSize + 4 + 4 * numFileNames, SeekOrigin.Begin);
            }
            else
            {
                // Version 2: still at beginning of file. (after version number ofc)
                header.Seek(4, SeekOrigin.Begin);
            }
            // Now the number of *actual* files in the archive.
            // Directories are not explicitly stored. Rather, they are inferred
            // by the path string each file has, which tells you in which folder
            // the file lives.
            uint numFiles = header.ReadUInt32LE();

            for (var i = 0; i < numFiles; i++)
            {
                // Version 3 uses 32-bit file offsets
                long arkFileOffset = 0;
                if (version != 1)
                {
                    arkFileOffset = (brokenv4 || version <= 3 ? header.ReadUInt32LE() : header.ReadInt64LE());
                }
                int filenameStringId = header.ReadInt32LE();
                int dirStringId      = header.ReadInt32LE();
                if (version == 1)
                {
                    arkFileOffset = header.ReadUInt32LE();
                }
                uint size = header.ReadUInt32LE();
                uint zero = header.ReadUInt32LE();
                // Version 7 uses this differently. now, files marked as 0 should be skipped,
                // while NON-zero values mean real files. I think.
                if ((version == 7 && zero != 0) || (version != 7 && zero == 0))
                {
                    ArkDirectory parent = dirStringId > 0 ? makeOrGetDir(fileNames[dirStringId]) : root;
                    parent.AddFile(new OffsetFile(fileNames[filenameStringId], parent, contentFileMeta, arkFileOffset, size));
                }
            }
        }
Esempio n. 4
0
        private void readHeader(Stream header, IFile hdrFile, uint version, bool brokenv4 = false)
        {
            root = new ArkDirectory(null, ROOT_DIR);
            if (version >= 6)                            // Versions 6,7 have some sort of hash/key at the beginning?
            {
                header.Seek(4 + 16, SeekOrigin.Current); // skip unknown data
            }

            if (version > 2)
            {
                // Version 3+: two counts of .ark files
                int numArks  = header.ReadInt32LE();
                int numArks2 = header.ReadInt32LE();
                if (numArks != numArks2)
                {
                    throw new InvalidDataException("Ark header appears to be invalid (.ark count mismatch).");
                }
                arkFileSizes = new long[numArks];
                for (var i = 0; i < numArks; i++)
                {
                    // All versions except 4 use 32-bit file sizes.
                    arkFileSizes[i] = (version == 4 ? header.ReadInt64LE() : header.ReadInt32LE());
                    if (version == 4 && arkFileSizes[i] > UInt32.MaxValue)
                    {
                        // RB TrackPack Classic has a broken v4, really a v5 mixed with v3
                        header.Position = 4;
                        readHeader(header, hdrFile, 5, true);
                        return;
                    }
                    totalArkFileSizes += arkFileSizes[i];
                }

                // Version 5+: List of .ark file paths (from root of game disc)
                if (version >= 5)
                {
                    int numArkPaths = header.ReadInt32LE();
                    if (numArkPaths != numArks)
                    {
                        throw new InvalidDataException("Ark header appears to be invalid (.ark count mismatch).");
                    }
                    contentFiles = new Stream[numArks];
                    for (var i = 0; i < numArkPaths; i++)
                    {
                        IFile arkFile = hdrFile.Parent.GetFile(header.ReadLengthUTF8().Split('/').Last());
                        if (version == 10)
                        {
                            var tmpStream = arkFile.GetStream();
                            if (tmpStream.Length > 32)
                            {
                                tmpStream.Seek(-32, SeekOrigin.End);

                                if (tmpStream.ReadASCIINullTerminated(32) == "mcnxyxcmvmcxyxcmskdldkjshagsdhfj")
                                {
                                    contentFiles[i] = new ProtectedFileStream(tmpStream);
                                    continue;
                                }
                            }
                            tmpStream.Close();
                        }
                        contentFiles[i] = arkFile.GetStream();
                    }

                    // Versions 6,7,9: appear to have checksums or something for each content file?
                    if (version >= 6 && version <= 9)
                    {
                        uint numChecksums = header.ReadUInt32LE();
                        header.Seek(4 * numChecksums, SeekOrigin.Current);
                    }
                }
                else // Versions <5: Just infer the .ark paths based on the .hdr filename.
                {
                    contentFiles = new Stream[numArks];
                    for (var i = 0; i < numArks2; i++)
                    {
                        IFile arkFile = hdrFile.Parent.GetFile(hdrFile.Name.Substring(0, hdrFile.Name.Length - 4) + "_" + i + ".ark");
                        contentFiles[i] = arkFile.GetStream();
                    }
                }
                contentFileMeta = new MultiStream(contentFiles);

                // new in version 7+: some sort of string table with game-specific data
                if (version >= 7)
                {
                    uint root_count = header.ReadUInt32LE();
                    while (root_count-- > 0)
                    {
                        uint num_strs = header.ReadUInt32LE();
                        while (num_strs-- > 0) // skip past strings because we don't need them.
                        {
                            header.Seek(header.ReadUInt32LE(), SeekOrigin.Current);
                        }
                    }
                }
                if (version < 8) // Gonna assume 8 has new file table
                {
                    readFileTable(header, version, brokenv4);
                }
                else
                {
                    readNewFileTable(header, version < 10);
                }
            }
            else if (version == 1 || version == 2)
            {
                // Version 1,2: Here be file records. Skip 'em for now.
                uint numRecords = header.ReadUInt32LE();
                header.Close();
                contentFileMeta = hdrFile.GetStream();
                contentFileMeta.Seek(8 + numRecords * 20, SeekOrigin.Begin);
                readFileTable(contentFileMeta, version, brokenv4);
            }
        }