예제 #1
0
        public void extractImage(ImageInfo imgInfo, string archiveDir = null, string fileName = null)
        {
            ImageFile imgFile;

            if (fileName == null)
            {
                fileName = texName + "_" + imgInfo.imgSize + getFileFormat();
            }

            byte[] imgBuffer;

            switch (imgInfo.storageType)
            {
            case storage.pccSto:
                imgBuffer = new byte[imgInfo.uncSize];
                Buffer.BlockCopy(imageData, imgInfo.offset, imgBuffer, 0, imgInfo.uncSize);
                break;

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

                using (FileStream archiveStream = File.OpenRead(archivePath))
                {
                    archiveStream.Seek(imgInfo.offset, SeekOrigin.Begin);
                    if (imgInfo.storageType == storage.arcCpr)
                    {
                        imgBuffer = ZBlock.Decompress(archiveStream, imgInfo.cprSize);
                    }
                    else
                    {
                        imgBuffer = new byte[imgInfo.uncSize];
                        archiveStream.Read(imgBuffer, 0, imgBuffer.Length);
                    }
                }
                break;

            default:
                throw new FormatException("Unsupported texture storage type");
            }

            if (getFileFormat() == ".dds")
            {
                imgFile = new DDS(fileName, imgInfo.imgSize, texFormat, imgBuffer);
            }
            else
            {
                imgFile = new TGA(fileName, imgInfo.imgSize, texFormat, imgBuffer);
            }

            byte[] saveImg = imgFile.ToArray();
            using (FileStream outputImg = new FileStream(imgFile.fileName, FileMode.Create, FileAccess.Write))
                outputImg.Write(saveImg, 0, saveImg.Length);
        }
예제 #2
0
        /// <summary>
        ///     given export data offset, the function recovers it from the file.
        /// </summary>
        /// <param name="offset">offset position of desired export data</param>
        private void getData(int offset, ExportEntry exp = null)
        {
            byte[] buffer;
            if (bCompressed)
            {
                Block  selected = blockList.Find(block => block.uncOffset <= offset && block.uncOffset + block.uncSize > offset);
                byte[] uncBlock;

                using (FileStream pccStream = File.OpenRead(pccFileName))
                {
                    pccStream.Seek(selected.cprOffset, SeekOrigin.Begin);
                    uncBlock = ZBlock.Decompress(pccStream, selected.cprSize);

                    // the selected block has been read
                    selected.bRead = true;
                }

                // fill all the exports data extracted from the uncBlock
                foreach (ExportEntry expInfo in Exports)
                {
                    if (expInfo.DataOffset >= selected.uncOffset && expInfo.DataOffset + expInfo.DataSize <= selected.uncOffset + selected.uncSize)
                    {
                        buffer = new byte[expInfo.DataSize];
                        Buffer.BlockCopy(uncBlock, expInfo.DataOffset - selected.uncOffset, buffer, 0, expInfo.DataSize);
                        expInfo.Data = buffer;
                    }
                }
            }
            else
            {
                ExportEntry expSelect;
                if (exp == null)
                {
                    int expIndex = Exports.FindIndex(export => export.DataOffset <= offset && export.DataOffset + export.DataSize > offset);
                    expSelect = Exports[expIndex];
                }
                else
                {
                    expSelect = exp;
                }
                using (FileStream pccStream = File.OpenRead(pccFileName))
                {
                    buffer = new byte[expSelect.DataSize];
                    pccStream.Seek(expSelect.DataOffset, SeekOrigin.Begin);
                    pccStream.Read(buffer, 0, buffer.Length);
                    expSelect.Data = buffer;
                }
            }
        }
예제 #3
0
        public byte[] extractRawData(ImageInfo imgInfo, string archiveDir = null)
        {
            byte[] imgBuffer;

            switch (imgInfo.storageType)
            {
            case storage.pccSto:
                imgBuffer = new byte[imgInfo.uncSize];
                System.Buffer.BlockCopy(imageData, imgInfo.offset, imgBuffer, 0, imgInfo.uncSize);
                break;

            case storage.arcCpr:
            case storage.arcUnc:
                string archivePath = GetTFC(arcName);
                if (archivePath != null && File.Exists(archivePath))
                {
                    Console.WriteLine("Loaded texture from tfc '" + archivePath + "'.");

                    using (FileStream archiveStream = File.OpenRead(archivePath))
                    {
                        archiveStream.Seek(imgInfo.offset, SeekOrigin.Begin);
                        if (imgInfo.storageType == storage.arcCpr)
                        {
                            imgBuffer = ZBlock.Decompress(archiveStream, imgInfo.cprSize);
                        }
                        else
                        {
                            imgBuffer = new byte[imgInfo.uncSize];
                            archiveStream.Read(imgBuffer, 0, imgBuffer.Length);
                        }
                    }
                }
                else
                {
                    //how do i put default unreal texture
                    imgBuffer = null;     //this will cause exception that will bubble up.
                }

                break;

            default:
                throw new FormatException("Unsupported texture storage type");
            }
            return(imgBuffer); //cannot be uninitialized.
        }
