Пример #1
0
        private static ArkFile ParseArkHeader(string input, Stream stream)
        {
            ArkFile ark = new ArkFile();

            ark._encrypted = false;
            ark._xor       = false;
            ark._arkPaths  = new[] { Path.GetFullPath(input) };

            using var ar = new AwesomeReader(stream);

            // Checks version
            int version = ar.ReadInt32();

            if (!Enum.IsDefined(typeof(ArkVersion), version))
            {
                throw new NotSupportedException($"Unsupported ark version 0x{version:X8}");
            }

            ark._version = (ArkVersion)version;

            // Skip entries and come back later
            var entryOffset = ar.BaseStream.Position;
            var entryCount  = ar.ReadInt32();

            ar.BaseStream.Seek(entryCount * 20, SeekOrigin.Current);

            // Read string blob + string indicies
            var strings = ReadStringBlob(ar);

            int[] stringIndex = ReadStringIndicies(ar);

            // Read entries
            ar.BaseStream.Seek(entryOffset + 4, SeekOrigin.Begin);

            for (int i = 0; i < entryCount; i++)
            {
                uint offset = ar.ReadUInt32();

                int fileIdx = ar.ReadInt32();
                int dirIdx  = ar.ReadInt32();

                string filePath = (fileIdx >= 0)
                    ? strings[stringIndex[fileIdx]]
                    : "";

                string direPath = (dirIdx >= 0)
                    ? strings[stringIndex[dirIdx]]
                    : "";

                uint size         = ar.ReadUInt32();
                uint inflatedSize = ar.ReadUInt32();

                ark._offsetEntries.Add(new OffsetArkEntry(offset, filePath, direPath, size, inflatedSize, 0, offset));
            }

            return(ark);
        }
Пример #2
0
        public static ArkFile Create(string hdrPath, ArkVersion version, int?key)
        {
            hdrPath = Path.GetFullPath(hdrPath);

            var ark = new ArkFile();

            ark._encrypted = key.HasValue;
            ark._xor       = (version >= ArkVersion.V10); // RB4/RBVR?

            if (key.HasValue)
            {
                ark._cryptKey = key.Value;
            }

            ark._version = version;

            var directory     = Path.GetDirectoryName(hdrPath);
            var fileNameNoExt = Path.GetFileNameWithoutExtension(hdrPath);

            // TODO: Add additional parts dynamically
            var arkPaths = Enumerable.Range(0, 1)
                           .Select(x => Path.Combine(directory, $"{fileNameNoExt}_{x}.ark"))
                           .ToList();

            // Create directory
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            // Create ark parts
            foreach (var partPath in arkPaths)
            {
                using var _ = File.Create(partPath);
            }

            ark._arkPaths = new[]
            {
                hdrPath,
                arkPaths.First()
            };

            return(ark);
        }
