public static byte[] Decompress(byte[] input, uint offset) { MemoryStream stream = new MemoryStream(input); BinaryReaderBE reader = new BinaryReaderBE(stream); reader.BaseStream.Position = offset; uint chunkCount = reader.ReadUInt32(); long position = reader.BaseStream.Position; List <CompressedChunk> totalChunk = new List <CompressedChunk>(); for (int i = 0; i < chunkCount; i++) { reader.BaseStream.Position = position; uint uncompressedOffset = reader.ReadUInt32(); uint uncompressedSize = reader.ReadUInt32(); uint compressedOffset = reader.ReadUInt32(); uint compressedSize = reader.ReadUInt32(); position = reader.BaseStream.Position; reader.BaseStream.Position = compressedOffset; byte[] compressedData = reader.ReadBytes((int)compressedSize); CompressedChunk chunk = new CompressedChunk(uncompressedOffset, uncompressedSize, compressedOffset, compressedSize); chunk.Decompress(compressedData); totalChunk.Add(chunk); } MemoryStream result = new MemoryStream(); BinaryWriter writer = new BinaryWriter(result); long unknowPosition = position; reader.BaseStream.Position = 0; writer.Write(reader.ReadBytes((int)ArchiveConfig.PackageFlagsOffset)); writer.Write(ArchiveConfig.UncompressedFlagsBytes); reader.BaseStream.Position += 4; writer.Write(reader.ReadBytes((int)(ArchiveConfig.CompressionTypeOffset - ArchiveConfig.PackageFlagsOffset - 4))); writer.Write(new byte[8]); reader.BaseStream.Position = unknowPosition; writer.Write(reader.ReadBytes(8)); position = ArchiveConfig.CompressionTypeOffset + 16; foreach (CompressedChunk chunk in totalChunk) { if (chunk.UncompressedOffset > position) { long zeroes = chunk.UncompressedOffset - position; writer.Write(new byte[zeroes]); position = chunk.UncompressedOffset; } writer.Write(chunk.UncompressedData); position += chunk.UncompressedSize; } writer.Close(); reader.Close(); return(result.ToArray()); }
public void Decompress(byte[] compressed_data) { MemoryStream stream = new MemoryStream(compressed_data); BinaryReaderBE reader = new BinaryReaderBE(stream); reader.BaseStream.Position = 8; UInt32 chunkCompressedSize = reader.ReadUInt32(); reader.BaseStream.Position += 4; UInt32 offset = CompressedSize - chunkCompressedSize; MemoryStream result = new MemoryStream(); BinaryWriter writer = new BinaryWriter(result); long chunkOffset = offset; while (reader.BaseStream.Position < offset) { UInt32 compressedSize = reader.ReadUInt32(); reader.BaseStream.Position += 4; long current = reader.BaseStream.Position; reader.BaseStream.Position = chunkOffset; chunkOffset += compressedSize; byte[] chunkCompressedData = reader.ReadBytes((int)compressedSize); byte[] chunkUncompressData = ZlibDecompress(chunkCompressedData); writer.Write(chunkUncompressData); reader.BaseStream.Position = current; } reader.Close(); writer.Close(); UncompressedData = result.ToArray(); }
public static List <DataMessage> Decrypt(byte[] input) { List <DataMessage> result = new List <DataMessage>(); MemoryStream stream = new MemoryStream(input); BinaryReaderBE reader = new BinaryReaderBE(stream); if (reader.ReadUInt32() == ArchiveConfig.Signature) { reader.BaseStream.Position = ArchiveConfig.CompressionTypeOffset; uint compressType = reader.ReadUInt32(); switch (compressType) { case 0: reader.BaseStream.Position = ArchiveConfig.TableOffset; uint nameCount = reader.ReadUInt32(); uint nameOffset = reader.ReadUInt32(); uint exportCount = reader.ReadUInt32(); uint exportOffset = reader.ReadUInt32(); uint importCount = reader.ReadUInt32(); uint importOffset = reader.ReadUInt32(); string[] nameTable = new string[nameCount]; reader.BaseStream.Position = nameOffset; for (int i = 0; i < nameCount; i++) { uint strLength = reader.ReadUInt32(); nameTable[i] = Encoding.UTF8.GetString(reader.ReadBytes((int)strLength - 1)); reader.BaseStream.Position += 9; } string[] nameImport = new string[importCount]; reader.BaseStream.Position = importOffset; for (int i = 0; i < importCount; i++) { reader.BaseStream.Position += 20; uint index = reader.ReadUInt32(); nameImport[i] = nameTable[(int)index]; reader.BaseStream.Position += 4; } reader.BaseStream.Position = exportOffset; long current = reader.BaseStream.Position; for (int i = 0; i < exportCount; i++) { reader.BaseStream.Position = current; uint indexType = (uint)reader.ReadInt32() ^ 0xFFFFFFFF; reader.BaseStream.Position += 8; uint nameIndex = reader.ReadUInt32(); uint suffixName = reader.ReadUInt32(); string name = nameTable[(int)nameIndex]; if (suffixName != 0) { name += $"_{suffixName}"; } reader.BaseStream.Position += 12; uint size = reader.ReadUInt32(); uint offset = reader.ReadUInt32(); reader.BaseStream.Position += 4; if (reader.ReadUInt32() > 0) { reader.BaseStream.Position += 4; } reader.BaseStream.Position += 20; current = reader.BaseStream.Position; if (nameImport[indexType] == "Sqex03DataMessage") { reader.BaseStream.Position = offset; uint order = reader.ReadUInt32(); List <Speaker> speakers = new List <Speaker>(); while (true) { string nameID = nameTable[reader.ReadInt32()]; if (nameID == "None") { break; } string classID = nameTable[reader.ReadInt64()]; if (classID == "IntProperty") { long lengthProperty = reader.ReadInt64(); long intProperty = reader.ReadInt64(); } else if (classID == "ArrayProperty") { long lengthProperty = reader.ReadInt64(); if (nameID == "m_String") { DataMessage dataMessage = GetStrings(ref reader, name, false); result.Add(dataMessage); } else if (nameID == "m_Name") { DataMessage dataMessage = GetStrings(ref reader, $"{name}_Name", true); if (!string.IsNullOrWhiteSpace(string.Join("", dataMessage.Strings))) { result.Add(dataMessage); } } else if (nameID == "m_MesData") { GetSpeakers(ref reader, ref speakers, nameTable); } else { reader.BaseStream.Position += lengthProperty + 4; } } } if (result.Any(entry => entry.Name == $"{name}_Name")) { DataMessage data = result.Find(entry => entry.Name == name); DataMessage dataName = result.Find(entry => entry.Name == $"{name}_Name"); for (int y = 0; y < speakers.Count; y++) { try { speakers[y].Name = dataName.Strings[speakers[y].ID]; } catch { speakers[y].Name = ""; } } data.Speakers = speakers; } } } break; case 1: byte[] decompressedData = Decompress(input, (uint)reader.BaseStream.Position); return(Decrypt(decompressedData)); default: throw new Exception("The file has an unsupported compression type."); } } else { throw new Exception("The file is not a Drakengard 3 (Unreal 3) file."); } reader.Close(); return(result); }
private static byte[] Reimport(byte[] input, Dictionary <string, List <string> > data) { MemoryStream result = new MemoryStream(); MemoryStream inputStream = new MemoryStream(input); BinaryReaderBE reader = new BinaryReaderBE(inputStream); BeBinaryWriter writer = new BeBinaryWriter(result); if (reader.ReadUInt32() == ArchiveConfig.Signature) { reader.BaseStream.Position = ArchiveConfig.CompressionTypeOffset; uint compressType = reader.ReadUInt32(); switch (compressType) { case 0: reader.BaseStream.Position = ArchiveConfig.TableOffset; uint nameCount = reader.ReadUInt32(); uint nameOffset = reader.ReadUInt32(); uint exportCount = reader.ReadUInt32(); uint exportOffset = reader.ReadUInt32(); uint importCount = reader.ReadUInt32(); uint importOffset = reader.ReadUInt32(); uint emptyOffset = reader.ReadUInt32(); uint unknownOffset = reader.ReadUInt32(); long emptyBytes = unknownOffset - emptyOffset; string[] nameTable = new string[nameCount]; reader.BaseStream.Position = nameOffset; for (int i = 0; i < nameCount; i++) { uint strLength = reader.ReadUInt32(); nameTable[i] = Encoding.UTF8.GetString(reader.ReadBytes((int)strLength - 1)); reader.BaseStream.Position += 9; } string[] nameImport = new string[importCount]; reader.BaseStream.Position = importOffset; for (int i = 0; i < importCount; i++) { reader.BaseStream.Position += 20; uint index = reader.ReadUInt32(); nameImport[i] = nameTable[(int)index]; reader.BaseStream.Position += 4; } reader.BaseStream.Position = 0; writer.Write(reader.ReadBytes((int)exportOffset)); //header long bytesChanged = 0; List <byte[]> newData = new List <byte[]>(); long current = exportOffset; for (int i = 0; i < exportCount; i++) { MemoryStream newRealData = new MemoryStream(); BeBinaryWriter writerData = new BeBinaryWriter(newRealData); reader.BaseStream.Position = current; long start = reader.BaseStream.Position; uint indexType = (uint)reader.ReadInt32() ^ 0xFFFFFFFF; reader.BaseStream.Position += 8; uint nameIndex = reader.ReadUInt32(); uint suffixName = reader.ReadUInt32(); string name = nameTable[(int)nameIndex]; if (suffixName != 0) { name += $"_{suffixName}"; } reader.BaseStream.Position += 12; uint size = reader.ReadUInt32(); uint offset = reader.ReadUInt32(); long newOffset = offset + bytesChanged; reader.BaseStream.Position += 4; if (reader.ReadUInt32() > 0) { reader.BaseStream.Position += 4; } reader.BaseStream.Position += 20; long headerLength = reader.BaseStream.Position - start; current = reader.BaseStream.Position; reader.BaseStream.Position = offset; long stringBytesChanged = 0; if (nameImport[indexType] == "Sqex03DataMessage") { uint order = reader.ReadUInt32(); writerData.Write(order); while (true) { int nameIDIndex = reader.ReadInt32(); string nameID = nameTable[nameIDIndex]; writerData.Write(nameIDIndex); if (nameID == "None") { writerData.Write(new byte[4]); break; } long classIDIndex = reader.ReadInt64(); string classID = nameTable[classIDIndex]; writerData.Write(classIDIndex); if (classID == "IntProperty") { writerData.Write(reader.ReadBytes(16)); } else if (classID == "ArrayProperty") { long lengthProperty = reader.ReadInt64(); if (nameID == "m_String") { List <string> strings; if (data.TryGetValue(name, out strings)) { byte[] temp = WriteStrings(ref reader, strings); long newStrLength = temp.Length - 4; writerData.Write(newStrLength); writerData.Write(temp); stringBytesChanged += newStrLength - lengthProperty; } else { writerData.Write(lengthProperty); writerData.Write(reader.ReadBytes((int)lengthProperty + 4)); } } else if (nameID == "m_Name") { List <string> strings; if (data.TryGetValue($"{name}_Name", out strings)) { byte[] temp = WriteStrings(ref reader, strings); long newStrLength = temp.Length - 4; writerData.Write(newStrLength); writerData.Write(temp); stringBytesChanged += newStrLength - lengthProperty; } else { writerData.Write(lengthProperty); writerData.Write(reader.ReadBytes((int)lengthProperty + 4)); } } else { writerData.Write(lengthProperty); writerData.Write(reader.ReadBytes((int)(lengthProperty + 4))); } } } } else { writerData.Write(reader.ReadBytes((int)size)); } writerData.Close(); newData.Add(newRealData.ToArray()); reader.BaseStream.Position = start; writer.Write(reader.ReadBytes(32)); if (stringBytesChanged != 0) { writer.Write((uint)(size + stringBytesChanged)); bytesChanged += stringBytesChanged; reader.BaseStream.Position += 4; } else { writer.Write(reader.ReadBytes(4)); } writer.Write((uint)newOffset); reader.BaseStream.Position += 4; writer.Write(reader.ReadBytes((int)headerLength - 40)); } writer.Write(new byte[emptyBytes]); foreach (byte[] dataMessage in newData) { writer.Write(dataMessage); } writer.Write(new byte[4]); break; case 1: byte[] decompressedData = Decompress(input, (uint)reader.BaseStream.Position); return(Reimport(decompressedData, data)); default: throw new Exception("The file has an unsupported compression type."); } } else { throw new Exception("The file is not a Drakengard 3 (Unreal 3) file."); } reader.Close(); writer.Close(); return(result.ToArray()); }
private static DataMessage GetStrings(ref BinaryReaderBE reader, string name, bool isSpeakerName) { List <string> strings = new List <string>(); long strCount = reader.ReadInt64(); for (int line = 0; line < strCount; line++) { int strLength = reader.ReadInt32(); if (strLength != 0) { int zeroBytes = strLength < 0 ? 2 : 1; strLength = strLength < 0 ? (int)((strLength ^ 0xFFFFFFFF) * 2) : strLength; string str = zeroBytes < 2 ? Encoding.GetEncoding(1252).GetString(reader.ReadBytes((int)strLength - zeroBytes)) : Encoding.Unicode.GetString(reader.ReadBytes((int)strLength)); for (int k = 0; k < ArchiveConfig.OriginalChars.Length; k++) { str = str.Replace(ArchiveConfig.OriginalChars[k], ArchiveConfig.ReplaceChars[k]); } strings.Add(str); reader.BaseStream.Position += zeroBytes; } else { strings.Add("{null}"); } } DataMessage dataMessage = new DataMessage(name, strings, isSpeakerName); return(dataMessage); }