mirror of
https://github.com/dcronqvist/DotTiled.git
synced 2025-02-05 17:02:49 +02:00
Add agnostic readers
This commit is contained in:
parent
8f9fa3a315
commit
aa8b390442
5 changed files with 328 additions and 0 deletions
50
src/DotTiled.Tests/Serialization/MapReaderTests.cs
Normal file
50
src/DotTiled.Tests/Serialization/MapReaderTests.cs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
using DotTiled.Model;
|
||||||
|
using DotTiled.Serialization;
|
||||||
|
|
||||||
|
namespace DotTiled.Tests;
|
||||||
|
|
||||||
|
public partial class MapReaderTests
|
||||||
|
{
|
||||||
|
public static IEnumerable<object[]> Maps => TestData.MapTests;
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(Maps))]
|
||||||
|
public void MapReaderReadMap_ValidFilesExternalTilesetsAndTemplates_ReturnsMapThatEqualsExpected(
|
||||||
|
string testDataFile,
|
||||||
|
Func<string, Map> expectedMap,
|
||||||
|
IReadOnlyCollection<ICustomTypeDefinition> customTypeDefinitions)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
string[] fileFormats = [".tmx", ".tmj"];
|
||||||
|
|
||||||
|
foreach (var fileFormat in fileFormats)
|
||||||
|
{
|
||||||
|
var testDataFileWithFormat = testDataFile + fileFormat;
|
||||||
|
var fileDir = Path.GetDirectoryName(testDataFileWithFormat);
|
||||||
|
var mapString = TestData.GetRawStringFor(testDataFileWithFormat);
|
||||||
|
Template ResolveTemplate(string source)
|
||||||
|
{
|
||||||
|
var templateString = TestData.GetRawStringFor($"{fileDir}/{source}");
|
||||||
|
using var templateReader = new TemplateReader(templateString, ResolveTileset, ResolveTemplate, ResolveCustomType);
|
||||||
|
return templateReader.ReadTemplate();
|
||||||
|
}
|
||||||
|
Tileset ResolveTileset(string source)
|
||||||
|
{
|
||||||
|
var tilesetString = TestData.GetRawStringFor($"{fileDir}/{source}");
|
||||||
|
using var tilesetReader = new TilesetReader(tilesetString, ResolveTileset, ResolveTemplate, ResolveCustomType);
|
||||||
|
return tilesetReader.ReadTileset();
|
||||||
|
}
|
||||||
|
ICustomTypeDefinition ResolveCustomType(string name)
|
||||||
|
{
|
||||||
|
return customTypeDefinitions.FirstOrDefault(ctd => ctd.Name == name)!;
|
||||||
|
}
|
||||||
|
using var mapReader = new MapReader(mapString, ResolveTileset, ResolveTemplate, ResolveCustomType);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var map = mapReader.ReadMap();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(map);
|
||||||
|
DotTiledAssert.AssertMap(expectedMap(fileFormat[1..]), map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -151,4 +151,6 @@ internal static partial class Helpers
|
||||||
field = value;
|
field = value;
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool StringIsXml(string s) => s.StartsWith("<?xml", StringComparison.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
92
src/DotTiled/Serialization/MapReader.cs
Normal file
92
src/DotTiled/Serialization/MapReader.cs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml;
|
||||||
|
using DotTiled.Model;
|
||||||
|
using DotTiled.Serialization.Tmj;
|
||||||
|
using DotTiled.Serialization.Tmx;
|
||||||
|
|
||||||
|
namespace DotTiled.Serialization;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a map from a string, regardless of format.
|
||||||
|
/// </summary>
|
||||||
|
public class MapReader : IMapReader
|
||||||
|
{
|
||||||
|
// External resolvers
|
||||||
|
private readonly Func<string, Tileset> _externalTilesetResolver;
|
||||||
|
private readonly Func<string, Template> _externalTemplateResolver;
|
||||||
|
private readonly Func<string, ICustomTypeDefinition> _customTypeResolver;
|
||||||
|
|
||||||
|
private readonly StringReader? _mapStringReader;
|
||||||
|
private readonly XmlReader? _xmlReader;
|
||||||
|
private readonly IMapReader _mapReader;
|
||||||
|
private bool disposedValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="MapReader"/>, capable of reading a map from a string, regardless of format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="map">The string containing the map data.</param>
|
||||||
|
/// <param name="externalTilesetResolver">A function that resolves external tilesets given their source.</param>
|
||||||
|
/// <param name="externalTemplateResolver">A function that resolves external templates given their source.</param>
|
||||||
|
/// <param name="customTypeResolver">A function that resolves custom types given their source.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when any of the arguments are null.</exception>
|
||||||
|
public MapReader(
|
||||||
|
string map,
|
||||||
|
Func<string, Tileset> externalTilesetResolver,
|
||||||
|
Func<string, Template> externalTemplateResolver,
|
||||||
|
Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||||
|
{
|
||||||
|
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||||
|
_externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver));
|
||||||
|
_customTypeResolver = customTypeResolver ?? throw new ArgumentNullException(nameof(customTypeResolver));
|
||||||
|
|
||||||
|
// Prepare reader
|
||||||
|
if (Helpers.StringIsXml(map))
|
||||||
|
{
|
||||||
|
_mapStringReader = new StringReader(map);
|
||||||
|
_xmlReader = XmlReader.Create(_mapStringReader);
|
||||||
|
_mapReader = new TmxMapReader(_xmlReader, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_mapReader = new TmjMapReader(map, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Map ReadMap() => _mapReader.ReadMap();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposedValue)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
// TODO: dispose managed state (managed objects)
|
||||||
|
_mapStringReader?.Dispose();
|
||||||
|
_xmlReader?.Dispose();
|
||||||
|
_mapReader.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||||
|
// TODO: set large fields to null
|
||||||
|
disposedValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||||
|
// ~MapReader()
|
||||||
|
// {
|
||||||
|
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
// Dispose(disposing: false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
92
src/DotTiled/Serialization/TemplateReader.cs
Normal file
92
src/DotTiled/Serialization/TemplateReader.cs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml;
|
||||||
|
using DotTiled.Model;
|
||||||
|
using DotTiled.Serialization.Tmj;
|
||||||
|
using DotTiled.Serialization.Tmx;
|
||||||
|
|
||||||
|
namespace DotTiled.Serialization;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a template from a string, regardless of format.
|
||||||
|
/// </summary>
|
||||||
|
public class TemplateReader : ITemplateReader
|
||||||
|
{
|
||||||
|
// External resolvers
|
||||||
|
private readonly Func<string, Tileset> _externalTilesetResolver;
|
||||||
|
private readonly Func<string, Template> _externalTemplateResolver;
|
||||||
|
private readonly Func<string, ICustomTypeDefinition> _customTypeResolver;
|
||||||
|
|
||||||
|
private readonly StringReader? _templateStringReader;
|
||||||
|
private readonly XmlReader? _xmlReader;
|
||||||
|
private readonly ITemplateReader _templateReader;
|
||||||
|
private bool disposedValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="TemplateReader"/>, capable of reading a template from a string, regardless of format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="template">The string containing the template data.</param>
|
||||||
|
/// <param name="externalTilesetResolver">A function that resolves external tilesets given their source.</param>
|
||||||
|
/// <param name="externalTemplateResolver">A function that resolves external templates given their source.</param>
|
||||||
|
/// <param name="customTypeResolver">A function that resolves custom types given their source.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when any of the arguments are null.</exception>
|
||||||
|
public TemplateReader(
|
||||||
|
string template,
|
||||||
|
Func<string, Tileset> externalTilesetResolver,
|
||||||
|
Func<string, Template> externalTemplateResolver,
|
||||||
|
Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||||
|
{
|
||||||
|
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||||
|
_externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver));
|
||||||
|
_customTypeResolver = customTypeResolver ?? throw new ArgumentNullException(nameof(customTypeResolver));
|
||||||
|
|
||||||
|
// Prepare reader
|
||||||
|
if (Helpers.StringIsXml(template))
|
||||||
|
{
|
||||||
|
_templateStringReader = new StringReader(template);
|
||||||
|
_xmlReader = XmlReader.Create(_templateStringReader);
|
||||||
|
_templateReader = new TxTemplateReader(_xmlReader, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_templateReader = new TjTemplateReader(template, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Template ReadTemplate() => _templateReader.ReadTemplate();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposedValue)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
// TODO: dispose managed state (managed objects)
|
||||||
|
_templateStringReader?.Dispose();
|
||||||
|
_xmlReader?.Dispose();
|
||||||
|
_templateReader.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||||
|
// TODO: set large fields to null
|
||||||
|
disposedValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||||
|
// ~MapReader()
|
||||||
|
// {
|
||||||
|
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
// Dispose(disposing: false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
92
src/DotTiled/Serialization/TilesetReader.cs
Normal file
92
src/DotTiled/Serialization/TilesetReader.cs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml;
|
||||||
|
using DotTiled.Model;
|
||||||
|
using DotTiled.Serialization.Tmj;
|
||||||
|
using DotTiled.Serialization.Tmx;
|
||||||
|
|
||||||
|
namespace DotTiled.Serialization;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a tileset from a string, regardless of format.
|
||||||
|
/// </summary>
|
||||||
|
public class TilesetReader : ITilesetReader
|
||||||
|
{
|
||||||
|
// External resolvers
|
||||||
|
private readonly Func<string, Tileset> _externalTilesetResolver;
|
||||||
|
private readonly Func<string, Template> _externalTemplateResolver;
|
||||||
|
private readonly Func<string, ICustomTypeDefinition> _customTypeResolver;
|
||||||
|
|
||||||
|
private readonly StringReader? _tilesetStringReader;
|
||||||
|
private readonly XmlReader? _xmlReader;
|
||||||
|
private readonly ITilesetReader _tilesetReader;
|
||||||
|
private bool disposedValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="TilesetReader"/>, capable of reading a tileset from a string, regardless of format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tileset">The string containing the tileset data.</param>
|
||||||
|
/// <param name="externalTilesetResolver">A function that resolves external tilesets given their source.</param>
|
||||||
|
/// <param name="externalTemplateResolver">A function that resolves external templates given their source.</param>
|
||||||
|
/// <param name="customTypeResolver">A function that resolves custom types given their source.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when any of the arguments are null.</exception>
|
||||||
|
public TilesetReader(
|
||||||
|
string tileset,
|
||||||
|
Func<string, Tileset> externalTilesetResolver,
|
||||||
|
Func<string, Template> externalTemplateResolver,
|
||||||
|
Func<string, ICustomTypeDefinition> customTypeResolver)
|
||||||
|
{
|
||||||
|
_externalTilesetResolver = externalTilesetResolver ?? throw new ArgumentNullException(nameof(externalTilesetResolver));
|
||||||
|
_externalTemplateResolver = externalTemplateResolver ?? throw new ArgumentNullException(nameof(externalTemplateResolver));
|
||||||
|
_customTypeResolver = customTypeResolver ?? throw new ArgumentNullException(nameof(customTypeResolver));
|
||||||
|
|
||||||
|
// Prepare reader
|
||||||
|
if (Helpers.StringIsXml(tileset))
|
||||||
|
{
|
||||||
|
_tilesetStringReader = new StringReader(tileset);
|
||||||
|
_xmlReader = XmlReader.Create(_tilesetStringReader);
|
||||||
|
_tilesetReader = new TsxTilesetReader(_xmlReader, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_tilesetReader = new TsjTilesetReader(tileset, _externalTilesetResolver, _externalTemplateResolver, _customTypeResolver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Tileset ReadTileset() => _tilesetReader.ReadTileset();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!disposedValue)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
// TODO: dispose managed state (managed objects)
|
||||||
|
_tilesetStringReader?.Dispose();
|
||||||
|
_xmlReader?.Dispose();
|
||||||
|
_tilesetReader.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||||
|
// TODO: set large fields to null
|
||||||
|
disposedValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||||
|
// ~MapReader()
|
||||||
|
// {
|
||||||
|
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
// Dispose(disposing: false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue