#include "MemoryLeak.h" #include "cNBTData.h" #include // memcpy #include #include "zlib.h" #include #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_Long] = &cNBTData::ParseLong; m_ParseFunctions[TAG_Double] = &cNBTData::ParseDouble; m_ParseFunctions[TAG_Float] = &cNBTData::ParseFloat; m_ParseFunctions[TAG_String] = &cNBTData::ParseString; m_ParseFunctions[TAG_List] = &cNBTData::ParseList; m_ParseFunctions[TAG_Compound] = &cNBTData::ParseCompound; m_ParseFunctions[TAG_ByteArray] = &cNBTData::ParseByteArray; m_BufferSize = a_BufferSize; m_Buffer = new char[m_BufferSize]; // Make a copy of the buffer memcpy( m_Buffer, a_Buffer, m_BufferSize ); m_Index = 0; tm = false; //tm to true will print more information for test mode if (m_BufferSize == 82659) { // tm = true; } m_CurrentCompound = this; m_bDecompressed = true; } 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 );//re const int MAXNBTSIZE = 1024 * 1024 * 120; 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");//re } if(m_Buffer) { delete [] m_Buffer; m_Buffer = 0; } //printf("Compressed size: %i\n", have );//re 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 );//re const int MAXNBTSIZE = 1024 * 1024 * 120 ; 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 );//re 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");//re 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 ); } for( DoubleMap::iterator itr = m_Doubles.begin(); itr != m_Doubles.end(); itr++ ) { a_Buffer.push_back( TAG_Double ); 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 ); } for( FloatMap::iterator itr = m_Floats.begin(); itr != m_Floats.end(); itr++ ) { a_Buffer.push_back( TAG_Float ); 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 ); } for( LongMap::iterator itr = m_Longs.begin(); itr != m_Longs.end(); itr++ ) { a_Buffer.push_back( TAG_Long ); 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("%sCOMPOUND (%s)\n", Prefix, a_Name.c_str() ); else printf("%sCOMPOUND (...)\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( StringMap::iterator itr = m_Strings.begin(); itr != m_Strings.end(); itr++ ) { printf("%s STRING %s (%s)\n", Prefix, itr->first.c_str(), itr->second.c_str() ); } 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( FloatMap::iterator itr = m_Floats.begin(); itr != m_Floats.end(); itr++ ) { printf("%s FLOAT %s (%f)\n", Prefix, itr->first.c_str(), itr->second ); } for( LongMap::iterator itr = m_Longs.begin(); itr != m_Longs.end(); itr++ ) { printf("%s LONG %s (%lli)\n", Prefix, itr->first.c_str(), itr->second ); } for( DoubleMap::iterator itr = m_Doubles.begin(); itr != m_Doubles.end(); itr++ ) { printf("%s Double %s (%f)\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 ); } for( ByteArrayMap::iterator itr = m_ByteArrays.begin(); itr != m_ByteArrays.end(); itr++ ) { printf("%s BYTE ARRAY %s (length: %li)\n", Prefix, itr->first.c_str(), sizeof(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(); //printf("m_BufferSize1: %i\n", m_BufferSize);//re //for(unsigned int i = 0; i < m_BufferSize; i++)//re //{//re // printf("%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] );//re //}//re } void cNBTData::ParseData() { if(!m_bDecompressed) { printf("WARNING: ParseData() called while data was not decompressed\n"); return; } m_Index = 0; //printf("m_BufferSize2: %i\n", m_BufferSize);//re //printf("cNBTData::ParseData()\n");//re //for(unsigned int i = 0; i < m_BufferSize; i++)//re //for(unsigned int i = 0; i < 70; i++)//re //{//re // printf("echo%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] );//re //}//re while( m_Index < m_BufferSize ) { if (tm) { printf("m_BufferSize3: %i\n", m_BufferSize); printf("m_Index: %i\n", m_Index); } ParseTags(); } delete [] m_Buffer; m_Buffer = 0; m_BufferSize = 0; } 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] );//re ENUM_TAG Tag = (ENUM_TAG)m_Buffer[m_Index]; if( Tag > 0 && m_ParseFunctions[ Tag ] ) { //printf("m_BufferSize4: %i\n", m_BufferSize); //printf("m_Index1: %i\n\n\n\n", m_Index); m_Index++; if (tm) { printf("Tag: %i\n", Tag); } (*this.*m_ParseFunctions[ Tag ])(true); } else if( Tag == TAG_End ) { if (tm) { printf("Tag End\n"); int n; std::cin >> n; } 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() );//re PutCompound( Name ); OpenCompound( Name ); while( m_Index < m_BufferSize && m_Buffer[ m_Index ] != TAG_End ) { ParseTags(); } CloseCompound(); m_Index++; //printf("CLOSE COMPOUND\n");//re } 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 );//re //for(unsigned int i = (m_Index-10 > 0)?m_Index-10:0 ; i < m_Index+10 && i < m_BufferSize; i++)//re //{//re //printf("%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] );//re //}//re if (tm) { printf("List Name, tag, length: %s, %i, %i\n", Name.c_str(), (int)TagType, Length); } 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); } } if (tm) { printf("List Done Name, tag, length: %s, %i, %i\n", Name.c_str(), (int)TagType, Length); } CloseList(); } void cNBTData::ParseByte( bool a_bNamed ) { std::string Name; if( a_bNamed ) Name = ReadName(); char Value = ReadByte(); PutByte( Name, Value ); if (tm) { printf("BYTE: %s %i\n", Name.c_str(), Value );//re } } void cNBTData::ParseShort( bool a_bNamed ) { std::string Name; if( a_bNamed ) Name = ReadName(); short Value = ReadShort(); PutShort( Name, Value ); if (tm) { printf("SHORT: %s %i\n", Name.c_str(), Value );//re } } void cNBTData::ParseInt( bool a_bNamed ) { std::string Name; if( a_bNamed ) Name = ReadName(); int Value = ReadInt(); PutInteger( Name, Value ); if (tm) { printf("INT: %s %i\n", Name.c_str(), Value );//re } } void cNBTData::ParseLong( bool a_bNamed ) { if (tm) { for(unsigned int i = (m_Index-10 > 0)?m_Index-10:0 ; i < m_Index+30 && i < m_BufferSize; i++) { printf("%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] ); } } std::string Name; if( a_bNamed ) Name = ReadName(); long long Value = ReadLong(); //PutInteger( Name, (int)Value ); PutLong( Name, Value ); if (tm) { printf("LONG: %s %lli\n", Name.c_str(), Value );//re } } void cNBTData::ParseDouble( bool a_bNamed ) { if (tm) { for(unsigned int i = (m_Index-10 > 0)?m_Index-10:0 ; i < m_Index+30 && i < m_BufferSize; i++) { printf("%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] ); } } std::string Name; if( a_bNamed ) Name = ReadName(); double Value = ReadDouble(); //PutInteger( Name, (int)Value ); PutDouble( Name, Value ); if (tm) { printf("Double: %s %f\n", Name.c_str(), Value );//re } } void cNBTData::ParseFloat( bool a_bNamed ) { if (tm) { for(unsigned int i = (m_Index-10 > 0)?m_Index-10:0 ; i < m_Index+30 && i < m_BufferSize; i++) { printf("%02i %02x %3i %c\n", i, (unsigned char)m_Buffer[i], (unsigned char)m_Buffer[i], m_Buffer[i] ); } } std::string Name; if( a_bNamed ) Name = ReadName(); float Value = ReadFloat(); //PutInteger( Name, (int)Value ); PutFloat( Name, Value ); if (tm) { printf("Float: %s %f\n", Name.c_str(), Value );//re } } void cNBTData::ParseString( bool a_bNamed ) { std::string Name; if( a_bNamed ) Name = ReadName(); std::string String = ReadName(); PutString( Name, String ); if (tm) { printf("STRING: %s (%s)\n", Name.c_str(), String.c_str() );//re } } void cNBTData::ParseByteArray( bool a_bNamed ) { std::string Name; if( a_bNamed ) Name = ReadName(); int Length = ReadInt(); std::string String; char* ByteArray = 0; if( Length > 0 ) { ByteArray = new char[ Length ]; memcpy( ByteArray, &m_Buffer[ m_Index ], Length ); m_Index += Length; } PutByteArray( Name, ByteArray ); if (tm) { 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] ); } } } std::string cNBTData::ReadName() { //printf("crui1 \n"); short Length = ReadShort(); //printf("crui Length: %i\n", Length); 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 ); } long long cNBTData::ReadLong() { if (tm) { printf( "here1 : %i, m_Index: %i\n", (int)sizeof(long long), (int)m_Index ); } long long Value = 0; memcpy( &Value, m_Buffer+m_Index, sizeof(long long) ); m_Index+=sizeof(long long); if (tm) { printf( "here2 : %i, m_Index: %i\n", (int)sizeof(long long), (int)m_Index ); } return Value; } double cNBTData::ReadDouble() { double Value = 0; memcpy( &Value, m_Buffer+m_Index, sizeof(double) ); m_Index+=sizeof(double); return Value; } float cNBTData::ReadFloat() { float Value = 0; memcpy( &Value, m_Buffer+m_Index, sizeof(float) ); m_Index+=sizeof(float); return 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 ); } } void cNBTCompound::PutFloat( std::string Name, float Value ) { if( m_CurrentList ) m_CurrentList->AddToList( (void*)((unsigned int*)&Value) ); else m_Floats[Name] = Value; } 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(); // Close ALL the compounds!! m_CurrentCompound->Clear(); // This recursively clears all compounds 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(); for( ByteArrayMap::iterator itr = m_ByteArrays.begin(); itr != m_ByteArrays.end(); itr++ ) { if( itr->second == 0 ) continue; delete [] itr->second; itr->second = 0; } m_ByteArrays.clear(); // Don't really have to do this, but meh m_Bytes.clear(); m_Shorts.clear(); m_Integers.clear(); m_Longs.clear(); m_Doubles.clear(); m_Floats.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(); }