예제 #4
0
        /// <summary>
        ///     decompress an entire pcc file.
        /// </summary>
        /// <param name="input">pcc file passed in stream format</param>
        /// <returns>a decompressed array of bytes</returns>
        public static byte[] Decompress(Stream input)
        {
            input.Seek(0, SeekOrigin.Begin);
            var magic = input.ReadValueU32(Endian.Little);

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

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

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

            long headerSize = 8;

            input.Seek(4, SeekOrigin.Current);
            headerSize += 4;

            var folderNameLength = input.ReadValueS32(endian);

            headerSize += 4;

            var folderNameByteLength =
                folderNameLength >= 0 ? folderNameLength : (-folderNameLength * 2);

            input.Seek(folderNameByteLength, SeekOrigin.Current);
            headerSize += folderNameByteLength;

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

            headerSize += 4;

            if ((packageFlags & 0x02000000u) == 0)
            {
                throw new FormatException("pcc file is already decompressed");
            }

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

            uint nameCount  = input.ReadValueU32(endian);
            uint nameOffset = input.ReadValueU32(endian);

            input.Seek(52, SeekOrigin.Current);
            headerSize += 60;

            var generationsCount = input.ReadValueU32(endian);

            input.Seek(generationsCount * 12, SeekOrigin.Current);
            headerSize += generationsCount * 12;

            input.Seek(20, SeekOrigin.Current);
            headerSize += 24;

            var blockCount            = input.ReadValueU32(endian);
            int headBlockOff          = (int)input.Position;
            var afterBlockTableOffset = headBlockOff + (blockCount * 16);
            var indataOffset          = afterBlockTableOffset + 8;

            byte[] buff;

            input.Seek(0, SeekOrigin.Begin);
            using (MemoryStream output = new MemoryStream())
            {
                output.Seek(0, SeekOrigin.Begin);

                output.WriteFromStream(input, headerSize);
                output.WriteValueU32(0, endian); // block count

                input.Seek(afterBlockTableOffset, SeekOrigin.Begin);
                output.WriteFromStream(input, 8);

                //check if has extra name list (don't know it's usage...)
                if ((packageFlags & 0x10000000) != 0)
                {
                    long curPos = output.Position;
                    output.WriteFromStream(input, nameOffset - curPos);
                }

                for (int i = 0; i < blockCount; i++)
                {
                    input.Seek(headBlockOff, SeekOrigin.Begin);
                    var uncompressedOffset = input.ReadValueU32(endian);
                    var uncompressedSize   = input.ReadValueU32(endian);
                    var compressedOffset   = input.ReadValueU32(endian);
                    var compressedSize     = input.ReadValueU32(endian);
                    headBlockOff = (int)input.Position;

                    buff = new byte[compressedSize];
                    input.Seek(compressedOffset, SeekOrigin.Begin);
                    input.Read(buff, 0, buff.Length);

                    byte[] temp = ZBlock.Decompress(buff, 0, buff.Length);
                    output.Seek(uncompressedOffset, SeekOrigin.Begin);
                    output.Write(temp, 0, temp.Length);
                }

                output.Seek(packageFlagsOffset, SeekOrigin.Begin);
                output.WriteValueU32(packageFlags & ~0x02000000u, endian);
                return(output.ToArray());
            }
        }
