Example #1
0
        /// <summary>
        ///     UDKPackage class constructor. It also load namelist, importlist and exportinfo (not exportdata) from udk file
        /// </summary>
        /// <param name="UDKPackagePath">full path + file name of desired udk file.</param>
        /// <param name="create">Create a file instead of reading from disk</param>
        private UDKPackage(string UDKPackagePath, bool create = false) : base(Path.GetFullPath(UDKPackagePath))
        {
            ME3ExpMemoryAnalyzer.MemoryAnalyzer.AddTrackedMemoryItem($"UDKPackage {Path.GetFileName(UDKPackagePath)}", new WeakReference(this));

            if (create)
            {
                folderName    = "None";
                engineVersion = 12791;
                //reasonable defaults?
                Flags = EPackageFlags.AllowDownload | EPackageFlags.NoExportsData;
                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();
                FullHeaderSize = fs.ReadInt32();
                int foldernameStrLen = fs.ReadInt32();
                //always "None", so don't bother saving result
                if (foldernameStrLen > 0)
                {
                    folderName = fs.ReadStringASCIINull(foldernameStrLen);
                }
                else
                {
                    folderName = fs.ReadStringUnicodeNull(foldernameStrLen * -2);
                }

                Flags = (EPackageFlags)fs.ReadUInt32();

                //if (Flags.HasFlag(EPackageFlags.Compressed))
                //{
                //    throw new FormatException("Cannot read compressed UDK packages!");
                //}

                NameCount               = fs.ReadInt32();
                NameOffset              = fs.ReadInt32();
                ExportCount             = fs.ReadInt32();
                ExportOffset            = fs.ReadInt32();
                ImportCount             = fs.ReadInt32();
                ImportOffset            = fs.ReadInt32();
                DependencyTableOffset   = fs.ReadInt32();
                importExportGuidsOffset = fs.ReadInt32();
                importGuidsCount        = fs.ReadInt32();
                exportGuidsCount        = fs.ReadInt32();
                thumbnailTableOffset    = fs.ReadInt32();
                PackageGuid             = fs.ReadGuid();

                uint generationsTableCount = fs.ReadUInt32();
                if (generationsTableCount > 0)
                {
                    generationsTableCount--;
                    Gen0ExportCount          = fs.ReadInt32();
                    Gen0NameCount            = fs.ReadInt32();
                    Gen0NetworkedObjectCount = fs.ReadInt32();
                }
                //don't care about other gens, so skip them
                fs.Skip(generationsTableCount * 12);
                engineVersion        = fs.ReadInt32();
                cookedContentVersion = fs.ReadInt32();

                //skip compression type chunks. Decompressor will handle that
                long compressionInfoOffset = fs.Position;
                fs.SkipInt32();
                int numChunks = fs.ReadInt32();
                fs.Skip(numChunks * 16);

                packageSource = fs.ReadUInt32();
                //additional packages to cook, and texture allocation, but we don't care about those, so we won't read them in.

                #endregion
                Stream inStream = fs;
                if (IsCompressed && numChunks > 0)
                {
                    inStream = CompressionHelper.DecompressUDK(fs, compressionInfoOffset);
                }

                inStream.JumpTo(NameOffset);
                for (int i = 0; i < NameCount; i++)
                {
                    names.Add(inStream.ReadUnrealString());
                    inStream.Skip(8);
                }

                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);
                }
            }
        }
