280 lines
7.3 KiB
C#
280 lines
7.3 KiB
C#
using System.Collections.Generic;
|
|
|
|
namespace LibAC.NBT.API;
|
|
|
|
using System;
|
|
using System.Text;
|
|
|
|
public abstract class Tag
|
|
{
|
|
private TagType _parentTagType = TagType.End;
|
|
private Tag _parentTag;
|
|
private string _key;
|
|
|
|
public byte GetType()
|
|
{
|
|
return (byte)GetTagType();
|
|
}
|
|
|
|
public abstract TagType GetTagType();
|
|
|
|
public bool HasParent => _parentTag != null;
|
|
|
|
public void UpdateParent(Tag tag)
|
|
{
|
|
if (tag == null)
|
|
{
|
|
_parentTag = null;
|
|
SetParentTagType(TagType.End);
|
|
}
|
|
else
|
|
{
|
|
_parentTag = tag;
|
|
SetParentTagType(tag.GetTagType());
|
|
}
|
|
}
|
|
|
|
public Tag GetParent => _parentTag;
|
|
|
|
public TagType ParentTagType => _parentTagType;
|
|
|
|
public void SetParentTagType(TagType type)
|
|
{
|
|
_parentTagType = type;
|
|
}
|
|
|
|
public abstract void WriteValue(ByteLayer data);
|
|
public abstract void ReadValue(ByteLayer data);
|
|
|
|
public string GetKey()
|
|
{
|
|
return _key ?? string.Empty;
|
|
}
|
|
|
|
public void SetKey(string key)
|
|
{
|
|
_key = key;
|
|
}
|
|
|
|
public abstract dynamic GetValue();
|
|
public abstract void SetValue(dynamic val);
|
|
|
|
public static Tag ReadNamedTag(ByteLayer data)
|
|
{
|
|
var type = data.ReadByte();
|
|
if (type == 0)
|
|
{
|
|
return new EndTag();
|
|
}
|
|
else
|
|
{
|
|
Tag tag = MakeTagOfType(TagTypeExtensions.GetTagTypeFromByte(type));
|
|
tag._key = data.ReadString();
|
|
tag.ReadValue(data);
|
|
|
|
return tag;
|
|
}
|
|
}
|
|
|
|
public static void WriteNamedTag(Tag tag, ByteLayer data)
|
|
{
|
|
data.WriteByte(tag.GetType());
|
|
if (tag.GetType() != 0)
|
|
{
|
|
data.WriteString(tag.GetKey());
|
|
tag.WriteValue(data);
|
|
}
|
|
}
|
|
|
|
public static void WriteStringifiedNamedTag(Tag tag, StringBuilder builder, int indents)
|
|
{
|
|
if (tag.GetType() != 0)
|
|
{
|
|
if (builder.Length > 0)
|
|
{
|
|
if (string.IsNullOrEmpty(tag.GetKey()))
|
|
{
|
|
builder.Append(new string('\t', indents));
|
|
}
|
|
else
|
|
{
|
|
if (tag.ShouldQuoteName())
|
|
{
|
|
builder.Append(new string('\t', indents) + $"\"{tag.GetKey()}\": ");
|
|
}
|
|
else
|
|
{
|
|
builder.Append(new string('\t', indents) + $"{tag.GetKey()}: ");
|
|
}
|
|
}
|
|
}
|
|
|
|
tag.WriteStringifiedValue(builder, indents + 1, false);
|
|
}
|
|
}
|
|
|
|
public static Tag ReadStringifiedNamedTag(StringReader stringReader)
|
|
{
|
|
string name = stringReader.Peek() == '{' || stringReader.Peek() == '[' ? "" : stringReader.ReadString();
|
|
if (!string.IsNullOrEmpty(name)) stringReader.Expect(':');
|
|
|
|
TagType type = TagTypeExtensions.GetStringifiedTagType(stringReader);
|
|
Tag tag = MakeTagOfType(type);
|
|
tag._key = name;
|
|
tag.ReadStringifiedValue(stringReader);
|
|
|
|
return tag;
|
|
}
|
|
|
|
public bool ShouldQuoteName()
|
|
{
|
|
if (string.IsNullOrEmpty(GetKey()))
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
foreach (char c in GetKey())
|
|
{
|
|
if (!letters.Contains(c.ToString())) return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool ShouldQuote(string value)
|
|
{
|
|
if (string.IsNullOrEmpty(value)) return true;
|
|
|
|
string letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
foreach (char c in value)
|
|
{
|
|
if (!letters.Contains(c.ToString())) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public abstract void WriteStringifiedValue(StringBuilder builder, int indent, bool isList);
|
|
public abstract void ReadStringifiedValue(StringReader reader);
|
|
|
|
public bool Equals(object obj)
|
|
{
|
|
if (obj == null || !(obj is Tag)) return false;
|
|
|
|
var tag = (Tag)obj;
|
|
if (tag.GetType() != GetType()) return false;
|
|
if (GetKey() != tag.GetKey()) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public static Tag MakeTagOfType(TagType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case TagType.Byte: return new ByteTag();
|
|
case TagType.ByteArray: return new ByteArrayTag();
|
|
case TagType.Compound: return new CompoundTag();
|
|
case TagType.Double: return new DoubleTag();
|
|
case TagType.End: return new EndTag();
|
|
case TagType.Short: return new ShortTag();
|
|
case TagType.Int: return new IntTag();
|
|
case TagType.Long: return new LongTag();
|
|
case TagType.Float: return new FloatTag();
|
|
case TagType.IntArray: return new IntArrayTag();
|
|
case TagType.LongArray: return new LongArrayTag();
|
|
case TagType.List: return new ListTag();
|
|
case TagType.String: return new StringTag();
|
|
default: throw new ArgumentOutOfRangeException();
|
|
}
|
|
}
|
|
|
|
public int AsByte()
|
|
{
|
|
if (this is ByteTag byteTag) return byteTag.Value;
|
|
return 0;
|
|
}
|
|
|
|
public List<byte> AsByteArray()
|
|
{
|
|
if (this is ByteArrayTag byteArrayTag) return byteArrayTag.Value;
|
|
return new List<byte>();
|
|
}
|
|
|
|
public double AsDouble()
|
|
{
|
|
if (this is DoubleTag doubleTag) return doubleTag.Value;
|
|
return 0.0;
|
|
}
|
|
|
|
public double AsFloat()
|
|
{
|
|
if (this is FloatTag floatTag) return floatTag.value;
|
|
return 0.0;
|
|
}
|
|
|
|
public List<int> AsIntArray()
|
|
{
|
|
if (this is IntArrayTag intArrayTag) return intArrayTag.Value;
|
|
return new List<int>();
|
|
}
|
|
|
|
public int AsInt()
|
|
{
|
|
if (this is IntTag intTag) return intTag.Value;
|
|
return 0;
|
|
}
|
|
|
|
public List<long> AsLongArray()
|
|
{
|
|
if (this is LongArrayTag longArrayTag) return longArrayTag.value;
|
|
return new List<long>();
|
|
}
|
|
|
|
public long AsLong()
|
|
{
|
|
if (this is LongTag longTag) return longTag.value;
|
|
return 0;
|
|
}
|
|
|
|
public short AsShort()
|
|
{
|
|
if (this is ShortTag shortTag) return shortTag.value;
|
|
return 0;
|
|
}
|
|
|
|
public string AsString()
|
|
{
|
|
if (this is StringTag stringTag) return stringTag.value;
|
|
return string.Empty;
|
|
}
|
|
|
|
public CompoundTag AsCompoundTag()
|
|
{
|
|
return this is CompoundTag compoundTag ? compoundTag : new CompoundTag();
|
|
}
|
|
|
|
public abstract void PrettyPrint(int indent, bool recurse);
|
|
|
|
public static string GetCanonicalName(TagType type)
|
|
{
|
|
return type switch
|
|
{
|
|
TagType.String => "TAG_String",
|
|
TagType.List => "TAG_List",
|
|
TagType.LongArray => "TAG_LongArray",
|
|
TagType.Long => "TAG_Long",
|
|
TagType.IntArray => "TAG_IntArray",
|
|
TagType.Int => "TAG_Int",
|
|
TagType.Compound => "TAG_Compound",
|
|
TagType.ByteArray => "TAG_ByteArray",
|
|
TagType.Byte => "TAG_Byte",
|
|
TagType.Double => "TAG_Double",
|
|
TagType.Float => "TAG_Float",
|
|
TagType.Short => "TAG_Short",
|
|
TagType.End => "TAG_End",
|
|
_ => throw new ArgumentOutOfRangeException()
|
|
};
|
|
}
|
|
}
|