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); } }
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); } }
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; } }
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(); }
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);*/ }
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); }
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(); }
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)); } }
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; } }
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); } }
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); } } } } }