예제 #1
0
        private static byte[] Compress(Hash hash, byte[] data)
        {
            byte[] result = null;
            using (var ms = new MemoryStream())
                using (var writer = new BinaryWriter(ms))
                {
                    var sw = Stopwatch.StartNew();
                    using (var msCompress = new MemoryStream())
                    {
                        using (var zs = new ZlibStream(msCompress, CompressionMode.Compress, CompressionLevel.None))
                        {
                            zs.Write(data, 0, data.Length);
                        }

                        var compressed = msCompress.ToArray();

                        writer.Write(data.Length);
                        writer.Write(compressed);

                        result = ms.ToArray();
                        sw.Stop();
                        Debug.WriteLine(string.Format("Compression : {0:N0} -> {1:N0} - {2} ms ", data.Length, compressed.Length, sw.ElapsedMilliseconds));
                    }
                }

            DecryptionUtility.Decrypt(result, 0, result.Length, ref hash);

            return(result);
        }
예제 #2
0
        private static byte[] Decompress(Hash hash, byte[] raw, int offset, int size)
        {
            var compressed = new byte[size - 4];

            Buffer.BlockCopy(raw, offset + 4, compressed, 0, size - 4);

            DecryptionUtility.Decrypt(raw, offset, 4, ref hash);

            var decomprssedSize = BitConverter.ToInt32(raw, offset);

            DecryptionUtility.Decrypt(compressed, 0, compressed.Length, ref hash);

            return(ZlibStream.UncompressBuffer(compressed));
        }
예제 #3
0
        public static StageDataFile Read(string path, string outputLocation)
        {
            var sd = new StageDataFile();

            FileUtility.PrepareFolder(outputLocation);


            string combineKey = null;

            using (var fs = File.OpenRead(path))
            {
                var raw = File.ReadAllBytes(path);

                sd.HashKey1 = fs.ReadInt32();
                sd.HashKey2 = fs.ReadInt32();
                sd.HashKey3 = fs.ReadInt32();

                // +0xc 이놈은 뭔지모르겠다. 그냥 덮어써버린다.

                sd.Hash = new Hash(sd.HashKey1, sd.HashKey2, sd.HashKey3);

                var hash = sd.Hash;

                var header = fs.ReadBytes(20);
                DecryptionUtility.Decrypt(header, ref hash);

                sd.Unknown1 = BitConverter.ToUInt32(header, 0);
                sd.Unknown2 = BitConverter.ToUInt32(header, 4);
                sd.Unknown3 = BitConverter.ToUInt32(header, 8);

                sd.EntityCount = BitConverter.ToUInt16(header, 12);
                sd.LookupStart = BitConverter.ToInt32(header, 16);

                var listData = fs.ReadBytes(sd.EntityCount * ENTITY_ITEM_LENGTH);
                DecryptionUtility.Decrypt(listData, ref hash);

                Debug.Assert(fs.Position == sd.LookupStart);

                var lookupData = fs.ReadBytes(sd.EntityCount * LOOKUP_ITEM_LENGTH);
                DecryptionUtility.Decrypt(lookupData, ref hash);


                sd.Entities   = new List <Entity>();
                sd.LookupList = new List <LookupBlock>();

                for (int i = 0; i < sd.EntityCount; i++)
                {
                    var offset = i * ENTITY_ITEM_LENGTH;
                    var entity = new Entity
                    {
                        Size     = BitConverter.ToUInt32(listData, offset),
                        Hash     = BitConverter.ToUInt32(listData, offset + 4),
                        Position = BitConverter.ToUInt32(listData, offset + 8),
                    };
                    sd.Entities.Add(entity);

                    offset = i * LOOKUP_ITEM_LENGTH;

                    var lookup = new LookupBlock
                    {
                        Key      = BitConverter.ToUInt32(lookupData, offset),
                        Index    = BitConverter.ToUInt32(lookupData, offset + 4),
                        Unknown1 = BitConverter.ToUInt32(lookupData, offset + 8),
                        Unknown2 = BitConverter.ToUInt32(lookupData, offset + 12)
                    };

                    sd.LookupList.Add(lookup);

                    var decompressed = Decompress(sd.Hash, raw, (int)entity.Position, (int)entity.Size);

                    if (BitConverter.ToInt32(decompressed, 0) == 0x636F6E2E) // '.noc'ache
                    {
                        using (var sr = new StringReader(Encoding.ASCII.GetString(decompressed)))
                        {
                            string line = null;

                            while ((line = sr.ReadLine()) != null)
                            {
                                if (line.EndsWith(".rlc"))
                                {
                                    combineKey = line.Remove(line.IndexOf('.'));
                                }
                            }
                        }
                    }

                    entity.Extension  = ResolveExtension(HashString(combineKey), (int)lookup.Key);
                    entity.CombineKey = combineKey;

                    var extension = entity.Extension == EntityExtensions.Unknown ? "" : entity.Extension.ToString();
                    var fileName  = Path.Combine(outputLocation, string.Format("{0:X8}.{1}", entity.Hash, extension));

                    File.WriteAllBytes(fileName, decompressed);
                }
            }


            return(sd);
        }
