public TextureGroup(PCCObject pccObj, byte[] data)
        {
            enumTextureGroups = new List<ByteProp>();
            pccRef = pccObj;

            MemoryStream buffer = new MemoryStream(data);

            firstVal = buffer.ReadValueU32();
            buffer.Seek(16, SeekOrigin.Begin);
            otherVal = buffer.ReadValueU32();

            int numEnums = buffer.ReadValueS32();
            for (int i = 0; i < numEnums; i++)
            {
                ByteProp aux = new ByteProp(pccRef.Names[buffer.ReadValueS32()], buffer.ReadValueS32());
                enumTextureGroups.Add(aux);
            }
        }
Exemple #2
0
 private void ReadImports(MemoryStream fs)
 {
     DebugOutput.PrintLn("Reading Imports...");
     Imports = new List<ME1ImportEntry>();
     fs.Seek(ImportOffset, SeekOrigin.Begin);
     for (int i = 0; i < ImportCount; i++)
     {
         ME1ImportEntry import = new ME1ImportEntry();
         import.Package = Names[fs.ReadValueS32()];
         fs.Seek(12, SeekOrigin.Current);
         import.link = fs.ReadValueS32();
         import.Name = Names[fs.ReadValueS32()];
         fs.Seek(-24, SeekOrigin.Current);
         import.raw = fs.ReadBytes(28);
         Imports.Add(import);
     }
 }
Exemple #3
0
        private void ReadExports(MemoryStream fs)
        {
            DebugOutput.PrintLn("Reading Exports...");
            fs.Seek(ExportOffset, SeekOrigin.Begin);
            Exports = new List<ME1ExportEntry>();

            for (int i = 0; i < ExportCount; i++)
            {
                long start = fs.Position;
                ME1ExportEntry exp = new ME1ExportEntry();
                exp.pccRef = this;
                exp.infoOffset = (int)start;

                fs.Seek(40, SeekOrigin.Current);
                int count = fs.ReadValueS32();
                fs.Seek(4 + count * 12, SeekOrigin.Current);
                count = fs.ReadValueS32();
                fs.Seek(4 + count * 4, SeekOrigin.Current);
                fs.Seek(16, SeekOrigin.Current);
                long end = fs.Position;
                fs.Seek(start, SeekOrigin.Begin);
                exp.info = fs.ReadBytes((int)(end - start));
                Exports.Add(exp);
                fs.Seek(end, SeekOrigin.Begin);

                if (LastExport == null || exp.DataOffset > LastExport.DataOffset)
                    LastExport = exp;
            }
        }
Exemple #4
0
        private void LoadHelper(MemoryStream tempStream)
        {
            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 + 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 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.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);
            LoadExports();
        }
