public static void ConvertToBin(string source, string destination) { var inputPath = Path.IsPathRooted(source) ? source : Path.Combine(GetExePath(), source); var outputPath = !destination.IsNullOrWhiteSpace() ? destination : Path.ChangeExtension(inputPath, ".bin"); if (!Path.IsPathRooted(outputPath)) { outputPath = Path.Combine(GetExePath(), outputPath); } if (!File.Exists(inputPath)) { return; } var file = XmlCoalesceFile.Load(inputPath); var coal = new CoalescedFileXml { ByteOrder = ByteOrder.LittleEndian, Version = 1 }; foreach (var asset in file.Assets) { var entry = new FileEntry(asset.Source) { Sections = new Dictionary<string, Dictionary<string, List<PropertyValue>>>() }; foreach (var section in asset.Sections) { var eSection = new Dictionary<string, List<PropertyValue>>(); foreach (var property in section.Value) { var eProperty = new List<PropertyValue>(); foreach (var value in property.Value) { if (!file.Settings.CompileTypes.Contains(value.ValueType)) { continue; } var valueValue = value.Value; if (!valueValue.IsNullOrWhiteSpace()) { valueValue = SpecialCharacters.Aggregate(valueValue, (current, c) => current.Replace(c.Value, c.Key)); } eProperty.Add(new PropertyValue(value.ValueType, valueValue)); } eSection.Add(property.Key, eProperty); } entry.Sections.Add(section.Key, eSection); } coal.Files.Add(entry); } using (var output = File.Create(outputPath)) { if (file.Settings != null) { coal.OverrideCompileValueTypes = file.Settings.OverrideCompileValueTypes; coal.CompileTypes = file.Settings.CompileTypes; } coal.Serialize(output); } }
public void Deserialize(Stream input) { var magic = input.ReadUInt32(); if (magic != 0x666D726D && magic.Swap() != 0x666D726D) { throw new FormatException(); } var endian = magic == 0x666D726D ? ByteOrder.LittleEndian : ByteOrder.BigEndian; var version = input.ReadUInt32(endian); if (version != 1) { throw new FormatException(); } Version = version; input.ReadInt32(endian); var maxValueLength = input.ReadInt32(endian); var stringTableSize = input.ReadUInt32(endian); var huffmanSize = input.ReadUInt32(endian); var indexSize = input.ReadUInt32(endian); var dataSize = input.ReadUInt32(endian); var strings = new List<KeyValuePair<uint, string>>(); using (var data = input.ReadToMemoryStream(stringTableSize)) { var localStringTableSize = data.ReadUInt32(endian); if (localStringTableSize != stringTableSize) { throw new FormatException(); } var count = data.ReadUInt32(endian); var offsets = new List<KeyValuePair<uint, uint>>(); for (uint i = 0; i < count; i++) { var hash = data.ReadUInt32(endian); var offset = data.ReadUInt32(endian); offsets.Add(new KeyValuePair<uint, uint>(hash, offset)); } foreach (var kv in offsets) { var hash = kv.Key; var offset = kv.Value; data.Seek(8 + offset, SeekOrigin.Begin); var length = data.ReadUInt16(endian); var text = data.ReadString(length, Encoding.UTF8); if (text.HashCrc32() != hash) { throw new InvalidOperationException(); } strings.Add(new KeyValuePair<uint, string>(hash, text)); } } Pair[] huffmanTree; using (var data = input.ReadToMemoryStream(huffmanSize)) { var count = data.ReadUInt16(endian); huffmanTree = new Pair[count]; for (ushort i = 0; i < count; i++) { var left = data.ReadInt32(endian); var right = data.ReadInt32(endian); huffmanTree[i] = new Pair(left, right); } } using (var index = input.ReadToMemoryStream(indexSize)) { var totalBits = input.ReadInt32(endian); var data = input.ReadBytes(dataSize); var bitArray = new BitArray(data) { Length = totalBits }; var files = new List<KeyValuePair<string, uint>>(); var fileCount = index.ReadUInt16(endian); for (ushort i = 0; i < fileCount; i++) { var nameIndex = index.ReadUInt16(endian); var name = strings[nameIndex].Value; var offset = index.ReadUInt32(endian); files.Add(new KeyValuePair<string, uint>(name, offset)); } foreach (var fileInfo in files.OrderBy(f => f.Key)) { var file = new FileEntry { Name = fileInfo.Key }; index.Seek(fileInfo.Value, SeekOrigin.Begin); var sectionCount = index.ReadUInt16(endian); var sections = new List<KeyValuePair<string, uint>>(); for (ushort i = 0; i < sectionCount; i++) { var nameIndex = index.ReadUInt16(endian); var name = strings[nameIndex].Value; var offset = index.ReadUInt32(endian); sections.Add(new KeyValuePair<string, uint>(name, offset)); } foreach (var sectionInfo in sections.OrderBy(s => s.Key)) { var section = new Dictionary<string, List<PropertyValue>>(); index.Seek(fileInfo.Value + sectionInfo.Value, SeekOrigin.Begin); var valueCount = index.ReadUInt16(endian); var values = new List<KeyValuePair<string, uint>>(); for (ushort i = 0; i < valueCount; i++) { var nameIndex = index.ReadUInt16(endian); var name = strings[nameIndex].Value; var offset = index.ReadUInt32(endian); values.Add(new KeyValuePair<string, uint>(name, offset)); } foreach (var valueInfo in values.OrderBy(v => v.Key)) { var value = new List<PropertyValue>(); index.Seek(fileInfo.Value + sectionInfo.Value + valueInfo.Value, SeekOrigin.Begin); var itemCount = index.ReadUInt16(endian); for (ushort i = 0; i < itemCount; i++) { var offset = index.ReadInt32(endian); var type = (offset & 0xE0000000) >> 29; switch (type) { case 1: { value.Add(new PropertyValue(1, null)); break; } case 0: case 2: case 3: case 4: { offset &= 0x1fffffff; var text = Decoder.Decode(huffmanTree, bitArray, offset, maxValueLength); value.Add(new PropertyValue((int) type, text)); break; } default: { throw new NotImplementedException(); } } } section.Add(valueInfo.Key, value); } file.Sections.Add(sectionInfo.Key, section); } Files.Add(file); } } ByteOrder = endian; }