Example #2
0
        private static void UpdateME2Offsets(ExportEntry export, int newDataOffset)
        {
            if (export.IsDefaultObject)
            {
                return; //this is not actually instance of that class
            }
            //update offsets for pcc-stored audio in wwisestreams
            if (export.ClassName == "WwiseStream" && export.GetProperty <NameProperty>("Filename") == null)
            {
                byte[] binData = export.getBinaryData();
                if (binData.Length < 44)
                {
                    return; //¯\_(ツ)_ /¯
                }
                binData.OverwriteRange(44, BitConverter.GetBytes(newDataOffset + export.propsEnd() + 48));
                export.setBinaryData(binData);
            }
            //update offsets for pcc-stored mips in Textures
            else if (export.ClassName == "WwiseBank")
            {
                byte[] binData = export.getBinaryData();
                binData.OverwriteRange(20, BitConverter.GetBytes(newDataOffset + export.propsEnd() + 24));
                export.setBinaryData(binData);
            }
            //update offsets for pcc-stored mips in Textures
            //else if (export.IsTexture())
            //{
            //    int baseOffset = newDataOffset + export.propsEnd();
            //    MemoryStream binData = new MemoryStream(export.getBinaryData());
            //    binData.Skip(12);
            //    binData.WriteInt32(baseOffset + (int)binData.Position + 4);
            //    for (int i = binData.ReadInt32(); i > 0 && binData.Position < binData.Length; i--)
            //    {
            //        var storageFlags = (StorageFlags)binData.ReadInt32();
            //        if (!storageFlags.HasFlag(StorageFlags.externalFile)) //pcc-stored
            //        {
            //            int uncompressedSize = binData.ReadInt32();
            //            int compressedSize = binData.ReadInt32();
            //            binData.WriteInt32(baseOffset + (int)binData.Position + 4);//update offset
            //            binData.Seek((storageFlags == StorageFlags.noFlags ? uncompressedSize : compressedSize) + 8, SeekOrigin.Current); //skip texture and width + height values
            //        }
            //        else
            //        {
            //            binData.Seek(20, SeekOrigin.Current);//skip whole rest of mip definition
            //        }
            //    }
            //    export.setBinaryData(binData.ToArray());
            //}
            else if (export.ClassName == "ShaderCache")
            {
                int oldDataOffset = export.DataOffset;

                MemoryStream binData = new MemoryStream(export.Data);
                binData.Seek(export.propsEnd() + 1, SeekOrigin.Begin);

                int nameList1Count = binData.ReadInt32();
                binData.Seek(nameList1Count * 12, SeekOrigin.Current);

                int shaderCount = binData.ReadInt32();
                for (int i = 0; i < shaderCount; i++)
                {
                    binData.Seek(24, SeekOrigin.Current);
                    int nextShaderOffset = binData.ReadInt32() - oldDataOffset;
                    binData.Seek(-4, SeekOrigin.Current);
                    binData.WriteInt32(nextShaderOffset + newDataOffset);
                    binData.Seek(nextShaderOffset, SeekOrigin.Begin);
                }

                int vertexFactoryMapCount = binData.ReadInt32();
                binData.Seek(vertexFactoryMapCount * 12, SeekOrigin.Current);

                int materialShaderMapCount = binData.ReadInt32();
                for (int i = 0; i < materialShaderMapCount; i++)
                {
                    binData.Seek(16, SeekOrigin.Current);

                    int switchParamCount = binData.ReadInt32();
                    binData.Seek(switchParamCount * 32, SeekOrigin.Current);

                    int componentMaskParamCount = binData.ReadInt32();
                    binData.Seek(componentMaskParamCount * 44, SeekOrigin.Current);

                    int nextMaterialShaderMapOffset = binData.ReadInt32() - oldDataOffset;
                    binData.Seek(-4, SeekOrigin.Current);
                    binData.WriteInt32(nextMaterialShaderMapOffset + newDataOffset);
                    binData.Seek(nextMaterialShaderMapOffset, SeekOrigin.Begin);
                }

                export.Data = binData.ToArray();
            }
            else if (export.ClassName == "StaticMeshComponent")
            {
                int          baseOffset = newDataOffset + export.propsEnd();
                MemoryStream bin        = new MemoryStream(export.Data);
                bin.JumpTo(export.propsEnd());

                int lodDataCount = bin.ReadInt32();
                for (int i = 0; i < lodDataCount; i++)
                {
                    int shadowMapCount = bin.ReadInt32();
                    bin.Skip(shadowMapCount * 4);
                    int shadowVertCount = bin.ReadInt32();
                    bin.Skip(shadowVertCount * 4);
                    int lightMapType = bin.ReadInt32();
                    if (lightMapType == 0)
                    {
                        continue;
                    }
                    int lightGUIDsCount = bin.ReadInt32();
                    bin.Skip(lightGUIDsCount * 16);
                    switch (lightMapType)
                    {
                    case 1:
                        bin.Skip(4 + 8);
                        int bulkDataSize = bin.ReadInt32();
                        bin.WriteInt32(baseOffset + (int)bin.Position + 4);
                        bin.Skip(bulkDataSize);
                        bin.Skip(12 * 4 + 8);
                        bulkDataSize = bin.ReadInt32();
                        bin.WriteInt32(baseOffset + (int)bin.Position + 4);
                        bin.Skip(bulkDataSize);
                        break;

                    case 2:
                        bin.Skip((16) * 4 + 16);
                        break;
                    }
                }
            }
        }
