public static DecompressME3 ( Stream input ) : |
||
input | Stream | pcc file passed in stream format |
return |
/// <summary> /// PCCObject class constructor. It also loads namelist, importlist, exportinfo, and exportdata from pcc file /// </summary> /// <param name="pccFilePath">full path + file name of desired pcc file.</param> private ME3Package(string pccFilePath) { FileName = Path.GetFullPath(pccFilePath); MemoryStream inStream; using (FileStream pccStream = File.OpenRead(FileName)) { header = pccStream.ReadBytes(headerSize); if (magic != ZBlock.magic && magic.Swap() != ZBlock.magic) { throw new FormatException("Not an Unreal package!"); } if (lowVers != 684 && highVers != 194) { throw new FormatException("Not an ME3 Package!"); } if (IsCompressed) { inStream = CompressionHelper.DecompressME3(pccStream); //read uncompressed header inStream.Seek(0, SeekOrigin.Begin); inStream.Read(header, 0, header.Length); //load uncompressed header } else { inStream = new MemoryStream(); pccStream.Seek(0, SeekOrigin.Begin); pccStream.CopyTo(inStream); } } names = new List <string>(); inStream.Seek(NameOffset, SeekOrigin.Begin); for (int i = 0; i < NameCount; i++) { int strLength = inStream.ReadValueS32(); string str = inStream.ReadString(strLength * -2, true, Encoding.Unicode); names.Add(str); } imports = new List <ImportEntry>(); inStream.Seek(ImportOffset, SeekOrigin.Begin); for (int i = 0; i < ImportCount; i++) { ImportEntry imp = new ImportEntry(this, inStream); imp.Index = i; imp.PropertyChanged += importChanged; imports.Add(imp); } exports = new List <IExportEntry>(); inStream.Seek(ExportOffset, SeekOrigin.Begin); for (int i = 0; i < ExportCount; i++) { ME3ExportEntry e = new ME3ExportEntry(this, inStream); e.Index = i; e.PropertyChanged += exportChanged; exports.Add(e); } }
private MEPackage(string filePath, MEGame forceGame = MEGame.Unknown) : base(Path.GetFullPath(filePath)) { ME3ExpMemoryAnalyzer.MemoryAnalyzer.AddTrackedMemoryItem($"MEPackage {Path.GetFileName(filePath)}", new WeakReference(this)); if (forceGame != MEGame.Unknown) { //new Package Game = forceGame; //reasonable defaults? Flags = EPackageFlags.Cooked | EPackageFlags.AllowDownload | EPackageFlags.DisallowLazyLoading | EPackageFlags.RequireImportsAlreadyLoaded; return; } using (var fs = File.OpenRead(filePath)) { #region Header uint magic = fs.ReadUInt32(); if (magic != packageTag) { throw new FormatException("Not an Unreal package!"); } ushort unrealVersion = fs.ReadUInt16(); ushort licenseeVersion = fs.ReadUInt16(); switch (unrealVersion) { case ME1UnrealVersion when licenseeVersion == ME1LicenseeVersion: Game = MEGame.ME1; break; case ME2UnrealVersion when licenseeVersion == ME2LicenseeVersion: Game = MEGame.ME2; break; case ME3UnrealVersion when licenseeVersion == ME3LicenseeVersion: Game = MEGame.ME3; break; default: throw new FormatException("Not a Mass Effect Package!"); } FullHeaderSize = fs.ReadInt32(); int foldernameStrLen = fs.ReadInt32(); //always "None", so don't bother saving result if (foldernameStrLen > 0) { fs.ReadStringASCIINull(foldernameStrLen); } else { fs.ReadStringUnicodeNull(foldernameStrLen * -2); } Flags = (EPackageFlags)fs.ReadUInt32(); if (Game == MEGame.ME3 && Flags.HasFlag(EPackageFlags.Cooked)) { fs.SkipInt32(); //always 0 } NameCount = fs.ReadInt32(); NameOffset = fs.ReadInt32(); ExportCount = fs.ReadInt32(); ExportOffset = fs.ReadInt32(); ImportCount = fs.ReadInt32(); ImportOffset = fs.ReadInt32(); DependencyTableOffset = fs.ReadInt32(); if (Game == MEGame.ME3) { ImportExportGuidsOffset = fs.ReadInt32(); fs.SkipInt32(); //ImportGuidsCount always 0 fs.SkipInt32(); //ExportGuidsCount always 0 fs.SkipInt32(); //ThumbnailTableOffset always 0 } PackageGuid = fs.ReadGuid(); uint generationsTableCount = fs.ReadUInt32(); if (generationsTableCount > 0) { generationsTableCount--; Gen0ExportCount = fs.ReadInt32(); Gen0NameCount = fs.ReadInt32(); Gen0NetworkedObjectCount = fs.ReadInt32(); } //should never be more than 1 generation, but just in case fs.Skip(generationsTableCount * 12); fs.SkipInt32(); //engineVersion Like unrealVersion and licenseeVersion, these 2 are determined by what game this is, fs.SkipInt32(); //cookedContentVersion so we don't have to read them in if (Game == MEGame.ME2 || Game == MEGame.ME1) { fs.SkipInt32(); //always 0 fs.SkipInt32(); //always 47699 unknown4 = fs.ReadInt32(); fs.SkipInt32(); //always 1 in ME1, always 1966080 in ME2 } unknown6 = fs.ReadInt32(); fs.SkipInt32(); //always -1 in ME1 and ME2, always 145358848 in ME3 if (Game == MEGame.ME1) { fs.SkipInt32(); //always -1 } //skip compression type chunks. Decompressor will handle that fs.SkipInt32(); int numChunks = fs.ReadInt32(); fs.Skip(numChunks * 16); packageSource = fs.ReadUInt32(); if (Game == MEGame.ME2 || Game == MEGame.ME1) { fs.SkipInt32(); //always 0 } //Doesn't need to be written out, so it doesn't need to be read in //keep this here in case one day we learn that this has a purpose /*if (Game == MEGame.ME2 || Game == MEGame.ME3) * { * int additionalPackagesToCookCount = fs.ReadInt32(); * var additionalPackagesToCook = new string[additionalPackagesToCookCount]; * for (int i = 0; i < additionalPackagesToCookCount; i++) * { * int strLen = fs.ReadInt32(); * if (strLen > 0) * { * additionalPackagesToCook[i] = fs.ReadStringASCIINull(strLen); * } * else * { * additionalPackagesToCook[i] = fs.ReadStringUnicodeNull(strLen * -2); * } * } * }*/ #endregion Stream inStream = fs; if (IsCompressed && numChunks > 0) { inStream = Game == MEGame.ME3 ? CompressionHelper.DecompressME3(fs) : CompressionHelper.DecompressME1orME2(fs); } //read namelist inStream.JumpTo(NameOffset); for (int i = 0; i < NameCount; i++) { names.Add(inStream.ReadUnrealString()); if (Game == MEGame.ME1) { inStream.Skip(8); } else if (Game == MEGame.ME2) { inStream.Skip(4); } } //read importTable inStream.JumpTo(ImportOffset); for (int i = 0; i < ImportCount; i++) { ImportEntry imp = new ImportEntry(this, inStream) { Index = i }; imp.PropertyChanged += importChanged; imports.Add(imp); } //read exportTable (ExportEntry constructor reads export data) inStream.JumpTo(ExportOffset); for (int i = 0; i < ExportCount; i++) { ExportEntry e = new ExportEntry(this, inStream) { Index = i }; e.PropertyChanged += exportChanged; exports.Add(e); } if (Game == MEGame.ME1) { ReadLocalTLKs(); } } }
/// <summary> /// PCCObject class constructor. It also loads namelist, importlist, exportinfo, and exportdata from pcc file /// </summary> /// <param name="pccFilePath">full path + file name of desired pcc file.</param> private ME3Package(string pccFilePath) { FileName = Path.GetFullPath(pccFilePath); MemoryStream listsStream; names = new List <string>(); imports = new List <ImportEntry>(); exports = new List <ME3ExportEntry>(); using (FileStream pccStream = File.OpenRead(FileName)) { header = pccStream.ReadBytes(headerSize); if (magic != ZBlock.magic && magic.Swap() != ZBlock.magic) { throw new FormatException("not a pcc file"); } if (lowVers != 684 && highVers != 194) { throw new FormatException("unsupported version"); } if (IsCompressed) { listsStream = CompressionHelper.DecompressME3(pccStream); //correcting the header listsStream.Seek(0, SeekOrigin.Begin); listsStream.Read(header, 0, header.Length); } else { listsStream = new MemoryStream(); pccStream.Seek(0, SeekOrigin.Begin); pccStream.CopyTo(listsStream); } } // fill names list listsStream.Seek(NameOffset, SeekOrigin.Begin); for (int i = 0; i < NameCount; i++) { long currOffset = listsStream.Position; int strLength = listsStream.ReadValueS32(); string str = listsStream.ReadString(strLength * -2, true, Encoding.Unicode); names.Add(str); } // fill import list listsStream.Seek(ImportOffset, SeekOrigin.Begin); for (int i = 0; i < ImportCount; i++) { long offset = listsStream.Position; ImportEntry imp = new ImportEntry(this, listsStream); imp.Index = i; imp.PropertyChanged += importChanged; imports.Add(imp); } // fill export list listsStream.Seek(ExportOffset, SeekOrigin.Begin); byte[] buffer; for (int i = 0; i < ExportCount; i++) { uint expInfoOffset = (uint)listsStream.Position; listsStream.Seek(44, SeekOrigin.Current); int count = listsStream.ReadValueS32(); listsStream.Seek(-48, SeekOrigin.Current); int expInfoSize = 68 + (count * 4); buffer = new byte[expInfoSize]; listsStream.Read(buffer, 0, buffer.Length); ME3ExportEntry e = new ME3ExportEntry(this, buffer, expInfoOffset); long headerEnd = listsStream.Position; buffer = new byte[e.DataSize]; listsStream.Seek(e.DataOffset, SeekOrigin.Begin); listsStream.Read(buffer, 0, buffer.Length); e.Data = buffer; e.DataChanged = false; e.Index = i; e.PropertyChanged += exportChanged; exports.Add(e); listsStream.Seek(headerEnd, SeekOrigin.Begin); } }