Sign in to follow this  
Plasmarobo

ogzstream failures

Recommended Posts

Alright, so some of you may have heard of the popular game Minecraft.
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 MAPPINGS

enum 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, Y
public:
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[i].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 1

int 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[i]);
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[i] = 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[i] = 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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this