From 09f2730cc6d9774131c30987b73cd9b76799c094 Mon Sep 17 00:00:00 2001
From: Amorilia <amorilia@users.sourceforge.net>
Date: Tue, 20 Sep 2011 21:55:53 +0100
Subject: [PATCH] Added missing_link_stack stuff to public interface, and added
 regression test for it.

---
 include/niflib.h                 | 11 ++++++
 test/CMakeLists.txt              |  3 +-
 test/missing_link_stack_test.cpp | 67 ++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+), 1 deletion(-)
 create mode 100644 test/missing_link_stack_test.cpp

diff --git a/include/niflib.h b/include/niflib.h
index e55ca36d..8f4cc2a7 100644
--- a/include/niflib.h
+++ b/include/niflib.h
@@ -58,6 +58,7 @@ namespace Niflib {
 
 //Classes used
 class NiObject;
+typedef Ref<NiObject> NiObjectRef;
 class NiNode;
 class NiAVObject;
 class NiControllerSequence;
@@ -141,6 +142,16 @@ NIFLIB_API Ref<NiObject> ReadNifTree( string const & file_name, NifInfo * info =
  */
 NIFLIB_API Ref<NiObject> ReadNifTree( istream & in, NifInfo * info = NULL );
 
+/*!
+ * Creates a new NIF file of the given file name by crawling through the data tree starting with the root objects given, and keeps track of links that cannot been written.
+ * \param[in] in The output stream to write the NIF data to.
+ * \param[in] roots The root objects to start from when writing out the NIF file.  All decedents of these blocks will be written to the file in tree-descending order.
+ * \param[in] missing_link_stack stack of links which are referred to but which are not inside the tree rooted by roots.
+ * \param[in] info A NifInfo structure that contains information such as the version of the NIF file to create.
+ * \sa ReadNifList, WriteNifTree
+ */
+NIFLIB_API void WriteNifTree( ostream & in, list<NiObjectRef> const & roots, list<NiObject *> & missing_link_stack, const NifInfo & info = NifInfo() );
+
 /*!
  * Creates a new NIF file of the given file name by crawling through the data tree starting with the root object given.
  * \param[in] file_name The desired file name for the new NIF file.  The path is relative to the working directory unless a full path is specified.
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6babbc28..37d342ea 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -9,7 +9,8 @@ foreach(TEST
         write_test
         skinpart_test
         ninode_test
-        skin_test)
+        skin_test
+        missing_link_stack_test)
     add_executable(${TEST} ${TEST}.cpp)
     target_link_libraries(${TEST} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} niflib)
     add_test(niflib::${TEST} ${TEST})
diff --git a/test/missing_link_stack_test.cpp b/test/missing_link_stack_test.cpp
new file mode 100644
index 00000000..e25c3433
--- /dev/null
+++ b/test/missing_link_stack_test.cpp
@@ -0,0 +1,67 @@
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#include <boost/test/unit_test.hpp>
+
+#include <sstream> // stringstream
+
+// evil hack to allow testing of private and protected data
+#define private public
+#define protected public 
+
+#include "niflib.h"
+#include "obj/NiNode.h"
+#include "obj/NiSkinInstance.h"
+#include "obj/NiTriStrips.h"
+#include "obj/NiTriStripsData.h"
+
+using namespace Niflib;
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(missing_link_stack_test_suite)
+
+BOOST_AUTO_TEST_CASE(missing_link_stack_simple_test)
+{
+  stringstream ss;
+  stringstream ss2;
+
+  // create a simple nif tree with a skin partition
+  NiNodeRef root = new NiNode;
+  NiNodeRef bone = new NiNode;
+  root->SetName("Root");
+  bone->SetName("Bone");
+  NiTriStripsRef shape = new NiTriStrips;
+  NiTriStripsDataRef data = new NiTriStripsData;
+  // set hierarchy
+  shape->SetData(data);
+  root->AddChild(DynamicCast<NiAVObject>(shape));
+  root->AddChild(DynamicCast<NiAVObject>(bone));
+  // bind skin to bone
+  {
+    vector<NiNodeRef> bones;
+    bones.push_back(bone);
+    shape->BindSkin(bones);
+  }
+  // write
+  list<NiObject *> missing_link_stack;
+  list<NiObjectRef> roots;
+  roots.push_back(StaticCast<NiObject>(shape));
+  BOOST_CHECK_NO_THROW(WriteNifTree(ss, roots, missing_link_stack, NifInfo(VER_20_0_0_5)));
+  bool has_root = false;
+  bool has_bone = false;
+  // check that root and bone are missing
+  for (list<NiObject *>::iterator it =  missing_link_stack.begin(); it != missing_link_stack.end(); it++) {
+    if ((*it) != NULL) {
+      if (!has_root && (*it) == root) {
+        has_root = true;
+      } else if (!has_bone && (*it) == bone) {
+        has_bone = true;
+      } else {
+        BOOST_CHECK(false);
+      }
+    };
+  }
+  BOOST_CHECK_EQUAL(has_root, true);
+  BOOST_CHECK_EQUAL(has_bone, true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
-- 
GitLab