public ME1PCCObject(String path) { lzo = new SaltLZOHelper(); fullname = path; BitConverter.IsLittleEndian = true; DebugOutput.PrintLn("Load file : " + path); pccFileName = Path.GetFullPath(path); MemoryStream tempStream = new MemoryStream(); if (!File.Exists(pccFileName)) throw new FileNotFoundException("PCC file not found"); using (FileStream fs = new FileStream(pccFileName, FileMode.Open, FileAccess.Read)) { FileInfo tempInfo = new FileInfo(pccFileName); tempStream.WriteFromStream(fs, tempInfo.Length); if (tempStream.Length != tempInfo.Length) { throw new FileLoadException("File not fully read in. Try again later"); } } LoadHelper(tempStream); }
/// <summary> /// ME3PCCObject class constructor. It also load namelist, importlist and exportinfo (not exportdata) from pcc file /// </summary> /// <param name="pccFilePath">full path + file name of desired pcc file.</param> public ME3PCCObject(string filePath, bool TablesOnly = false) { pccFileName = Path.GetFullPath(filePath); BitConverter.IsLittleEndian = true; MemoryStream tempStream = new MemoryStream(); if (!File.Exists(pccFileName)) throw new FileNotFoundException("LET ME KNOW ABOUT THIS! filename: " + pccFileName); int trycout = 0; while (trycout < 50) { try { using (FileStream fs = new FileStream(pccFileName, FileMode.Open, FileAccess.Read)) { FileInfo tempInfo = new FileInfo(pccFileName); tempStream.WriteFromStream(fs, tempInfo.Length); if (tempStream.Length != tempInfo.Length) { throw new FileLoadException("File not fully read in. Try again later"); } } break; } catch (Exception e) { // KFreon: File inaccessible or someting Console.WriteLine(e.Message); DebugOutput.PrintLn("File inaccessible: " + filePath + ". Attempt: " + trycout); trycout++; System.Threading.Thread.Sleep(100); } } ME3PCCObjectHelper(tempStream, filePath, TablesOnly); }
/// <summary> /// decompress an entire ME3 pcc file into a new stream /// </summary> /// <param name="input">pcc file passed in stream format</param> /// <returns>a decompressed array of bytes</returns> public static MemoryStream DecompressME3(Stream input) { input.Seek(0, SeekOrigin.Begin); var magic = input.ReadValueU32(Endian.Little); if (magic != 0x9E2A83C1 && magic.Swap() != 0x9E2A83C1) { throw new FormatException("not a pcc file"); } var endian = magic == 0x9E2A83C1 ? Endian.Little : Endian.Big; var versionLo = input.ReadValueU16(endian); var versionHi = input.ReadValueU16(endian); if (versionLo != 684 && versionHi != 194) { throw new FormatException("unsupported pcc version"); } long headerSize = 8; input.Seek(4, SeekOrigin.Current); headerSize += 4; var folderNameLength = input.ReadValueS32(endian); headerSize += 4; var folderNameByteLength = folderNameLength >= 0 ? folderNameLength : (-folderNameLength * 2); input.Seek(folderNameByteLength, SeekOrigin.Current); headerSize += folderNameByteLength; var packageFlagsOffset = input.Position; var packageFlags = input.ReadValueU32(endian); headerSize += 4; if ((packageFlags & 0x02000000u) == 0) { throw new FormatException("pcc file is already decompressed"); } if ((packageFlags & 8) != 0) { input.Seek(4, SeekOrigin.Current); headerSize += 4; } uint nameCount = input.ReadValueU32(endian); uint nameOffset = input.ReadValueU32(endian); input.Seek(52, SeekOrigin.Current); headerSize += 60; var generationsCount = input.ReadValueU32(endian); input.Seek(generationsCount * 12, SeekOrigin.Current); headerSize += generationsCount * 12; input.Seek(20, SeekOrigin.Current); headerSize += 24; var blockCount = input.ReadValueU32(endian); int headBlockOff = (int)input.Position; var afterBlockTableOffset = headBlockOff + (blockCount * 16); var indataOffset = afterBlockTableOffset + 8; byte[] buff; input.Seek(0, SeekOrigin.Begin); MemoryStream output = new MemoryStream(); output.Seek(0, SeekOrigin.Begin); output.WriteFromStream(input, headerSize); output.WriteValueU32(0, endian); // block count input.Seek(afterBlockTableOffset, SeekOrigin.Begin); output.WriteFromStream(input, 8); //check if has extra name list (don't know it's usage...) if ((packageFlags & 0x10000000) != 0) { long curPos = output.Position; output.WriteFromStream(input, nameOffset - curPos); } //decompress blocks in parallel Task<byte[]>[] tasks = new Task<byte[]>[blockCount]; uint[] uncompressedOffsets = new uint[blockCount]; for (int i = 0; i < blockCount; i++) { input.Seek(headBlockOff, SeekOrigin.Begin); uncompressedOffsets[i] = input.ReadValueU32(endian); var uncompressedSize = input.ReadValueU32(endian); var compressedOffset = input.ReadValueU32(endian); var compressedSize = input.ReadValueU32(endian); headBlockOff = (int)input.Position; buff = new byte[compressedSize]; input.Seek(compressedOffset, SeekOrigin.Begin); input.Read(buff, 0, buff.Length); tasks[i] = ZBlock.DecompressAsync(buff); } Task.WaitAll(tasks); for (int i = 0; i < blockCount; i++) { output.Seek(uncompressedOffsets[i], SeekOrigin.Begin); output.WriteBytes(tasks[i].Result); } output.Seek(packageFlagsOffset, SeekOrigin.Begin); output.WriteValueU32(packageFlags & ~0x02000000u, endian); return output; }
private ME1Package(string path) { DebugOutput.PrintLn("Load file : " + path); FileName = Path.GetFullPath(path); MemoryStream tempStream = new MemoryStream(); if (!File.Exists(FileName)) throw new FileNotFoundException("PCC file not found"); using (FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read)) { FileInfo tempInfo = new FileInfo(FileName); tempStream.WriteFromStream(fs, tempInfo.Length); if (tempStream.Length != tempInfo.Length) { throw new FileLoadException("File not fully read in. Try again later"); } } tempStream.Seek(12, SeekOrigin.Begin); int tempNameSize = tempStream.ReadValueS32(); tempStream.Seek(64 + tempNameSize, SeekOrigin.Begin); int tempGenerations = tempStream.ReadValueS32(); tempStream.Seek(36 + tempGenerations * 12, SeekOrigin.Current); int tempPos = (int)tempStream.Position + 4; tempStream.Seek(0, SeekOrigin.Begin); header = tempStream.ReadBytes(tempPos); tempStream.Seek(0, SeekOrigin.Begin); if (magic != ZBlock.magic && magic.Swap() != ZBlock.magic) { DebugOutput.PrintLn("Magic number incorrect: " + magic); throw new FormatException("This is not an ME1 Package file. The magic number is incorrect."); } MemoryStream listsStream; if (IsCompressed) { DebugOutput.PrintLn("File is compressed"); listsStream = CompressionHelper.DecompressME1orME2(tempStream); //Correct the header IsCompressed = false; listsStream.Seek(0, SeekOrigin.Begin); listsStream.WriteBytes(header); // Set numblocks to zero listsStream.WriteValueS32(0); //Write the magic number listsStream.WriteBytes(new byte[] { 0xF2, 0x56, 0x1B, 0x4E }); // Write 4 bytes of 0 listsStream.WriteValueS32(0); } else { DebugOutput.PrintLn("File already decompressed. Reading decompressed data."); //listsStream = tempStream; listsStream = new MemoryStream(); tempStream.WriteTo(listsStream); } tempStream.Dispose(); ReadNames(listsStream); ReadImports(listsStream); ReadExports(listsStream); }
public PCCObject(String path, Boolean littleEndian=true) { lzo = new SaltLZOHelper(); fullname = path; BitConverter.IsLittleEndian = littleEndian; StreamHelpers.setIsLittleEndian(littleEndian); DebugOutput.PrintLn("Load file : " + path); pccFileName = Path.GetFullPath(path); MemoryStream tempStream = new MemoryStream(); if (!File.Exists(pccFileName)) throw new FileNotFoundException("PCC file not found"); using (FileStream fs = new FileStream(pccFileName, FileMode.Open, FileAccess.Read)) { FileInfo tempInfo = new FileInfo(pccFileName); tempStream.WriteFromStream(fs, tempInfo.Length); if (tempStream.Length != tempInfo.Length) { throw new FileLoadException("File not fully read in. Try again later"); } } tempStream.Seek(12, SeekOrigin.Begin); int tempNameSize = tempStream.ReadValueS32(); tempStream.Seek(64 + tempNameSize, SeekOrigin.Begin); int tempGenerator = tempStream.ReadValueS32(); tempStream.Seek(36 + tempGenerator * 12, SeekOrigin.Current); int tempPos = (int)tempStream.Position; NumChunks = tempStream.ReadValueS32(); tempStream.Seek(0, SeekOrigin.Begin); header = tempStream.ReadBytes(tempPos); tempStream.Seek(0, SeekOrigin.Begin); if (magic != ZBlock.magic && magic.Swap() != ZBlock.magic) { DebugOutput.PrintLn("Magic number incorrect: " + magic); throw new FormatException("This is not a pcc file. The magic number is incorrect."); } if (bCompressed) { DebugOutput.PrintLn("File is compressed"); { listsStream = lzo.DecompressPCC(tempStream, this); //Correct the header bCompressed = false; listsStream.Seek(0, SeekOrigin.Begin); listsStream.WriteBytes(header); //Set numblocks to zero listsStream.WriteValueS32(0); //Write the magic number listsStream.WriteValueS32(1026281201); //Write 8 bytes of 0 listsStream.WriteValueS32(0); listsStream.WriteValueS32(0); } } else { DebugOutput.PrintLn("File already decompressed. Reading decompressed data."); listsStream = tempStream; } ReadNames(listsStream); ReadImports(listsStream); ReadExports(listsStream); LoadExports(); }
public static MemoryStream Decompress(Stream input) { var basePosition = input.Position; if (input.ReadValueU32(false) != Magic) // CDRM { throw new FormatException(); } var version = input.ReadValueU32(true); if (version != 0 && version != 2 && version.Swap() != 2) { throw new FormatException(); } bool littleEndian; uint count; uint padding; if (version == 0) { count = input.ReadValueU32(true); if (count > 0x7FFFFF) { count = count.Swap(); littleEndian = false; } else { littleEndian = true; } input.ReadValueU32(littleEndian); padding = (uint)(basePosition + 16 + (count * 8)); padding = padding.Align(16) - padding; } else { littleEndian = version == 2; count = input.ReadValueU32(littleEndian); padding = input.ReadValueU32(littleEndian); } var startOfData = basePosition + 16 + (count * 8) + padding; var blocks = new Block[count]; using (var buffer = input.ReadToMemoryStream((count * 8).Align(16))) { for (uint i = 0; i < count; i++) { var block = new Block(); var flags = buffer.ReadValueU32(littleEndian); block.UncompressedSize = (flags >> 8) & 0xFFFFFF; block.Type = (byte)(flags & 0xFF); block.CompressedSize = buffer.ReadValueU32(littleEndian); blocks[i] = block; } } if (startOfData != input.Position) { throw new InvalidOperationException(); } var output = new MemoryStream(); long offset = 0; foreach (var block in blocks) { var nextPosition = input.Position + block.CompressedSize.Align(16); using (var buffer = input.ReadToMemoryStream(block.CompressedSize)) { if (block.Type == 1) { if (block.CompressedSize != block.UncompressedSize) { throw new InvalidOperationException(); } output.Seek(offset, SeekOrigin.Begin); output.WriteFromStream(buffer, block.CompressedSize); offset += block.CompressedSize.Align(16); } else if (block.Type == 2) { var zlib = new InflaterInputStream(buffer); output.Seek(offset, SeekOrigin.Begin); output.WriteFromStream(zlib, block.UncompressedSize); offset += block.UncompressedSize.Align(16); } else { throw new FormatException(); } } input.Seek(nextPosition, SeekOrigin.Begin); } output.Position = 0; return output; }
public Stream Serialize() { MemoryStream data = new MemoryStream(); uint sectionCount = (uint)this.Sections.Count; Stream[] resolvers = new MemoryStream[sectionCount]; // for serialized resolvers uint unknown04_size = 0; uint unknown08_size = 0; // Write DRM Header data.WriteValueU32(this.Version, this.Endianness); data.WriteValueU32(0); // skip for now data.WriteValueU32(0); // skip for now data.WriteValueU32(0); // unknown0C data.WriteValueU32(0); // unknown10 data.WriteValueU32(sectionCount, this.Endianness); // Write DRM Section Headers for (int i = 0; i < sectionCount; i++) { DRM.Section section = this.Sections[i]; // Serialize resolvers to get length, data will be used later uint resolverLen; if (section.Resolver != null) { resolvers[i] = section.Resolver.Serialize(this.Endianness); resolverLen = (uint)resolvers[i].Length; } else { resolvers[i] = null; resolverLen = 0; } data.WriteValueU32((uint)section.Data.Length, this.Endianness); data.WriteValueU8((byte)section.Type); data.WriteValueU8(section.Unknown05); data.WriteValueU16(section.Unknown06, this.Endianness); data.WriteValueU32((uint)section.Flags | (resolverLen << 8), this.Endianness); data.WriteValueU32(section.Id, this.Endianness); data.WriteValueU32(section.Unknown10, this.Endianness); } // Write Unknown08s for (int i = 0; i < Unknown08s.Count; i++) { unknown08_size += ((uint)Unknown08s[i].Length + 1); data.WriteStringZ(Unknown08s[i]); } // Write Unknown04s for (int i = 0; i < Unknown04s.Count; i++) { unknown04_size += ((uint)Unknown04s[i].Length + 1); data.WriteStringZ(Unknown04s[i]); } // Write DRM Section Data for (int i = 0; i < sectionCount; i++) { if (resolvers[i] != null) { data.WriteFromStream(resolvers[i], resolvers[i].Length); } data.WriteFromStream(this.Sections[i].Data, this.Sections[i].Data.Length); this.Sections[i].Data.Position = 0; } // Go back and write unknowns length data.Seek(4, SeekOrigin.Begin); data.WriteValueU32(unknown04_size); data.WriteValueU32(unknown08_size); data.Position = 0; return data; }