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); }
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)); }
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); }
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); }
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); } } }
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); } } }