Exemple #5
0
        public List<ImageInfo> imgList { get; private set; } // showable image list

        public Texture2D(ME3Package pccObj, int texIdx)
        {
            pccRef = pccObj;
            // check if texIdx is an Export index and a Texture2D class
            if (pccObj.isExport(texIdx) && (pccObj.Exports[texIdx].ClassName == className))
            {
                IExportEntry expEntry = pccObj.Exports[texIdx];
                properties = new Dictionary<string, PropertyReader.Property>();
                byte[] rawData = expEntry.Data;
                int propertiesOffset = PropertyReader.detectStart(pccObj, rawData, expEntry.ObjectFlags);
                headerData = new byte[propertiesOffset];
                Buffer.BlockCopy(rawData, 0, headerData, 0, propertiesOffset);
                pccOffset = (uint)expEntry.DataOffset;
                List<PropertyReader.Property> tempProperties = PropertyReader.getPropList(expEntry);
                texName = expEntry.ObjectName;
                for (int i = 0; i < tempProperties.Count; i++)
                {
                    PropertyReader.Property property = tempProperties[i];
                    if (!properties.ContainsKey(pccObj.Names[property.Name]))
                        properties.Add(pccObj.Names[property.Name], property);

                    switch (pccObj.Names[property.Name])
                    {
                        case "Format": texFormat = pccObj.Names[property.Value.IntValue].Substring(3); break;
                        case "TextureFileCacheName": arcName = pccObj.Names[property.Value.IntValue]; break;
                        case "LODGroup": LODGroup = pccObj.Names[property.Value.IntValue]; break;
                        case "None": dataOffset = (uint)(property.offsetval + property.Size); break;
                    }
                }

                // if "None" property isn't found throws an exception
                if (dataOffset == 0)
                    throw new Exception("\"None\" property not found");
                else
                {
                    imageData = new byte[rawData.Length - dataOffset];
                    Buffer.BlockCopy(rawData, (int)dataOffset, imageData, 0, (int)(rawData.Length - dataOffset));
                }
            }
            else
                throw new Exception("Texture2D " + texIdx + " not found");

            pccExpIdx = texIdx;
            MemoryStream dataStream = new MemoryStream(imageData);
            numMipMaps = dataStream.ReadValueU32();
            uint count = numMipMaps;

            imgList = new List<ImageInfo>();
            while (dataStream.Position < dataStream.Length && count > 0)
            {
                ImageInfo imgInfo = new ImageInfo();
                imgInfo.storageType = (storage)dataStream.ReadValueS32();
                imgInfo.uncSize = dataStream.ReadValueS32();
                imgInfo.cprSize = dataStream.ReadValueS32();
                imgInfo.offset = dataStream.ReadValueS32();
                if (imgInfo.storageType == storage.pccSto)
                {
                    //imgInfo.offset = (int)(pccOffset + dataOffset); // saving pcc offset as relative to exportdata offset, not absolute
                    imgInfo.offset = (int)dataStream.Position; // saving pcc offset as relative to exportdata offset, not absolute
                    //MessageBox.Show("Pcc class offset: " + pccOffset + "\nimages data offset: " + imgInfo.offset.ToString());
                    dataStream.Seek(imgInfo.uncSize, SeekOrigin.Current);
                }
                imgInfo.imgSize = new ImageSize(dataStream.ReadValueU32(), dataStream.ReadValueU32());
                imgList.Add(imgInfo);
                count--;
            }

            // save what remains
            /*int remainingBytes = (int)(dataStream.Length - dataStream.Position);
            footerData = new byte[remainingBytes];
            dataStream.Read(footerData, 0, footerData.Length);*/
        }
