From 625a4accdad2e6acfe1135634cb32ee149415645 Mon Sep 17 00:00:00 2001 From: "admin@omencraft.com" Date: Sat, 29 Oct 2011 21:19:06 +0000 Subject: Added denotch map converter. Program currently reads the only mcr file in the region dir and writes the uncompressed chunk data in world/X0-Z0.pak. I compile in linux with "g++ cConvert.cpp -lz -o denotch" git-svn-id: http://mc-server.googlecode.com/svn/trunk@20 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- converter/cNBTData.cpp | 700 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 700 insertions(+) create mode 100644 converter/cNBTData.cpp (limited to 'converter/cNBTData.cpp') diff --git a/converter/cNBTData.cpp b/converter/cNBTData.cpp new file mode 100644 index 000000000..9bc25b789 --- /dev/null +++ b/converter/cNBTData.cpp @@ -0,0 +1,700 @@ +#include "cNBTData.h" +#include // memcpy +#include +#include "zlib.h" +#include + +#ifndef _WIN32 +#include +#include +#endif + +#ifdef _WIN32 +#include +#endif + +cNBTData::~cNBTData() +{ + // TODO: Delete all compounds and stuff in it + Clear(); +} + +cNBTData::cNBTData( char* a_Buffer, unsigned int a_BufferSize ) + : cNBTCompound( 0 ) +{ + m_NumUnnamedElements = 0; + for(int i = 0; i < TAG_NumTags; i++) + { + m_ParseFunctions[i] = 0; + } + m_ParseFunctions[TAG_Byte] = &cNBTData::ParseByte; + m_ParseFunctions[TAG_Short] = &cNBTData::ParseShort; + m_ParseFunctions[TAG_Int] = &cNBTData::ParseInt; + m_ParseFunctions[TAG_String] = &cNBTData::ParseString; + m_ParseFunctions[TAG_List] = &cNBTData::ParseList; + m_ParseFunctions[TAG_Compound] = &cNBTData::ParseCompound; + + + m_Buffer = a_Buffer; + m_BufferSize = a_BufferSize; + m_Index = 0; + + m_CurrentCompound = this; + + m_bDecompressed = false; +} + +bool cNBTData::OpenCompound( std::string a_Name ) +{ + cNBTCompound* Compound = GetCompound( a_Name ); + if( Compound ) + { + m_CurrentCompound = Compound; + return true; + } + printf("WARNING: Could not open NBT Compound %s\n", a_Name.c_str() ); + return false; +} + +bool cNBTData::CloseCompound() +{ + if( m_CurrentCompound->GetParentCompound() ) + { + m_CurrentCompound = m_CurrentCompound->GetParentCompound(); + return true; + } + printf("WARNING: Could not close NBT Compound, already at root!\n" ); + return false; +} + +bool cNBTCompound::OpenList( std::string a_Name ) +{ + if( GetList( a_Name ) ) + { + m_CurrentList = GetList( a_Name ); + return true; + } + printf("WARNING: Could not open NBT List %s\n", a_Name.c_str() ); + return false; +} + +bool cNBTCompound::CloseList() +{ + if( m_CurrentList ) + { + m_CurrentList = m_CurrentList->GetParentList(); + return true; + } + printf("WARNING: Could not close NBT List, no list open!\n" ); + return false; +} + +bool cNBTData::OpenList( std::string a_Name ) +{ + return m_CurrentCompound->OpenList( a_Name ); +} + +bool cNBTData::CloseList() +{ + return m_CurrentCompound->CloseList(); +} + +void cNBTData::Compress() +{ + //printf("Before Compress size: %i\n", m_BufferSize ); + const int MAXNBTSIZE = 1024 * 2; + + int ret; + unsigned have; + z_stream strm; + unsigned char* Compressed = new unsigned char[MAXNBTSIZE]; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = m_BufferSize; + strm.avail_out = MAXNBTSIZE; + strm.next_in =(Bytef*)m_Buffer; + strm.next_out = Compressed; + strm.total_in = 0; + strm.total_out = 0; + ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15+MAX_WBITS, 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) + { + printf("deflateInit2 returned NOT OK\n"); + return; + } + + + + /* run deflate() on input until output buffer not full, finish + compression if all of source has been read in */ + + ret = deflate(&strm, Z_FULL_FLUSH); /* no bad return value */ + if( ret != Z_OK ) + { + printf("WARNING: deflate returned NOT OK\n"); + } + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + have = strm.total_out; + + assert(strm.avail_in == 0); /* all input will be used */ + + if( ret != Z_STREAM_END ) + { + //printf("WARNING: Compressing didn't go to end of stream\n"); + } + + if(m_Buffer) + { + delete [] m_Buffer; + m_Buffer = 0; + } + + //printf("Compressed size: %i\n", have ); + + m_BufferSize = have; + m_Buffer = new char[ m_BufferSize ]; + memcpy( m_Buffer, Compressed, m_BufferSize ); + delete Compressed; + + /* clean up and return */ + deflateEnd(&strm); + m_bDecompressed = false; + return; +} + +bool cNBTData::Decompress() +{ + if( m_bDecompressed ) + { + printf("WARNING: Decompress called, while it has already been decompressed\n"); + return false; + } + if( m_BufferSize == 0 ) + { + printf("WARNING: Decompress called, with m_BufferSize of 0\n"); + return false; + } + + //printf("Before Decompress size: %i\n", m_BufferSize ); + + const int MAXNBTSIZE = 1024 * 2; + + int ret; + z_stream strm; + unsigned char* out = new unsigned char[MAXNBTSIZE]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = Z_NULL; + strm.next_in = Z_NULL; + strm.avail_in = m_BufferSize; + strm.avail_out = Z_NULL; + strm.next_in = (Bytef*)m_Buffer; + strm.next_out = Z_NULL; + strm.avail_out = MAXNBTSIZE; + strm.next_out = out; + strm.total_in = 0; + strm.total_out = 0; + + ret = inflateInit2(&strm, 16+MAX_WBITS); + if (ret != Z_OK) + { + printf("inflateInit2 returned NOT OK\n"); + delete out; + return false; + } + + if( (ret = inflate(&strm, Z_NO_FLUSH)) != Z_STREAM_END) + { + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + printf("ret != Z_STREAM_END\n"); + } + unsigned UncompressedSize = strm.total_out; //MAXNBTSIZE - strm.avail_out; + + m_Buffer = new char[ UncompressedSize ]; + memcpy( m_Buffer, out, UncompressedSize ); + m_BufferSize = UncompressedSize; + + inflateEnd(&strm); + delete [] out; + + if( ret != Z_STREAM_END ) + { + printf("WARNING: NBT Data received was too big! (More than %i bytes)\n", MAXNBTSIZE); + } + + //printf("Decompressed Size: %i\n", UncompressedSize ); + m_bDecompressed = true; + return (ret == Z_STREAM_END) ? true : false; +} + +void cNBTCompound::AppendShort( std::string & a_Buffer, short a_Value ) +{ + a_Buffer.push_back( (char)((a_Value>>8)&0xff) ); + a_Buffer.push_back( (char)((a_Value)&0xff) ); +} + +void cNBTCompound::AppendInteger( std::string & a_Buffer, int a_Value ) +{ + int NetVal = htonl( a_Value ); + a_Buffer.append( (char*)&NetVal, sizeof( int ) ); +} + +void cNBTCompound::Serialize(std::string & a_Buffer) +{ + //printf("cNBTCompound::Serialize()\n"); + for( CompoundMap::iterator itr = m_Compounds.begin(); itr != m_Compounds.end(); itr++ ) + { + if( itr->second == 0 ) continue; + a_Buffer.push_back( TAG_Compound ); + AppendShort( a_Buffer, (short)itr->first.size() ); + if( itr->first.size() > 0 ) + { + a_Buffer.append( itr->first.c_str(), itr->first.size() ); + } + itr->second->Serialize( a_Buffer ); + a_Buffer.push_back( TAG_End ); + } + + for( ListMap::iterator itr = m_Lists.begin(); itr != m_Lists.end(); itr++ ) + { + if( itr->second == 0 ) continue; + a_Buffer.push_back( TAG_List ); + AppendShort( a_Buffer, (short)itr->first.size() ); + if( itr->first.size() > 0 ) + { + a_Buffer.append( itr->first.c_str(), itr->first.size() ); + } + a_Buffer.push_back( (char)itr->second->GetType() ); + AppendInteger( a_Buffer, itr->second->GetSize() ); + itr->second->Serialize( a_Buffer ); + } + + for( IntegerMap::iterator itr = m_Integers.begin(); itr != m_Integers.end(); itr++ ) + { + a_Buffer.push_back( TAG_Int ); + AppendShort( a_Buffer, (short)itr->first.size() ); + if( itr->first.size() > 0 ) + { + a_Buffer.append( itr->first.c_str(), itr->first.size() ); + } + AppendInteger( a_Buffer, itr->second ); + } + + for( ShortMap::iterator itr = m_Shorts.begin(); itr != m_Shorts.end(); itr++ ) + { + a_Buffer.push_back( TAG_Short ); + AppendShort( a_Buffer, (short)itr->first.size() ); + if( itr->first.size() > 0 ) + { + a_Buffer.append( itr->first.c_str(), itr->first.size() ); + } + AppendShort( a_Buffer, itr->second ); + } + + for( ByteMap::iterator itr = m_Bytes.begin(); itr != m_Bytes.end(); itr++ ) + { + a_Buffer.push_back( TAG_Byte ); + AppendShort( a_Buffer, (short)itr->first.size() ); + if( itr->first.size() > 0 ) + { + a_Buffer.append( itr->first.c_str(), itr->first.size() ); + } + a_Buffer.push_back( itr->second ); + } +} + +void cNBTCompound::PrintData( int a_Depth, std::string a_Name ) +{ + char* Prefix = new char[a_Depth*4+1]; + for(int i = 0; i < a_Depth*4; i++) + Prefix[i] = ' '; + Prefix[ a_Depth*4 ] = 0; + + if( a_Name.size() > 0 ) + printf("%s COMPOUND (%s)\n", Prefix, a_Name.c_str() ); + else + printf("%s COMPOUND\n", Prefix ); + + delete Prefix; + a_Depth++; + Prefix = new char[a_Depth*4]; + for(int i = 0; i < a_Depth*4; i++) + Prefix[i] = ' '; + Prefix[ a_Depth*4-1 ] = 0; + + for( CompoundMap::iterator itr = m_Compounds.begin(); itr != m_Compounds.end(); itr++ ) + { + if( itr->second == 0 ) continue; + itr->second->PrintData( a_Depth, itr->first ); + } + + for( ListMap::iterator itr = m_Lists.begin(); itr != m_Lists.end(); itr++) + { + if( itr->second == 0 ) continue; + itr->second->PrintData( a_Depth, itr->first ); + } + + for( IntegerMap::iterator itr = m_Integers.begin(); itr != m_Integers.end(); itr++ ) + { + printf("%s INTEGER %s (%i)\n", Prefix, itr->first.c_str(), itr->second ); + } + + for( ShortMap::iterator itr = m_Shorts.begin(); itr != m_Shorts.end(); itr++ ) + { + printf("%s SHORT %s (%i)\n", Prefix, itr->first.c_str(), itr->second ); + } + + for( ByteMap::iterator itr = m_Bytes.begin(); itr != m_Bytes.end(); itr++ ) + { + printf("%s BYTE %s (%i)\n", Prefix, itr->first.c_str(), itr->second ); + } + + delete Prefix; +} + +void cNBTData::PrintData() +{ + printf("==== STRUCTURED NBT DATA ====\n"); + m_CurrentCompound->PrintData( 0, " " ); + printf("=============================\n"); +} + +void cNBTData::Serialize() +{ + std::string Buffer; + m_CurrentCompound->Serialize( Buffer ); + + if( m_Buffer ) + delete m_Buffer; + m_Buffer = new char[Buffer.size()]; + memcpy( m_Buffer, Buffer.c_str(), Buffer.size() ); + m_BufferSize = Buffer.size(); + +// for(unsigned int i = 0; i < m_BufferSize; i++) +// { +// printf("%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] ); +// } +} + +void cNBTData::ParseData() +{ + if(!m_bDecompressed) + { + printf("WARNING: ParseData() called while data was not decompressed\n"); + return; + } + + m_Index = 0; +// printf("cNBTData::ParseData()\n"); +// for(unsigned int i = 0; i < m_BufferSize; i++) +// { +// printf("%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] ); +// } + + while( m_Index < m_BufferSize ) + { + ParseTags(); + } +} + +void cNBTData::ParseTags() +{ + if( m_Index < m_BufferSize ) + { + //printf("ParseTags idx:%02i %02x %3i %c\n", m_Index, (unsigned char)m_Buffer[m_Index], (unsigned char)m_Buffer[m_Index], m_Buffer[m_Index] ); + unsigned char Tag = m_Buffer[m_Index]; + if( Tag > 0 && m_ParseFunctions[ Tag ] ) + { + m_Index++; + (*this.*m_ParseFunctions[ Tag ])(true); + } + else if( Tag == TAG_End ) + { + m_Index++; + } + else + { + printf("UNKNOWN TAG %x\n", m_Buffer[m_Index] ); + for(unsigned int i = (m_Index-10 > 0)?m_Index-10:0 ; i < m_Index+10 && i < m_BufferSize; i++) + { + printf("%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] ); + } + m_Index = m_BufferSize; + return; + } + } +} + +void cNBTData::ParseCompound( bool a_bNamed ) +{ + std::string Name; + if( a_bNamed ) Name = ReadName(); + //printf("OPEN COMPOUND: %s\n", Name.c_str() ); + + PutCompound( Name ); + OpenCompound( Name ); + while( m_Index < m_BufferSize && m_Buffer[ m_Index ] != TAG_End ) + { + ParseTags(); + } + CloseCompound(); + //printf("CLOSE COMPOUND\n"); +} + +void cNBTData::ParseList( bool a_bNamed ) +{ + std::string Name; + if( a_bNamed ) Name = ReadName(); + ENUM_TAG TagType = (ENUM_TAG)ReadByte(); + int Length = ReadInt(); + //printf("LIST: %s Type: %02x Length: %i\n", Name.c_str(), TagType, Length ); + +// for(unsigned int i = (m_Index-10 > 0)?m_Index-10:0 ; i < m_Index+10 && i < m_BufferSize; i++) +// { +// printf("%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] ); +// } + + PutList( Name, TagType ); + OpenList( Name ); + for(int i = 0; i < Length && m_Index < m_BufferSize; i++) + { + if( m_ParseFunctions[ TagType ] ) + { + (*this.*m_ParseFunctions[ TagType ] )(false); + m_Index++; + } + } + CloseList(); + +} + +void cNBTData::ParseByte( bool a_bNamed ) +{ + std::string Name; + if( a_bNamed ) Name = ReadName(); + char Value = ReadByte(); + + PutByte( Name, Value ); + + //printf("BYTE: %s %i\n", Name.c_str(), Value ); +} + +void cNBTData::ParseShort( bool a_bNamed ) +{ + std::string Name; + if( a_bNamed ) Name = ReadName(); + short Value = ReadShort(); + + PutShort( Name, Value ); + + //printf("SHORT: %s %i\n", Name.c_str(), Value ); +} + +void cNBTData::ParseInt( bool a_bNamed ) +{ + std::string Name; + if( a_bNamed ) Name = ReadName(); + int Value = ReadInt(); + + PutInteger( Name, Value ); + + //printf("INT: %s %i\n", Name.c_str(), Value ); +} + +void cNBTData::ParseString( bool a_bNamed ) +{ + std::string Name; + if( a_bNamed ) Name = ReadName(); + std::string String = ReadName(); + + PutString( Name, String ); + + //printf("STRING: %s (%s)\n", Name.c_str(), String.c_str() ); +} + +std::string cNBTData::ReadName() +{ + short Length = ReadShort(); + + std::string Name; + if( Length > 0 ) + { + for(int i = 0; i < Length; i++, m_Index++) + { + Name.push_back( m_Buffer[m_Index] ); + } + } + return Name; +} + +char cNBTData::ReadByte() +{ + unsigned char Byte = m_Buffer[ m_Index ]; m_Index++; + return Byte; +} + +short cNBTData::ReadShort() +{ + short Length = 0; + Length |= m_Buffer[ m_Index ] << 8; m_Index++; + Length |= m_Buffer[ m_Index ]; m_Index++; + return Length; +} + +int cNBTData::ReadInt() +{ + int Value = 0; + memcpy( &Value, m_Buffer+m_Index, sizeof(int) ); + m_Index+=sizeof(int); + + return ntohl( Value ); +} + +void cNBTCompound::PutList( std::string Name, ENUM_TAG Type ) +{ + m_Lists[Name] = new cNBTList( m_CurrentList, Type ); +} + +void cNBTCompound::PutCompound( std::string Name ) +{ + if( m_CurrentList ) + { + m_CurrentList->AddToList( new cNBTCompound( this ) ); + } + else + { + m_Compounds[Name] = new cNBTCompound( this ); + } +} + +cNBTCompound* cNBTCompound::GetCompound( std::string Name ) +{ + if( m_CurrentList ) + { + if( m_CurrentList->GetType() != TAG_Compound ) + return 0; + + return (cNBTCompound*)m_CurrentList->GetLastElement(); + } + return m_Compounds[Name]; +} + +void cNBTList::PrintData(int a_Depth, std::string a_Name) +{ + char* Prefix = new char[a_Depth*4]; + for(int i = 0; i < a_Depth*4; i++) + Prefix[i] = ' '; + Prefix[ a_Depth*4-1 ] = 0; + + if( a_Name.size() > 0 ) + printf("%s LIST (%s)\n", Prefix, a_Name.c_str() ); + else + printf("%s LIST\n", Prefix ); + + delete [] Prefix; + + for( VoidList::iterator itr = m_List.begin(); itr != m_List.end(); itr++) + { + switch( m_Type ) + { + case cNBTCompound::TAG_Compound: + { + ((cNBTCompound*)*itr)->PrintData(a_Depth+1, "..."); + } + break; + default: + break; + } + } +} + +void cNBTList::Serialize(std::string & a_Buffer) +{ + for( VoidList::iterator itr = m_List.begin(); itr != m_List.end(); itr++ ) + { + switch( m_Type ) + { + case cNBTCompound::TAG_Compound: + { + ((cNBTCompound*)(*itr))->Serialize( a_Buffer ); + a_Buffer.push_back( cNBTCompound::TAG_End ); + } + break; + default: + break; + } + } +} + +void cNBTData::Clear() +{ + while( m_CurrentCompound != this ) CloseCompound(); + m_CurrentCompound->Clear(); + + if( m_Buffer ) + { + delete m_Buffer; + m_Buffer = 0; + } + m_BufferSize = 0; +} + +void cNBTCompound::Clear() +{ + for( CompoundMap::iterator itr = m_Compounds.begin(); itr != m_Compounds.end(); itr++ ) + { + if( itr->second == 0 ) continue; + itr->second->Clear(); + delete itr->second; + itr->second = 0; + } + m_Compounds.clear(); + + for( ListMap::iterator itr = m_Lists.begin(); itr != m_Lists.end(); itr++ ) + { + if( itr->second == 0 ) continue; + itr->second->Clear(); + delete itr->second; + itr->second = 0; + } + m_Lists.clear(); + m_Bytes.clear(); + m_Shorts.clear(); + m_Integers.clear(); + m_Strings.clear(); +} + +void cNBTList::Clear() +{ + for( VoidList::iterator itr = m_List.begin(); itr != m_List.end(); itr++) + { + switch( m_Type ) + { + case cNBTCompound::TAG_Compound: + { + cNBTCompound* Compound = (cNBTCompound*)(*itr); + Compound->Clear(); + delete Compound; + *itr = 0; + } + break; + case cNBTCompound::TAG_List: + { + cNBTList* List = (cNBTList*)(*itr); + List->Clear(); + delete List; + *itr = 0; + } + break; + default: + break; + } + } + m_List.clear(); +} -- cgit v1.2.3