DecompressME3() public static method

decompress an entire ME3 pcc file into a new stream
public static DecompressME3 ( Stream input ) : MemoryStream
input Stream pcc file passed in stream format
return System.IO.MemoryStream
Beispiel #1
0
        /// <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);
            }
        }
Beispiel #2
0
        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();
                }
            }
        }
Beispiel #3
0
        /// <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);
            }
        }