public Resource Read() { using (this.reader = new BinaryReader(stream)) { LSBHeader header; header.signature = reader.ReadUInt32(); if (header.signature != LSBHeader.Signature) throw new InvalidFormatException(String.Format("Illegal signature in header; expected {0}, got {1}", LSBHeader.Signature, header.signature)); header.totalSize = reader.ReadUInt32(); if (stream.Length != header.totalSize) throw new InvalidFormatException(String.Format("Invalid LSB file size; expected {0}, got {1}", header.totalSize, stream.Length)); header.bigEndian = reader.ReadUInt32(); // The game only uses little-endian files on all platforms currently and big-endian support isn't worth the hassle if (header.bigEndian != 0) throw new InvalidFormatException("Big-endian LSB files are not supported"); header.unknown = reader.ReadUInt32(); header.metadata.timestamp = reader.ReadUInt64(); header.metadata.majorVersion = reader.ReadUInt32(); header.metadata.minorVersion = reader.ReadUInt32(); header.metadata.revision = reader.ReadUInt32(); header.metadata.buildNumber = reader.ReadUInt32(); ReadStaticStrings(); Resource rsrc = new Resource(); rsrc.Metadata = header.metadata; ReadRegions(rsrc); return rsrc; } }
public void Write(Resource rsrc) { using (this.writer = new BinaryWriter(stream)) { writer.Write(LSBHeader.Signature); var sizeOffset = stream.Position; writer.Write((UInt32)0); // Total size of file, will be updater after we finished serializing writer.Write((UInt32)0); // Little-endian format writer.Write((UInt32)0); // Unknown writer.Write(rsrc.Metadata.timestamp); writer.Write(rsrc.Metadata.majorVersion); writer.Write(rsrc.Metadata.minorVersion); writer.Write(rsrc.Metadata.revision); writer.Write(rsrc.Metadata.buildNumber); CollectStaticStrings(rsrc); WriteStaticStrings(); WriteRegions(rsrc); UInt32 fileSize = (UInt32)stream.Position; stream.Seek(sizeOffset, SeekOrigin.Begin); writer.Write(fileSize); } }
private void WriteRegions(Resource rsrc) { writer.Write((UInt32)rsrc.Regions.Count); var regionMapOffset = stream.Position; foreach (var rgn in rsrc.Regions) { writer.Write(staticStrings[rgn.Key]); writer.Write((UInt32)0); // Offset of region, will be updater after we finished serializing } List<UInt32> regionPositions = new List<UInt32>(); foreach (var rgn in rsrc.Regions) { regionPositions.Add((UInt32)stream.Position); WriteNode(rgn.Value); } var endOffset = stream.Position; stream.Seek(regionMapOffset, SeekOrigin.Begin); foreach (var position in regionPositions) { stream.Seek(4, SeekOrigin.Current); writer.Write(position); } stream.Seek(endOffset, SeekOrigin.Begin); }
public void Write(Resource rsrc) { var settings = new XmlWriterSettings(); settings.Indent = PrettyPrint; settings.IndentChars = "\t"; using (this.writer = XmlWriter.Create(stream, settings)) { writer.WriteStartElement("save"); writer.WriteStartElement("header"); writer.WriteAttributeString("version", LSXReader.CurrentVersion); writer.WriteAttributeString("time", rsrc.Metadata.timestamp.ToString()); writer.WriteEndElement(); writer.WriteStartElement("version"); writer.WriteAttributeString("major", rsrc.Metadata.majorVersion.ToString()); writer.WriteAttributeString("minor", rsrc.Metadata.minorVersion.ToString()); writer.WriteAttributeString("revision", rsrc.Metadata.revision.ToString()); writer.WriteAttributeString("build", rsrc.Metadata.buildNumber.ToString()); writer.WriteEndElement(); WriteRegions(rsrc); writer.WriteEndElement(); writer.Flush(); } }
private void WriteRegions(Resource rsrc) { foreach (var region in rsrc.Regions) { writer.WriteStartElement("region"); writer.WriteAttributeString("id", region.Key); WriteNode(region.Value); writer.WriteEndElement(); } }
private void ReadRegions(Resource rsrc) { UInt32 regions = reader.ReadUInt32(); for (UInt32 i = 0; i < regions; i++) { UInt32 regionNameId = reader.ReadUInt32(); UInt32 regionOffset = reader.ReadUInt32(); Region rgn = new Region(); rgn.RegionName = staticStrings[regionNameId]; var lastRegionPos = stream.Position; stream.Seek(regionOffset, SeekOrigin.Begin); ReadNode(rgn); rsrc.Regions[rgn.RegionName] = rgn; stream.Seek(lastRegionPos, SeekOrigin.Begin); } }
public Resource Read() { using (this.reader = XmlReader.Create(stream)) { Resource rsrc = new Resource(); Region currentRegion = null; List <Node> stack = new List <Node>(); while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { switch (reader.Name) { case "save": // Root element if (stack.Count() > 0) { throw new InvalidFormatException("Node <save> was unexpected."); } break; case "header": // LSX metadata part 1 string version = reader["version"]; if (version != InitialVersion && version != CurrentVersion) { throw new InvalidFormatException(String.Format("Unsupported LSX version; expected {0}, found {1}", CurrentVersion, version)); } rsrc.Metadata.timestamp = Convert.ToUInt64(reader["time"]); break; case "version": // LSX metadata part 2 rsrc.Metadata.majorVersion = Convert.ToUInt32(reader["major"]); rsrc.Metadata.minorVersion = Convert.ToUInt32(reader["minor"]); rsrc.Metadata.revision = Convert.ToUInt32(reader["revision"]); rsrc.Metadata.buildNumber = Convert.ToUInt32(reader["build"]); break; case "region": if (currentRegion != null) { throw new InvalidFormatException("A <region> can only start at the root level of a resource."); } Debug.Assert(!reader.IsEmptyElement); var region = new Region(); region.RegionName = reader["id"]; Debug.Assert(region.RegionName != null); rsrc.Regions.Add(region.RegionName, region); currentRegion = region; break; case "node": if (currentRegion == null) { throw new InvalidFormatException("A <node> must be located inside a region."); } Node node; if (stack.Count() == 0) { // The node is the root node of the region node = currentRegion; } else { // New node under the current parent node = new Node(); node.Parent = stack.Last(); } node.Name = reader["id"]; Debug.Assert(node.Name != null); if (node.Parent != null) { node.Parent.AppendChild(node); } if (!reader.IsEmptyElement) { stack.Add(node); } break; case "attribute": var attrTypeId = Convert.ToUInt32(reader["type"]); var attrName = reader["id"]; var attrValue = reader["value"]; if (attrTypeId > (int)NodeAttribute.DataType.DT_Max) { throw new InvalidFormatException(String.Format("Unsupported attribute data type: {0}", attrTypeId)); } Debug.Assert(attrName != null); Debug.Assert(attrValue != null); var attr = new NodeAttribute((NodeAttribute.DataType)attrTypeId); attr.FromString(attrValue); if (attr.Type == NodeAttribute.DataType.DT_TranslatedString) { var ts = ((TranslatedString)attr.Value); ts.Handle = reader["handle"]; Debug.Assert(ts.Handle != null); } else if (attr.Type == NodeAttribute.DataType.DT_TranslatedFSString) { var fs = ((TranslatedFSString)attr.Value); ReadTranslatedFSString(fs); } stack.Last().Attributes.Add(attrName, attr); break; case "children": // Child nodes are handled in the "node" case break; default: throw new InvalidFormatException(String.Format("Unknown element encountered: {0}", reader.Name)); } } else if (reader.NodeType == XmlNodeType.EndElement) { switch (reader.Name) { case "save": case "header": case "version": case "attribute": case "children": // These elements don't change the stack, just discard them break; case "region": Debug.Assert(stack.Count == 0); Debug.Assert(currentRegion != null); Debug.Assert(currentRegion.Name != null); currentRegion = null; break; case "node": stack.RemoveAt(stack.Count - 1); break; default: throw new InvalidFormatException(String.Format("Unknown element encountered: {0}", reader.Name)); } } } return(rsrc); } }
public Resource Read() { using (var reader = new BinaryReader(Stream)) { var hdr = BinUtils.ReadStruct <Header>(reader); if (hdr.Magic != BitConverter.ToUInt32(Header.Signature, 0)) { var msg = String.Format( "Invalid LSF signature; expected {0,8:X}, got {1,8:X}", BitConverter.ToUInt32(Header.Signature, 0), hdr.Magic ); throw new InvalidDataException(msg); } if (hdr.Version < (ulong)FileVersion.VerInitial || hdr.Version > (ulong)FileVersion.CurrentVersion) { var msg = String.Format("LSF version {0} is not supported", hdr.Version); throw new InvalidDataException(msg); } Names = new List <List <String> >(); bool isCompressed = BinUtils.CompressionFlagsToMethod(hdr.CompressionFlags) != CompressionMethod.None; if (hdr.StringsSizeOnDisk > 0 || hdr.StringsUncompressedSize > 0) { uint onDiskSize = isCompressed ? hdr.StringsSizeOnDisk : hdr.StringsUncompressedSize; byte[] compressed = reader.ReadBytes((int)onDiskSize); byte[] uncompressed; if (isCompressed) { uncompressed = BinUtils.Decompress(compressed, (int)hdr.StringsUncompressedSize, hdr.CompressionFlags); } else { uncompressed = compressed; } #if DUMP_LSF_SERIALIZATION using (var nodesFile = new FileStream("names.bin", FileMode.Create, FileAccess.Write)) { nodesFile.Write(uncompressed, 0, uncompressed.Length); } #endif using (var namesStream = new MemoryStream(uncompressed)) { ReadNames(namesStream); } } Nodes = new List <NodeInfo>(); if (hdr.NodesSizeOnDisk > 0 || hdr.NodesUncompressedSize > 0) { uint onDiskSize = isCompressed ? hdr.NodesSizeOnDisk : hdr.NodesUncompressedSize; var uncompressed = Decompress(reader, onDiskSize, hdr.NodesUncompressedSize, hdr); #if DUMP_LSF_SERIALIZATION using (var nodesFile = new FileStream("nodes.bin", FileMode.Create, FileAccess.Write)) { nodesFile.Write(uncompressed, 0, uncompressed.Length); } #endif using (var nodesStream = new MemoryStream(uncompressed)) { var longNodes = hdr.Version >= (ulong)FileVersion.VerExtendedNodes && hdr.Extended == 1; ReadNodes(nodesStream, longNodes); } } Attributes = new List <AttributeInfo>(); if (hdr.AttributesSizeOnDisk > 0 || hdr.AttributesUncompressedSize > 0) { uint onDiskSize = isCompressed ? hdr.AttributesSizeOnDisk : hdr.AttributesUncompressedSize; var uncompressed = Decompress(reader, onDiskSize, hdr.AttributesUncompressedSize, hdr); #if DUMP_LSF_SERIALIZATION using (var attributesFile = new FileStream("attributes.bin", FileMode.Create, FileAccess.Write)) { attributesFile.Write(uncompressed, 0, uncompressed.Length); } #endif using (var attributesStream = new MemoryStream(uncompressed)) { var longAttributes = hdr.Version >= (ulong)FileVersion.VerExtendedNodes && hdr.Extended == 1; if (longAttributes) { ReadAttributesV3(attributesStream); } else { ReadAttributesV2(attributesStream); } } } if (hdr.ValuesSizeOnDisk > 0 || hdr.ValuesUncompressedSize > 0) { uint onDiskSize = isCompressed ? hdr.ValuesSizeOnDisk : hdr.ValuesUncompressedSize; var uncompressed = Decompress(reader, onDiskSize, hdr.ValuesUncompressedSize, hdr); var valueStream = new MemoryStream(uncompressed); this.Values = valueStream; #if DUMP_LSF_SERIALIZATION using (var valuesFile = new FileStream("values.bin", FileMode.Create, FileAccess.Write)) { valuesFile.Write(uncompressed, 0, uncompressed.Length); } #endif } else { this.Values = new MemoryStream(); } Resource resource = new Resource(); ReadRegions(resource); resource.Metadata.majorVersion = (hdr.EngineVersion & 0xff000000) >> 24; resource.Metadata.minorVersion = (hdr.EngineVersion & 0xff0000) >> 16; resource.Metadata.revision = (hdr.EngineVersion & 0xff00) >> 8; resource.Metadata.buildNumber = (hdr.EngineVersion & 0xff); return(resource); } }
private void CollectStaticStrings(Resource rsrc) { staticStrings.Clear(); foreach (var rgn in rsrc.Regions) { AddStaticString(rgn.Key); CollectStaticStrings(rgn.Value); } }
private void resourceConvertBtn_Click(object sender, EventArgs e) { try { Resource = ResourceUtils.LoadResource(resourceInputPath.Text); var format = ResourceUtils.ExtensionToResourceFormat(resourceOutputPath.Text); int outputVersion = -1; if (GetGame() == DivGame.DOS2) { outputVersion = (int)FileVersion.VerExtendedNodes; } else { outputVersion = (int)FileVersion.VerChunkedCompress; } ResourceUtils.SaveResource(Resource, resourceOutputPath.Text, format, outputVersion); MessageBox.Show("Resource saved successfully."); } catch (Exception exc) { MessageBox.Show("Internal error!\r\n\r\n" + exc.ToString(), "Conversion Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
public Resource Read() { using (this.reader = XmlReader.Create(stream)) { Resource rsrc = new Resource(); Region currentRegion = null; List<Node> stack = new List<Node>(); while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { switch (reader.Name) { case "save": // Root element if (stack.Count() > 0) throw new InvalidFormatException("Node <save> was unexpected."); break; case "header": // LSX metadata part 1 string version = reader["version"]; if (version != InitialVersion && version != CurrentVersion) throw new InvalidFormatException(String.Format("Unsupported LSX version; expected {0}, found {1}", CurrentVersion, version)); rsrc.Metadata.timestamp = Convert.ToUInt64(reader["timestamp"]); break; case "version": // LSX metadata part 2 rsrc.Metadata.majorVersion = Convert.ToUInt32(reader["major"]); rsrc.Metadata.minorVersion = Convert.ToUInt32(reader["minor"]); rsrc.Metadata.revision = Convert.ToUInt32(reader["revision"]); rsrc.Metadata.buildNumber = Convert.ToUInt32(reader["build"]); break; case "region": if (currentRegion != null) throw new InvalidFormatException("A <region> can only start at the root level of a resource."); Debug.Assert(!reader.IsEmptyElement); var region = new Region(); region.RegionName = reader["id"]; Debug.Assert(region.RegionName != null); rsrc.Regions.Add(region.RegionName, region); currentRegion = region; break; case "node": if (currentRegion == null) throw new InvalidFormatException("A <node> must be located inside a region."); Node node; if (stack.Count() == 0) { // The node is the root node of the region node = currentRegion; } else { // New node under the current parent node = new Node(); node.Parent = stack.Last(); } node.Name = reader["id"]; Debug.Assert(node.Name != null); if (node.Parent != null) node.Parent.AppendChild(node); if (!reader.IsEmptyElement) stack.Add(node); break; case "attribute": var attrTypeId = Convert.ToUInt32(reader["type"]); var attrName = reader["id"]; var attrValue = reader["value"]; if (attrTypeId > (int)NodeAttribute.DataType.DT_Max) throw new InvalidFormatException(String.Format("Unsupported attribute data type: {0}", attrTypeId)); Debug.Assert(attrName != null); Debug.Assert(attrValue != null); var attr = new NodeAttribute((NodeAttribute.DataType)attrTypeId); attr.FromString(attrValue); if (attr.Type == NodeAttribute.DataType.DT_TranslatedString) { ((TranslatedString)attr.Value).Handle = reader["handle"]; Debug.Assert(((TranslatedString)attr.Value).Handle != null); } stack.Last().Attributes.Add(attrName, attr); break; case "children": // Child nodes are handled in the "node" case break; default: throw new InvalidFormatException(String.Format("Unknown element encountered: {0}", reader.Name)); } } else if (reader.NodeType == XmlNodeType.EndElement) { switch (reader.Name) { case "save": case "header": case "version": case "attribute": case "children": // These elements don't change the stack, just discard them break; case "region": Debug.Assert(stack.Count == 0); Debug.Assert(currentRegion != null); Debug.Assert(currentRegion.Name != null); currentRegion = null; break; case "node": stack.RemoveAt(stack.Count - 1); break; default: throw new InvalidFormatException(String.Format("Unknown element encountered: {0}", reader.Name)); } } } return rsrc; } }