Пример #1
0
        public void extractTextureToPng(string outputFile, string packagePath, int exportID)
        {
            Package package = new Package(packagePath);
            Texture texture = new Texture(package, exportID, package.getExportData(exportID));

            package.Dispose();
            PixelFormat format = Image.getPixelFormatType(texture.properties.getProperty("Format").valueName);

            Texture.MipMap mipmap = texture.getTopMipmap();
            byte[]         data   = texture.getTopImageData();
            if (data == null)
            {
                MessageBox.Show("Failed to extract to PNG file. Broken game files!");
                return;
            }

            /*
             * PngBitmapEncoder image = Image.convertToPng(data, mipmap.width, mipmap.height, format);
             * if (File.Exists(outputFile))
             *  File.Delete(outputFile);
             * using (FileStream fs = new FileStream(outputFile, FileMode.CreateNew, FileAccess.Write))
             * {
             *  image.Save(fs);
             * }
             */
        }
        private string FindTextures(List <FoundTexture> textures, string packagePath, CachePackageMgr cachePackageMgr, ref string log)
        {
            string  errors  = "";
            Package package = null;

            try
            {
                if (cachePackageMgr != null)
                {
                    package = cachePackageMgr.OpenPackage(packagePath);
                }
                else
                {
                    package = new Package(packagePath);
                }
            }
            catch (Exception e)
            {
                string err = "";
                err    += "---- Start --------------------------------------------" + Environment.NewLine;
                err    += "Issue with open package file: " + packagePath + Environment.NewLine;
                err    += e.Message + Environment.NewLine + Environment.NewLine;
                err    += e.StackTrace + Environment.NewLine + Environment.NewLine;
                err    += "---- End ----------------------------------------------" + Environment.NewLine + Environment.NewLine;
                errors += err;
                log    += err;
                return(errors);
            }
            for (int i = 0; i < package.exportsTable.Count; i++)
            {
                int id = package.getClassNameId(package.exportsTable[i].classId);
                if (id == package.nameIdTexture2D ||
                    id == package.nameIdLightMapTexture2D ||
                    id == package.nameIdShadowMapTexture2D ||
                    id == package.nameIdTextureFlipBook)
                {
                    Texture texture = new Texture(package, i, package.getExportData(i));
                    if (!texture.hasImageData())
                    {
                        continue;
                    }

                    Texture.MipMap mipmap       = texture.getTopMipmap();
                    string         name         = package.exportsTable[i].objectName;
                    MatchedTexture matchTexture = new MatchedTexture();
                    bool           slave        = false;
                    matchTexture.exportID = i;
                    matchTexture.path     = GameData.RelativeGameData(packagePath);
                    if (GameData.gameType != MeType.ME1_TYPE)
                    {
                        slave = true;
                    }
                    else
                    if (texture.packageName.ToLowerInvariant() != Path.GetFileNameWithoutExtension(package.packageFile.Name).ToLowerInvariant())
                    {
                        slave = true;
                    }

                    uint crc = texture.getCrcTopMipmap();
                    if (crc == 0)
                    {
                        errors += "Error: Texture " + package.exportsTable[i].objectName + " is broken in package: " + packagePath + ", skipping..." + Environment.NewLine;
                        log    += "Error: Texture " + package.exportsTable[i].objectName + " is broken in package: " + packagePath + ", skipping..." + Environment.NewLine;
                        continue;
                    }

                    FoundTexture foundTexName = textures.Find(s => s.crc == crc);
                    if (foundTexName.crc != 0)
                    {
                        if (slave)
                        {
                            foundTexName.list.Add(matchTexture);
                        }
                        else
                        {
                            foundTexName.list.Insert(0, matchTexture);
                        }
                    }
                    else
                    {
                        FoundTexture foundTex = new FoundTexture();
                        foundTex.list = new List <MatchedTexture>();
                        foundTex.list.Add(matchTexture);
                        foundTex.name        = name;
                        foundTex.crc         = crc;
                        foundTex.packageName = texture.packageName;
                        textures.Add(foundTex);
                    }
                }
            }
            if (cachePackageMgr == null)
            {
                package.Dispose();
            }
            else
            {
                package.DisposeCache();
            }

            return(errors);
        }
