diff --git a/niflib.cpp b/niflib.cpp index 313545380af8b9c35382b88beebf1bd509ac2530..f32beac70d074de987b2b0d473bed08f897d0dfd 100644 --- a/niflib.cpp +++ b/niflib.cpp @@ -1006,3 +1006,103 @@ IPosData * QueryPosData ( blk_ref & block ) { IPosData const * QueryPosData ( blk_ref const & block ) { return (IPosData const *)block->QueryInterface( ID_POS_DATA ); } + +//--Kfm Functions--// + +void KfmEventString::Read( istream & in, unsigned int version ) { + unk_int = ReadUInt(in); + event = ReadString(in); +}; + +void KfmEventString::Write( ostream & out, unsigned int version ) { + WriteUInt(unk_int, out); + WriteString(event, out); +}; + +void KfmEvent::Read( istream & in, uint version ) { + id = ReadUInt(in); + type = ReadUInt(in); + if ( type != 5 ) { + unk_float = ReadFloat(in); + event_strings.resize(ReadUInt(in)); + for ( vector<KfmEventString>::iterator it = event_strings.begin(); it != event_strings.end(); it++ ) it->Read(in, version); + unk_int3 = ReadUInt(in); + }; +}; + +void KfmAction::Read( istream & in, uint version ) { + if ( version <= VER_KFM_1_2_4b ) action_name = ReadString(in); + action_filename = ReadString(in); + unk_int1 = ReadUInt(in); + events.resize(ReadUInt(in)); + for ( vector<KfmEvent>::iterator it = events.begin(); it != events.end(); it++ ) it->Read(in, version); + unk_int2 = ReadUInt(in); +}; + +unsigned int Kfm::Read( string const & file_name ) { + ifstream in( file_name.c_str(), ifstream::binary ); + unsigned int version = Read(in); + if ( in.eof() ) + throw runtime_error("End of file reached prematurely. This KFM may be corrupt or improperly supported."); + ReadByte( in ); // this should fail, and trigger the in.eof() flag + if ( ! in.eof() ) + throw runtime_error("End of file not reached. This KFM may be corrupt or improperly supported."); + return version; +}; + +unsigned int Kfm::Read( istream & in ) { + //--Read Header--// + char header_string[64]; + in.getline( header_string, 64 ); + string headerstr(header_string); + + // make sure this is a KFM file + if ( headerstr.substr(0, 26) != ";Gamebryo KFM File Version" ) { + version = VER_INVALID; + return version; + }; + + // supported versions + if ( headerstr == ";Gamebryo KFM File Version 2.0.0.0b" ) version = VER_KFM_2_0_0_0b; + else if ( headerstr == ";Gamebryo KFM File Version 1.2.4b" ) version = VER_KFM_1_2_4b; + //else if ( headerstr == ";Gamebryo KFM File Version 1.0" ) version = VER_KFM_1_0; + //else if ( headerstr == ";Gamebryo KFM File Version 1.0\r" ) version = VER_KFM_1_0; // Windows eol style + else { + version = VER_UNSUPPORTED; + return version; + }; + + //--Read remainder--// + if (version == VER_KFM_1_0) { + // TODO write a parser + } else { + if (version >= VER_KFM_2_0_0_0b) unk_byte = ReadByte(in); + else unk_byte = 1; + nif_file_name = ReadString(in); + master = ReadString(in); + unk_int1 = ReadUInt(in); + unk_int2 = ReadUInt(in); + unk_float1 = ReadFloat(in); + unk_float2 = ReadFloat(in); + actions.resize(ReadUInt(in)); + unk_int3 = ReadUInt(in); + for ( vector<KfmAction>::iterator it = actions.begin(); it != actions.end(); it++ ) it->Read(in, version); + }; + return version; +}; + +/* +void Kfm::Write( ostream & out, uint version ) { + if ( version == VER_KFM_1_0 ) { + // handle this case seperately + out << ";Gamebryo KFM File Version 1.0" << endl; + // TODO write the rest of the data + } else { + if ( version == VER_KFM_1_2_4b ) + out.write(";Gamebryo KFM File Version 1.2.4b\n", 34); + else if ( version == VER_KFM_2_0_0_0b ) + out.write(";Gamebryo KFM File Version 2.0.0.0b\n", 37); + else throw runtime_error("Cannot write KFM file of this version."); + }; +}; +*/ \ No newline at end of file diff --git a/niflib.h b/niflib.h index b8cbd2be90f3f86aec22e777a16c32e684764e70..ab006845efeab5b88df9c97456b29c5fe5a7a941 100644 --- a/niflib.h +++ b/niflib.h @@ -231,11 +231,25 @@ enum PixelFormat { * <b>Example:</b> * \code * unsigned int ver = CheckNifHeader("test_in.nif"); + * if ( ver == VER_UNSUPPORTED ) cout << "unsupported" << endl; + * else if ( ver == VER_INVALID ) cout << "invalid" << endl; + * else { + * vector<blk_ref> blocks = ReadNifList( "test_in.nif" ); + * cout << blocks[0] << endl; + * }; + * * \endcode * * <b>In Python:</b> * \code * ver = CheckNifHeader("test_in.nif") + * if ( ver == VER_UNSUPPORTED ): + * print "unsupported" + * elif ( ver == VER_INVALID ): + * print "invalid" + * else: + * blocks = ReadNifList( "test_in.nif" ) + * print blocks[0] * \endcode */ unsigned int CheckNifHeader( string const & file_name ); @@ -3331,6 +3345,92 @@ struct TexDesc { float unknownFloat2; /*!< An unknown floating point value that exists from version 10.1.0.0 on. */ }; +//--KFM File Format--// + +//KFM Versions +const unsigned int VER_KFM_1_0 = 0x01000000; /*!< Kfm Version 1.0 */ +const unsigned int VER_KFM_1_2_4b = 0x01020400; /*!< Kfm Version 1.2.4b */ +const unsigned int VER_KFM_2_0_0_0b = 0x02000000; /*!< Kfm Version 2.0.0.0b */ + +//KFM Data Structure + +struct KfmEventString { + unsigned int unk_int; + string event; + + KfmEventString() : unk_int(0), event() {}; + void Read( istream & in, unsigned int version ); + void Write( ostream & out, unsigned int version ); +}; + +struct KfmEvent { + unsigned int id; + unsigned int type; + float unk_float; + vector<KfmEventString> event_strings; + unsigned int unk_int3; + + KfmEvent() : id(0), type(0), unk_float(0.5f), event_strings(), unk_int3(0) {}; + void Read( istream & in, unsigned int version ); + //void Write( ostream & out, unsigned int version ); +}; + +struct KfmAction { + string action_name; + string action_filename; + unsigned int unk_int1; + vector<KfmEvent> events; + unsigned int unk_int2; + + void Read( istream & in, unsigned int version ); + //void Write( ostream & out, unsigned int version ); +}; + +struct Kfm { + unsigned int version; + unsigned char unk_byte; + string nif_file_name; + string master; + unsigned int unk_int1; + unsigned int unk_int2; + float unk_float1; + float unk_float2; + unsigned int unk_int3; + vector<KfmAction> actions; + + /*! + * Reads the given file and returns the KFM version. + * \param file_name The input file name. + * \return The KFM version of the file, in hexadecimal format. If the file is not a KFM file, it returns VER_INVALID. If it is a KFM file, but its version is not supported by the library, it returns VER_UNSUPPORTED. + * + * <b>Example:</b> + * \code + * Kfm kfm; + * unsigned int ver = kfm.Read( "test_in.kfm" ); + * if ( ver == VER_UNSUPPORTED ) cout << "unsupported" << endl; + * else if ( ver == VER_INVALID ) cout << "invalid" << endl; + * else cout << "Describes keyframes for NIF file " << kfm.nif_file_name << "." << endl; + * + * \endcode + * + * <b>In Python:</b> + * \code + * kfm = Kfm() + * ver = kfm.Read( "test_in.kfm" ) + * if ( ver == VER_UNSUPPORTED ): + * print "unsupported" + * elif ( ver == VER_INVALID ): + * print "invalid" + * else: + * print "Describes keyframes for NIF file %s."%kfm.nif_file_name + * \endcode + */ + unsigned int Read( string const & file_name ); // returns Kfm version + unsigned int Read( istream & in ); // returns Kfm version + //void Write( string const & file_name, unsigned int version ); + //void Write( ostream & out, unsigned int version ); +}; + //--USER GUIDE DOCUMENTATION--// /*! \mainpage Niflib Documentation