Beispiel #1
0
        public ME1PCCObject(String path)
        {
            lzo = new SaltLZOHelper();
            fullname = path;
            BitConverter.IsLittleEndian = true;
            DebugOutput.PrintLn("Load file : " + path);
            pccFileName = Path.GetFullPath(path);
            MemoryStream tempStream = new MemoryStream();
            if (!File.Exists(pccFileName))
                throw new FileNotFoundException("PCC file not found");
            using (FileStream fs = new FileStream(pccFileName, FileMode.Open, FileAccess.Read))
            {
                FileInfo tempInfo = new FileInfo(pccFileName);
                tempStream.WriteFromStream(fs, tempInfo.Length);
                if (tempStream.Length != tempInfo.Length)
                {
                    throw new FileLoadException("File not fully read in. Try again later");
                }
            }

            LoadHelper(tempStream);
        }
        /// <summary>
        ///     ME3PCCObject 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 ME3PCCObject(string filePath, bool TablesOnly = false)
        {
            pccFileName = Path.GetFullPath(filePath);
            BitConverter.IsLittleEndian = true;

            MemoryStream tempStream = new MemoryStream();
            if (!File.Exists(pccFileName))
                throw new FileNotFoundException("LET ME KNOW ABOUT THIS! filename: " + pccFileName);

            int trycout = 0;
            while (trycout < 50)
            {
                try
                {
                    using (FileStream fs = new FileStream(pccFileName, FileMode.Open, FileAccess.Read))
                    {
                        FileInfo tempInfo = new FileInfo(pccFileName);
                        tempStream.WriteFromStream(fs, tempInfo.Length);
                        if (tempStream.Length != tempInfo.Length)
                        {
                            throw new FileLoadException("File not fully read in. Try again later");
                        }
                    }
                    break;
                }
                catch (Exception e)
                {
                    // KFreon: File inaccessible or someting
                    Console.WriteLine(e.Message);
                    DebugOutput.PrintLn("File inaccessible: " + filePath + ".  Attempt: " + trycout);
                    trycout++;
                    System.Threading.Thread.Sleep(100);
                }
            }

            ME3PCCObjectHelper(tempStream, filePath, TablesOnly);
        }
        /// <summary>
        ///     decompress an entire ME3 pcc file into a new stream
        /// </summary>
        /// <param name="input">pcc file passed in stream format</param>
        /// <returns>a decompressed array of bytes</returns>
        public static MemoryStream DecompressME3(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);
            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);
            }

            //decompress blocks in parallel
            Task<byte[]>[] tasks = new Task<byte[]>[blockCount];
            uint[] uncompressedOffsets = new uint[blockCount];
            for (int i = 0; i < blockCount; i++)
            {
                input.Seek(headBlockOff, SeekOrigin.Begin);
                uncompressedOffsets[i] = 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);

                tasks[i] = ZBlock.DecompressAsync(buff);
            }
            Task.WaitAll(tasks);
            for (int i = 0; i < blockCount; i++)
            {
                output.Seek(uncompressedOffsets[i], SeekOrigin.Begin);
                output.WriteBytes(tasks[i].Result);
            }

            output.Seek(packageFlagsOffset, SeekOrigin.Begin);
            output.WriteValueU32(packageFlags & ~0x02000000u, endian);
            return output;
        }