Пример #3
0
        private void FindTextures(MeType gameId, List <FoundTexture> textures, string packagePath, bool modified, bool ipc)
        {
            Package package = null;

            try
            {
                package = new Package(GameData.GamePath + packagePath);
            }
            catch (Exception e)
            {
                if (e.Message.Contains("Problem with PCC file header:"))
                {
                    return;
                }
                if (ipc)
                {
                    Console.WriteLine("[IPC]ERROR Issue opening package file: " + packagePath);
                    Console.Out.Flush();
                }
                else
                {
                    string err = "";
                    err += "---- Start --------------------------------------------" + Environment.NewLine;
                    err += "Issue opening package file: " + packagePath + Environment.NewLine;
                    err += e.Message + Environment.NewLine + Environment.NewLine;
                    err += e.StackTrace + Environment.NewLine + Environment.NewLine;
                    err += "---- End ----------------------------------------------" + Environment.NewLine + Environment.NewLine;
                    Console.WriteLine(err);
                }
                return;
            }
            for (int i = 0; i < package.exportsTable.Count; i++)
            {
                int id = package.getClassNameId(package.exportsTable[i].classId);
                if (id == package.nameIdTexture2D ||
                    id == package.nameIdLightMapTexture2D ||
                    id == package.nameIdShadowMapTexture2D ||
                    id == package.nameIdTextureFlipBook)
                {
                    Texture texture = new Texture(package, i, package.getExportData(i));
                    if (!texture.hasImageData())
                    {
                        continue;
                    }

                    Texture.MipMap mipmap       = texture.getTopMipmap();
                    string         name         = package.exportsTable[i].objectName;
                    MatchedTexture matchTexture = new MatchedTexture();
                    matchTexture.exportID        = i;
                    matchTexture.path            = packagePath;
                    matchTexture.packageName     = texture.packageName;
                    matchTexture.removeEmptyMips = texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty);
                    matchTexture.numMips         = texture.mipMapsList.FindAll(s => s.storageType != Texture.StorageTypes.empty).Count;
                    if (gameId == MeType.ME1_TYPE)
                    {
                        matchTexture.basePackageName = texture.basePackageName;
                        matchTexture.slave           = texture.slave;
                        matchTexture.weakSlave       = texture.weakSlave;
                        matchTexture.linkToMaster    = -1;
                        if (matchTexture.slave)
                        {
                            matchTexture.mipmapOffset = mipmap.dataOffset;
                        }
                        else
                        {
                            matchTexture.mipmapOffset = package.exportsTable[i].dataOffset + (uint)texture.properties.propertyEndOffset + mipmap.internalOffset;
                        }
                    }

                    uint crc = 0;
                    try
                    {
                        crc = texture.getCrcTopMipmap();
                    }
                    catch (Exception e)
                    {
                        if (ipc)
                        {
                            Console.WriteLine("[IPC]ERROR Texture " + package.exportsTable[i].objectName + " is broken in package: " + packagePath + ", skipping...");
                            Console.Out.Flush();
                        }
                        else
                        {
                            Console.WriteLine(">>>>>>>>>");
                            Console.WriteLine("Error: Texture " + package.exportsTable[i].objectName + " is broken in package: " +
                                              Environment.NewLine + packagePath);
                            Console.WriteLine(e.Message);
                            Console.WriteLine("Export Id: " + (i + 1));
                            Console.WriteLine("skipping...");
                            Console.WriteLine("<<<<<<<<<" + Environment.NewLine);
                        }
                        continue;
                    }

                    FoundTexture foundTexName = textures.Find(s => s.crc == crc);
                    if (foundTexName.crc != 0)
                    {
                        if (modified && foundTexName.list.Exists(s => (s.exportID == i && s.path.ToLowerInvariant() == packagePath.ToLowerInvariant())))
                        {
                            continue;
                        }
                        if (matchTexture.slave || gameId != MeType.ME1_TYPE)
                        {
                            foundTexName.list.Add(matchTexture);
                        }
                        else
                        {
                            foundTexName.list.Insert(0, matchTexture);
                        }
                    }
                    else
                    {
                        if (modified)
                        {
                            for (int k = 0; k < textures.Count; k++)
                            {
                                bool found = false;
                                for (int t = 0; t < textures[k].list.Count; t++)
                                {
                                    if (textures[k].list[t].exportID == i &&
                                        textures[k].list[t].path.ToLowerInvariant() == packagePath.ToLowerInvariant())
                                    {
                                        MatchedTexture f = textures[k].list[t];
                                        f.path = "";
                                        textures[k].list[t] = f;
                                        found = true;
                                        break;
                                    }
                                }
                                if (found)
                                {
                                    break;
                                }
                            }
                        }
                        FoundTexture foundTex = new FoundTexture();
                        foundTex.list = new List <MatchedTexture>();
                        foundTex.list.Add(matchTexture);
                        foundTex.name = name;
                        foundTex.crc  = crc;
                        if (generateBuiltinMapFiles)
                        {
                            foundTex.width  = texture.getTopMipmap().width;
                            foundTex.height = texture.getTopMipmap().height;
                            foundTex.pixfmt = Image.getPixelFormatType(texture.properties.getProperty("Format").valueName);
                            if (texture.properties.exists("CompressionSettings"))
                            {
                                string cmp = texture.properties.getProperty("CompressionSettings").valueName;
                                if (cmp == "TC_OneBitAlpha")
                                {
                                    foundTex.flags = TexProperty.TextureTypes.OneBitAlpha;
                                }
                                else if (cmp == "TC_Displacementmap")
                                {
                                    foundTex.flags = TexProperty.TextureTypes.Displacementmap;
                                }
                                else if (cmp == "TC_Grayscale")
                                {
                                    foundTex.flags = TexProperty.TextureTypes.GreyScale;
                                }
                                else if (cmp == "TC_Normalmap" ||
                                         cmp == "TC_NormalmapHQ" ||
                                         cmp == "TC_NormalmapAlpha" ||
                                         cmp == "TC_NormalmapUncompressed")
                                {
                                    foundTex.flags = TexProperty.TextureTypes.Normalmap;
                                }
                                else
                                {
                                    throw new Exception();
                                }
                            }
                            else
                            {
                                foundTex.flags = TexProperty.TextureTypes.Normal;
                            }
                        }
                        textures.Add(foundTex);
                    }
                }
            }

            package.Dispose();
        }