Example #3
0
        private static void UpdateME3Offsets(ExportEntry export, int newDataOffset)
        {
            if (export.IsDefaultObject)
            {
                return; //this is not actually instance of that class
            }
            //update offsets for pcc-stored audio in wwisestreams
            if ((export.ClassName == "WwiseStream" && export.GetProperty <NameProperty>("Filename") == null) || export.ClassName == "WwiseBank")
            {
                byte[] binData = export.getBinaryData();
                binData.OverwriteRange(12, BitConverter.GetBytes(newDataOffset + export.propsEnd() + 16));
                export.setBinaryData(binData);
            }
            //update offsets for pcc-stored movies in texturemovies
            else if (export.ClassName == "TextureMovie" && export.GetProperty <NameProperty>("TextureFileCacheName") == null)
            {
                byte[] binData = export.getBinaryData();
                binData.OverwriteRange(12, BitConverter.GetBytes(newDataOffset + export.propsEnd() + 16));
                export.setBinaryData(binData);
            }
            //update offsets for pcc-stored mips in Textures
            //Keeping around just in case I somehow forgot something. -Mgamerz
            //else if (export.IsTexture())
            //{
            //    int baseOffset = newDataOffset + export.propsEnd();
            //    MemoryStream binData = new MemoryStream(export.getBinaryData());
            //    for (int i = binData.ReadInt32(); i > 0 && binData.Position < binData.Length; i--)
            //    {
            //        if (binData.ReadInt32() == (int)StorageTypes.pccUnc) //pcc-stored
            //        {
            //            int uncompressedSize = binData.ReadInt32();
            //            binData.Seek(4, SeekOrigin.Current); //skip compressed size
            //            binData.WriteInt32(baseOffset + (int)binData.Position + 4);//update offset
            //            binData.Seek(uncompressedSize + 8, SeekOrigin.Current); //skip texture and width + height values
            //        }
            //        else
            //        {
            //            binData.Seek(20, SeekOrigin.Current);//skip whole rest of mip definition
            //        }
            //    }
            //    export.setBinaryData(binData.ToArray());
            //}
            else if (export.ClassName == "ShaderCache")
            {
                int oldDataOffset = export.DataOffset;

                MemoryStream binData = new MemoryStream(export.Data);
                binData.Seek(export.propsEnd() + 1, SeekOrigin.Begin);

                int nameList1Count = binData.ReadInt32();
                binData.Seek(nameList1Count * 12, SeekOrigin.Current);

                int namelist2Count = binData.ReadInt32();//namelist2
                binData.Seek(namelist2Count * 12, SeekOrigin.Current);

                int shaderCount = binData.ReadInt32();
                for (int i = 0; i < shaderCount; i++)
                {
                    binData.Seek(24, SeekOrigin.Current);
                    int nextShaderOffset = binData.ReadInt32() - oldDataOffset;
                    binData.Seek(-4, SeekOrigin.Current);
                    binData.WriteInt32(nextShaderOffset + newDataOffset);
                    binData.Seek(nextShaderOffset, SeekOrigin.Begin);
                }

                int vertexFactoryMapCount = binData.ReadInt32();
                binData.Seek(vertexFactoryMapCount * 12, SeekOrigin.Current);

                int materialShaderMapCount = binData.ReadInt32();
                for (int i = 0; i < materialShaderMapCount; i++)
                {
                    binData.Seek(16, SeekOrigin.Current);

                    int switchParamCount = binData.ReadInt32();
                    binData.Seek(switchParamCount * 32, SeekOrigin.Current);

                    int componentMaskParamCount = binData.ReadInt32();
                    binData.Seek(componentMaskParamCount * 44, SeekOrigin.Current);

                    int normalParams = binData.ReadInt32();
                    binData.Seek(normalParams * 29, SeekOrigin.Current);

                    binData.Seek(8, SeekOrigin.Current);

                    int nextMaterialShaderMapOffset = binData.ReadInt32() - oldDataOffset;
                    binData.Seek(-4, SeekOrigin.Current);
                    binData.WriteInt32(nextMaterialShaderMapOffset + newDataOffset);
                    binData.Seek(nextMaterialShaderMapOffset, SeekOrigin.Begin);
                }

                export.Data = binData.ToArray();
            }
            else if (export.ClassName == "StaticMeshComponent")
            {
                int          baseOffset = newDataOffset + export.propsEnd();
                MemoryStream bin        = new MemoryStream(export.Data);
                bin.JumpTo(export.propsEnd());

                int lodDataCount = bin.ReadInt32();
                for (int i = 0; i < lodDataCount; i++)
                {
                    int shadowMapCount = bin.ReadInt32();
                    bin.Skip(shadowMapCount * 4);
                    int shadowVertCount = bin.ReadInt32();
                    bin.Skip(shadowVertCount * 4);
                    int lightMapType = bin.ReadInt32();
                    if (lightMapType == 0)
                    {
                        continue;
                    }
                    int lightGUIDsCount = bin.ReadInt32();
                    bin.Skip(lightGUIDsCount * 16);
                    int bulkDataSize;
                    switch (lightMapType)
                    {
                    case 1:
                        bin.Skip(4 + 8);
                        bulkDataSize = bin.ReadInt32();
                        bin.WriteInt32(baseOffset + (int)bin.Position + 4);
                        bin.Skip(bulkDataSize);
                        bin.Skip(12 * 3 + 8);
                        bulkDataSize = bin.ReadInt32();
                        bin.WriteInt32(baseOffset + (int)bin.Position + 4);
                        bin.Skip(bulkDataSize);
                        break;

                    case 2:
                        bin.Skip((16) * 3 + 16);
                        break;

                    case 3:
                        bin.Skip(8);
                        bulkDataSize = bin.ReadInt32();
                        bin.WriteInt32(baseOffset + (int)bin.Position + 4);
                        bin.Skip(bulkDataSize);
                        bin.Skip(24);
                        break;

                    case 4:
                    case 6:
                        bin.Skip(124);
                        break;

                    case 5:
                        bin.Skip(4 + 8);
                        bulkDataSize = bin.ReadInt32();
                        bin.WriteInt32(baseOffset + (int)bin.Position + 4);
                        bin.Skip(bulkDataSize);
                        bin.Skip(12);
                        break;
                    }
                }
            }
        }
