예제 #1
0
        /// <summary>
        ///     compress an entire pcc into a byte array.
        /// </summary>
        /// <param name="uncompressedPcc">uncompressed pcc stream.</param>
        /// <returns>a compressed array of bytes.</returns>
        public static Stream Compress(Stream uncompressedPcc)
        {
            uncompressedPcc.Position = 0;

            var magic = uncompressedPcc.ReadValueU32(Endian.Little);

            if (magic != 0x9E2A83C1 &&
                magic.Swap() != 0x9E2A83C1)
            {
                throw new FormatException("not a pcc package");
            }
            var endian = magic == 0x9E2A83C1 ?
                         Endian.Little : Endian.Big;
            var encoding = endian == Endian.Little ?
                           Encoding.Unicode : Encoding.BigEndianUnicode;

            var versionLo = uncompressedPcc.ReadValueU16(endian);
            var versionHi = uncompressedPcc.ReadValueU16(endian);

            if (versionLo != 684 &&
                versionHi != 194)
            {
                throw new FormatException("unsupported version");
            }

            uncompressedPcc.Seek(4, SeekOrigin.Current);

            var folderNameLength     = uncompressedPcc.ReadValueS32(endian);
            var folderNameByteLength =
                folderNameLength >= 0 ? folderNameLength : (-folderNameLength * 2);

            uncompressedPcc.Seek(folderNameByteLength, SeekOrigin.Current);

            var packageFlagsOffset = uncompressedPcc.Position;
            var packageFlags       = uncompressedPcc.ReadValueU32(endian);

            if ((packageFlags & 8) != 0)
            {
                uncompressedPcc.Seek(4, SeekOrigin.Current);
            }

            var nameCount         = uncompressedPcc.ReadValueU32(endian);
            var namesOffset       = uncompressedPcc.ReadValueU32(endian);
            var exportCount       = uncompressedPcc.ReadValueU32(endian);
            var exportInfosOffset = uncompressedPcc.ReadValueU32(endian);
            SortedDictionary <uint, uint> exportDataOffsets = new SortedDictionary <uint, uint>();

            Stream data;

            if ((packageFlags & 0x02000000) == 0)
            {
                data = uncompressedPcc;
            }
            else
            {
                throw new FormatException("pcc data is compressed");
            }

            // get info about export data, sizes and offsets
            data.Seek(exportInfosOffset, SeekOrigin.Begin);
            for (uint i = 0; i < exportCount; i++)
            {
                var classIndex = data.ReadValueS32(endian);
                data.Seek(4, SeekOrigin.Current);
                var outerIndex      = data.ReadValueS32(endian);
                var objectNameIndex = data.ReadValueS32(endian);
                data.Seek(16, SeekOrigin.Current);

                uint exportDataSize   = data.ReadValueU32(endian);
                uint exportDataOffset = data.ReadValueU32(endian);
                exportDataOffsets.Add(exportDataOffset, exportDataSize);

                data.Seek(4, SeekOrigin.Current);
                var count = data.ReadValueU32(endian);
                data.Seek(count * 4, SeekOrigin.Current);
                data.Seek(20, SeekOrigin.Current);
            }

            const uint maxBlockSize = 0x100000;
            Stream     outputStream = new MemoryStream();

            // copying pcc header
            byte[] buffer = new byte[130];
            uncompressedPcc.Seek(0, SeekOrigin.Begin);
            uncompressedPcc.Read(buffer, 0, 130);
            outputStream.Write(buffer, 0, buffer.Length);

            //add compressed pcc flag
            uncompressedPcc.Seek(12, SeekOrigin.Begin);
            folderNameLength     = uncompressedPcc.ReadValueS32();
            folderNameByteLength =
                folderNameLength >= 0 ? folderNameLength : (-folderNameLength * 2);
            uncompressedPcc.Seek(folderNameByteLength, SeekOrigin.Current);
            outputStream.Seek(uncompressedPcc.Position, SeekOrigin.Begin);

            packageFlags  = uncompressedPcc.ReadValueU32();
            packageFlags |= 0x02000000; // add compression flag
            outputStream.WriteValueU32(packageFlags);

            outputStream.Seek(buffer.Length, SeekOrigin.Begin);

            long       outOffsetData;
            long       outOffsetBlockInfo;
            long       inOffsetData = namesOffset;
            List <int> blockSizes   = new List <int>();
            int        countSize    = (int)(exportDataOffsets.Min(obj => obj.Key) - namesOffset);

            //count the number of blocks and relative sizes
            uint lastOffset = exportDataOffsets.Min(obj => obj.Key);

            foreach (KeyValuePair <uint, uint> exportInfo in exportDataOffsets)
            {
                // part that adds empty spaces (leaved when editing export data and moved to the end of pcc) into the count
                if (exportInfo.Key != lastOffset)
                {
                    int emptySpace = (int)(exportInfo.Key - lastOffset);
                    if (countSize + emptySpace > maxBlockSize)
                    {
                        blockSizes.Add(countSize);
                        countSize = 0;
                    }
                    else
                    {
                        countSize += emptySpace;
                    }
                }

                // adds export data into the count
                if (countSize + exportInfo.Value > maxBlockSize)
                {
                    blockSizes.Add(countSize);
                    countSize = (int)exportInfo.Value;
                }
                else
                {
                    countSize += (int)exportInfo.Value;
                }

                lastOffset = exportInfo.Key + exportInfo.Value;
            }
            blockSizes.Add(countSize);

            outputStream.WriteValueS32(blockSizes.Count);
            outOffsetBlockInfo = outputStream.Position;
            outOffsetData      = namesOffset + (blockSizes.Count * 16);

            uncompressedPcc.Seek(namesOffset, SeekOrigin.Begin);
            //divide the block in segments
            for (int i = 0; i < blockSizes.Count; i++)
            {
                int currentUncBlockSize = blockSizes[i];

                outputStream.Seek(outOffsetBlockInfo, SeekOrigin.Begin);
                outputStream.WriteValueU32((uint)uncompressedPcc.Position);
                outputStream.WriteValueS32(currentUncBlockSize);
                outputStream.WriteValueU32((uint)outOffsetData);

                byte[] inputBlock = new byte[currentUncBlockSize];
                uncompressedPcc.Read(inputBlock, 0, currentUncBlockSize);
                byte[] compressedBlock = ZBlock.Compress(inputBlock, 0, inputBlock.Length);

                outputStream.WriteValueS32(compressedBlock.Length);
                outOffsetBlockInfo = outputStream.Position;

                outputStream.Seek(outOffsetData, SeekOrigin.Begin);
                outputStream.Write(compressedBlock, 0, compressedBlock.Length);
                outOffsetData = outputStream.Position;
            }

            //copying some unknown values + extra names list
            int bufferSize = (int)namesOffset - 0x86;

            buffer = new byte[bufferSize];
            uncompressedPcc.Seek(0x86, SeekOrigin.Begin);
            uncompressedPcc.Read(buffer, 0, buffer.Length);
            outputStream.Seek(outOffsetBlockInfo, SeekOrigin.Begin);
            outputStream.Write(buffer, 0, buffer.Length);

            outputStream.Seek(0, SeekOrigin.Begin);

            return(outputStream);
        }