Пример #3
0
        private static ArkFile ParseHeader(string input, Stream stream)
        {
            ArkFile ark = new ArkFile();

            ark._encrypted = false;
            ark._xor       = false;

            using var ar = new AwesomeReader(stream);

            // Checks version
            int version = ar.ReadInt32();

            if (Enum.IsDefined(typeof(ArkVersion), version))
            {
                ark._version = (ArkVersion)version;
            }
            else
            {
                // Decrypt stream and re-checks version
                Crypt.DTBCrypt(ar.BaseStream, version, true);
                ark._cryptKey = version; // Set crypt key

                version        = ar.ReadInt32();
                ark._encrypted = true;

                if (!Enum.IsDefined(typeof(ArkVersion), version))
                {
                    version  = (int)((uint)version ^ 0xFFFFFFFF);
                    ark._xor = true;

                    // Check one last time
                    if (!Enum.IsDefined(typeof(ArkVersion), version))
                    {
                        throw new Exception($"Ark version of \'{version}\' is unsupported");
                    }

                    long start = ar.BaseStream.Position;
                    int  b;

                    // 0xFF xor rest of stream
                    while ((b = stream.ReadByte()) > -1)
                    {
                        stream.Seek(-1, SeekOrigin.Current);
                        stream.WriteByte((byte)(b ^ 0xFF));
                    }

                    ar.BaseStream.Seek(start, SeekOrigin.Begin);
                }

                ark._version = (ArkVersion)version;
            }

            if (version >= 6)
            {
                // TODO: Save 16-byte hashes
                uint hashCount = ar.ReadUInt32();
                ar.BaseStream.Position += hashCount << 4;
            }

            uint arkFileCount     = ar.ReadUInt32();
            uint arkFileSizeCount = ar.ReadUInt32(); // Should be same as ark file count

            long[] partSizes = new long[arkFileSizeCount];

            // Reads ark file sizes
            if (version != 4)
            {
                for (int i = 0; i < partSizes.Length; i++)
                {
                    partSizes[i] = ar.ReadUInt32();
                }
            }
            else
            {
                // Version 4 uses 64-bit sizes
                for (int i = 0; i < partSizes.Length; i++)
                {
                    partSizes[i] = ar.ReadInt64();
                }
            }

            // TODO: Verify the ark parts exist and the sizes match header listing
            if (version >= 5)
            {
                // Read ark names from hdr
                uint arkPathsCount = ar.ReadUInt32();
                ark._arkPaths = new string[arkPathsCount + 1];

                string directory = Path.GetDirectoryName(input);
                ark._arkPaths[0] = input;

                var hdrFileName = Path.GetFileNameWithoutExtension(input);

                for (int i = 0; i < arkPathsCount; i++)
                {
                    ar.ReadString(); // Ehh just ignore what's in hdr. Sometimes it'll be absolute instead of relative

                    ark._arkPaths[i + 1] = Path.Combine(directory, $"{hdrFileName}_{i}.ark");
                }
            }
            else
            {
                // Make a good guess
                ark._arkPaths = GetPartNames(input, partSizes.Length);
            }

            if (version >= 6 && version <= 9)
            {
                // TODO: Save hashes?
                uint hash2Count = ar.ReadUInt32();
                ar.BaseStream.Position += hash2Count << 2;
            }

            if (version >= 7)
            {
                // TODO: Save file collection paths
                uint fileCollectionCount = ar.ReadUInt32();
                for (int i = 0; i < fileCollectionCount; i++)
                {
                    uint fileCount = ar.ReadUInt32();

                    for (int j = 0; j < fileCount; j++)
                    {
                        ar.ReadString();
                    }
                }
            }

            if (version <= 7)
            {
                // Read string blob + string indicies
                var   strings     = ReadStringBlob(ar);
                int[] stringIndex = ReadStringIndicies(ar);

                // Reads entries
                uint entryCount = ar.ReadUInt32();

                if (version >= 4)
                {
                    for (int i = 0; i < entryCount; i++)
                    {
                        long   entryOffset  = ar.ReadInt64();
                        string filePath     = strings[stringIndex[ar.ReadInt32()]];
                        string direPath     = strings[stringIndex[ar.ReadInt32()]];
                        uint   size         = ar.ReadUInt32();
                        uint   inflatedSize = ar.ReadUInt32();

                        (int partIdx, long partOffset) = GetArkOffsetForEntry(entryOffset, partSizes);
                        ark._offsetEntries.Add(new OffsetArkEntry(entryOffset, filePath, direPath, size, inflatedSize, partIdx + 1, partOffset));
                    }
                }
                else
                {
                    for (int i = 0; i < entryCount; i++)
                    {
                        uint   entryOffset  = ar.ReadUInt32();
                        string filePath     = strings[stringIndex[ar.ReadInt32()]];
                        string direPath     = strings[stringIndex[ar.ReadInt32()]];
                        uint   size         = ar.ReadUInt32();
                        uint   inflatedSize = ar.ReadUInt32();

                        (int partIdx, long partOffset) = GetArkOffsetForEntry(entryOffset, partSizes);
                        ark._offsetEntries.Add(new OffsetArkEntry(entryOffset, filePath, direPath, size, inflatedSize, partIdx + 1, partOffset));
                    }
                }
            }
            else
            {
                uint entryCount = ar.ReadUInt32();
                var  flags1     = new (string path, int nextIdx)[entryCount];