public void Serialize(Stream output) { if (this.Version == 1) { throw new NotSupportedException(); } else if (this.Version == 2) { throw new NotSupportedException(); } else if (this.Version == 3) { output.WriteString("ERF V3.0", Encoding.Unicode); var strings = new List<string>(); foreach (var entry in this.Entries) { if (entry.Name != null && strings.Contains(entry.Name) == false) { strings.Add(entry.Name); } } strings.Sort(); var stringOffsets = new Dictionary<string, uint>(); var stringTable = new MemoryStream(); foreach (var str in strings) { stringOffsets[str] = (uint)stringTable.Length; stringTable.WriteStringZ(str, Encoding.UTF8); } stringTable.SetLength(stringTable.Length.Align(16)); stringTable.Position = 0; output.WriteValueU32((uint)stringTable.Length); output.WriteValueS32(this.Entries.Count); if (this.Encryption != EncryptionScheme.None || this.Compression != CompressionScheme.None) { throw new NotSupportedException(); } uint flags = 0; flags |= ((uint)this.Encryption) << 4; flags |= ((uint)this.Compression) << 29; output.WriteValueU32(flags); output.WriteValueU32(this.ContentId); if (this.PasswordDigest == null) { output.Write(new byte[16], 0, 16); } else { output.Write(this.PasswordDigest, 0, 16); } output.WriteFromStream(stringTable, stringTable.Length, 0x00100000); foreach (var entry in this.Entries) { if (entry.Name != null) { entry.CalculateHashes(); output.WriteValueU32(stringOffsets[entry.Name]); } else { output.WriteValueU32(0xFFFFFFFF); } output.WriteValueU64(entry.NameHash); output.WriteValueU32(entry.TypeHash); output.WriteValueU32((uint)entry.Offset); output.WriteValueU32(entry.CompressedSize); output.WriteValueU32(entry.UncompressedSize); } } else { throw new InvalidOperationException(); } }
public string saveToFile(bool fileOverwrite = true) { bChanged = false; string finalTocFile = fileOverwrite ? tocFilePath : tocFilePath + ".tmp"; using (FileStream newFileStream = File.Create(finalTocFile)) { newFileStream.WriteValueU32(0x3AB70C13); newFileStream.WriteValueS32(0x0); newFileStream.WriteValueS32(chunkList.Count); int chunkOffset = 12; int fileOffset = 12 + (chunkList.Count * 8); string lastFile = chunkList.Last(x => (x.fileList != null) && x.fileList.Count(/*y => y.exist*/) != 0).fileList.Last(/*z => z.exist*/).filePath; //foreach (chunk element in chunkList) for(int i = 0; i < chunkList.Count; i++) { chunk element = chunkList[i]; newFileStream.Seek(chunkOffset, SeekOrigin.Begin); if (element.countNextFiles == 0)// || element.fileList.Count(x => x.exist) == 0) { newFileStream.WriteValueS64(0x0); chunkOffset = (int)newFileStream.Position; } else { newFileStream.WriteValueS32(fileOffset - chunkOffset); newFileStream.WriteValueS32(element.fileList.Count/*(x => x.exist)*/); chunkOffset = (int)newFileStream.Position; newFileStream.Seek(fileOffset, SeekOrigin.Begin); //foreach (fileStruct fileElement in element.fileList.Where(x => x.exist)) for(int j = 0; j < element.fileList.Count; j++) { fileStruct fileElement = element.fileList[j]; //if (!fileElement.exist) // continue; MemoryStream buffer = new MemoryStream(fileElement.blockSize); { if (fileElement.filePath == lastFile) buffer.WriteValueS16(0x0); else buffer.WriteValueS16(fileElement.blockSize); buffer.WriteValueS16(fileElement.flag); buffer.WriteValueS32(fileElement.fileSize); buffer.WriteBytes(fileElement.sha1); buffer.WriteStringZ(fileElement.filePath); byte[] byteBuff = new byte[fileElement.blockSize]; buffer.ToArray().CopyTo(byteBuff, 0); newFileStream.WriteBytes(byteBuff); } //newFileStream.Seek(fileOffset, SeekOrigin.Begin); } fileOffset = (int)newFileStream.Position; } } } return finalTocFile; }
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; }