예제 #5
0
        /// <summary>
        ///     PCCObject class constructor. It also load namelist, importlist and exportinfo (not exportdata) from pcc file
        /// </summary>
        /// <param name="pccFilePath">full path + file name of desired pcc file.</param>
        public PCCObject(string pccFilePath, bool fullFileInMemory = false)
        {
            Loaded      = true;
            pccFileName = Path.GetFullPath(pccFilePath);
            Debug.WriteLine("Loading pcc " + pccFileName);
            using (FileStream pccStream = File.OpenRead(pccFileName))
            {
                Names   = new List <string>();
                Imports = new List <ImportEntry>();
                Exports = new List <ExportEntry>();

                pccStream.Read(header, 0, header.Length);
                if (magic != ZBlock.magic &&
                    magic.Swap() != ZBlock.magic)
                {
                    throw new FormatException("not a pcc file");
                }

                // BitConverter isn't working?!?!
                if (magic == 0x9E2A83C1)
                {
                    BitConverter.IsLittleEndian = true;
                }
                else
                {
                    BitConverter.IsLittleEndian = true;
                }

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

                Stream listsStream;

                if (bCompressed)
                {
                    Debug.WriteLine("COMPRESSED...");
                    // seeks the blocks info position
                    pccStream.Seek(idxOffsets + 60, SeekOrigin.Begin);
                    int generator = pccStream.ReadValueS32();
                    pccStream.Seek((generator * 12) + 20, SeekOrigin.Current);

                    int blockCount = pccStream.ReadValueS32();
                    blockList = new List <Block>();

                    // creating the Block list
                    for (int i = 0; i < blockCount; i++)
                    {
                        Block temp = new Block();
                        temp.uncOffset = pccStream.ReadValueS32();
                        temp.uncSize   = pccStream.ReadValueS32();
                        temp.cprOffset = pccStream.ReadValueS32();
                        temp.cprSize   = pccStream.ReadValueS32();
                        blockList.Add(temp);
                    }

                    // correcting the header, in case there's need to be saved
                    Buffer.BlockCopy(BitConverter.GetBytes((int)0), 0, header, header.Length - 12, sizeof(int));
                    pccStream.Read(header, header.Length - 8, 8);
                    headerEnd = (int)pccStream.Position;

                    // copying the extraNamesList
                    int extraNamesLenght = blockList[0].cprOffset - headerEnd;
                    if (extraNamesLenght > 0)
                    {
                        extraNamesList = new byte[extraNamesLenght];
                        pccStream.Read(extraNamesList, 0, extraNamesLenght);
                        //FileStream fileStream = File.Create(Path.GetDirectoryName(pccFileName) + "\\temp.bin");
                        //fileStream.Write(extraNamesList, 0, extraNamesLenght);
                        //MessageBox.Show("posizione: " + pccStream.Position.ToString("X8"));
                    }

                    // decompress first block that holds infos about names, imports and exports
                    pccStream.Seek(blockList[0].cprOffset, SeekOrigin.Begin);
                    byte[] uncBlock = ZBlock.Decompress(pccStream, blockList[0].cprSize);

                    // write decompressed block inside temporary stream
                    listsStream = new MemoryStream();
                    listsStream.Seek(blockList[0].uncOffset, SeekOrigin.Begin);
                    listsStream.Write(uncBlock, 0, uncBlock.Length);
                }
                else
                {
                    listsStream = pccStream;
                    headerEnd   = (int)NameOffset;

                    // copying the extraNamesList
                    int extraNamesLenght = headerEnd - headerSize;
                    if (extraNamesLenght > 0)
                    {
                        extraNamesList = new byte[extraNamesLenght];
                        listsStream.Seek(headerSize, SeekOrigin.Begin);
                        listsStream.Read(extraNamesList, 0, extraNamesLenght);
                        //FileStream fileStream = File.Create(Path.GetDirectoryName(pccFileName) + "\\temp.bin");
                        //fileStream.Write(extraNamesList, 0, extraNamesLenght);
                        //MessageBox.Show("posizione: " + pccStream.Position.ToString("X8"));
                    }
                }

                /*if(bExtraNamesList)
                 * {
                 *  int extraNamesListSize = namesOffset - headerEnd;
                 *  extraNamesList = new byte[extraNamesListSize];
                 *  pccStream.Seek(headerEnd, SeekOrigin.Begin);
                 *  pccStream.Read(extraNamesList, 0, extraNamesList.Length);
                 * }*/

                // fill names list
                listsStream.Seek(NameOffset, SeekOrigin.Begin);
                for (int i = 0; i < NameCount; i++)
                {
                    long   currOffset = listsStream.Position;
                    int    strLength  = listsStream.ReadValueS32();
                    string str        = listsStream.ReadString(strLength * -2, true, Encoding.Unicode);
                    //Debug.WriteLine("Read name "+i+" "+str+" length: " + strLength+", offset: "+currOffset);
                    Names.Add(str);
                }
                //Debug.WriteLine("Names done. Current offset: "+listsStream.Position);
                //Debug.WriteLine("Import Offset: " + ImportOffset);

                // fill import list
                //Console.Out.WriteLine("IMPORT OFFSET: " + ImportOffset);
                listsStream.Seek(ImportOffset, SeekOrigin.Begin);
                byte[] buffer = new byte[ImportEntry.byteSize];
                for (int i = 0; i < ImportCount; i++)
                {
                    long        offset = listsStream.Position;
                    ImportEntry e      = new ImportEntry(this, listsStream);
                    Imports.Add(e);
                    //Debug.WriteLine("Read import " + i + " " + e.ObjectName + ", offset: " + offset);
                }
                ;

                // fill export list (only the headers, not the data)
                listsStream.Seek(ExportOffset, SeekOrigin.Begin);
                //Console.Out.WriteLine("Export OFFSET: " + ImportOffset);
                for (int i = 0; i < ExportCount; i++)
                {
                    uint expInfoOffset = (uint)listsStream.Position;

                    listsStream.Seek(44, SeekOrigin.Current);
                    int count = listsStream.ReadValueS32();
                    listsStream.Seek(-48, SeekOrigin.Current);

                    int expInfoSize = 68 + (count * 4);
                    buffer = new byte[expInfoSize];

                    listsStream.Read(buffer, 0, buffer.Length);
                    ExportEntry e = new ExportEntry(this, buffer, expInfoOffset);
                    //Debug.WriteLine("Read export " + i + " " + e.ObjectName + ", offset: " + expInfoOffset+ ", size: "+expInfoSize);
                    Exports.Add(e);
                }
            }
            //Debug.WriteLine(getMetadataString());
        }