Exemple #6
0
        public ME2Texture2D(ME2PCCObject pcc, int pccExpID, String pathBioGame)
        {
            ME2ExportEntry exp = pcc.Exports[pccExpID];
            if (String.Compare(exp.ClassName, className) != 0 && String.Compare(exp.ClassName, class2) != 0 && String.Compare(exp.ClassName, class3) != 0)
            {
                throw new FormatException("Export is not a texture");
            }
            Class = exp.ClassName;
            exportOffset = exp.DataOffset;
            FullPackage = exp.PackageFullName;
            texName = exp.ObjectName;
            pccFileName = pcc.pccFileName;
            allPccs = new List<string>();
            allPccs.Add(pcc.pccFileName);
            properties = new Dictionary<string, SaltPropertyReader.Property>();
            byte[] rawData = (byte[])exp.Data.Clone();
            Compression = "No Compression";
            int propertiesOffset = SaltPropertyReader.detectStart(pcc, rawData);
            headerData = new byte[propertiesOffset];
            Buffer.BlockCopy(rawData, 0, headerData, 0, propertiesOffset);
            pccOffset = (uint)exp.DataOffset;
            UnpackNum = 0;
            List<SaltPropertyReader.Property> tempProperties = SaltPropertyReader.getPropList(pcc, rawData);
            for (int i = 0; i < tempProperties.Count; i++)
            {
                SaltPropertyReader.Property property = tempProperties[i];
                if (property.Name == "UnpackMin")
                    UnpackNum++;

                if (!properties.ContainsKey(property.Name))
                    properties.Add(property.Name, property);

                switch (property.Name)
                {
                    case "Format": texFormat = property.Value.StringValue; break;
                    case "TextureFileCacheName": arcName = property.Value.StringValue; break;
                    case "LODGroup": LODGroup = property.Value.StringValue; break;
                    case "CompressionSettings": Compression = property.Value.StringValue; break;
                    case "None": dataOffset = (uint)(property.offsetval + property.Size); break;
                }
            }
            // if "None" property isn't found throws an exception
            if (dataOffset == 0)
                throw new Exception("\"None\" property not found");

            if (!String.IsNullOrEmpty(arcName))
                FullArcPath = GetTexArchive(pathBioGame);

            imageData = new byte[rawData.Length - dataOffset];
            Buffer.BlockCopy(rawData, (int)dataOffset, imageData, 0, (int)(rawData.Length - dataOffset));

            //DebugOutput.PrintLn("ImageData size = " + imageData.Length);
            pccExpIdx = pccExpID;

            MemoryStream dataStream = new MemoryStream(imageData);
            privateimgList = new List<ImageInfo>();
            dataStream.ReadValueU32(); //Current position in pcc
            numMipMaps = dataStream.ReadValueU32();
            uint count = numMipMaps;
            ArcDataSize = 0;
            //DebugOutput.PrintLn(numMipMaps + " derp");
            while (dataStream.Position < dataStream.Length && count > 0)
            {
                ImageInfo imgInfo = new ImageInfo();
                imgInfo.storageType = (storage)dataStream.ReadValueS32();
                imgInfo.uncSize = dataStream.ReadValueS32();
                imgInfo.cprSize = dataStream.ReadValueS32();
                imgInfo.offset = dataStream.ReadValueS32();
                if (imgInfo.storageType == storage.pccSto)
                {
                    imgInfo.offset = (int)dataStream.Position;
                    dataStream.Seek(imgInfo.uncSize, SeekOrigin.Current);
                }
                else if (imgInfo.storageType == storage.arcCpr || imgInfo.storageType == storage.arcUnc)
                {
                    ArcDataSize += imgInfo.uncSize;
                }

                imgInfo.imgSize = new ImageSize(dataStream.ReadValueU32(), dataStream.ReadValueU32());
                if (privateimgList.Exists(img => img.imgSize == imgInfo.imgSize))
                {
                    uint width = imgInfo.imgSize.width;
                    uint height = imgInfo.imgSize.height;
                    if (width == 4 && privateimgList.Exists(img => img.imgSize.width == width))
                        width = privateimgList.Last().imgSize.width / 2;
                    if (width == 0)
                        width = 1;
                    if (height == 4 && privateimgList.Exists(img => img.imgSize.height == height))
                        height = privateimgList.Last().imgSize.height / 2;
                    if (height == 0)
                        height = 1;
                    imgInfo.imgSize = new ImageSize(width, height);
                    if (privateimgList.Exists(img => img.imgSize == imgInfo.imgSize))
                        throw new Exception("Duplicate image size found");
                }
                privateimgList.Add(imgInfo);
                count--;
                //DebugOutput.PrintLn("ImgInfo no: " + count + ", Storage Type = " + imgInfo.storageType + ", offset = " + imgInfo.offset);
            }
            // Grab the rest for the footer
            footerData = new byte[dataStream.Length - dataStream.Position];
            footerData = dataStream.ReadBytes(footerData.Length);
        }
        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);
        }
 void ReadNames(MemoryStream fs)
 {
     fs.Seek(NameOffset, SeekOrigin.Begin);
     names = new List<string>();
     for (int i = 0; i < NameCount; i++)
     {
         int len = fs.ReadValueS32();
         string s = fs.ReadString((uint)(len - 1));
         fs.Seek(5, SeekOrigin.Current);
         names.Add(s);
     }
 }
        private static void Main(string[] args)
        {
            var paths = Directory.GetFiles("saves", "*.sav");

            var successes = 0;
            var failures = 0;

            foreach (var path in paths)
            {
                var name = Path.GetFileNameWithoutExtension(path);

                using (var input = File.OpenRead(path))
                {
                    var readHash = input.ReadBytes(20);
                    using (var data = input.ReadToMemoryStream(input.Length - 20))
                    {
                        byte[] computedHash;
                        using (var sha1 = new System.Security.Cryptography.SHA1Managed())
                        {
                            computedHash = sha1.ComputeHash(data);
                        }

                        if (readHash.SequenceEqual(computedHash) == false)
                        {
                            Console.WriteLine("{0}: failed (SHA1 mismatch)", name);
                            failures++;
                            continue;
                        }

                        data.Position = 0;
                        var uncompressedSize = data.ReadValueU32(Endian.Big);
                        var actualUncompressedSize = (int)uncompressedSize;
                        var uncompressedBytes = new byte[uncompressedSize];
                        var compressedSize = (int)(data.Length - 4);
                        var compressedBytes = data.ReadBytes(compressedSize);
                        var result = LZO.Decompress(compressedBytes,
                                                    0,
                                                    compressedSize,
                                                    uncompressedBytes,
                                                    0,
                                                    ref actualUncompressedSize);
                        if (result != LZO.ErrorCode.Success)
                        {
                            Console.WriteLine("{0}: failed (LZO error {1})", name, result);
                            failures++;
                            continue;
                        }

                        using (var outerData = new MemoryStream(uncompressedBytes))
                        {
                            var innerSize = outerData.ReadValueU32(Endian.Big);
                            var magic = outerData.ReadString(3);
                            if (magic != "WSG")
                            {
                                Console.WriteLine("{0}: failed (bad magic)", name);
                                failures++;
                                continue;
                            }

                            var version = outerData.ReadValueU32(Endian.Little);
                            if (version != 2 &&
                                version.Swap() != 2)
                            {
                                Console.WriteLine("{0}: failed (bad version)", name);
                                failures++;
                                continue;
                            }

                            var endian = version == 2 ? Endian.Little : Endian.Big;

                            var hash = outerData.ReadValueU32(endian);
                            var innerUncompressedSize = outerData.ReadValueS32(endian);

                            var innerCompressedBytes = outerData.ReadBytes(innerSize - 3 - 4 - 4 - 4);
                            var innerUncompressedBytes = Huffman.Decoder.Decode(innerCompressedBytes,
                                                                                innerUncompressedSize);
                            using (var innerUncompressedData = new MemoryStream(innerUncompressedBytes))
                            {
                                using (var output = File.Create("temp.bin"))
                                {
                                    output.WriteBytes(innerUncompressedBytes);
                                }

                                var save =
                                    Serializer.Deserialize<WillowTwoSave.WillowTwoPlayerSaveGame>(innerUncompressedData);

                                using (var testData = new MemoryStream())
                                {
                                    Serializer.Serialize(testData, save);

                                    testData.Position = 0;
                                    var testBytes = testData.ReadBytes((uint)testData.Length);
                                    if (innerUncompressedBytes.SequenceEqual(testBytes) == false)
                                    {
                                        Console.WriteLine("{0}: failed (reencode mismatch)", name);

                                        using (var output = File.Create(Path.Combine("failures", name + "_before.bin")))
                                        {
                                            output.WriteBytes(innerUncompressedBytes);
                                        }

                                        using (var output = File.Create(Path.Combine("failures", name + "_after.bin")))
                                        {
                                            output.WriteBytes(testBytes);
                                        }

                                        failures++;
                                        continue;
                                    }

                                    successes++;
                                }
                            }
                        }
                    }
                }
            }

            Console.WriteLine("{0} processed ({1} failed, {2} succeeded).",
                              paths.Length,
                              failures,
                              successes);
        }
