LibZNI/NBT/API/Tag.cs

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()
};
}
}