NBTExplorer/NBTModel/Data/Nodes/NbtFileDataNode.cs

283 lines
7.9 KiB
C#

using System.IO;
using System.Text.RegularExpressions;
using Substrate.Core;
using Substrate.Nbt;
using System.Collections.Generic;
using System;
using NBTModel.Interop;
namespace NBTExplorer.Model
{
public class NbtFileDataNode : DataNode, IMetaTagContainer
{
private NbtTree _tree;
private string _path;
private CompressionType _compressionType;
private CompoundTagContainer _container;
private static Regex _namePattern = new Regex(@"\.(dat|nbt|schematic)$");
private NbtFileDataNode (string path, CompressionType compressionType)
{
_path = path;
_compressionType = compressionType;
_container = new CompoundTagContainer(new TagNodeCompound());
}
public static NbtFileDataNode TryCreateFrom (string path)
{
return TryCreateFrom(path, CompressionType.GZip)
?? TryCreateFrom(path, CompressionType.None);
}
private static NbtFileDataNode TryCreateFrom (string path, CompressionType compressionType)
{
try {
NBTFile file = new NBTFile(path);
NbtTree tree = new NbtTree();
tree.ReadFrom(file.GetDataInputStream(compressionType));
if (tree.Root == null)
return null;
return new NbtFileDataNode(path, compressionType);
}
catch {
return null;
}
}
public static bool SupportedNamePattern (string path)
{
path = Path.GetFileName(path);
return _namePattern.IsMatch(path);
}
protected override NodeCapabilities Capabilities
{
get
{
return NodeCapabilities.CreateTag
| NodeCapabilities.PasteInto
| NodeCapabilities.Search
| NodeCapabilities.Refresh
| NodeCapabilities.Rename;
}
}
public override string NodeName
{
get { return Path.GetFileName(_path); }
}
public override string NodePathName
{
get { return Path.GetFileName(_path); }
}
public override string NodeDisplay
{
get
{
if (_tree != null && _tree.Root != null) {
if (!string.IsNullOrEmpty(_tree.Name))
return NodeName + " [" + _tree.Name + ": " + _tree.Root.Count + " entries]";
else
return NodeName + " [" + _tree.Root.Count + " entries]";
}
else
return NodeName;
}
}
public override bool HasUnexpandedChildren
{
get { return !IsExpanded; }
}
public override bool IsContainerType
{
get { return true; }
}
protected override void ExpandCore ()
{
if (_tree == null) {
NBTFile file = new NBTFile(_path);
_tree = new NbtTree();
_tree.ReadFrom(file.GetDataInputStream(_compressionType));
if (_tree.Root != null) {
_container = new CompoundTagContainer(_tree.Root);
}
}
var list = new SortedList<TagKey, TagNode>();
foreach (var item in _tree.Root) {
list.Add(new TagKey(item.Key, item.Value.GetTagType()), item.Value);
}
foreach (TagNode tag in list.Values) {
TagDataNode node = TagDataNode.CreateFromTag(tag);
if (node != null)
Nodes.Add(node);
}
}
protected override void ReleaseCore ()
{
_tree = null;
Nodes.Clear();
}
protected override void SaveCore ()
{
NBTFile file = new NBTFile(_path);
using (Stream str = file.GetDataOutputStream(_compressionType)) {
_tree.WriteTo(str);
}
}
public override bool RefreshNode ()
{
Dictionary<string, object> expandSet = BuildExpandSet(this);
Release();
RestoreExpandSet(this, expandSet);
return true;
}
public override bool CanRenameNode
{
get { return _tree != null; }
}
public override bool RenameNode ()
{
if (CanRenameNode && FormRegistry.EditString != null) {
RestrictedStringFormData data = new RestrictedStringFormData(_tree.Name ?? "") {
AllowEmpty = true,
};
if (FormRegistry.RenameTag(data)) {
if (_tree.Name != data.Value) {
_tree.Name = data.Value;
IsDataModified = true;
return true;
}
}
}
return false;
}
public override bool CanCreateTag (TagType type)
{
return _tree != null && _tree.Root != null && Enum.IsDefined(typeof(TagType), type) && type != TagType.TAG_END;
}
public override bool CanPasteIntoNode
{
get { return _tree != null && _tree.Root != null && NbtClipboardController.ContainsData; }
}
public override bool CreateNode (TagType type)
{
if (!CanCreateTag(type))
return false;
if (FormRegistry.CreateNode != null) {
CreateTagFormData data = new CreateTagFormData() {
TagType = type,
HasName = true,
};
data.RestrictedNames.AddRange(_container.TagNamesInUse);
if (FormRegistry.CreateNode(data)) {
AddTag(data.TagNode, data.TagName);
return true;
}
}
return false;
}
public override bool PasteNode ()
{
if (!CanPasteIntoNode)
return false;
NbtClipboardData clipboard = NbtClipboardController.CopyFromClipboard();
if (clipboard == null || clipboard.Node == null)
return false;
string name = clipboard.Name;
if (String.IsNullOrEmpty(name))
name = "UNNAMED";
AddTag(clipboard.Node, MakeUniqueName(name));
return true;
}
public bool IsNamedContainer
{
get { return true; }
}
public bool IsOrderedContainer
{
get { return false; }
}
public INamedTagContainer NamedTagContainer
{
get { return _container; }
}
public IOrderedTagContainer OrderedTagContainer
{
get { return null; }
}
public int TagCount
{
get { return _container.TagCount; }
}
public bool DeleteTag (TagNode tag)
{
return _container.DeleteTag(tag);
}
private void AddTag (TagNode tag, string name)
{
_container.AddTag(tag, name);
IsDataModified = true;
if (IsExpanded) {
TagDataNode node = TagDataNode.CreateFromTag(tag);
if (node != null)
Nodes.Add(node);
}
}
private string MakeUniqueName (string name)
{
List<string> names = new List<string>(_container.TagNamesInUse);
if (!names.Contains(name))
return name;
int index = 1;
while (names.Contains(MakeCandidateName(name, index)))
index++;
return MakeCandidateName(name, index);
}
private string MakeCandidateName (string name, int index)
{
return name + " (Copy " + index + ")";
}
}
}