Exemple #10
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();
        }
Exemple #11
0
 private void ReadNames(MemoryStream fs)
 {
     DebugOutput.PrintLn("Reading Names...");
     fs.Seek(NameOffset, SeekOrigin.Begin);
     Names = new List<string>();
     for (int i = 0; i < NameCount; i++)
     {
         int len = fs.ReadValueS32();
         string s = fs.ReadString((uint)(len - 1));
         fs.Seek(5, SeekOrigin.Current);
         Names.Add(s);
     }
 }
        public static SaveFile Deserialize(Stream input, DeserializeSettings settings)
        {
            if (input.Position + 20 > input.Length)
            {
                throw new SaveCorruptionException("not enough data for save header");
            }

            var check = input.ReadValueU32(Endian.Big);
            if (check == 0x434F4E20)
            {
                throw new SaveFormatException("Xbox 360 save game loading is in the works");

            }
            input.Seek(-4, SeekOrigin.Current);

            var readSha1Hash = input.ReadBytes(20);
            using (var data = input.ReadToMemoryStream(input.Length - 20))
            {
                byte[] computedSha1Hash;
                using (var sha1 = new System.Security.Cryptography.SHA1Managed())
                {
                    computedSha1Hash = sha1.ComputeHash(data);
                }

                if ((settings & DeserializeSettings.IgnoreSha1Mismatch) == 0 &&
                    readSha1Hash.SequenceEqual(computedSha1Hash) == false)
                {
                    throw new SaveCorruptionException("invalid SHA1 hash");
                }

                data.Position = 0;
                var uncompressedSize = data.ReadValueU32(Endian.Big);

                var uncompressedBytes = new byte[uncompressedSize];
                if (uncompressedSize <= BlockSize)
                {
                    var actualUncompressedSize = (int)uncompressedSize;
                    var compressedSize = (uint)(data.Length - 4);
                    var compressedBytes = data.ReadBytes(compressedSize);
                    var result = LZO.Decompress(compressedBytes,
                                                0,
                                                (int)compressedSize,
                                                uncompressedBytes,
                                                0,
                                                ref actualUncompressedSize);
                    if (result != LZO.ErrorCode.Success)
                    {
                        throw new SaveCorruptionException(string.Format("LZO decompression failure ({0})", result));
                    }

                    if (actualUncompressedSize != (int)uncompressedSize)
                    {
                        throw new SaveCorruptionException("LZO decompression failure (uncompressed size mismatch)");
                    }
                }
                else
                {
                    var blockCount = data.ReadValueU32(Endian.Big);
                    var blockInfos = new List<Tuple<uint, uint>>();
                    for (uint i = 0; i < blockCount; i++)
                    {
                        var blockCompressedSize = data.ReadValueU32(Endian.Big);
                        var blockUncompressedSize = data.ReadValueU32(Endian.Big);
                        blockInfos.Add(new Tuple<uint, uint>(blockCompressedSize, blockUncompressedSize));
                    }

                    int uncompressedOffset = 0;
                    int uncompressedSizeLeft = (int)uncompressedSize;
                    foreach (var blockInfo in blockInfos)
                    {
                        var blockUncompressedSize = Math.Min((int)blockInfo.Item2, uncompressedSizeLeft);
                        var actualUncompressedSize = blockUncompressedSize;
                        var compressedSize = (int)blockInfo.Item1;
                        var compressedBytes = data.ReadBytes(compressedSize);
                        var result = LZO.Decompress(compressedBytes,
                                                    0,
                                                    compressedSize,
                                                    uncompressedBytes,
                                                    uncompressedOffset,
                                                    ref actualUncompressedSize);
                        if (result != LZO.ErrorCode.Success)
                        {
                            throw new SaveCorruptionException(string.Format("LZO decompression failure ({0})", result));
                        }

                        if (actualUncompressedSize != blockUncompressedSize)
                        {
                            throw new SaveCorruptionException("LZO decompression failure (uncompressed size mismatch)");
                        }

                        uncompressedOffset += blockUncompressedSize;
                        uncompressedSizeLeft -= blockUncompressedSize;
                    }

                    if (uncompressedSizeLeft != 0)
                    {
                        throw new SaveCorruptionException("LZO decompression failure (uncompressed size left != 0)");
                    }
                }

                using (var outerData = new MemoryStream(uncompressedBytes))
                {
                    var innerSize = outerData.ReadValueU32(Endian.Big);
                    var magic = outerData.ReadString(3);
                    if (magic != "WSG")
                    {
                        throw new SaveCorruptionException("invalid magic");
                    }

                    var version = outerData.ReadValueU32(Endian.Little);
                    if (version != 2 &&
                        version.Swap() != 2)
                    {
                        throw new SaveCorruptionException("invalid or unsupported version");
                    }
                    var endian = version == 2 ? Endian.Little : Endian.Big;

                    var readCRC32Hash = outerData.ReadValueU32(endian);
                    var innerUncompressedSize = outerData.ReadValueS32(endian);

                    var innerCompressedBytes = outerData.ReadBytes(innerSize - 3 - 4 - 4 - 4);
                    var innerUncompressedBytes = Huffman.Decoder.Decode(innerCompressedBytes,
                                                                        innerUncompressedSize);
                    if (innerUncompressedBytes.Length != innerUncompressedSize)
                    {
                        throw new SaveCorruptionException("huffman decompression failure");
                    }

                    var computedCRC32Hash = CRC32.Hash(innerUncompressedBytes, 0, innerUncompressedBytes.Length);
                    if ((settings & DeserializeSettings.IgnoreCrc32Mismatch) == 0 &&
                        computedCRC32Hash != readCRC32Hash)
                    {
                        throw new SaveCorruptionException("invalid CRC32 hash");
                    }

                    using (var innerUncompressedData = new MemoryStream(innerUncompressedBytes))
                    {
                        var saveGame =
                            ProtoBuf.Serializer.Deserialize<WillowTwoSave.WillowTwoPlayerSaveGame>(innerUncompressedData);

                        if ((settings & DeserializeSettings.IgnoreReencodeMismatch) == 0)
                        {
                            using (var testData = new MemoryStream())
                            {
                                ProtoBuf.Serializer.Serialize(testData, saveGame);

                                testData.Position = 0;
                                var testBytes = testData.ReadBytes((uint)testData.Length);
                                if (innerUncompressedBytes.SequenceEqual(testBytes) == false)
                                {
                                    throw new SaveCorruptionException("reencode mismatch");
                                }
                            }
                        }

                        saveGame.Decompose();
                        return new SaveFile()
                        {
                            Endian = endian,
                            SaveGame = saveGame,
                        };
                    }
                }
            }
        }
        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));
            }
        }