Beispiel #4
0
        private ME1Package(string path)
        {
            
            DebugOutput.PrintLn("Load file : " + path);
            FileName = Path.GetFullPath(path);
            MemoryStream tempStream = new MemoryStream();
            if (!File.Exists(FileName))
                throw new FileNotFoundException("PCC file not found");
            using (FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
            {
                FileInfo tempInfo = new FileInfo(FileName);
                tempStream.WriteFromStream(fs, tempInfo.Length);
                if (tempStream.Length != tempInfo.Length)
                {
                    throw new FileLoadException("File not fully read in. Try again later");
                }
            }

            tempStream.Seek(12, SeekOrigin.Begin);
            int tempNameSize = tempStream.ReadValueS32();
            tempStream.Seek(64 + tempNameSize, SeekOrigin.Begin);
            int tempGenerations = tempStream.ReadValueS32();
            tempStream.Seek(36 + tempGenerations * 12, SeekOrigin.Current);
            int tempPos = (int)tempStream.Position + 4;
            tempStream.Seek(0, SeekOrigin.Begin);
            header = tempStream.ReadBytes(tempPos);
            tempStream.Seek(0, SeekOrigin.Begin);

            if (magic != ZBlock.magic && magic.Swap() != ZBlock.magic)
            {
                DebugOutput.PrintLn("Magic number incorrect: " + magic);
                throw new FormatException("This is not an ME1 Package file. The magic number is incorrect.");
            }
            MemoryStream listsStream;
            if (IsCompressed)
            {
                DebugOutput.PrintLn("File is compressed");
                listsStream = CompressionHelper.DecompressME1orME2(tempStream);

                //Correct the header
                IsCompressed = false;
                listsStream.Seek(0, SeekOrigin.Begin);
                listsStream.WriteBytes(header);

                // Set numblocks to zero
                listsStream.WriteValueS32(0);
                //Write the magic number
                listsStream.WriteBytes(new byte[] { 0xF2, 0x56, 0x1B, 0x4E });
                // Write 4 bytes of 0
                listsStream.WriteValueS32(0);
            }
            else
            {
                DebugOutput.PrintLn("File already decompressed. Reading decompressed data.");
                //listsStream = tempStream;
                listsStream = new MemoryStream();
                tempStream.WriteTo(listsStream);
            }
            tempStream.Dispose();
            ReadNames(listsStream);
            ReadImports(listsStream);
            ReadExports(listsStream);
        }
Beispiel #5
0
        public PCCObject(String path, Boolean littleEndian=true)
        {
            lzo = new SaltLZOHelper();
            fullname = path;
            BitConverter.IsLittleEndian = littleEndian;
            StreamHelpers.setIsLittleEndian(littleEndian);
            DebugOutput.PrintLn("Load file : " + path);
            pccFileName = Path.GetFullPath(path);
            MemoryStream tempStream = new MemoryStream();
            if (!File.Exists(pccFileName))
                throw new FileNotFoundException("PCC file not found");
            using (FileStream fs = new FileStream(pccFileName, FileMode.Open, FileAccess.Read))
            {
                FileInfo tempInfo = new FileInfo(pccFileName);
                tempStream.WriteFromStream(fs, tempInfo.Length);
                if (tempStream.Length != tempInfo.Length)
                {
                    throw new FileLoadException("File not fully read in. Try again later");
                }
            }

            tempStream.Seek(12, SeekOrigin.Begin);
            int tempNameSize = tempStream.ReadValueS32();
            tempStream.Seek(64 + tempNameSize, SeekOrigin.Begin);
            int tempGenerator = tempStream.ReadValueS32();
            tempStream.Seek(36 + tempGenerator * 12, SeekOrigin.Current);
            int tempPos = (int)tempStream.Position;
            NumChunks = tempStream.ReadValueS32();
            tempStream.Seek(0, SeekOrigin.Begin);
            header = tempStream.ReadBytes(tempPos);
            tempStream.Seek(0, SeekOrigin.Begin);

            if (magic != ZBlock.magic && magic.Swap() != ZBlock.magic)
            {
                DebugOutput.PrintLn("Magic number incorrect: " + magic);
                throw new FormatException("This is not a pcc file. The magic number is incorrect.");
            }

            if (bCompressed)
            {
                DebugOutput.PrintLn("File is compressed");
                {
                    listsStream = lzo.DecompressPCC(tempStream, this);

                    //Correct the header
                    bCompressed = false;
                    listsStream.Seek(0, SeekOrigin.Begin);
                    listsStream.WriteBytes(header);

                    //Set numblocks to zero
                    listsStream.WriteValueS32(0);
                    //Write the magic number
                    listsStream.WriteValueS32(1026281201);
                    //Write 8 bytes of 0
                    listsStream.WriteValueS32(0);
                    listsStream.WriteValueS32(0);
                }
            }
            else
            {
                DebugOutput.PrintLn("File already decompressed. Reading decompressed data.");
                listsStream = tempStream;
            }

            ReadNames(listsStream);
            ReadImports(listsStream);
            ReadExports(listsStream);
            LoadExports();
        }
Beispiel #6
0
        public static MemoryStream Decompress(Stream input)
        {
            var basePosition = input.Position;

            if (input.ReadValueU32(false) != Magic) // CDRM
            {
                throw new FormatException();
            }

            var version = input.ReadValueU32(true);

            if (version != 0 &&
                version != 2 && version.Swap() != 2)
            {
                throw new FormatException();
            }

            bool littleEndian;
            uint count;
            uint padding;

            if (version == 0)
            {
                count = input.ReadValueU32(true);

                if (count > 0x7FFFFF)
                {
                    count = count.Swap();
                    littleEndian = false;
                }
                else
                {
                    littleEndian = true;
                }

                input.ReadValueU32(littleEndian);

                padding = (uint)(basePosition + 16 + (count * 8));
                padding = padding.Align(16) - padding;
            }
            else
            {
                littleEndian = version == 2;
                count = input.ReadValueU32(littleEndian);
                padding = input.ReadValueU32(littleEndian);
            }

            var startOfData = basePosition + 16 + (count * 8) + padding;

            var blocks = new Block[count];
            using (var buffer = input.ReadToMemoryStream((count * 8).Align(16)))
            {
                for (uint i = 0; i < count; i++)
                {
                    var block = new Block();
                    var flags = buffer.ReadValueU32(littleEndian);
                    block.UncompressedSize = (flags >> 8) & 0xFFFFFF;
                    block.Type = (byte)(flags & 0xFF);
                    block.CompressedSize = buffer.ReadValueU32(littleEndian);
                    blocks[i] = block;
                }
            }

            if (startOfData != input.Position)
            {
                throw new InvalidOperationException();
            }

            var output = new MemoryStream();

            long offset = 0;
            foreach (var block in blocks)
            {
                var nextPosition = input.Position + block.CompressedSize.Align(16);

                using (var buffer = input.ReadToMemoryStream(block.CompressedSize))
                {
                    if (block.Type == 1)
                    {
                        if (block.CompressedSize != block.UncompressedSize)
                        {
                            throw new InvalidOperationException();
                        }

                        output.Seek(offset, SeekOrigin.Begin);
                        output.WriteFromStream(buffer, block.CompressedSize);
                        offset += block.CompressedSize.Align(16);
                    }
                    else if (block.Type == 2)
                    {
                        var zlib = new InflaterInputStream(buffer);
                        output.Seek(offset, SeekOrigin.Begin);
                        output.WriteFromStream(zlib, block.UncompressedSize);
                        offset += block.UncompressedSize.Align(16);
                    }
                    else
                    {
                        throw new FormatException();
                    }
                }

                input.Seek(nextPosition, SeekOrigin.Begin);
            }

            output.Position = 0;
            return output;
        }
Beispiel #7
0
        public Stream Serialize()
        {
            MemoryStream data = new MemoryStream();
            uint sectionCount = (uint)this.Sections.Count;
            Stream[] resolvers = new MemoryStream[sectionCount]; // for serialized resolvers

            uint unknown04_size = 0;
            uint unknown08_size = 0;

            // Write DRM Header
            data.WriteValueU32(this.Version, this.Endianness);
            data.WriteValueU32(0); // skip for now
            data.WriteValueU32(0); // skip for now
            data.WriteValueU32(0); // unknown0C
            data.WriteValueU32(0); // unknown10
            data.WriteValueU32(sectionCount, this.Endianness);

            // Write DRM Section Headers
            for (int i = 0; i < sectionCount; i++)
            {
                DRM.Section section = this.Sections[i];

                // Serialize resolvers to get length, data will be used later
                uint resolverLen;
                if (section.Resolver != null)
                {
                    resolvers[i] = section.Resolver.Serialize(this.Endianness);
                    resolverLen = (uint)resolvers[i].Length;
                }
                else
                {
                    resolvers[i] = null;
                    resolverLen = 0;
                }

                data.WriteValueU32((uint)section.Data.Length, this.Endianness);
                data.WriteValueU8((byte)section.Type);
                data.WriteValueU8(section.Unknown05);
                data.WriteValueU16(section.Unknown06, this.Endianness);
                data.WriteValueU32((uint)section.Flags | (resolverLen << 8), this.Endianness);
                data.WriteValueU32(section.Id, this.Endianness);
                data.WriteValueU32(section.Unknown10, this.Endianness);
            }

            // Write Unknown08s
            for (int i = 0; i < Unknown08s.Count; i++)
            {
                unknown08_size += ((uint)Unknown08s[i].Length + 1);
                data.WriteStringZ(Unknown08s[i]);
            }

            // Write Unknown04s
            for (int i = 0; i < Unknown04s.Count; i++)
            {
                unknown04_size += ((uint)Unknown04s[i].Length + 1);
                data.WriteStringZ(Unknown04s[i]);
            }

            // Write DRM Section Data
            for (int i = 0; i < sectionCount; i++)
            {
                if (resolvers[i] != null)
                {
                    data.WriteFromStream(resolvers[i], resolvers[i].Length);
                }
                data.WriteFromStream(this.Sections[i].Data, this.Sections[i].Data.Length);
                this.Sections[i].Data.Position = 0;
            }

            // Go back and write unknowns length
            data.Seek(4, SeekOrigin.Begin);
            data.WriteValueU32(unknown04_size);
            data.WriteValueU32(unknown08_size);

            data.Position = 0;
            return data;
        }