예제 #2
0
        public void replaceImage(string strImgSize, ImageFile im, string archiveDir)
        {
            ImageSize imgSize = ImageSize.stringToSize(strImgSize);

            if (!imgList.Exists(img => img.imgSize == imgSize))
            {
                throw new FileNotFoundException("Image with resolution " + imgSize + " isn't found");
            }

            int       imageIdx = privateImageList.FindIndex(img => img.imgSize == imgSize);
            ImageInfo imgInfo  = privateImageList[imageIdx];

            ImageFile         imgFile       = im;
            ImageEngineFormat imgFileFormat = Textures.Methods.ParseFormat(imgFile.format);


            // check if images have same format type
            if (texFormat != imgFileFormat)
            {
                bool res = KFreonLib.Misc.Methods.DisplayYesNoDialogBox("Warning, replacing image has format " + imgFile.subtype() + " while original has " + texFormat + ", would you like to replace it anyway?", "Warning, different image format found");
                if (res)
                {
                    imgFile.format = Textures.Methods.StringifyFormat(texFormat);
                }
                else
                {
                    return;
                }
                //throw new FormatException("Different image format, original is " + texFormat + ", new is " + imgFile.subtype());
            }

            byte[] imgBuffer;

            // if the image is empty then recover the archive compression from the image list
            if (imgInfo.storageType == storage.empty)
            {
                imgInfo.storageType = privateImageList.Find(img => img.storageType != storage.empty && img.storageType != storage.pccSto).storageType;
                imgInfo.uncSize     = imgFile.resize().Length;
                imgInfo.cprSize     = imgFile.resize().Length;
            }

            switch (imgInfo.storageType)
            {
            case storage.arcCpr:
            case storage.arcUnc:
                string archivePath = archiveDir + "\\" + arcName + ".tfc";
                if (!File.Exists(archivePath))
                {
                    throw new FileNotFoundException("Texture archive not found in " + archivePath);
                }

                if (getFileFormat() == ".tga")
                {
                    imgBuffer = imgFile.resize();     // shrink image to essential data
                }
                else
                {
                    imgBuffer = imgFile.imgData;
                }

                if (imgBuffer.Length != imgInfo.uncSize)
                {
                    throw new FormatException("image sizes do not match, original is " + imgInfo.uncSize + ", new is " + imgBuffer.Length);
                }

                using (FileStream archiveStream = new FileStream(archivePath, FileMode.Append, FileAccess.Write))
                {
                    int newOffset = (int)archiveStream.Position;

                    if (imgInfo.storageType == storage.arcCpr)
                    {
                        imgBuffer = ZBlock.Compress(imgBuffer);

                        /*byte[] compressed = ZBlock.Compress(imgBuffer);
                         * archiveStream.Write(compressed, 0, compressed.Length);*/
                        imgInfo.cprSize = imgBuffer.Length;
                    }
                    //else
                    archiveStream.Write(imgBuffer, 0, imgBuffer.Length);

                    imgInfo.offset = newOffset;
                }
                break;

            case storage.pccSto:
                imgBuffer = imgFile.imgData;     // copy image data as-is
                if (imgBuffer.Length != imgInfo.uncSize)
                {
                    throw new FormatException("image sizes do not match, original is " + imgInfo.uncSize + ", new is " + imgBuffer.Length);
                }

                using (MemoryStream dataStream = new MemoryStream(imageData))
                {
                    dataStream.Seek(imgInfo.offset, SeekOrigin.Begin);
                    dataStream.Write(imgBuffer, 0, imgBuffer.Length);
                }

                break;
            }

            imgList[imageIdx] = imgInfo;
        }