Exemple #14
0
        public static byte[] Decompress(byte[] buffer, int offset, int count)
        {
            if (buffer == null)
                throw new ArgumentNullException();
            if (count < 0)
                throw new FormatException();
            if (offset + count > buffer.Length)
                throw new IndexOutOfRangeException();

            using (MemoryStream buffStream = new MemoryStream(buffer, offset, count))
            {
                InflaterInputStream zipStream;
                uint magicStream = buffStream.ReadValueU32();
                if (magicStream != magic && magicStream.Swap() != magic)
                {
                    throw new InvalidDataException("found an invalid zlib block");
                }

                uint buffMaxSegmentSize = buffStream.ReadValueU32();
                if (buffMaxSegmentSize != maxSegmentSize)
                {
                    throw new FormatException();
                }

                uint totComprSize = buffStream.ReadValueU32();
                uint totUncomprSize = buffStream.ReadValueU32();

                byte[] outputBuffer = new byte[totUncomprSize];
                int numOfSegm = (int)Math.Ceiling((double)totUncomprSize / (double)maxSegmentSize);
                int headSegm = 16;
                int dataSegm = headSegm + (numOfSegm * 8);
                int buffOff = 0;

                for (int i = 0; i < numOfSegm; i++)
                {
                    buffStream.Seek(headSegm, SeekOrigin.Begin);
                    int comprSegm = buffStream.ReadValueS32();
                    int uncomprSegm = buffStream.ReadValueS32();
                    headSegm = (int)buffStream.Position;

                    buffStream.Seek(dataSegm, SeekOrigin.Begin);
                    //Console.WriteLine("compr size: {0}, uncompr size: {1}, data offset: 0x{2:X8}", comprSegm, uncomprSegm, dataSegm);
                    zipStream = new InflaterInputStream(buffStream);
                    zipStream.Read(outputBuffer, buffOff, uncomprSegm);
                    zipStream.Flush();
                    buffOff += uncomprSegm;
                    dataSegm += comprSegm;
                }
                buffStream.Close();
                return outputBuffer;
            }
        }
Exemple #15
0
 private void ReadNames(MemoryStream fs)
 {
     DebugOutput.PrintLn("Reading Names...");
     fs.Seek(NameOffset, SeekOrigin.Begin);
     Names = new List<string>();
     for (int i = 0; i < NameCount; i++)
     {
         int len = fs.ReadValueS32();
         string s = "";
         if (len > 0)
         {
             s = fs.ReadString((uint)(len - 1));
             fs.Seek(9, SeekOrigin.Current);
         }
         else
         {
             len *= -1;
             for (int j = 0; j < len - 1; j++)
             {
                 s += (char)fs.ReadByte();
                 fs.ReadByte();
             }
             fs.Seek(10, SeekOrigin.Current);
         }
         Names.Add(s);
     }
 }
Exemple #16
0
        private void ReadExports(MemoryStream fs)
        {
            DebugOutput.PrintLn("Reading Exports...");
            fs.Seek(ExportOffset, SeekOrigin.Begin);
            exports = new List<ME1ExportEntry>();
            byte[] buffer;

            for (int i = 0; i < ExportCount; i++)
            {
                long start = fs.Position;

                fs.Seek(40, SeekOrigin.Current);
                int count = fs.ReadValueS32();
                fs.Seek(4 + count * 12, SeekOrigin.Current);
                count = fs.ReadValueS32();
                fs.Seek(4 + count * 4, SeekOrigin.Current);
                fs.Seek(16, SeekOrigin.Current);
                long end = fs.Position;
                fs.Seek(start, SeekOrigin.Begin);

                ME1ExportEntry exp = new ME1ExportEntry(this, fs.ReadBytes((int)(end - start)), (uint)start);
                buffer = new byte[exp.DataSize];
                fs.Seek(exp.DataOffset, SeekOrigin.Begin);
                fs.Read(buffer, 0, buffer.Length);
                exp.Data = buffer;
                exp.DataChanged = false;
                exp.Index = i;
                exp.PropertyChanged += exportChanged;
                exports.Add(exp);
                fs.Seek(end, SeekOrigin.Begin);
            }
        }
        public ME3SaltTexture2D(ME3PCCObject pccObj, int texIdx, String pathBioGame, uint hash = 0)
        {
            allPccs = new List<string>();
            hasChanged = false;
            Hash = hash;

            if (pccObj.isExport(texIdx) && (pccObj.Exports[texIdx].ClassName == className || pccObj.Exports[texIdx].ClassName == class2 || pccObj.Exports[texIdx].ClassName == class3))
            {
                Class = pccObj.Exports[texIdx].ClassName;
                ME3ExportEntry expEntry = pccObj.Exports[texIdx];
                properties = new Dictionary<string, SaltPropertyReader.Property>();
                byte[] rawData = (byte[])expEntry.Data.Clone();
                int propertiesOffset = SaltPropertyReader.detectStart(pccObj, rawData);
                headerData = new byte[propertiesOffset];
                Buffer.BlockCopy(rawData, 0, headerData, 0, propertiesOffset);
                pccOffset = expEntry.DataOffset;
                List<SaltPropertyReader.Property> tempProperties = SaltPropertyReader.getPropList(pccObj, rawData);
                texName = expEntry.ObjectName;
                for (int i = 0; i < tempProperties.Count; i++)
                {
                    SaltPropertyReader.Property property = tempProperties[i];
                    if (property.Name == "UnpackMin")
                        UnpackNum++;

                    if (!properties.ContainsKey(property.Name))
                        properties.Add(property.Name, property);

                    switch (property.Name)
                    {
                        case "Format":
                            texFormat = Textures.Methods.ParseFormat(pccObj.Names[property.Value.IntValue].Substring(3));
                            break;
                        case "TextureFileCacheName": arcName = property.Value.NameValue.Name; break;
                        case "LODGroup": LODGroup = property.Value.NameValue.Name; break;
                        case "None": dataOffset = (uint)(property.offsetval + property.Size); break;
                    }
                }
                if (!String.IsNullOrEmpty(arcName))
                    FullArcPath = GetTexArchive(pathBioGame);

                // if "None" property isn't found throws an exception
                if (dataOffset == 0)
                    throw new Exception("\"None\" property not found");
                else
                {
                    imageData = new byte[rawData.Length - dataOffset];
                    Buffer.BlockCopy(rawData, (int)dataOffset, imageData, 0, (int)(rawData.Length - dataOffset));
                }
            }
            else
                throw new Exception("Texture2D " + texIdx + " not found");

            pccExpIdx = texIdx;
            MemoryStream dataStream = new MemoryStream(imageData);  // FG: we will move forward with the memorystream (we are reading an export entry for a texture object data inside the pcc)
            numMipMaps = dataStream.ReadValueU32();                 // FG: 1st int32 (4 bytes / 32bits) is number of mipmaps
            uint count = numMipMaps;

            privateimgList = new List<ImageInfo>();
            ArcDataSize = 0;
            while (dataStream.Position < dataStream.Length && count > 0)
            {
                ImageInfo imgInfo = new ImageInfo();                            // FG: store properties in ImageInfo struct (code at top)
                imgInfo.storageType = (storage)dataStream.ReadValueS32();       // FG: 2nd int32 storage type (see storage types above in enum_struct)
                imgInfo.uncSize = dataStream.ReadValueS32();                    // FG: 3rd int32 uncompressed texture size
                imgInfo.cprSize = dataStream.ReadValueS32();                    // FG: 4th int32 compressed texture size
                imgInfo.offset = dataStream.ReadValueS32();                     // FG: 5th int32 texture offset
                if (imgInfo.storageType == storage.pccSto)
                {
                    //imgInfo.offset = (int)(pccOffset + dataOffset); // saving pcc offset as relative to exportdata offset, not absolute
                    imgInfo.offset = (int)dataStream.Position; // saving pcc offset as relative to exportdata offset, not absolute
                    //MessageBox.Show("Pcc class offset: " + pccOffset + "\nimages data offset: " + imgInfo.offset.ToString());
                    dataStream.Seek(imgInfo.uncSize, SeekOrigin.Current);       // FG: if local storage, texture data follows, so advance datastream to after uncompressed_size (pcc storage type only)
                }
                else if (imgInfo.storageType == storage.arcCpr || imgInfo.storageType == storage.arcUnc)
                {
                    ArcDataSize += imgInfo.uncSize;
                }
                imgInfo.imgSize = new ImageSize(dataStream.ReadValueU32(), dataStream.ReadValueU32());  // FG: 6th & 7th [or nth and (nth + 1) if local] int32 are width x height
                privateimgList.Add(imgInfo);                                                                   // FG: A salty's favorite, add the struct to a list<struct>
                count--;
            }


            // save what remains
            int remainingBytes = (int)(dataStream.Length - dataStream.Position);
            footerData = new byte[remainingBytes];
            dataStream.Read(footerData, 0, footerData.Length);


            dataStream.Dispose();
        }
        private static void Main(string[] args)
        {
            bool showHelp = false;
            bool overwriteFiles = false;
            bool verbose = false;

            var options = new OptionSet()
            {
                {
                    "o|overwrite",
                    "overwrite existing files",
                    v => overwriteFiles = v != null
                    },
                {
                    "v|verbose",
                    "be verbose",
                    v => verbose = v != null
                    },
                {
                    "h|help",
                    "show this message and exit",
                    v => showHelp = v != null
                    },
            };

            List<string> extras;

            try
            {
                extras = options.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", GetExecutableName());
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName());
                return;
            }

            if (extras.Count < 1 || extras.Count > 2 || showHelp == true)
            {
                Console.WriteLine("Usage: {0} [OPTIONS]+ input_tms [output_dir]", GetExecutableName());
                Console.WriteLine();
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }

            string inputPath = extras[0];
            string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, null) + "_unpack";

            var endian = Endian.Little;

            using (var input = File.OpenRead(inputPath))
            {
                var uncompressedSize3 = input.ReadValueU32(endian);
                var fileCount = input.ReadValueU32(endian);
                var magic = input.ReadValueU32(endian);
                var version = input.ReadValueU32(endian);

                if (magic != 0x9E2A83C1 ||
                    version != 0x00020000)
                {
                    throw new FormatException();
                }

                var compressedSize1 = input.ReadValueU32(endian);
                var uncompressedSize1 = input.ReadValueU32(endian);
                var compressedSize2 = input.ReadValueU32(endian);
                var uncompressedSize2 = input.ReadValueU32(endian);

                if (compressedSize1 != compressedSize2 ||
                    uncompressedSize1 != uncompressedSize2 ||
                    uncompressedSize1 != uncompressedSize3)
                {
                    throw new FormatException();
                }

                var compressedBytes = input.ReadBytes(compressedSize1);
                var uncompressedBytes = new byte[uncompressedSize1];

                var actualUncompressedSize = (int)uncompressedSize1;
                var result = LZO.Decompress(compressedBytes,
                                            0,
                                            (int)compressedSize1,
                                            uncompressedBytes,
                                            0,
                                            ref actualUncompressedSize);
                if (result != LZO.ErrorCode.Success)
                {
                    throw new FormatException();
                }

                if (actualUncompressedSize != uncompressedSize1)
                {
                    throw new FormatException();
                }

                using (var data = new MemoryStream(uncompressedBytes))
                {
                    for (uint i = 0; i < fileCount; i++)
                    {
                        var entryNameLength = data.ReadValueS32(endian);
                        if (entryNameLength < 0)
                        {
                            throw new NotImplementedException();
                        }

                        var entryName = data.ReadString(entryNameLength, true, Encoding.ASCII);
                        var entryTextLength = data.ReadValueS32(endian);

                        Encoding entryTextEncoding;
                        if (entryTextLength >= 0)
                        {
                            entryTextEncoding = Encoding.ASCII;
                        }
                        else
                        {
                            entryTextEncoding = Encoding.Unicode;
                            entryTextLength = (-entryTextLength) * 2;
                        }
                        var entryText = data.ReadString(entryTextLength, true, entryTextEncoding);

                        var entryPath = Path.Combine(outputPath, entryName);
                        if (overwriteFiles == false &&
                            File.Exists(entryPath) == true)
                        {
                            continue;
                        }

                        if (verbose == true)
                        {
                            Console.WriteLine(entryName);
                        }

                        var entryParentPath = Path.GetDirectoryName(entryPath);
                        if (string.IsNullOrEmpty(entryParentPath) == false)
                        {
                            Directory.CreateDirectory(entryParentPath);
                        }

                        using (var output = new StreamWriter(entryPath, false, entryTextEncoding))
                        {
                            output.Write(entryText);
                        }
                    }
                }
            }
        }