diff --git a/PriFileFormat.backup.7z b/PriFileFormat.backup.7z
new file mode 100644
index 0000000..e710bce
Binary files /dev/null and b/PriFileFormat.backup.7z differ
diff --git a/PriFileFormat/ComStreamWrapper.cs b/PriFileFormat/ComStreamWrapper.cs
index 6ec1882..4524735 100644
--- a/PriFileFormat/ComStreamWrapper.cs
+++ b/PriFileFormat/ComStreamWrapper.cs
@@ -17,15 +17,15 @@ namespace PriFileFormat
}
public override bool CanRead
{
- get { return comStream != null; }
+ get { return true; }
}
public override bool CanSeek
{
- get { return comStream != null; }
+ get { return true; }
}
public override bool CanWrite
{
- get { return comStream != null; }
+ get { return true; }
}
public override long Length
{
@@ -144,8 +144,9 @@ namespace PriFileFormat
}
public override void Close ()
{
- base.Close ();
comStream = null;
+ base.Close ();
}
+ ~ComStreamWrapper () { comStream = null;}
}
}
diff --git a/PriFileFormat/DataItemSection.cs b/PriFileFormat/DataItemSection.cs
index df2f0f7..da3e0b4 100644
--- a/PriFileFormat/DataItemSection.cs
+++ b/PriFileFormat/DataItemSection.cs
@@ -48,6 +48,7 @@ namespace PriFileFormat
_dataItems?.Clear ();
_dataItems = null;
}
+ ~DataItemSection () { ClearData (); }
}
public struct DataItemRef
diff --git a/PriFileFormat/DataTree.cs b/PriFileFormat/DataTree.cs
new file mode 100644
index 0000000..e1ceb67
--- /dev/null
+++ b/PriFileFormat/DataTree.cs
@@ -0,0 +1,213 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml.Serialization;
+
+namespace PriFileFormat
+{
+ ///
+ /// 树节点接口
+ ///
+ public interface ITreeNode: IDisposable, IEnumerable
+ {
+ string Name { get; set; }
+ string Value { get; set; }
+ ITreeNode Parent { get; set; }
+ IList Children { get; }
+ ITreeNode AddChild (string name, string value);
+ IEnumerable DescendantsAndSelf ();
+ ITreeNode Find (string name);
+ IEnumerable FindAll (string name);
+ }
+ ///
+ /// 树节点实现
+ ///
+ [Serializable]
+ public class TreeNode: ITreeNode
+ {
+ // 节点基本属性
+ public string Name { get; set; }
+ public string Value { get; set; }
+ // 父节点引用
+ [XmlIgnore]
+ public TreeNode Parent { get; set; }
+ ITreeNode ITreeNode.Parent
+ {
+ get { return Parent; }
+ set { Parent = (TreeNode)value; }
+ }
+ // 子节点列表
+ [XmlArray ("Children")]
+ [XmlArrayItem ("Node")]
+ public IList Children { get; set; }
+ IList ITreeNode.Children
+ {
+ get
+ {
+ List list = new List ();
+ foreach (TreeNode node in Children)
+ {
+ list.Add (node);
+ }
+ return list;
+ }
+ }
+ public TreeNode ()
+ {
+ Name = "";
+ Value = "";
+ Children = new List ();
+ Parent = null;
+ }
+ public TreeNode (string name, string value)
+ {
+ Name = name;
+ Value = value;
+ Children = new List ();
+ Parent = null;
+ }
+ ///
+ /// 添加子节点
+ ///
+ public TreeNode AddChild (string name, string value)
+ {
+ TreeNode child = new TreeNode (name, value);
+ child.Parent = this;
+ Children.Add (child);
+ return child;
+ }
+ ITreeNode ITreeNode.AddChild (string name, string value)
+ {
+ return AddChild (name, value);
+ }
+ ///
+ /// 深度优先遍历节点,包括自身
+ ///
+ public IEnumerable DescendantsAndSelf ()
+ {
+ yield return this;
+ foreach (TreeNode child in Children)
+ {
+ foreach (TreeNode desc in child.DescendantsAndSelf ())
+ {
+ yield return desc;
+ }
+ }
+ }
+ IEnumerable ITreeNode.DescendantsAndSelf ()
+ {
+ foreach (TreeNode n in DescendantsAndSelf ())
+ {
+ yield return n;
+ }
+ }
+ ///
+ /// 查找第一个匹配节点
+ ///
+ public TreeNode Find (string name)
+ {
+ foreach (TreeNode n in DescendantsAndSelf ())
+ {
+ if (n.Name == name)
+ return n;
+ }
+ return null;
+ }
+ ITreeNode ITreeNode.Find (string name)
+ {
+ return Find (name);
+ }
+ ///
+ /// 查找所有匹配节点
+ ///
+ public IEnumerable FindAll (string name)
+ {
+ foreach (TreeNode n in DescendantsAndSelf ())
+ {
+ if (n.Name == name)
+ yield return n;
+ }
+ }
+ IEnumerable ITreeNode.FindAll (string name)
+ {
+ foreach (TreeNode n in FindAll (name))
+ {
+ yield return n;
+ }
+ }
+ #region IEnumerable
+ public IEnumerator GetEnumerator ()
+ {
+ return Children.GetEnumerator ();
+ }
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return GetEnumerator ();
+ }
+ #endregion
+ #region IEnumerable 显示实现
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ foreach (TreeNode child in Children)
+ {
+ yield return child;
+ }
+ }
+ #endregion
+ #region XML 序列化
+ public void SaveToXml (string filePath)
+ {
+ XmlSerializer serializer = new XmlSerializer (typeof (TreeNode));
+ using (StreamWriter writer = new StreamWriter (filePath, false, System.Text.Encoding.UTF8))
+ {
+ serializer.Serialize (writer, this);
+ }
+ }
+
+ public static TreeNode LoadFromXml (string filePath)
+ {
+ XmlSerializer serializer = new XmlSerializer (typeof (TreeNode));
+ using (StreamReader reader = new StreamReader (filePath, System.Text.Encoding.UTF8))
+ {
+ TreeNode root = (TreeNode)serializer.Deserialize (reader);
+ SetParentRecursive (root, null);
+ return root;
+ }
+ }
+
+ private static void SetParentRecursive (TreeNode node, TreeNode parent)
+ {
+ node.Parent = parent;
+ foreach (TreeNode child in node.Children)
+ {
+ SetParentRecursive (child, node);
+ }
+ }
+ #endregion
+ #region IDisposable
+ public virtual void Dispose ()
+ {
+ foreach (TreeNode child in Children)
+ {
+ child.Dispose ();
+ }
+ Children.Clear ();
+ Parent = null;
+ Children = null;
+ }
+ #endregion
+ }
+ ///
+ /// 树根节点
+ ///
+ [Serializable]
+ public class TreeRoot: TreeNode
+ {
+ public TreeRoot ()
+ : base ("Root", "")
+ {
+ }
+ }
+}
diff --git a/PriFileFormat/HierarchicalSchemaSection.cs b/PriFileFormat/HierarchicalSchemaSection.cs
index 77435c8..d6985f7 100644
--- a/PriFileFormat/HierarchicalSchemaSection.cs
+++ b/PriFileFormat/HierarchicalSchemaSection.cs
@@ -10,8 +10,8 @@ namespace PriFileFormat
public HierarchicalSchemaVersionInfo Version { get; private set; }
public string UniqueName { get; private set; }
public string Name { get; private set; }
- public IReadOnlyList Scopes { get; private set; }
- public IReadOnlyList Items { get; private set; }
+ public IReadOnlyList Scopes { get; private set; }
+ public IReadOnlyList Items { get; private set; }
bool extendedVersion;
internal const string Identifier1 = "[mrm_hschema] \0";
internal const string Identifier2 = "[mrm_hschemaex] ";
@@ -64,7 +64,7 @@ namespace PriFileFormat
uint unicodeDataLength = binaryReader.ReadUInt32 ();
binaryReader.ReadUInt32 (); // meaning unknown
if (extendedHNames) binaryReader.ReadUInt32 (); // meaning unknown
- List scopeAndItemInfos = new List ((int)(numScopes + numItems));
+ List scopeAndItemInfos = new List ((int)(numScopes + numItems));
for (int i = 0; i < numScopes + numItems; i++)
{
ushort parent = binaryReader.ReadUInt16 ();
@@ -78,7 +78,7 @@ namespace PriFileFormat
bool nameInAscii = (flags & 0x20) != 0;
scopeAndItemInfos.Add (new ScopeAndItemInfo (parent, fullPathLength, isScope, nameInAscii, nameOffset, index));
}
- List scopeExInfos = new List ((int)numScopes);
+ List scopeExInfos = new List ((int)numScopes);
for (int i = 0; i < numScopes; i++)
{
ushort scopeIndex = binaryReader.ReadUInt16 ();
@@ -127,7 +127,7 @@ namespace PriFileFormat
}
for (int i = 0; i < numScopes; i++)
{
- List children = new List (scopeExInfos [i].ChildCount);
+ List children = new List (scopeExInfos [i].ChildCount);
for (int j = 0; j < scopeExInfos [i].ChildCount; j++)
{
ScopeAndItemInfo saiInfo = scopeAndItemInfos [scopeExInfos [i].FirstChildIndex + j];
@@ -172,6 +172,18 @@ namespace PriFileFormat
FirstChildIndex = firstChildIndex;
}
}
+ ~HierarchicalSchemaSection ()
+ {
+ try
+ {
+ Version = null;
+ foreach (var item in Items) { item.Parent = null; }
+ foreach (var scope in Scopes) { scope.Parent = null; }
+ Scopes = null;
+ Items = null;
+ }
+ catch { }
+ }
// Checksum computation is buggy for some files
//private uint ComputeHierarchicalSchemaVersionInfoChecksum()
@@ -258,19 +270,21 @@ namespace PriFileFormat
return fullName;
}
}
+ ~ResourceMapEntry () { Parent = null; }
}
public class ResourceMapScope: ResourceMapEntry
{
- internal ResourceMapScope (ushort index, ResourceMapScope parent, string name) : base (index, parent, name) { }
- public IReadOnlyList Children { get; internal set; }
+ internal ResourceMapScope (ushort index, ResourceMapScope parent, string name) : base (index, parent, name) {}
+ public IReadOnlyList Children { get; internal set; }
public override string ToString ()
{
return $"Scope {Index} {FullName} ({Children.Count} children)";
}
+ ~ResourceMapScope () { Children = null; }
}
public class ResourceMapItem: ResourceMapEntry
{
- internal ResourceMapItem (ushort index, ResourceMapScope parent, string name) : base (index, parent, name) { }
+ internal ResourceMapItem (ushort index, ResourceMapScope parent, string name) : base (index, parent, name) {}
public override string ToString ()
{
return $"Item {Index} {FullName}";
diff --git a/PriFileFormat/PriDescriptorSection.cs b/PriFileFormat/PriDescriptorSection.cs
index 2234876..3650c90 100644
--- a/PriFileFormat/PriDescriptorSection.cs
+++ b/PriFileFormat/PriDescriptorSection.cs
@@ -46,6 +46,15 @@ namespace PriFileFormat
DataItemSections = dataItemSections;
return true;
}
+ ~PriDescriptorSection ()
+ {
+ HierarchicalSchemaSections = null;
+ DecisionInfoSections = null;
+ ResourceMapSections = null;
+ ReferencedFileSections = null;
+ DataItemSections = null;
+ PrimaryResourceMapSection = null;
+ }
}
[Flags]
public enum PriDescriptorFlags: ushort
diff --git a/PriFileFormat/PriFile.cs b/PriFileFormat/PriFile.cs
index 308e7ee..8e0abf2 100644
--- a/PriFileFormat/PriFile.cs
+++ b/PriFileFormat/PriFile.cs
@@ -6,12 +6,14 @@ using System;
namespace PriFileFormat
{
- public class PriFile
+ public class PriFile: IDisposable
{
public string Version { get; private set; }
public uint TotalFileSize { get; private set; }
public IReadOnlyList TableOfContents { get; private set; }
public IReadOnlyList Sections { get; private set; }
+ private bool _disposed = false;
+ private Stream _internalStream; // 跟踪内部流
private PriFile ()
{
}
@@ -35,6 +37,7 @@ namespace PriFileFormat
private void ParseInternal (Stream stream, bool ownStream)
{
+ if (ownStream) { _internalStream = stream; }
using (BinaryReader binaryReader = new BinaryReader (stream, Encoding.ASCII, true))
{
long fileStartOffset = binaryReader.BaseStream.Position;
@@ -109,6 +112,48 @@ namespace PriFileFormat
}
}
+ public void Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+ protected virtual void Dispose (bool disposing)
+ {
+ if (_disposed) return;
+ if (disposing)
+ {
+ // 释放托管资源
+ if (_internalStream != null)
+ {
+ _internalStream.Dispose ();
+ _internalStream = null;
+ }
+
+ // 释放 section 内容
+ if (Sections != null)
+ {
+ foreach (var section in Sections)
+ {
+ var unknown = section as UnknownSection;
+ if (unknown != null)
+ unknown.ClearContent ();
+
+ var dataSection = section as DataItemSection;
+ if (dataSection != null)
+ dataSection.ClearData ();
+ }
+ Sections = null;
+ }
+ }
+
+ _disposed = true;
+ }
+
+ ~PriFile ()
+ {
+ Dispose (false);
+ }
+
PriDescriptorSection priDescriptorSection;
public PriDescriptorSection PriDescriptorSection
diff --git a/PriFileFormat/ReferencedFileSection.cs b/PriFileFormat/ReferencedFileSection.cs
index 162f323..48cde41 100644
--- a/PriFileFormat/ReferencedFileSection.cs
+++ b/PriFileFormat/ReferencedFileSection.cs
@@ -121,6 +121,11 @@ namespace PriFileFormat
FileNameOffset = fileNameOffset;
}
}
+ ~ReferencedFileSection ()
+ {
+ foreach (var file in ReferencedFiles) { file.Parent = null; }
+ ReferencedFiles = null;
+ }
}
public class ReferencedEntry
{
@@ -145,11 +150,13 @@ namespace PriFileFormat
return fullName;
}
}
+ ~ReferencedEntry () { Parent = null; }
}
public class ReferencedFolder: ReferencedEntry
{
internal ReferencedFolder (ReferencedFolder parent, string name) : base (parent, name) {}
public IReadOnlyList Children { get; internal set; }
+ ~ReferencedFolder () { Children = null; }
}
public class ReferencedFile: ReferencedEntry
{
diff --git a/PriFileFormat/ResourceMapSection.cs b/PriFileFormat/ResourceMapSection.cs
index d0b3251..6d3a818 100644
--- a/PriFileFormat/ResourceMapSection.cs
+++ b/PriFileFormat/ResourceMapSection.cs
@@ -296,6 +296,11 @@ namespace PriFileFormat
DataOffset = dataOffset;
}
}
+ ~ResourceMapSection ()
+ {
+ HierarchicalSchemaReference = null;
+ CandidateSets = null;
+ }
}
public enum ResourceValueType
{
@@ -318,6 +323,10 @@ namespace PriFileFormat
DecisionIndex = decisionIndex;
Candidates = candidates;
}
+ ~CandidateSet ()
+ {
+ Candidates = null;
+ }
}
public class Candidate
@@ -343,6 +352,12 @@ namespace PriFileFormat
DataItem = null;
Data = data;
}
+ ~Candidate ()
+ {
+ SourceFile = null;
+ DataItem = null;
+ Data = null;
+ }
}
public class HierarchicalSchemaReference
{
@@ -357,6 +372,10 @@ namespace PriFileFormat
Unknown2 = unknown2;
UniqueName = uniqueName;
}
+ ~HierarchicalSchemaReference ()
+ {
+ VersionInfo = null;
+ }
}
public struct ResourceMapItemRef
{
diff --git a/PriFileFormat/ReverseMapSection.cs b/PriFileFormat/ReverseMapSection.cs
index 8398218..2d68af3 100644
--- a/PriFileFormat/ReverseMapSection.cs
+++ b/PriFileFormat/ReverseMapSection.cs
@@ -148,6 +148,12 @@ namespace PriFileFormat
return true;
}
+ ~ReverseMapSection ()
+ {
+ Mapping = null;
+ Scopes = null;
+ Items = null;
+ }
}
}
diff --git a/PriFileFormat/Section.cs b/PriFileFormat/Section.cs
index abdb45f..d5b7395 100644
--- a/PriFileFormat/Section.cs
+++ b/PriFileFormat/Section.cs
@@ -81,5 +81,9 @@ namespace PriFileFormat
}
}
+ ~Section ()
+ {
+ PriFile = null;
+ }
}
}
diff --git a/PriFileFormat/SubStream.cs b/PriFileFormat/SubStream.cs
index 57a5c2d..72a1ecd 100644
--- a/PriFileFormat/SubStream.cs
+++ b/PriFileFormat/SubStream.cs
@@ -71,10 +71,6 @@ namespace PriFileFormat
throw new NotSupportedException ();
}
- public override void Close ()
- {
- base.Close ();
- baseStream = null;
- }
+ ~SubStream () { baseStream = null; }
}
}
diff --git a/PriFileFormat/UnknownSection.cs b/PriFileFormat/UnknownSection.cs
index 75460dc..f445452 100644
--- a/PriFileFormat/UnknownSection.cs
+++ b/PriFileFormat/UnknownSection.cs
@@ -18,5 +18,6 @@ namespace PriFileFormat
{
SectionContent = null;
}
+ ~UnknownSection () { ClearContent (); }
}
}
diff --git a/priformatcli/priformatcli.cpp b/priformatcli/priformatcli.cpp
index 1a22feb..dad909c 100644
--- a/priformatcli/priformatcli.cpp
+++ b/priformatcli/priformatcli.cpp
@@ -20,32 +20,6 @@
#include
#include
-LPWSTR AllocWideString (const std::wstring &str)
-{
- size_t size = (str.length () + 1) * sizeof (WCHAR);
- LPWSTR buf = (LPWSTR)CoTaskMemAlloc (size);
- if (!buf) return nullptr;
- ZeroMemory (buf, size);
- wcscpy (buf, str.c_str ());
- return buf;
-}
-//
-LPWSTR AllocWideString (LPCWSTR str)
-{
- if (!str) return nullptr;
- size_t size = (wcslen (str) + 1) * sizeof (WCHAR);
- LPWSTR buf = (LPWSTR)CoTaskMemAlloc (size);
- if (!buf) return nullptr;
- ZeroMemory (buf, size);
- wcscpy (buf, str);
- return buf;
-}
-#define _wcsdup AllocWideString
-#define free CoTaskMemFree
-#define malloc CoTaskMemAlloc
-#define realloc CoTaskMemRealloc
-#define calloc(_cnt_, _size_) CoTaskMemAlloc (_cnt_ * _size_)
-
const std::wstring g_swMsResUriProtocolName = L"ms-resource:";
const size_t g_cbMsResPNameLength = lstrlenW (g_swMsResUriProtocolName.c_str ());
std::wstring g_swExcept = L"";