Example #1
0
        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;
		}