Example #4
0
        private static void UpdateME1Offsets(ExportEntry export, int newDataOffset)
        {
            if (export.IsDefaultObject)
            {
                return; //this is not actually instance of that class
            }
            if (export.IsTexture())
            {
                int          baseOffset = newDataOffset + export.propsEnd();
                MemoryStream binData    = new MemoryStream(export.getBinaryData());
                binData.Skip(12);
                binData.WriteInt32(baseOffset + (int)binData.Position + 4);
                for (int i = binData.ReadInt32(); i > 0 && binData.Position < binData.Length; i--)
                {
                    var storageFlags = (StorageFlags)binData.ReadInt32();
                    if (!storageFlags.HasFlag(StorageFlags.externalFile)) //pcc-stored
                    {
                        int uncompressedSize = binData.ReadInt32();
                        int compressedSize   = binData.ReadInt32();
                        binData.WriteInt32(baseOffset + (int)binData.Position + 4);                                                       //update offset
                        binData.Seek((storageFlags == StorageFlags.noFlags ? uncompressedSize : compressedSize) + 8, SeekOrigin.Current); //skip texture and width + height values
                    }
                    else
                    {
                        binData.Seek(20, SeekOrigin.Current);//skip whole rest of mip definition
                    }
                }
                export.setBinaryData(binData.ToArray());
            }
            else if (export.ClassName == "StaticMeshComponent")
            {
                int          baseOffset = newDataOffset + export.propsEnd();
                MemoryStream bin        = new MemoryStream(export.Data);
                bin.JumpTo(export.propsEnd());

                int lodDataCount = bin.ReadInt32();
                for (int i = 0; i < lodDataCount; i++)
                {
                    int shadowMapCount = bin.ReadInt32();
                    bin.Skip(shadowMapCount * 4);
                    int shadowVertCount = bin.ReadInt32();
                    bin.Skip(shadowVertCount * 4);
                    int lightMapType = bin.ReadInt32();
                    if (lightMapType == 0)
                    {
                        continue;
                    }
                    int lightGUIDsCount = bin.ReadInt32();
                    bin.Skip(lightGUIDsCount * 16);
                    switch (lightMapType)
                    {
                    case 1:
                        bin.Skip(4 + 8);
                        int bulkDataSize = bin.ReadInt32();
                        bin.WriteInt32(baseOffset + (int)bin.Position + 4);
                        bin.Skip(bulkDataSize);
                        bin.Skip(12 * 4 + 8);
                        bulkDataSize = bin.ReadInt32();
                        bin.WriteInt32(baseOffset + (int)bin.Position + 4);
                        bin.Skip(bulkDataSize);
                        break;

                    case 2:
                        bin.Skip((16) * 4 + 16);
                        break;
                    }
                }
            }
        }