예제 #4
0
        public void Write(string outputPath)
        {
            var path = Path.GetTempFileName();

            using (var writer = new BinaryWriter(File.Create(path)))
            {
                Hash        = new Hash(HashKey1, HashKey2, HashKey3);
                EntityCount = (ushort)Entities.Count;
                LookupStart = 32 + EntityCount * ENTITY_ITEM_LENGTH;

                writer.Write(HashKey1);
                writer.Write(HashKey2);
                writer.Write(HashKey3);


                writer.BaseStream.Position = LookupStart + EntityCount * LOOKUP_ITEM_LENGTH;

                var index = 0;

                foreach (var entity in Entities)
                {
                    Debug.Write(string.Format("[{0} / {1}] ", ++index, Entities.Count));

                    entity.Position = (uint)writer.BaseStream.Position;
                    var data       = Path.Combine(Settings.Working, "STAGEDAT", string.Format("{0:X8}.{1}", entity.Hash, entity.Extension));
                    var raw        = File.ReadAllBytes(data);
                    var compressed = Compress(Hash, raw);
                    entity.Size = (uint)compressed.Length;
                    writer.Write(compressed);
                }


                byte[] subBuffer;
                var    hash = Hash;

                writer.BaseStream.Position = 12;

                using (var msSub = new MemoryStream(20))
                    using (var subWriter = new BinaryWriter(msSub))
                    {
                        subWriter.Write(Unknown1);
                        subWriter.Write(Unknown2);
                        subWriter.Write(Unknown3);
                        subWriter.Write(EntityCount);
                        subWriter.Write((ushort)5);
                        subWriter.Write(LookupStart);

                        subBuffer = msSub.ToArray();
                    }

                DecryptionUtility.Decrypt(subBuffer, ref hash);

                writer.Write(subBuffer);


                using (var msSub = new MemoryStream(Entities.Count * ENTITY_ITEM_LENGTH))
                    using (var subWriter = new BinaryWriter(msSub))
                    {
                        foreach (var entity in Entities)
                        {
                            subWriter.Write(entity.Size);
                            subWriter.Write(entity.Hash);
                            subWriter.Write(entity.Position);
                        }

                        subBuffer = msSub.ToArray();
                    }

                DecryptionUtility.Decrypt(subBuffer, ref hash);
                writer.Write(subBuffer);


                using (var msSub = new MemoryStream(Entities.Count * LOOKUP_ITEM_LENGTH))
                    using (var subWriter = new BinaryWriter(msSub))
                    {
                        foreach (var lookup in LookupList)
                        {
                            subWriter.Write(lookup.Key);
                            subWriter.Write(lookup.Index);
                            subWriter.Write(lookup.Unknown1);
                            subWriter.Write(lookup.Unknown2);
                        }

                        subBuffer = msSub.ToArray();
                    }

                DecryptionUtility.Decrypt(subBuffer, ref hash);

                writer.Write(subBuffer);
            }

            if (File.Exists(outputPath))
            {
                File.Delete(outputPath);
            }
            File.Move(path, outputPath);
        }
