diff --git a/compression.c b/compression.c new file mode 100644 index 0000000..d69137f --- /dev/null +++ b/compression.c @@ -0,0 +1,121 @@ +#include "compression.h" + +ssize_t inflateGzip(void* compData, size_t compDataLen, void** unCompData) { + unsigned int increase = compDataLen/2; + unsigned int uncompLength = compDataLen; // Later to be increased + + char* uncomp = (char*)calloc(uncompLength, sizeof(char)); + + z_stream strm; + strm.next_in = (Bytef*) compData; + strm.avail_in = compDataLen; + strm.total_out = 0; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + + if (inflateInit2(&strm, (16+MAX_WBITS)) != Z_OK) { + fprintf(stderr, "Unable to initialize zlib zstream for decompression\n"); + free(uncomp); + return -1; + } + + int err = Z_OK; + do { + // If our output buffer is too small + if(strm.total_out >= uncompLength ) { + // Increase size of output buffer + void* newptr = realloc(uncomp,uncompLength + increase); + if(newptr == NULL) { + fprintf(stderr,"Unable to request memory realloc\n"); + inflateEnd(&strm); + free(uncomp); + return -2; + } + uncomp = newptr; + uncompLength += increase; + } + + strm.next_out = (Bytef *) (uncomp + strm.total_out); + strm.avail_out = uncompLength - strm.total_out; + + // Inflate another chunk. + err = inflate (&strm, Z_SYNC_FLUSH); + if(err != Z_OK && err != Z_STREAM_END) { + fprintf(stderr, "zlib error: %d.\n", err); + inflateEnd(&strm); + free(uncomp); + return -3; + } + } while(err != Z_STREAM_END); + uncompLength = strm.total_out; + + if(inflateEnd(&strm) != Z_OK) { + fprintf(stderr,"Error while deallocating libz zstream\n"); + free(uncomp); + return -4; + } + + *unCompData = uncomp; + return uncompLength; +} + +ssize_t deflateGzip(void* unCompData, size_t unCompDataLen, void** compData) { + unsigned int compLength = unCompDataLen; + unsigned int increase = compLength/4; + char* comp = (char*)calloc(compLength, sizeof(char)); + + z_stream strm; + strm.next_in = (Bytef*) unCompData; + strm.avail_in = unCompDataLen; + strm.total_out = 0; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + + if(deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (16+MAX_WBITS),8 , Z_DEFAULT_STRATEGY) != Z_OK) { + fprintf(stderr, "Unable to initialize zlib zstream for compression\n"); + free(comp); + return -1; + } + + int err = Z_OK; + do { + // If our output buffer is too small + if (strm.total_out >= compLength) { + // Increase size of output buffer + void* newptr = realloc(comp, compLength + increase); + if(newptr == NULL) { + fprintf(stderr,"Unable to request memory realloc\n"); + deflateEnd(&strm); + free(comp); + return -2; + } + comp = newptr; + compLength += increase; + } + + strm.next_out = (Bytef*) (comp + strm.total_out); + strm.avail_out = compLength - strm.total_out; + + // deflate another chunk + err = deflate(&strm, Z_FINISH); + if(err != Z_OK && err != Z_STREAM_END) { + fprintf(stderr, "Error while deflating buffer\n"); + deflateEnd(&strm); + free(comp); + return -3; + } + } while(err != Z_STREAM_END); + compLength = strm.total_out; + + if(deflateEnd(&strm) != Z_OK) { + fprintf(stderr,"Error while deallocating libz zstream\n"); + free(comp); + return -4; + } + + // Set OS Flag to 0x00: "FAT filesystem (MS-DOS, OS/2, NT/Win32)" + comp[OS_FLAG_OFFSET] = 0x00; + + *compData = comp; + return compLength; +} \ No newline at end of file diff --git a/compression.h b/compression.h new file mode 100644 index 0000000..630d97b --- /dev/null +++ b/compression.h @@ -0,0 +1,13 @@ +#ifndef _COMPRESSION_H +#define _COMPRESSION_H + +#include +#include +#include + +#define OS_FLAG_OFFSET 0x9 + +ssize_t deflateGzip(void* unCompData, size_t unCompDataLen, void** compData); +ssize_t inflateGzip(void* compData, size_t compDataLen, void** unCompData); + +#endif \ No newline at end of file diff --git a/nbt.c b/nbt.c index 79fb47a..094ead2 100644 --- a/nbt.c +++ b/nbt.c @@ -1,4 +1,6 @@ #include "nbt.h" +#include "compression.h" +#include "chunk.h" ssize_t loadDB(const char* filename, void** data); void destroyTag(Tag* t); @@ -26,67 +28,31 @@ ssize_t loadDB(const char* filename, void** data) { } fstat(fd, &sb); - uint16_t header = 0; - if(pread(fd,&header,sizeof(uint16_t),0) == -1) { - perror("Unable to read header"); - close(fd); - return -3; - } - void* filedata; ssize_t filesize = sb.st_size; - if(header == GZIP_MAGIC) { - close(fd); - filedata = calloc(GZIP_BUFFER,sizeof(char)); - gzFile file = gzopen(filename,"r"); - if(!file) { - perror("Failed to gzopen() file"); - free(filedata); - return -4; - } - int err; - int nRead; - size_t totalBytes = 0; - while((nRead = gzread(file, filedata+totalBytes, GZIP_BUFFER)) != 0) { - totalBytes += nRead; - if(!(totalBytes % GZIP_BUFFER)) { - void* newptr = realloc(filedata,totalBytes + GZIP_BUFFER); - if(newptr == NULL) { - perror("Unable to realloc for decompression"); - gzclose(file); - free(filedata); - return -6; - } - filedata = newptr; - } - } - if(!gzeof(file)) { - const char * errorStr; - errorStr = gzerror(file, &err); - fprintf(stderr, "libz error: %s.\n", errorStr); - gzclose(file); - free(filedata); - return -5; - } - filesize = totalBytes; - gzclose (file); - } else { - filedata = malloc(filesize); - ssize_t nRead = 0; - size_t totalRead = 0; - - while((nRead = read(fd,filedata+totalRead,filesize-totalRead))) { - if(nRead == -1) { - if(errno == EINTR) { - continue; - } - perror("Error reading file"); - return -7; + filedata = malloc(filesize); + ssize_t nRead = 0; + size_t totalRead = 0; + + while((nRead = read(fd,filedata+totalRead,filesize-totalRead))) { + if(nRead == -1) { + if(errno == EINTR) { + continue; } - totalRead += nRead; + perror("Error reading file"); + return -7; } + totalRead += nRead; } + + if(*(uint16_t*)filedata == GZIP_MAGIC) { + void* decompressedFileData; + filesize = inflateGzip(filedata,filesize,&decompressedFileData); + free(filedata); + filedata = decompressedFileData; + } + *data = filedata; return filesize; } @@ -190,6 +156,12 @@ unsigned int parseCompound(void* addr, TagCompound* tc) { pos += parseTag(pos,&list[numTags]); } while(list[numTags++].type != TAG_END); + void* newptr = reallocarray(list, numTags, sizeof(Tag)); + if(!newptr) { + fprintf(stderr,"Unable to request memory realloc\n"); + } + list = newptr; + tc->list = list; tc->numTags = numTags-1; return pos - addr;