예제 #6
0
        public void ME3PCCObjectHelper(MemoryStream tempStream, string filePath, bool TablesOnly)
        {
            tempStream.Seek(0, SeekOrigin.Begin);
            DataStream = new MemoryStream();
            tempStream.WriteTo(DataStream);
            Names   = new List <string>();
            Imports = new List <ME3ImportEntry>();
            Exports = new List <ME3ExportEntry>();

            header = tempStream.ReadBytes(headerSize);
            if (magic != ZBlock.magic &&
                magic.Swap() != ZBlock.magic)
            {
                throw new FormatException(filePath + " is not a pcc file");
            }

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

            if (bCompressed)
            {
                // seeks the blocks info position
                tempStream.Seek(idxOffsets + 60, SeekOrigin.Begin);
                int generator = tempStream.ReadValueS32();
                tempStream.Seek((generator * 12) + 20, SeekOrigin.Current);

                int blockCount = tempStream.ReadValueS32();
                blockList = new List <Block>();

                // creating the Block list
                for (int i = 0; i < blockCount; i++)
                {
                    Block temp = new Block();
                    temp.uncOffset = tempStream.ReadValueS32();
                    temp.uncSize   = tempStream.ReadValueS32();
                    temp.cprOffset = tempStream.ReadValueS32();
                    temp.cprSize   = tempStream.ReadValueS32();
                    blockList.Add(temp);
                }

                // correcting the header, in case there's need to be saved
                Buffer.BlockCopy(BitConverter.GetBytes(0), 0, header, header.Length - 12, sizeof(int));
                tempStream.Read(header, header.Length - 8, 8);
                headerEnd = (int)tempStream.Position;

                // copying the extraNamesList
                int extraNamesLenght = blockList[0].cprOffset - headerEnd;
                if (extraNamesLenght > 0)
                {
                    extraNamesList = new byte[extraNamesLenght];
                    tempStream.Read(extraNamesList, 0, extraNamesLenght);
                    //FileStream fileStream = File.Create(Path.GetDirectoryName(pccFileName) + "\\temp.bin");
                    //fileStream.Write(extraNamesList, 0, extraNamesLenght);
                    //MessageBox.Show("posizione: " + pccStream.Position.ToString("X8"));
                }

                int dataStart = 0;
                using (MemoryStream he = new MemoryStream(header))
                {
                    he.Seek(0, SeekOrigin.Begin);
                    he.ReadValueS32();
                    he.ReadValueS32();
                    dataStart = he.ReadValueS32();
                }

                if (TablesOnly)
                {
                    int TableStart = 0;
                    for (int m = 0; m < blockList.Count; m++)
                    {
                        if (blockList[m].uncOffset + blockList[m].uncSize > dataStart)
                        {
                            TableStart = m;
                            break;
                        }
                    }

                    listsStream = new MemoryStream();
                    tempStream.Seek(blockList[TableStart].cprOffset, SeekOrigin.Begin);
                    listsStream.Seek(blockList[TableStart].uncOffset, SeekOrigin.Begin);
                    listsStream.WriteBytes(ZBlock.Decompress(tempStream, blockList[TableStart].cprSize));
                    DataStream = new MemoryStream();
                    tempStream.WriteTo(DataStream);
                    bCompressed = true;
                }
                else
                {
                    //Decompress ALL blocks
                    listsStream = new MemoryStream();
                    for (int i = 0; i < blockCount; i++)
                    {
                        tempStream.Seek(blockList[i].cprOffset, SeekOrigin.Begin);
                        listsStream.Seek(blockList[i].uncOffset, SeekOrigin.Begin);
                        listsStream.WriteBytes(ZBlock.Decompress(tempStream, blockList[i].cprSize));
                    }
                }
                bCompressed = false;
            }
            else
            {
                listsStream = new MemoryStream();
                listsStream.WriteBytes(tempStream.ToArray());
            }
            tempStream.Dispose();

            //Fill name list
            listsStream.Seek(NameOffset, SeekOrigin.Begin);
            for (int i = 0; i < NameCount; i++)
            {
                int strLength = listsStream.ReadValueS32();
                Names.Add(listsStream.ReadString(strLength * -2, true, Encoding.Unicode));
            }

            // fill import list
            listsStream.Seek(ImportOffset, SeekOrigin.Begin);
            byte[] buffer = new byte[ME3ImportEntry.byteSize];
            for (int i = 0; i < ImportCount; i++)
            {
                Imports.Add(new ME3ImportEntry(this, listsStream));
            }

            //fill export list
            listsStream.Seek(ExportOffset, SeekOrigin.Begin);
            for (int i = 0; i < ExportCount; i++)
            {
                uint expInfoOffset = (uint)listsStream.Position;

                listsStream.Seek(44, SeekOrigin.Current);
                int count = listsStream.ReadValueS32();
                listsStream.Seek(-48, SeekOrigin.Current);

                int expInfoSize = 68 + (count * 4);
                buffer = new byte[expInfoSize];

                listsStream.Read(buffer, 0, buffer.Length);
                Exports.Add(new ME3ExportEntry(this, buffer, expInfoOffset));
            }
        }