예제 #5
0
        public static void Pack(string location, string[] filter)
        {
            var keyPath  = Path.Combine(location, "SLOT.KEY");
            var dataPath = Path.Combine(location, "SLOT.DAT");

            File.Copy(Path.Combine(location, "SLOT.DAT.original"), Path.Combine(location, "SLOT.DAT"), true);

            Hash hash;

            byte[] rawKeys;

            using (var reader = new BinaryReader(File.OpenRead(keyPath)))
            {
                var hash0 = reader.ReadInt32();
                var hash1 = reader.ReadInt32();
                var hash2 = reader.ReadInt32();

                rawKeys = reader.ReadBytes((int)reader.BaseStream.Length - 12);
                hash    = new Hash(hash0, hash1, hash2);
            }

            if (!Directory.Exists("SLOT"))
            {
                Directory.CreateDirectory("SLOT");
            }

            HashSet <string> filterSet;

            if (filter == null)
            {
                filterSet = new HashSet <string>();
            }
            else
            {
                filterSet = new HashSet <string>(filter);
            }
            var items = new List <SlotItemInfo>();

            using (var keyReader = new BinaryReader(new MemoryStream(rawKeys)))
            {
                while (keyReader.BaseStream.Position < keyReader.BaseStream.Length)
                {
                    var rawStart = keyReader.ReadUInt32();
                    var rawEnd   = keyReader.ReadUInt32();

                    var start = (0x000FFFFF & rawStart) << 0xB;
                    var end   = (0x000FFFFF & rawEnd) << 0xB;

                    items.Add(new SlotItemInfo
                    {
                        Start = start,
                        End   = end,
                        Hash  = keyReader.ReadInt32()
                    });
                }
            }

            var current = 0;

            using (var writer = new BinaryWriter(File.OpenWrite(dataPath)))
            {
                foreach (var item in items)
                {
                    current++;
                    var sourcePath = string.Format(@"SLOT\{0:X8}_{1:X8}.slot", item.Start, item.Hash);
                    if (!filterSet.Contains(sourcePath))
                    {
                        continue;
                    }
                    Debug.WriteLine(string.Format("Process {0:X8} ({1}/{2})", item.Start, current, items.Count));

                    var data = File.ReadAllBytes(sourcePath);

                    byte[] compressed;
                    if (Compress(data, (int)item.Length - 16, out compressed) == false)
                    {
                        Debug.WriteLine("Failed to compress!");
                        continue;
                    }

                    var raw = new byte[item.Length];

                    using (var rawWriter = new BinaryWriter(new MemoryStream(raw)))
                    {
                        rawWriter.Write(0x00100004);
                        rawWriter.Write(0x00000000);
                        rawWriter.Write(compressed.Length);
                        rawWriter.Write(data.Length);

                        rawWriter.Write(compressed);
                        rawWriter.Flush();
                    }

                    var hashCopy = hash;
                    DecryptionUtility.Decrypt(raw, ref hashCopy);
                    writer.BaseStream.Position = item.Start;
                    writer.Write(raw);
                }
            }
        }
예제 #6
0
        public static void Unpack(string location)
        {
            var keyPath  = Path.Combine(location, "SLOT.KEY");
            var dataPath = Path.Combine(location, "SLOT.DAT");


            Hash hash;

            byte[] keys;

            using (var reader = new BinaryReader(File.OpenRead(keyPath)))
            {
                var hash0 = reader.ReadInt32();
                var hash1 = reader.ReadInt32();
                var hash2 = reader.ReadInt32();

                keys = reader.ReadBytes((int)reader.BaseStream.Length - 12);
                hash = new Hash(hash0, hash1, hash2);
            }


            var lastEnd = 0u;

            using (var keyReader = new BinaryReader(new MemoryStream(keys)))
                using (var dataReader = new BinaryReader(File.OpenRead(dataPath)))
                {
                    while (keyReader.BaseStream.Position < keyReader.BaseStream.Length)
                    {
                        var rawStart = keyReader.ReadUInt32();
                        var rawEnd   = keyReader.ReadUInt32();

                        var start = (0x000FFFFF & rawStart) << 0xB;
                        var end   = (0x000FFFFF & rawEnd) << 0xB;

                        lastEnd = end;

                        var remStart = rawStart >> 20;
                        var remEnd   = rawEnd >> 20;

                        Debug.WriteLine(string.Format("{0:X3} {1:X3} ", rawStart >> 20, rawEnd >> 20));

                        var itemHash = keyReader.ReadInt32();

                        dataReader.BaseStream.Position = start;

                        if (end < start)
                        {
                            continue;
                        }

                        var raw = dataReader.ReadBytes((int)(end - start));

                        var hashCopy = hash;

                        DecryptionUtility.Decrypt(raw, ref hashCopy);
                        var unknown1 = BitConverter.ToInt32(raw, 0);
                        var unknown2 = BitConverter.ToInt32(raw, 4);

                        if (unknown1 != 0x00100004)
                        {
                        }
                        else if (unknown2 != 0)
                        {
                        }

                        var compressedSize   = BitConverter.ToInt32(raw, 8);
                        var uncompressedSize = BitConverter.ToInt32(raw, 12);

                        var data = new byte[compressedSize];
                        Buffer.BlockCopy(raw, 16, data, 0, compressedSize);


                        var uncompressed = ZlibStream.UncompressBuffer(data);

                        var t5     = BitConverter.ToInt32(uncompressed, 0);
                        var output = string.Format(@"SLOT\{0:X8}_{1:X8}.slot", start, itemHash);

                        if (Directory.Exists("SLOT") == false)
                        {
                            Directory.CreateDirectory("SLOT");
                        }
                        File.WriteAllBytes(output, uncompressed);

                        Console.WriteLine("{0:X8} {1:X8} {2:X8} {3:X8} {4:X8} {5:X8}", itemHash, unknown1, unknown2, compressedSize, uncompressedSize, t5);
                    }
                }
        }