Пример #4
0
        private string FindTextures(List <FoundTexture> textures, string packagePath, CachePackageMgr cachePackageMgr, ref string log)
        {
            string  errors  = "";
            Package package = null;

            try
            {
                if (cachePackageMgr != null)
                {
                    package = cachePackageMgr.OpenPackage(packagePath);
                }
                else
                {
                    package = new Package(packagePath);
                }
            }
            catch (Exception e)
            {
                string err = "";
                err    += "---- Start --------------------------------------------" + Environment.NewLine;
                err    += "Issue with open package file: " + packagePath + Environment.NewLine;
                err    += e.Message + Environment.NewLine + Environment.NewLine;
                err    += e.StackTrace + Environment.NewLine + Environment.NewLine;
                err    += "---- End ----------------------------------------------" + Environment.NewLine + Environment.NewLine;
                errors += err;
                log    += err;
                return(errors);
            }
            for (int i = 0; i < package.exportsTable.Count; i++)
            {
                int id = package.getClassNameId(package.exportsTable[i].classId);
                if (id == package.nameIdTexture2D ||
                    id == package.nameIdLightMapTexture2D ||
                    id == package.nameIdShadowMapTexture2D ||
                    id == package.nameIdTextureFlipBook)
                {
                    Texture texture = new Texture(package, i, package.getExportData(i));
                    if (!texture.hasImageData())
                    {
                        continue;
                    }

                    Texture.MipMap mipmap       = texture.getTopMipmap();
                    string         name         = package.exportsTable[i].objectName;
                    MatchedTexture matchTexture = new MatchedTexture();
                    matchTexture.exportID    = i;
                    matchTexture.path        = GameData.RelativeGameData(packagePath);
                    matchTexture.packageName = texture.packageName;
                    if (GameData.gameType == MeType.ME1_TYPE)
                    {
                        matchTexture.basePackageName = texture.basePackageName;
                        matchTexture.slave           = texture.slave;
                        matchTexture.weakSlave       = texture.weakSlave;
                        matchTexture.linkToMaster    = -1;
                        if (matchTexture.slave)
                        {
                            matchTexture.mipmapOffset = mipmap.dataOffset;
                        }
                        else
                        {
                            matchTexture.mipmapOffset = package.exportsTable[i].dataOffset + (uint)texture.properties.propertyEndOffset + mipmap.internalOffset;
                        }
                    }

                    uint crc = 0;
                    try
                    {
                        crc = texture.getCrcTopMipmap();
                    }
                    catch
                    {
                    }
                    if (crc == 0)
                    {
                        errors += "Error: Texture " + package.exportsTable[i].objectName + " is broken in package: " + packagePath + ", skipping..." + Environment.NewLine;
                        log    += "Error: Texture " + package.exportsTable[i].objectName + " is broken in package: " + packagePath + ", skipping..." + Environment.NewLine;
                        continue;
                    }

                    FoundTexture foundTexName = textures.Find(s => s.crc == crc);
                    if (foundTexName.crc != 0)
                    {
                        if (matchTexture.slave || GameData.gameType != MeType.ME1_TYPE)
                        {
                            foundTexName.list.Add(matchTexture);
                        }
                        else
                        {
                            foundTexName.list.Insert(0, matchTexture);
                        }
                    }
                    else
                    {
                        FoundTexture foundTex = new FoundTexture();
                        foundTex.list = new List <MatchedTexture>();
                        foundTex.list.Add(matchTexture);
                        foundTex.name = name;
                        foundTex.crc  = crc;
                        if (generateBuiltinMapFiles)
                        {
                            foundTex.width  = texture.getTopMipmap().width;
                            foundTex.height = texture.getTopMipmap().height;
                            foundTex.pixfmt = Image.getEngineFormatType(texture.properties.getProperty("Format").valueName);
                            if (foundTex.pixfmt == PixelFormat.DXT1 &&
                                texture.properties.exists("CompressionSettings") &&
                                texture.properties.getProperty("CompressionSettings").valueName == "TC_OneBitAlpha")
                            {
                                foundTex.alphadxt1 = true;
                            }
                        }
                        textures.Add(foundTex);
                    }
                }
            }

            if (cachePackageMgr == null)
            {
                package.Dispose();
            }
            else
            {
                package.DisposeCache();
            }

            return(errors);
        }
        public string replaceTexture(DDSImage image, List <MatchedTexture> list, CachePackageMgr cachePackageMgr, string textureName, uint crc)
        {
            List <Texture> masterTextures = new List <Texture>();
            Texture        arcTexture = null, cprTexture = null;
            string         errors = "";

            for (int n = 0; n < list.Count; n++)
            {
                MatchedTexture nodeTexture = list[n];
                Package        package     = cachePackageMgr.OpenPackage(GameData.GamePath + nodeTexture.path);
                Texture        texture     = new Texture(package, nodeTexture.exportID, package.getExportData(nodeTexture.exportID));
                while (texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty))
                {
                    texture.mipMapsList.Remove(texture.mipMapsList.First(s => s.storageType == Texture.StorageTypes.empty));
                }
                bool master = true;
                if (GameData.gameType == MeType.ME1_TYPE)
                {
                    if (texture.packageName.ToLowerInvariant() != Path.GetFileNameWithoutExtension(package.packageFile.Name).ToLowerInvariant())
                    {
                        master = false;
                        if (!masterTextures.Exists(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()))
                        {
                            errors += "Error in texture: " + textureName + " Broken game file: " + nodeTexture.path + ", skipping texture..." + Environment.NewLine;
                            continue;
                        }
                    }
                }

                if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1)
                {
                    errors += "Error in texture: " + textureName + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine;
                    break;
                }

                string    fmt       = texture.properties.getProperty("Format").valueName;
                DDSFormat ddsFormat = DDSImage.convertFormat(fmt);
                if (image.ddsFormat != ddsFormat)
                {
                    errors += "Error in texture: " + textureName + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine;
                    break;
                }

                if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight !=
                    texture.mipMapsList[0].width / texture.mipMapsList[0].height)
                {
                    errors += "Error in texture: " + textureName + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine;
                    break;
                }

                // remove lower mipmaps from source image which not exist in game data
                for (int t = 0; t < image.mipMaps.Count(); t++)
                {
                    if (image.mipMaps[t].origWidth <= texture.mipMapsList[0].width &&
                        image.mipMaps[t].origHeight <= texture.mipMapsList[0].height &&
                        texture.mipMapsList.Count > 1)
                    {
                        if (!texture.mipMapsList.Exists(m => m.width == image.mipMaps[t].origWidth && m.height == image.mipMaps[t].origHeight))
                        {
                            image.mipMaps.RemoveAt(t--);
                        }
                    }
                }

                bool skip = false;
                // reuse lower mipmaps from game data which not exist in source image
                for (int t = 0; t < texture.mipMapsList.Count; t++)
                {
                    if (texture.mipMapsList[t].width <= image.mipMaps[0].origWidth &&
                        texture.mipMapsList[t].height <= image.mipMaps[0].origHeight)
                    {
                        if (!image.mipMaps.Exists(m => m.origWidth == texture.mipMapsList[t].width && m.origHeight == texture.mipMapsList[t].height))
                        {
                            byte[] data = texture.getMipMapData(texture.mipMapsList[t]);
                            if (data == null)
                            {
                                errors += "Error in game data: " + nodeTexture.path + ", skipping texture..." + Environment.NewLine;
                                skip    = true;
                                break;
                            }
                            DDSImage.MipMap mipmap = new DDSImage.MipMap(data, ddsFormat, texture.mipMapsList[t].width, texture.mipMapsList[t].height);
                            image.mipMaps.Add(mipmap);
                        }
                    }
                }
                if (skip)
                {
                    continue;
                }

                package.DisposeCache();

                bool   triggerCacheArc = false, triggerCacheCpr = false;
                string archiveFile = "";
                byte[] origGuid    = new byte[16];
                if (texture.properties.exists("TextureFileCacheName"))
                {
                    Array.Copy(texture.properties.getProperty("TFCFileGuid").valueStruct, origGuid, 16);
                    string archive = texture.properties.getProperty("TextureFileCacheName").valueName;
                    archiveFile = Path.Combine(GameData.MainData, archive + ".tfc");
                    if (nodeTexture.path.ToLowerInvariant().Contains("\\dlc"))
                    {
                        string DLCArchiveFile = Path.Combine(Path.GetDirectoryName(GameData.GamePath + nodeTexture.path), archive + ".tfc");
                        if (File.Exists(DLCArchiveFile))
                        {
                            archiveFile = DLCArchiveFile;
                        }
                        else if (!File.Exists(archiveFile))
                        {
                            List <string> files = Directory.GetFiles(GameData.bioGamePath, archive + ".tfc",
                                                                     SearchOption.AllDirectories).Where(item => item.EndsWith(".tfc", StringComparison.OrdinalIgnoreCase)).ToList();
                            if (files.Count == 0)
                            {
                                archiveFile = Path.Combine(GameData.MainData, "Textures.tfc");
                            }
                            else if (files.Count == 1)
                            {
                                archiveFile = files[0];
                            }
                            else
                            {
                                throw new Exception("");
                            }
                        }
                    }
                    long fileLength = new FileInfo(archiveFile).Length;
                    if (fileLength + 0x5000000 > 0x80000000)
                    {
                        archiveFile = "";
                        foreach (TFCTexture newGuid in guids)
                        {
                            archiveFile = Path.Combine(GameData.MainData, newGuid.name + ".tfc");
                            if (!File.Exists(archiveFile))
                            {
                                texture.properties.setNameValue("TextureFileCacheName", newGuid.name);
                                texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid);
                                using (FileStream fs = new FileStream(archiveFile, FileMode.CreateNew, FileAccess.Write))
                                {
                                    fs.WriteFromBuffer(newGuid.guid);
                                }
                                break;
                            }
                            else
                            {
                                fileLength = new FileInfo(archiveFile).Length;
                                if (fileLength + 0x5000000 < 0x80000000)
                                {
                                    texture.properties.setNameValue("TextureFileCacheName", newGuid.name);
                                    texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid);
                                    break;
                                }
                            }
                            archiveFile = "";
                        }
                        if (archiveFile == "")
                        {
                            throw new Exception("No free TFC texture file!");
                        }
                    }
                }

                List <Texture.MipMap> mipmaps = new List <Texture.MipMap>();
                for (int m = 0; m < image.mipMaps.Count(); m++)
                {
                    Texture.MipMap mipmap = new Texture.MipMap();
                    mipmap.width  = image.mipMaps[m].origWidth;
                    mipmap.height = image.mipMaps[m].origHeight;
                    if (texture.existMipmap(mipmap.width, mipmap.height))
                    {
                        mipmap.storageType = texture.getMipmap(mipmap.width, mipmap.height).storageType;
                    }
                    else
                    {
                        mipmap.storageType = texture.getTopMipmap().storageType;
                        if (GameData.gameType == MeType.ME1_TYPE && master == false)
                        {
                            if (mipmap.storageType == Texture.StorageTypes.pccUnc ||
                                mipmap.storageType == Texture.StorageTypes.pccLZO ||
                                mipmap.storageType == Texture.StorageTypes.pccZlib)
                            {
                                mipmap.storageType = Texture.StorageTypes.extLZO;
                            }
                        }
                        else if (GameData.gameType == MeType.ME2_TYPE || GameData.gameType == MeType.ME3_TYPE)
                        {
                            if (texture.properties.exists("TextureFileCacheName") && texture.mipMapsList.Count > 1)
                            {
                                if (texture.mipMapsList.Count < 6)
                                {
                                    mipmap.storageType = Texture.StorageTypes.pccUnc;
                                    if (!texture.properties.exists("NeverStream"))
                                    {
                                        if (package.existsNameId("NeverStream"))
                                        {
                                            texture.properties.addBoolValue("NeverStream", true);
                                        }
                                        else
                                        {
                                            goto skip;
                                        }
                                    }
                                }
                                else
                                {
                                    if (GameData.gameType == MeType.ME2_TYPE)
                                    {
                                        mipmap.storageType = Texture.StorageTypes.extLZO;
                                    }
                                    else
                                    {
                                        mipmap.storageType = Texture.StorageTypes.extZlib;
                                    }
                                }
                            }
                        }
                    }

                    if (mipmap.storageType == Texture.StorageTypes.extLZO)
                    {
                        mipmap.storageType = Texture.StorageTypes.extZlib;
                    }
                    if (mipmap.storageType == Texture.StorageTypes.pccLZO)
                    {
                        mipmap.storageType = Texture.StorageTypes.pccZlib;
                    }

                    mipmap.uncompressedSize = image.mipMaps[m].data.Length;
                    if (GameData.gameType == MeType.ME1_TYPE)
                    {
                        if (mipmap.storageType == Texture.StorageTypes.pccLZO ||
                            mipmap.storageType == Texture.StorageTypes.pccZlib)
                        {
                            if (master)
                            {
                                mipmap.newData = texture.compressTexture(image.mipMaps[m].data, mipmap.storageType);
                            }
                            else
                            {
                                mipmap.newData = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].newData;
                            }
                            mipmap.compressedSize = mipmap.newData.Length;
                        }
                        if (mipmap.storageType == Texture.StorageTypes.pccUnc)
                        {
                            mipmap.compressedSize = mipmap.uncompressedSize;
                            mipmap.newData        = image.mipMaps[m].data;
                        }
                        if ((mipmap.storageType == Texture.StorageTypes.extLZO ||
                             mipmap.storageType == Texture.StorageTypes.extZlib) && master == false)
                        {
                            mipmap.compressedSize = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].compressedSize;
                            mipmap.dataOffset     = masterTextures.Find(s => s.packageName.ToLowerInvariant() == texture.packageName.ToLowerInvariant()).mipMapsList[m].dataOffset;
                        }
                    }
                    else
                    {
                        if (mipmap.storageType == Texture.StorageTypes.extZlib ||
                            mipmap.storageType == Texture.StorageTypes.extLZO)
                        {
                            if (cprTexture == null || (cprTexture != null && mipmap.storageType != cprTexture.mipMapsList[m].storageType))
                            {
                                mipmap.newData  = texture.compressTexture(image.mipMaps[m].data, mipmap.storageType);
                                triggerCacheCpr = true;
                            }
                            else
                            {
                                if (cprTexture.mipMapsList[m].width != mipmap.width ||
                                    cprTexture.mipMapsList[m].height != mipmap.height)
                                {
                                    throw new Exception();
                                }
                                mipmap.newData = cprTexture.mipMapsList[m].newData;
                            }
                            mipmap.compressedSize = mipmap.newData.Length;
                        }
                        if (mipmap.storageType == Texture.StorageTypes.pccUnc ||
                            mipmap.storageType == Texture.StorageTypes.extUnc)
                        {
                            mipmap.compressedSize = mipmap.uncompressedSize;
                            mipmap.newData        = image.mipMaps[m].data;
                        }
                        if (mipmap.storageType == Texture.StorageTypes.extZlib ||
                            mipmap.storageType == Texture.StorageTypes.extLZO ||
                            mipmap.storageType == Texture.StorageTypes.extUnc)
                        {
                            if (arcTexture == null ||
                                !StructuralComparisons.StructuralEqualityComparer.Equals(
                                    arcTexture.properties.getProperty("TFCFileGuid").valueStruct,
                                    texture.properties.getProperty("TFCFileGuid").valueStruct))
                            {
                                triggerCacheArc = true;
                                Texture.MipMap oldMipmap = texture.getMipmap(mipmap.width, mipmap.height);
                                if (StructuralComparisons.StructuralEqualityComparer.Equals(origGuid,
                                                                                            texture.properties.getProperty("TFCFileGuid").valueStruct) &&
                                    oldMipmap.width != 0 && mipmap.newData.Length <= oldMipmap.compressedSize)
                                {
                                    try
                                    {
                                        using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.Write))
                                        {
                                            fs.JumpTo(oldMipmap.dataOffset);
                                            mipmap.dataOffset = oldMipmap.dataOffset;
                                            fs.WriteFromBuffer(mipmap.newData);
                                        }
                                    }
                                    catch
                                    {
                                        throw new Exception("Problem with access to TFC file: " + archiveFile);
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.Write))
                                        {
                                            fs.SeekEnd();
                                            mipmap.dataOffset = (uint)fs.Position;
                                            fs.WriteFromBuffer(mipmap.newData);
                                        }
                                    }
                                    catch
                                    {
                                        throw new Exception("Problem with access to TFC file: " + archiveFile);
                                    }
                                }
                            }
                            else
                            {
                                if (arcTexture.mipMapsList[m].width != mipmap.width ||
                                    arcTexture.mipMapsList[m].height != mipmap.height)
                                {
                                    throw new Exception();
                                }
                                mipmap.dataOffset = arcTexture.mipMapsList[m].dataOffset;
                            }
                        }
                    }

                    mipmap.width  = image.mipMaps[m].width;
                    mipmap.height = image.mipMaps[m].height;
                    mipmaps.Add(mipmap);
                    if (texture.mipMapsList.Count() == 1)
                    {
                        break;
                    }
                }
                texture.replaceMipMaps(mipmaps);
                texture.properties.setIntValue("SizeX", texture.mipMapsList.First().width);
                texture.properties.setIntValue("SizeY", texture.mipMapsList.First().height);
                if (texture.properties.exists("MipTailBaseIdx"))
                {
                    texture.properties.setIntValue("MipTailBaseIdx", texture.mipMapsList.Count() - 1);
                }
                if (GameData.gameType == MeType.ME1_TYPE && crc == 0x39A26907)
                {
                    if (!texture.properties.exists("LODGroup"))
                    {
                        texture.properties.addByteValue("LODGroup", "TEXTUREGROUP_Character", 1025);
                    }
                    else
                    {
                        texture.properties.setByteValue("LODGroup", "TEXTUREGROUP_Character", 1025);
                    }
                }

                using (MemoryStream newData = new MemoryStream())
                {
                    newData.WriteFromBuffer(texture.properties.toArray());
                    newData.WriteFromBuffer(texture.toArray(0)); // filled later
                    package.setExportData(nodeTexture.exportID, newData.ToArray());
                }

                using (MemoryStream newData = new MemoryStream())
                {
                    newData.WriteFromBuffer(texture.properties.toArray());
                    newData.WriteFromBuffer(texture.toArray(package.exportsTable[nodeTexture.exportID].dataOffset + (uint)newData.Position));
                    package.setExportData(nodeTexture.exportID, newData.ToArray());
                }

                if (GameData.gameType == MeType.ME1_TYPE)
                {
                    if (master)
                    {
                        masterTextures.Add(texture);
                    }
                }
                else
                {
                    if (triggerCacheCpr)
                    {
                        cprTexture = texture;
                    }
                    if (triggerCacheArc)
                    {
                        arcTexture = texture;
                    }
                }
skip:
                package = null;
            }
            masterTextures = null;
            arcTexture     = cprTexture = null;

            return(errors);
        }