diff --git a/nif/.gitignore b/nif/.gitignore new file mode 100644 index 000000000..731498d9a --- /dev/null +++ b/nif/.gitignore @@ -0,0 +1 @@ +old_d diff --git a/nif/nif_file.h b/nif/nif_file.h new file mode 100644 index 000000000..cab3ff96c --- /dev/null +++ b/nif/nif_file.h @@ -0,0 +1,180 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008-2010 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.sourceforge.net/ + + This file (nif_file.h) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +#ifndef _NIF_FILE_H_ +#define _NIF_FILE_H_ + +#include +#include "../mangle/stream/stream.h" +#include "../mangle/stream/filters/buffer_stream.h" +#include "../mangle/tools/str_exception.h" +#include "../tools/stringops.h" + +#include + +// Only used during development. Remove later. +#include +using namespace std; + +using namespace Mangle::Stream; + +// A simple array implementation containing a pointer and a +// length. Used for holding slices into a data buffer. +#include +template +struct SliceArray +{ + const T* ptr; + size_t length; + + SliceArray(const T* _ptr, size_t _length) + : ptr(_ptr), length(_length) {} + + bool operator==(SliceArray &t) + { + return + length == t.length && + (memcmp(ptr,t.ptr, length*sizeof(T)) == 0); + } + + /// Only use this for stings + bool operator==(const char* str) + { + return + str[length] == 0 && + (strncmp(ptr, str, length) == 0); + } + + /** This allocates a copy of the data. Only use this for debugging + and error messages. + */ + std::string toString() + { return std::string(ptr,length); } +}; + +typedef SliceArray SString; +typedef SliceArray IntArray; +typedef SliceArray FloatArray; + +class NIFFile +{ + enum NIFVersion + { + VER_MW = 0x04000002 // Morrowind NIFs + }; + + /// Nif file version + int ver; + + /// Input stream + StreamPtr inp; + + /// File name, used for error messages + std::string filename; + + /// Record list + typedef void NifRecord; + std::vector records; + + /// Used for error handling + void fail(const std::string &msg) + { + std::string err = "NIFFile Error: " + msg; + err += "\nFile: " + filename; + throw str_exception(err); + } + + /// Parse the file + void parse() + { + // Check the header string + const char* head = getString(40); + if(!begins(head, "NetImmerse File Format")) + fail("Invalid NIF header"); + + // Get BCD version + ver = getInt(); + if(ver != VER_MW) + fail("Unsupported NIF version"); + + // Number of records + int recNum = getInt(); + records.resize(recNum); + + for(int i=0;i X getType() { return *((X*)inp->getPtr(sizeof(X))); } + int getInt() { return getType(); } + + template + SliceArray getArray() + { + int len = getInt(); + return SliceArray((const X*)inp->getPtr(len), len); + } + + SString getString() { return getArray(); } + + const char *getString(int size) + { return (const char*)inp->getPtr(size); } +}; + +#endif diff --git a/nif/tests/.gitignore b/nif/tests/.gitignore new file mode 100644 index 000000000..55c42ffa1 --- /dev/null +++ b/nif/tests/.gitignore @@ -0,0 +1,3 @@ +niftool +*_test +*.nif diff --git a/nif/tests/Makefile b/nif/tests/Makefile new file mode 100644 index 000000000..cf5ccf390 --- /dev/null +++ b/nif/tests/Makefile @@ -0,0 +1,9 @@ +GCC=g++ + +all: niftool + +niftool: niftool.cpp ../nif_file.h + $(GCC) $< ../../tools/stringops.cpp -o $@ + +clean: + rm niftool diff --git a/nif/tests/niftool.cpp b/nif/tests/niftool.cpp new file mode 100644 index 000000000..624231a99 --- /dev/null +++ b/nif/tests/niftool.cpp @@ -0,0 +1,23 @@ +#include "../nif_file.h" + +/* + Test of the NIFFile class + */ + +#include +#include "../../mangle/stream/servers/file_stream.h" + +using namespace Mangle::Stream; +using namespace std; + +int main(int argc, char **args) +{ + if(argc != 2) + { + cout << "Specify a NIF file on the command line\n"; + return 1; + } + + StreamPtr file(new FileStream(args[1])); + NIFFile nif(file, args[1]); +} diff --git a/nif/tests/test.sh b/nif/tests/test.sh new file mode 100755 index 000000000..b1ca6f1a6 --- /dev/null +++ b/nif/tests/test.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +make || exit + +mkdir -p output + +PROGS=*_test + +for a in $PROGS; do + if [ -f "output/$a.out" ]; then + echo "Running $a:" + $a | diff output/$a.out - + else + echo "Creating $a.out" + $a > "output/$a.out" + git add "output/$a.out" + fi +done diff --git a/tools/stringops.cpp b/tools/stringops.cpp new file mode 100644 index 000000000..f009cabf6 --- /dev/null +++ b/tools/stringops.cpp @@ -0,0 +1,14 @@ +#include "stringops.h" + +/// Returns true if str1 begins with substring str2 +bool begins(const char* str1, const char* str2) +{ + while(*str2) + { + if(*str1 == 0 || *str1 != *str2) return false; + + str1++; + str2++; + } + return true; +} diff --git a/tools/stringops.h b/tools/stringops.h new file mode 100644 index 000000000..575791dff --- /dev/null +++ b/tools/stringops.h @@ -0,0 +1,7 @@ +#ifndef __STRINGOPS_H +#define __STRINGOPS_H + +/// Returns true if str1 begins with substring str2 +bool begins(const char* str1, const char* str2); + +#endif