The map files use a named-binary-tag format that is gzipped with zlib.
I'm a windows programmer and a C++ programmer, so naturally I am working with the self-built zlib using gzstream. My problem is that it doesn't work.
The code compiles beautifully, but even when fed a known valid gz file (tested via 7zip), it returns a true bad() call. I've tried every file path combination I can think of, relative, absolute, drive-root, and I simply cannot get this thing to work.
I could use some help on this one, I'll post my code, but really, I need a starting point. Others on the internet have had similar problems, but as far as I know gzstream support is limited, and most people seem to be programming in straight-up C.
So here are the files in this order:
<MCmapper.h>
<MCmapper.cpp>
<nbtdef.h>
<nbtdef.cpp>
#ifndef _MCMAPPER_H_#define _MCMAPPER_H_//#include <wx/dir.h>#include "nbtdef.h"//#include <string>//DATA MAPPINGSenum blocks{ air = 0, stone, grass, dirt, cobble, board, sapling, bedrock, water1, water2, lava1, lava2, sand, shale, gold, iron, coal, wood, leaf, sponge, glass, c_r, c_o, c_y, c_l, c_g, c_ag, c_cy, c_b, c_p, c_in, c_vi, c_ma, c_pi, c_bl, c_gr, c_w, f_y, f_r, m_b, m_r, gold_b, iron_b, dstep, step, brick, tnt, shelf, moss, obsidian, torch, fire, mod, stair_w, chest, wire, diamond, diamond_b, workbench, crops, soil, furnace, furnace_b, sign, door, ladder, rail, stairs_s, sign_w, lever, plate_s, door_i, redstone, redstone_g, torch_r, torch_r_o, button, snow, ice, snow_b, cactus, clay, reed, phonograph, fence, pumpkin, netherstone, slow, lightstone, portal, jac_o_lantern};class CHUNK{protected: int x; int z; short blocks[16][16][128]; //X, Z, Ypublic: CHUNK();};void EnumerateChunks(std::string filename);#endif
// MCmapper.cpp : Defines the entry point for the console application.//##include <wx/dir.h>#include <wx/filefn.h>#include <wx/arrstr.h>#include "MCmapper.h"void EnumerateChunks(std::string fname, wxArrayString &files, size_t &sz){ wxDir dir(wxGetCwd()); if(!dir.IsOpened()){ return; } //Enumerate files in directory wxString filename(fname.c_str(), wxConvUTF8); if(!dir.Open(filename)) return; sz = dir.GetAllFiles(filename,&files); //We now have every chunk file in the string array. We need to open each file //read the chunk data and build the surface array //for(int i = 0; i < sz-2; i++){ // std::cout << std::string(files.mb_str()) << std::endl; //} //char a; //std::cin >> a;}void NBTDUMP(wxString file, size_t sz, std::string fileout){ //READ THE FILE WITH AN NBT FILE char buf[1024];//MAX 1024 length strcpy(buf,(const char*) file.mb_str(wxConvUTF8)); std::string str(buf); nbt_file f; //f.ReadFile(buf); f.ReadFile(buf); std::ofstream files; files.open(fileout.c_str()); if(files.is_open()){ //Begin dump std::string str; for(std::vector<nbt_tag>::iterator iter = f.Begin(); iter != f.End(); ++iter){ //For every tag, print it's string //files << TypeToString(iter->GetType()) << std::endl; switch (iter->GetType()) { case nbt_type::TAG_END: str = "TAG_END"; break; case nbt_type::TAG_BYTE: str = "TAG_BYTE"; break; case nbt_type::TAG_SHORT: str = "TAG_SHORT"; break; case nbt_type::TAG_INT: str = "TAG_INT"; break; case nbt_type::TAG_LONG: str = "TAG_LONG"; break; case nbt_type::TAG_FLOAT: str = "TAG_FLOAT"; break; case nbt_type::TAG_DOUBLE: str = "TAG_DOUBLE"; break; case nbt_type::TAG_BYTE_ARRAY: str = "TAG_BYTE_ARRAY"; break; case nbt_type::TAG_STRING: str = "TAG_STRING"; break; case nbt_type::TAG_LIST: str = "TAG_LIST"; break; case nbt_type::TAG_COMPOUND: str = "TAG_COMPOUND"; break; default: str = "TAG_Unknown"; break; } files << str << std::endl; } files.close(); }}void ExtractChunk(wxArrayString files, size_t sz, CHUNK** data){ };int main(int argc, char* argv[]){ wxArrayString files; size_t s; EnumerateChunks("world",files, s); NBTDUMP(files[0],s,"dump.txt"); return 0;}
#ifndef NBTDEF_H_#define NBTDEF_H_#include <cstdint>//#define ZLIB_WINAPI#include "gzstream.h"#include <string>#include <list>#include <vector>//#include "endianness.h"#define L_ENDIAN 0#define B_ENDIAN 1int get_endianness();uint64_t swpd(double d);double uswpd(uint64_t d);float swapf(float);double swapd(double);void swaps(uint16_t *x);void swapi(uint32_t *x);void swapl(uint64_t *x);enum nbt_status{ NBT_OK = 0, NBT_ERR = -1, NBT_EMEM = -2, NBT_EGZ = -3};enum nbt_type{ TAG_END = 0, /* No name, no payload */ TAG_BYTE = 1, /* char, 8 bits, signed */ TAG_SHORT = 2, /* short, 16 bits, signed */ TAG_INT = 3, /* long, 32 bits, signed */ TAG_LONG = 4, /* long long, 64 bits, signed */ TAG_FLOAT = 5, /* float, 32 bits, signed */ TAG_DOUBLE = 6, /* double, 64 bits, signed */ TAG_BYTE_ARRAY = 7, /* char *, 8 bits, unsigned, TAG_INT length */ TAG_STRING = 8, /* char *, 8 bits, signed, TAG_SHORT length */ TAG_LIST = 9, /* X *, X bits, TAG_INT length, no names inside */ TAG_COMPOUND = 10 /* nbt_tag * */};//std::string TypeToString(nbt_type t);class nbt_tag{protected: //THIS IS A TEMPLATE nbt_type type; /* Type of the value */ std::string name; /* tag name */ void *value;public: nbt_tag(); nbt_tag(nbt_type t); nbt_tag(nbt_type t, std::string n, void *v); nbt_tag(const nbt_tag &rhs); ~nbt_tag(); void* GetValue(); nbt_type GetType(); void SetType(nbt_type t); void SetName(std::string n); std::string GetName(); void SetValue(void *v); void SwapEndian();};class nbt_byte_array{protected: int32_t length; unsigned char *content;public: nbt_byte_array(); nbt_byte_array(int32_t l, unsigned char *c); nbt_byte_array(const nbt_byte_array &rhs); ~nbt_byte_array(); int32_t Size(); unsigned char *Get();};template <typename T>int nbt_read_tag(igzstream &fs, nbt_tag &t);class nbt_file{protected: int _Read(igzstream &fs, char &t, nbt_tag &tg); std::vector<nbt_tag> tags;public: nbt_file(); nbt_file(const nbt_file &rhs); nbt_file(std::vector<nbt_tag> t); ~nbt_file(); void ReadFile(igzstream &fs); void ReadFile(std::string filename); void ReadFile(const char* filename); nbt_tag First(); std::vector<nbt_tag>::iterator Begin() {return tags.begin();} std::vector<nbt_tag>::iterator End() {return tags.end();} void WriteFile(std::string filename); void AddTag(nbt_tag t, int index);};#endif NBTDEF_H_
#include <cstdint>#include "gzstream.h"#include "nbtdef.h"//#include "endianness.h"#include <string>nbt_tag::nbt_tag(nbt_type t) {type = t; name = ""; value = NULL;}nbt_tag::nbt_tag(){type = nbt_type::TAG_END; name = ""; value = NULL;}nbt_tag::nbt_tag(nbt_type t, std::string n, void *v){type = t; name = n; value = v;} nbt_tag::nbt_tag(const nbt_tag &rhs){type = rhs.type; name = rhs.name; delete value; memcpy(value,rhs.value,sizeof(rhs.value));}nbt_tag::~nbt_tag(){delete value;}void* nbt_tag::GetValue(){return value;}nbt_type nbt_tag::GetType(){return type;}void nbt_tag::SetValue(void *v){delete value; memcpy(value, v, sizeof(v));}void nbt_tag::SetType(nbt_type t){type = t;}void nbt_tag::SetName(std::string n){name= n;}void nbt_tag::SwapEndian(){ switch(type){ case TAG_END: break; case TAG_BYTE: break; case TAG_SHORT: if(get_endianness() == L_ENDIAN) swaps((uint16_t*)value); break; case TAG_INT: if(get_endianness() == L_ENDIAN) swapi((uint32_t*)value); break; case TAG_LONG: if(get_endianness() == L_ENDIAN) swapl((uint64_t*)value); break; case TAG_FLOAT: if(get_endianness() == L_ENDIAN) swapf(*((float*)value)); break; case TAG_DOUBLE: if(get_endianness() == L_ENDIAN) swapd(*((double*)value)); break; case TAG_BYTE_ARRAY: break; }}nbt_byte_array::nbt_byte_array(){content = NULL; length = 0;}nbt_byte_array::nbt_byte_array(int32_t l, unsigned char *c){length = l; delete content; memcpy(content, c, l);}nbt_byte_array::nbt_byte_array(const nbt_byte_array &rhs){length = rhs.length; delete content; memcpy(content, rhs.content, length);}nbt_byte_array::~nbt_byte_array(){delete content;}int32_t nbt_byte_array::Size(){return length;}unsigned char *nbt_byte_array::Get(){return content;}nbt_file::nbt_file(){}nbt_file::nbt_file(const nbt_file &rhs){ tags = rhs.tags; }nbt_file::nbt_file(std::vector<nbt_tag> t){ tags = t; }nbt_file::~nbt_file(){}int read_name(igzstream &fs, nbt_tag &t){ char *buffer; int16_t len; fs.read((char*)&len, sizeof(len)); if(get_endianness() == L_ENDIAN) swaps((uint16_t *)&len); buffer = new char[len]; fs.read(buffer, len); std::string str(buffer); delete [] buffer; buffer = NULL; t.SetName(str); return 0;}template <typename T> int nbt_read(igzstream &fs, nbt_tag &t){ t.SetValue((void*)(new T)); read_name(fs, t); fs.read((char*)t.GetValue(), sizeof(T)); return 1;} void nbt_file::ReadFile(igzstream &fs){ char t = nbt_type::TAG_END; int i = 0; fs.read((char*)&i, t); nbt_tag tg; while(_Read(fs, t, tg)){ tags.push_back(tg); } tags.push_back(tg); } int nbt_file::_Read(igzstream &fs, char &t, nbt_tag &tg){ fs.read(&t, 1); tg.SetType((nbt_type) t); switch (t) { case TAG_END: return 0; break; case TAG_BYTE: nbt_read<char>(fs,tg); break; case TAG_SHORT: nbt_read<int16_t>(fs, tg); break; case TAG_INT: nbt_read<int32_t>(fs,tg); break; case TAG_LONG: nbt_read<int64_t>(fs, tg); break; case TAG_FLOAT: nbt_read<float>(fs, tg); break; case TAG_DOUBLE: nbt_read<double>(fs, tg); break; case TAG_STRING: { /* to make it shut up about the variable declaration */ //This function uses a lot of hackery, we assign the std::string varaible rather than a char array //because the nbt_tag destructor does not expect an array pointer read_name(fs, tg); char *buffer; // std::string *str = new std::string; int16_t len; fs.read((char*)&len, sizeof(len)); if(get_endianness() == L_ENDIAN) swaps((uint16_t *)&len); buffer = new char[len]; fs.read(buffer, len); std::string *str = new std::string(buffer); delete [] buffer; buffer = NULL; tg.SetValue(str); } break; case TAG_BYTE_ARRAY: { read_name(fs, tg); std::list<unsigned char> *lst = new std::list<unsigned char>; unsigned char *buffer; //int32_t len = nbt_read_byte_array(nbt, &bytestring); int32_t len; fs.read((char*)&len, sizeof(len)); if(get_endianness() == L_ENDIAN) swapi((uint32_t *)&len); buffer = new unsigned char[len]; fs.read((char*)buffer, len); for(int i = 0; i < len; ++i) lst->push_back(buffer); tg.SetValue(lst); delete [] buffer; buffer = NULL; } break; case TAG_LIST: { read_name(fs, tg); std::list<nbt_tag> *lst = new std::list<nbt_tag>; char type; int32_t len; fs.read(&type,1); //All tags share a type in a list fs.read((char*)&len, sizeof(len)); //Length of tag seqeuence for(int i = 0; i < len; ++i){ lst->push_back(nbt_tag()); _Read(fs, type, lst->back()); } tg.SetValue(lst); } break; case TAG_COMPOUND: { //Series of tags of different types //Create a vector and read in types to the vector until the next TAG END read_name(fs, tg); std::list<nbt_tag> *lst = new std::list<nbt_tag>; char type; do{ fs.read(&type,1); lst->push_back(nbt_tag()); } while(_Read(fs, t,lst->back())==1); } break; } return 1; } void nbt_file::ReadFile(std::string filename){ igzstream fs; fs.open(filename.c_str(),std::ios::binary | std::ios::in | std::ios::app); if(fs.good()) ReadFile(fs); } void nbt_file::ReadFile(const char* filename){ igzstream fs; fs.open(filename, std::ios::binary | std::ios::in | std::ios::app); if(!fs.bad()) ReadFile(fs); fs.close(); } nbt_tag nbt_file::First(){ return tags.front(); } void nbt_file::WriteFile(std::string filename){} // Don't worry about this for now void nbt_file::AddTag(nbt_tag t, int index){} // Don't worry about this for now int get_endianness(){ union { uint32_t i; char c[4]; } t = { 0x01020304 }; return t.c[0] == 1;}uint64_t swpd(double d){ int i; uint64_t res; unsigned char *dest = (unsigned char *)&res; unsigned char *src = (unsigned char *)&d; for (i = 0; i < 8; ++i) dest = src[7 - i]; return res;}double uswpd(uint64_t d){ int i; double res; unsigned char *src = (unsigned char *)&res; unsigned char *dest = (unsigned char *)&d; for (i = 0; i < 8; ++i) dest = src[7 - i]; return res;}float swapf(float fx){ float rv; char *ftc = (char *)&fx; char *rtf = (char *)&rv; rtf[0] = ftc[3]; rtf[1] = ftc[2]; rtf[2] = ftc[1]; rtf[3] = ftc[0]; return rv;}double swapd(double dx){ double rv; char *ftc = (char *)&dx; char *rtv = (char *)&rv; rtv[0] = ftc[7]; rtv[1] = ftc[6]; rtv[2] = ftc[5]; rtv[3] = ftc[4]; rtv[4] = ftc[3]; rtv[5] = ftc[2]; rtv[6] = ftc[1]; rtv[7] = ftc[0]; return rv;}void swaps(uint16_t *x){ *x = (*x >> 8) | (*x << 8);}void swapi(uint32_t *x){ *x = (*x >> 24) | ((*x<<8) & 0x00FF0000) | ((*x>>8) & 0x0000FF00) | (*x << 24);}void swapl(uint64_t *x){ *x = (*x>>56) | ((*x<<40) & 0x00FF000000000000ULL) | ((*x<<24) & 0x0000FF0000000000ULL) | ((*x<<8) & 0x000000FF00000000ULL) | ((*x>>8) & 0x00000000FF000000ULL) | ((*x>>24) & 0x0000000000FF0000ULL) | ((*x>>40) & 0x000000000000FF00ULL) | (*x<<56);}
They depend on zlib and gzstream right now, and some of my code is trail-test hardcoding. Anyway, I'm going to go beat my head against a brick wall (attempt to debug) for a while.