예제 #7
0
        // KFreon: Decompresses specific blocks if compressed, or returns data specified by offset and length.
        public byte[] Decompressor(uint offset, int length)
        {
            using (MemoryStream retval = new MemoryStream())
            {
                uint newoffset = 0;

                /*if (blockList.Count == 1)
                 *  bCompressed = false;*/
                /*if (bCompressed)
                 * {*/
                // KFreon: Find datablocks to decompress
                int DataStart = 0;
                int DataEnd   = 0;
                int got       = 0;
                for (int m = 0; m < blockList.Count; m++)
                {
                    if (got == 0 && blockList[m].uncOffset + blockList[m].uncSize > offset)
                    {
                        DataStart = m;
                        got++;
                    }

                    if (got == 1 && blockList[m].uncOffset + blockList[m].uncSize > offset + length)
                    {
                        DataEnd = m;
                        got++;
                    }

                    if (got == 2)
                    {
                        break;
                    }
                }

                if (DataEnd == 0 && DataStart != 0)
                {
                    DataEnd = DataStart;
                }

                /*// KFreon: Move end along so as able to read
                 * if (DataStart == DataEnd)
                 *  DataEnd++;*/

                // KFreon: Decompress blocks
                newoffset = offset - (uint)blockList[DataStart].uncOffset;
                for (int i = DataStart; i <= DataEnd; i++)
                {
                    DataStream.Seek(blockList[i].cprOffset, SeekOrigin.Begin);
                    //retval.Seek(blockList[i].uncOffset, SeekOrigin.Begin);
                    retval.WriteBytes(ZBlock.Decompress(DataStream, blockList[i].cprSize));
                }

                /*}
                 * else
                 * {
                 *  listsStream.Seek(offset, SeekOrigin.Begin);
                 *  retval.ReadFrom(listsStream, length);
                 *  newoffset = 0;
                 * }*/
                //retval.Seek(offset, SeekOrigin.Begin);
                retval.Seek(newoffset, SeekOrigin.Begin);
                return(retval.ReadBytes(length));
            }
        }