예제 #3
0
        public void replaceImage(string strImgSize, string fileToReplace, string archiveDir)
        {
            ImageSize imgSize = ImageSize.stringToSize(strImgSize);

            if (!imgList.Exists(img => img.imgSize == imgSize))
            {
                throw new FileNotFoundException("Image with resolution " + imgSize + " isn't found");
            }

            int       imageIdx = imgList.FindIndex(img => img.imgSize == imgSize);
            ImageInfo imgInfo  = imgList[imageIdx];

            if (!File.Exists(fileToReplace))
            {
                throw new FileNotFoundException("invalid file to replace: " + fileToReplace);
            }

            // check if replacing image is supported
            ImageFile imgFile;
            string    fileFormat = Path.GetExtension(fileToReplace);

            switch (fileFormat)
            {
            case ".dds": imgFile = new DDS(fileToReplace, null); break;

            case ".tga": imgFile = new TGA(fileToReplace, null); break;

            default: throw new FileFormatException(fileFormat + " image extension not supported");
            }

            // check if images have same format type
            if (texFormat != imgFile.format)
            {
                DialogResult selection = MessageBox.Show("Warning, replacing image has format " + imgFile.subtype() + " while original has " + texFormat + ", would you like to replace it anyway?", "Warning, different image format found", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                if (selection == DialogResult.Yes)
                {
                    imgFile.format = texFormat;
                }
                else
                {
                    return;
                }
                //throw new FormatException("Different image format, original is " + texFormat + ", new is " + imgFile.subtype());
            }

            byte[] imgBuffer;

            // if the image is empty then recover the archive compression from the image list
            if (imgInfo.storageType == storage.empty)
            {
                imgInfo.storageType = imgList.Find(img => img.storageType != storage.empty && img.storageType != storage.pccSto).storageType;
                imgInfo.uncSize     = imgFile.resize().Length;
                imgInfo.cprSize     = imgFile.resize().Length;
            }

            switch (imgInfo.storageType)
            {
            case storage.arcCpr:
            case storage.arcUnc:
                string archivePath = archiveDir + "\\" + arcName + ".tfc";
                if (!File.Exists(archivePath))
                {
                    throw new FileNotFoundException("Texture archive not found in " + archivePath);
                }

                if (getFileFormat() == ".tga")
                {
                    imgBuffer = imgFile.resize();     // shrink image to essential data
                }
                else
                {
                    imgBuffer = imgFile.imgData;
                }

                if (imgBuffer.Length != imgInfo.uncSize)
                {
                    throw new FormatException("image sizes do not match, original is " + imgInfo.uncSize + ", new is " + imgBuffer.Length);
                }

                using (FileStream archiveStream = new FileStream(archivePath, FileMode.Append, FileAccess.Write))
                {
                    int newOffset = (int)archiveStream.Position;

                    if (imgInfo.storageType == storage.arcCpr)
                    {
                        imgBuffer = ZBlock.Compress(imgBuffer);

                        /*byte[] compressed = ZBlock.Compress(imgBuffer);
                         * archiveStream.Write(compressed, 0, compressed.Length);*/
                        imgInfo.cprSize = imgBuffer.Length;
                    }
                    //else
                    archiveStream.Write(imgBuffer, 0, imgBuffer.Length);

                    imgInfo.offset = newOffset;
                }
                break;

            case storage.pccSto:
                imgBuffer = imgFile.imgData;     // copy image data as-is
                if (imgBuffer.Length != imgInfo.uncSize)
                {
                    throw new FormatException("image sizes do not match, original is " + imgInfo.uncSize + ", new is " + imgBuffer.Length);
                }

                using (MemoryStream dataStream = new MemoryStream(imageData))
                {
                    dataStream.Seek(imgInfo.offset, SeekOrigin.Begin);
                    dataStream.Write(imgBuffer, 0, imgBuffer.Length);
                }

                break;
            }

            imgList[imageIdx] = imgInfo;
        }
예제 #4
0
        public void ImportFromFile(int tfc)
        {
            OpenFileDialog Dialog = new OpenFileDialog();

            if (T2D.PixelFormat == "PF_DXT1\0" ||
                T2D.PixelFormat == "PF_DXT5\0")
            {
                Dialog.Filter = "DDS Files (*.dds)|*.dds";
            }
            if (T2D.PixelFormat == "PF_G8\0" ||
                T2D.PixelFormat == "PF_V8U8\0" ||
                T2D.PixelFormat == "PF_A8R8G8B8\0")
            {
                Dialog.Filter = "TGA Files (*.tga)|*.tga";
            }
            int format = -1;

            if (T2D.PixelFormat == "PF_DXT1\0")
            {
                format = 0;
            }
            if (T2D.PixelFormat == "PF_DXT5\0")
            {
                format = 1;
            }
            if (T2D.PixelFormat == "PF_V8U8\0")
            {
                format = 2;
            }
            if (T2D.PixelFormat == "PF_A8R8G8B8\0")
            {
                format = 3;
            }
            if (T2D.PixelFormat == "PF_G8\0")
            {
                format = 4;
            }
            if (!TextureTFCs[tfc].InCache)
            {
                if (Dialog.ShowDialog() == DialogResult.OK)
                {
                    if (format == 0 || format == 1)
                    {
                        ImageFile t = new ImageFile();
                        t.ImportFromFile(Dialog.FileName);
                        if (t.ImageSizeX == TextureTFCs[tfc].sizeX &&
                            t.ImageSizeY == TextureTFCs[tfc].sizeY &&
                            t.ImageFormat == format &&
                            t.memsize == TextureTFCs[tfc].size)
                        {
                            for (int i = 0; i < t.memsize; i++)
                            {
                                memory[TextureTFCs[tfc].offset + i] = t.memory[i];
                            }
                            MessageBox.Show("Done.");
                        }
                    }
                    if (format > 1 && format < 5)
                    {
                        ImageFile t = new ImageFile();
                        t.ImportFromFile(Dialog.FileName);
                        if (t.ImageSizeX == TextureTFCs[tfc].sizeX &&
                            t.ImageSizeY == TextureTFCs[tfc].sizeY)
                        {
                            if (t.ImageBits != 32)
                            {
                                MessageBox.Show("Please use 32 bit Targa image!");
                            }
                            else
                            {
                                switch (format)
                                {
                                case 2:
                                    for (int i = 0; i < t.memsize / 4; i++)
                                    {
                                        memory[TextureTFCs[tfc].offset + i * 2]     = t.memory[i * 4];
                                        memory[TextureTFCs[tfc].offset + i * 2 + 1] = t.memory[i * 4 + 2];
                                    }
                                    break;

                                case 3:
                                    for (int i = 0; i < t.memsize; i++)
                                    {
                                        memory[TextureTFCs[tfc].offset + i] = t.memory[i];
                                    }
                                    break;

                                case 4:
                                    for (int i = 0; i < t.memsize / 4; i++)
                                    {
                                        memory[TextureTFCs[tfc].offset + i] = t.memory[i * 4];
                                    }
                                    break;
                                }
                                MessageBox.Show("Done.");
                            }
                        }
                    }
                }
            }
            else
            if (Dialog.ShowDialog() == DialogResult.OK)
            {
                ImageFile t = new ImageFile();
                t.ImportFromFile(Dialog.FileName);
                if ((format == 0 || format == 1) && t.ImageFormat == format)
                {
                    if (t.ImageSizeX == TextureTFCs[tfc].sizeX &&
                        t.ImageSizeY == TextureTFCs[tfc].sizeY)
                    {
                        TFCFile TFCf = new TFCFile(T2D.Tsource);
                        byte[]  buff;
                        if (TFCf.isTFCCompressed())
                        {
                            buff = ZBlock.Compress(t.memory);
                        }
                        else
                        {
                            buff = t.memory;
                        }
                        byte[] buff2 = BitConverter.GetBytes(TFCf.getFileSize());
                        for (int i = 0; i < 4; i++)
                        {
                            memory[TextureTFCs[tfc].HeaderOffset + 20 + i] = buff2[i];
                        }
                        buff2 = BitConverter.GetBytes(buff.Length);
                        for (int i = 0; i < 4; i++)
                        {
                            memory[TextureTFCs[tfc].HeaderOffset + 16 + i] = buff2[i];
                        }
                        TFCf.AppendToTFC(buff);
                        int size = TFCf.getFileSize();
                        if (size != -1)
                        {
                            TOCeditor tc = new TOCeditor();
                            if (!tc.UpdateFile(T2D.Tsource + ".tfc", (uint)size))
                            {
                                MessageBox.Show("Didn't found Entry");
                            }
                            tc.Close();
                        }
                    }
                    else
                    {
                        System.Windows.Forms.DialogResult m = MessageBox.Show("The size doesn't match, import anyway?", "ME3 Explorer", MessageBoxButtons.YesNo);
                        if (m == DialogResult.Yes)
                        {
                            TFCFile TFCf = new TFCFile(T2D.Tsource);
                            byte[]  buff;
                            if (TFCf.isTFCCompressed())
                            {
                                buff = ZBlock.Compress(t.memory);
                            }
                            else
                            {
                                buff = t.memory;
                            }
                            byte[] buff2 = BitConverter.GetBytes(TFCf.getFileSize());
                            for (int i = 0; i < 4; i++)
                            {
                                memory[TextureTFCs[tfc].HeaderOffset + 20 + i] = buff2[i];
                            }
                            buff2 = BitConverter.GetBytes(buff.Length);
                            for (int i = 0; i < 4; i++)
                            {
                                memory[TextureTFCs[tfc].HeaderOffset + 16 + i] = buff2[i];
                            }
                            if (tfc == 0)
                            {
                                buff2 = BitConverter.GetBytes(t.ImageSizeX);
                                for (int i = 0; i < 4; i++)
                                {
                                    memory[T2D.offSizeX + i] = buff2[i];
                                }
                                buff2 = BitConverter.GetBytes(t.ImageSizeY);
                                for (int i = 0; i < 4; i++)
                                {
                                    memory[T2D.offSizeY + i] = buff2[i];
                                }
                            }
                            else
                            {
                                buff2 = BitConverter.GetBytes(t.ImageSizeX * 2);
                                for (int i = 0; i < 4; i++)
                                {
                                    memory[TextureTFCs[tfc].HeaderOffset + i] = buff2[i];
                                }
                                buff2 = BitConverter.GetBytes(t.ImageSizeY * 2);
                                for (int i = 0; i < 4; i++)
                                {
                                    memory[TextureTFCs[tfc].HeaderOffset + 4 + i] = buff2[i];
                                }
                                TFCf.AppendToTFC(buff);
                            }
                            TFCf.AppendToTFC(buff);
                            int size = TFCf.getFileSize();
                            if (size != -1)
                            {
                                TOCeditor tc = new TOCeditor();
                                if (!tc.UpdateFile(T2D.Tsource + ".tfc", (uint)size))
                                {
                                    MessageBox.Show("Didn't found Entry");
                                }
                                tc.Close();
                            }
                        }
                    }
                }
                if (format > 1 && format < 5)
                {
                    if (t.ImageSizeX == TextureTFCs[tfc].sizeX &&
                        t.ImageSizeY == TextureTFCs[tfc].sizeY)
                    {
                        if (t.ImageBits != 32)
                        {
                            MessageBox.Show("Please use 32 bit Targa image!");
                        }
                        else
                        {
                            byte[] buf = new byte[0];
                            switch (format)
                            {
                            case 2:
                                buf = new byte[t.memsize / 2];
                                for (int i = 0; i < t.memsize / 4; i++)
                                {
                                    buf[i * 2]     = t.memory[i * 4];
                                    buf[i * 2 + 1] = t.memory[i * 4 + 2];
                                }
                                break;

                            case 3:
                                buf = t.memory;
                                break;

                            case 4:
                                buf = new byte[t.memsize / 4];
                                for (int i = 0; i < t.memsize / 4; i++)
                                {
                                    buf[i] = t.memory[i * 4];
                                }
                                break;
                            }
                            TFCFile TFCf = new TFCFile(T2D.Tsource);
                            byte[]  buff;
                            if (TFCf.isTFCCompressed())
                            {
                                buff = ZBlock.Compress(t.memory);
                            }
                            else
                            {
                                buff = t.memory;
                            }
                            byte[] buff2 = BitConverter.GetBytes(TFCf.getFileSize());
                            for (int i = 0; i < 4; i++)
                            {
                                memory[TextureTFCs[tfc].HeaderOffset + 20 + i] = buff2[i];
                            }
                            buff2 = BitConverter.GetBytes(buff.Length);
                            for (int i = 0; i < 4; i++)
                            {
                                memory[TextureTFCs[tfc].HeaderOffset + 12 + i] = buff2[i];
                            }
                            TFCf.AppendToTFC(buff);
                            int size = TFCf.getFileSize();
                            if (size != -1)
                            {
                                TOCeditor tc = new TOCeditor();
                                if (!tc.UpdateFile(T2D.Tsource + ".tfc", (uint)size))
                                {
                                    MessageBox.Show("Didn't found Entry");
                                }
                                tc.Close();
                            }
                            MessageBox.Show("Done.");
                        }
                    }
                }
            }
        }