private Property.Node DeserializeNode(MemoryStream input) { var node = new Property.Node(); var endian = this.Endian; while (true) { var id = input.ReadValueU32(endian); var type = input.ReadValueEnum <SectionType>(endian); var dataOffset = input.ReadValueS32(endian); var nextOffset = input.ReadValueS32(endian); switch (type) { case SectionType.Node: { // why? WHY? :( if (dataOffset != -1) { input.Seek(dataOffset, SeekOrigin.Begin); dataOffset = input.ReadValueS32(endian); } if (dataOffset == -1) { node.Nodes.Add(id, new Property.Node()); } else { input.Seek(dataOffset, SeekOrigin.Begin); node.Nodes.Add(id, this.DeserializeNode(input)); } break; } case SectionType.Variant: { if (dataOffset == -1) { node.Variants.Add(id, null); } else { input.Seek(dataOffset, SeekOrigin.Begin); node.Variants.Add(id, this.DeserializeVariant(input)); } break; } default: { throw new FormatException("unknown object section type " + type.ToString()); } } if (nextOffset == -1) { break; } input.Seek(nextOffset, SeekOrigin.Begin); } return(node); }
private Property.Node DeserializeNode(Stream input) { var node = new Property.Node(); var endian = this.Endian; var sectionsHandled = new List <SectionType>(); var sectionCount = input.ReadValueU8(); for (byte i = 0; i < sectionCount; i++) { var sectionType = (SectionType)input.ReadValueU16(endian); var elementCount = input.ReadValueU16(endian); if (sectionsHandled.Contains(sectionType) == true) { throw new FormatException(); } sectionsHandled.Add(sectionType); switch (sectionType) { case SectionType.Node: { for (ushort j = 0; j < elementCount; j++) { var length = input.ReadValueU32(endian); if (length >= 0x7FFF) { throw new FormatException(); } var name = input.ReadString(length, true, Encoding.ASCII); var id = name.HashJenkins(); if (node.KnownNames.ContainsKey(id) == false) { node.KnownNames.Add(id, name); } else if (node.KnownNames[id] != name) { throw new FormatException(); } node.Nodes.Add(id, this.DeserializeNode(input)); } break; } case SectionType.Variant: { for (ushort j = 0; j < elementCount; j++) { var length = input.ReadValueU32(endian); if (length >= 0x7FFF) { throw new FormatException(); } var name = input.ReadString(length, true, Encoding.ASCII); var id = name.HashJenkins(); if (node.KnownNames.ContainsKey(id) == false) { node.KnownNames.Add(id, name); } else if (node.KnownNames[id] != name) { throw new FormatException(); } node.Variants.Add(id, this.DeserializeVariant(input)); } break; } case SectionType.Tag: { node.Tag = input.ReadString(elementCount, Encoding.ASCII); break; } case SectionType.NodeByHash: { for (ushort j = 0; j < elementCount; j++) { var id = input.ReadValueU32(endian); node.Nodes.Add(id, this.DeserializeNode(input)); } break; } case SectionType.VariantByHash: { for (ushort j = 0; j < elementCount; j++) { var id = input.ReadValueU32(endian); node.Variants.Add(id, this.DeserializeVariant(input)); } break; } default: { throw new FormatException("unknown object section type " + sectionType.ToString()); } } } return(node); }
private void SerializeNode(MemoryStream output, Property.Node node) { var endian = this.Endian; if (node.Tag != null) { throw new InvalidOperationException("node tags not supported"); } var nodes = new List <KeyValuePair <long, Property.Node> >(); foreach (var kv in node.Nodes) { var baseOffset = output.Position; output.WriteValueU32(kv.Key, endian); output.WriteValueEnum <SectionType>(SectionType.Node, endian); output.WriteValueS32(-1, endian); output.WriteValueU32((uint)(baseOffset + 16), endian); nodes.Add(new KeyValuePair <long, Property.Node>(baseOffset + 8, kv.Value)); } var variants = new List <KeyValuePair <long, Property.IVariant> >(); foreach (var kv in node.Variants) { var baseOffset = output.Position; output.WriteValueU32(kv.Key, endian); output.WriteValueEnum <SectionType>(SectionType.Variant, endian); output.WriteValueS32(-1, endian); output.WriteValueU32((uint)(baseOffset + 16), endian); variants.Add(new KeyValuePair <long, Property.IVariant>(baseOffset + 8, kv.Value)); } output.Seek(-4, SeekOrigin.Current); output.WriteValueS32(-1, endian); var dataNodes = new List <KeyValuePair <long, Property.Node> >(); foreach (var kv in nodes) { if (kv.Value.Nodes.Count == 0 && kv.Value.Variants.Count == 0) { continue; } var baseOffset = output.Position; dataNodes.Add(new KeyValuePair <long, Property.Node>(output.Position, kv.Value)); output.Seek(4, SeekOrigin.Current); var nextOffset = output.Position; output.Position = kv.Key; output.WriteValueU32((uint)baseOffset, endian); output.Position = nextOffset; } //output.Position = output.Position.Align(16); foreach (var kv in variants) { if (kv.Value != null) { var baseOffset = output.Position; this.SerializeVariant(output, kv.Value); var nextOffset = output.Position; output.Position = kv.Key; output.WriteValueU32((uint)baseOffset, endian); output.Position = nextOffset.Align(4); //output.Position = nextOffset.Align(16); } } foreach (var kv in dataNodes) { var baseOffset = output.Position; this.SerializeNode(output, kv.Value); var nextOffset = output.Position; output.Position = kv.Key; output.WriteValueU32((uint)baseOffset, endian); output.Position = nextOffset; } }
private void SerializeNode(Stream output, Property.Node node) { var endian = this.Endian; byte count = 0; var nodesByName = node.Nodes .Where(kv => node.KnownNames.ContainsKey(kv.Key) == true) .ToArray(); var variantsByName = node.Variants .Where(kv => node.KnownNames.ContainsKey(kv.Key) == true) .ToArray(); var nodesByHash = node.Nodes .Where(kv => node.KnownNames.ContainsKey(kv.Key) == false) .ToArray(); var variantsByHash = node.Variants .Where(kv => node.KnownNames.ContainsKey(kv.Key) == false) .ToArray(); if (nodesByName.Length > 0) { count++; } if (variantsByName.Length > 0) { count++; } if (nodesByHash.Length > 0) { count++; } if (variantsByHash.Length > 0) { count++; } if (node.Tag != null) { count++; } output.WriteValueU8(count); if (nodesByName.Length > 0) { if (nodesByName.Length > 0xFFFF) { throw new InvalidOperationException(); } output.WriteValueU16((ushort)SectionType.Node, endian); output.WriteValueU16((ushort)nodesByName.Length, endian); foreach (var kv in nodesByName) { var name = node.KnownNames[kv.Key]; output.WriteValueS32(name.Length, endian); output.WriteString(name, Encoding.ASCII); this.SerializeNode(output, kv.Value); } } if (variantsByName.Length > 0) { if (variantsByName.Length > 0xFFFF) { throw new InvalidOperationException(); } output.WriteValueU16((ushort)SectionType.Variant, endian); output.WriteValueU16((ushort)variantsByName.Length, endian); foreach (var kv in variantsByName) { var name = node.KnownNames[kv.Key]; output.WriteValueS32(name.Length, endian); output.WriteString(name, Encoding.ASCII); this.SerializeVariant(output, kv.Value); } } if (node.Tag != null) { var bytes = Encoding.ASCII.GetBytes(node.Tag); if (bytes.Length > 0xFFFF) { throw new InvalidOperationException(); } output.WriteValueU16(3, endian); output.WriteValueU16((ushort)bytes.Length, endian); output.WriteBytes(bytes); } if (nodesByHash.Length > 0) { if (nodesByHash.Length > 0xFFFF) { throw new InvalidOperationException(); } output.WriteValueU16((ushort)SectionType.NodeByHash, endian); output.WriteValueU16((ushort)nodesByHash.Length, endian); foreach (var kv in nodesByHash) { output.WriteValueU32(kv.Key, endian); this.SerializeNode(output, kv.Value); } } if (variantsByHash.Length > 0) { if (variantsByHash.Length > 0xFFFF) { throw new InvalidOperationException(); } output.WriteValueU16((ushort)SectionType.VariantByHash, endian); output.WriteValueU16((ushort)variantsByHash.Length, endian); foreach (var kv in variantsByHash) { output.WriteValueU32(kv.Key, endian); this.SerializeVariant(output, kv.Value); } } }