Example #5
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();
                }
            }
        }
        public void RemoveTrailingTrash()
        {
            ExportEntry trashPackage = exports.FirstOrDefault(exp => exp.ObjectName == TrashPackageName);

            if (trashPackage == null)
            {
                return;
            }
            int trashPackageUIndex = trashPackage.UIndex;

            //make sure the first trashed export is the trashpackage
            foreach (ExportEntry exp in exports)
            {
                if (exp == trashPackage)
                {
                    //trashpackage is the first trashed export, so we're good
                    break;
                }
                if (exp.idxLink == trashPackageUIndex)
                {
                    //turn this into trashpackage, turn old trashpackage into regular Trash, and point all trash entries to the new trashpackage
                    exp.ObjectName  = TrashPackageName;
                    exp.idxLink     = 0;
                    exp.PackageGUID = TrashPackageGuid;

                    trashPackage.ObjectName  = "Trash";
                    trashPackage.idxLink     = exp.UIndex;
                    trashPackage.PackageGUID = Guid.Empty;

                    foreach (IEntry entry in trashPackage.GetChildren())
                    {
                        entry.idxLink = exp.UIndex;
                    }

                    trashPackage       = exp;
                    trashPackageUIndex = trashPackage.UIndex;
                    break;
                }
            }


            //remove imports
            for (int i = ImportCount - 1; i >= 0; i--)
            {
                ImportEntry lastImport = imports[i];
                if (lastImport.idxLink != trashPackageUIndex)
                {
                    //non-trash import, so stop removing
                    break;
                }

                imports.RemoveAt(i);
            }
            if (ImportCount != imports.Count)
            {
                ImportCount = imports.Count;
                OnPropertyChanged(nameof(ImportCount));
            }

            //remove exports
            for (int i = ExportCount - 1; i >= 0; i--)
            {
                ExportEntry lastExport = exports[i];
                if (lastExport.idxLink != trashPackageUIndex)
                {
                    //non-trash export, so stop removing
                    break;
                }

                exports.RemoveAt(i);
            }
            if (ExportCount != exports.Count)
            {
                ExportCount = exports.Count;
                OnPropertyChanged(nameof(ExportCount));
            }
            //if there are no more trashed imports or exports, and if the TrashPackage is the last export, remove it
            if (exports.LastOrDefault() is ExportEntry finalExport && finalExport == trashPackage && trashPackage.GetChildren().IsEmpty())
            {
                exports.Remove(trashPackage);
            }
            if (ExportCount != exports.Count)
            {
                ExportCount = exports.Count;
                OnPropertyChanged(nameof(ExportCount));
            }
        }
Example #7
0
 public static T GetProperty <T>(this ExportEntry export, string name) where T : UProperty
 {
     return(export.GetProperties().GetProp <T>(name));
 }
 public static void setBinaryData(this ExportEntry export, ObjectBinary bin) => export.setBinaryData(bin.ToBytes(export.FileRef, export.DataOffset + export.propsEnd()));