Sign in to follow this  
Code-R

Problems with ZLIB

Recommended Posts

I'm trying to create a data compresser for a PAK file like system, nicknamed Big Data Files (Hence the BDF Header ;) ). The problem is, whenever i try to extract, i keep gettin Z_DATA_ERROR from the uncompress function. the source for the compressor and extractor are below:
// BDF Creator.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

using namespace std;
using namespace boost;

int main(int argc, char* argv[])
{
	try
	{
		//
		using namespace boost::filesystem;
		cout << "BDF Creator\n";
		path Source(argv[1]);
		if(!exists(Source))
		{
			cout << "Error: Cannot find source directory! Aborting...\n";
			return -1;
		}
		//To Support huge output files expected
		//we will write a temp output file on the fly as we go.
		vector<ix_BDFFileLocationData> FileData;
		directory_iterator end_itr; // default construction yields past-the-end
		//Get the number of files
		uint32 FileNum = 0;
		vector<string> FileName;
		for(directory_iterator itr(Source); itr != end_itr; ++itr)
		{
			FileName.push_back(itr->leaf());
			++FileNum;
		}
		cout << FileNum << " Files Found, Processing...\n";
		//sort the list
		sort(FileName.begin(), FileName.end());
		vector<string> FilePath(FileNum);
		for(unsigned int i = 0; i < FileNum; i++)
		{
			FilePath[i] = argv[1] + FileName[i];
		}
		//create the intermediate temp output
		ofstream Temp("bdfcreate.tmp", ios::binary);
		int NextOffset = 0;
		for(unsigned int i = 0; i < FileNum; i++)
		{
			ix_BDFFileLocationData TempData;
			TempData.Filename = FileName[i];
			TempData.UnpackedSize = uint32(file_size(FilePath[i]));
			TempData.Offset = NextOffset;
			//Pack it and get the packed size
			//prepare the buffers
			unsigned int DestSize = unsigned int(TempData.UnpackedSize + (TempData.UnpackedSize * 0.1f) + 12);
			Bytef* src = new Bytef[TempData.UnpackedSize];
			Bytef* dst = new Bytef[DestSize];
			//copy the source file into the buffer
			std::ifstream SourceFile(FilePath[i].c_str() , ios::binary);
			SourceFile.read((char*)src, TempData.UnpackedSize);
			SourceFile.close();
			//compress it into the dest
			uLongf DLen = DestSize;
			uLong SLen = TempData.UnpackedSize;
			int CompressionResult = compress(dst, &DLen, src, SLen);
			//error checking
			if(CompressionResult != Z_OK)
			{
				cout << "Compression Error In File " << TempData.Filename << " :\n";
				if(CompressionResult == Z_MEM_ERROR)
				{
					cout << "\tNot Enough Memory.\n";
				}
				if(CompressionResult == Z_BUF_ERROR)
				{
					cout << "\tBuffer Error: Please Report.\n";
				}
				return -2;
			}
			//free the source buffer, no longer needed
			delete [] src;
			//Check for the rare case that a compressed file is greater than the uncompressed file
			//issue a warning, but continue.
			if(DLen > SLen)
			{
				cout << "Warning: File " << TempData.Filename << " Expanded Under Compression.\n";
			}
			//copy the packed size into the temp data
			TempData.PackedSize = DLen;
			//append the dest to the temp file
			Temp.write((char*)dst, DLen);
			//Free The destination buffer
			delete [] dst;
			//add the packed size to the next offset
			NextOffset += DLen;
			//Add the temp data to the data list
			FileData.push_back(TempData);
		}
		Temp.close();
		//output the bdf file
		const char* HDR = "BDFV1";
		uint32 Version = 0;
		uint32 TI;
		ofstream Output(argv[2], ios::binary);
		//Header
		Output.write(HDR, 5);
		Output.write((char*)&Version, sizeof(uint32));
		TI = 0; //Flags
		Output.write((char*)&TI, sizeof(uint32));
		//RealOffset
		uint32 OffsetBeginning = 21; //Initial Size
		//calc the file index difference
		for(unsigned int i  = 0; i < FileData.size(); i++)
		{
			OffsetBeginning += 17 + FileData[i].Filename.size();
		}
		Output.write((char*)&OffsetBeginning, sizeof(uint32));
		Output.write((char*)&FileNum, sizeof(uint32));
		//write the file data list
		for(unsigned int i = 0; i < FileData.size(); i++)
		{
			TI = uint32(FileData[i].Filename.size() + 1);
			Output.write((char*)&TI, sizeof(uint32));
			Output.write(FileData[i].Filename.c_str(), TI);
			Output.write((char*)&FileData[i].Offset, sizeof(uint32));
			Output.write((char*)&FileData[i].PackedSize, sizeof(uint32));
			Output.write((char*)&FileData[i].UnpackedSize, sizeof(uint32));
		}
		//now append the compiled binary temp file into this
		ifstream AppendFile("bdfcreate.tmp" , ios::binary);
		unsigned int AppendSize = unsigned int(file_size("bdfcreate.tmp"));
		byte* TempData = new byte [AppendSize];
		//read the data
		AppendFile.read((char*)TempData, AppendSize);
		//close the file
		AppendFile.close();
		//write the data
		Output.write((char*)TempData, AppendSize);
		//close the output
		Output.close();
		//delete  the buffer
		delete [] TempData;
		//delete the temp output file
		if(remove("bdfcreate.tmp"))
		{
			cout << "Error: Couldn't Delete Temporary Intermediate File bdfcreate.tmp\n";
			return -3;
		}
		return 0;
	}
	catch(std::exception& e)
	{
		cout << "Exception Thrown:\n";
		cout << "\t" << e.what();
		return -65536;
	}
}
// BDF Extractor.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

using namespace std;

int main(int argc, char* argv[])
{
	try
	{
		cout << "Extracting BDF File " << argv[1] << " To " << argv[2] << " ...\n";
		ifstream Input(argv[1]);
		char HDR[5];
		Input.read(HDR, 5);
		if(!(HDR[0] == 'B' &&
			 HDR[1] == 'D' &&
			 HDR[2] == 'F' &&
			 HDR[3] == 'V' &&
			 HDR[4] == '1'))
		{
			cout << "Not A BDF File (Bad Header)!\n";
			Input.close();
			return -1;
		}
		uint32 TI;
		//Version
		Input.read((char*)&TI, sizeof(uint32));
		//Flags
		Input.read((char*)&TI, sizeof(uint32));
		//Offset
		Input.read((char*)&TI, sizeof(uint32));
		//Number Of Files
		uint32 FileNum;
		Input.read((char*)&FileNum, sizeof(uint32));
		//Read The File Data
		vector<ix_BDFFileLocationData> FileData(FileNum);
		for(unsigned int i = 0; i < FileNum; i++)
		{
			ix_BDFFileLocationData TempData;
			Input.read((char*)&TI, sizeof(uint32));
			char* TC = new char [TI];
			Input.read(TC, TI);
			TempData.Filename = TC;
			delete [] TC;
			Input.read((char*)&TempData.Offset, sizeof(uint32));
			Input.read((char*)&TempData.PackedSize, sizeof(uint32));
			Input.read((char*)&TempData.UnpackedSize, sizeof(uint32));
			FileData[i] = TempData; //won't push back coz I already know the number
			//Saving me having to resize the vector everytime.
		}
		//Now Begin The Extraction
		for(unsigned int i = 0; i < FileNum; i++)
		{
			string FullPath(argv[2]);
			FullPath += FileData[i].Filename;
			Bytef* src = new Bytef [FileData[i].PackedSize];
			Bytef* dst = new Bytef [FileData[i].UnpackedSize];
			Input.read((char*)src, FileData[i].PackedSize);
			//deflate
			uLongf SLen = FileData[i].PackedSize, DLen = FileData[i].UnpackedSize;
			int CompressionResult = uncompress(dst, &DLen, src, SLen);
			//error checking
			if(CompressionResult != Z_OK)
			{
				cout << "Decompression Error In File " << FileData[i].Filename << " :\n";
				if(CompressionResult == Z_MEM_ERROR)
				{
					cout << "\tNot Enough Memory.\n";
				}
				if(CompressionResult == Z_BUF_ERROR)
				{
					cout << "\tBuffer Error: Please Report.\n";
				}
				if(CompressionResult == Z_DATA_ERROR)
				{
					cout << "\tCorrupt Data\n";
				}
				//return -2;
			}
			//delete the src
			delete [] src;
			//write the dest
			ofstream Output(FullPath.c_str(), ios::binary);
			Output.write((char*)dst, DLen);
			Output.close();
			//delete it
			delete [] dst;
		}
		Input.close();
		return 0;
	}
	catch(std::exception& e)
	{
		cout << "Exception Thrown:\n";
		cout << "\t" << e.what();
		return -65536;
	}
}

Any help would be appreciated...

Share this post


Link to post
Share on other sites
I don't think anyone will ever read through all that, not me at least.

However, check manually using the debugger that you are reading from the same position (check e.g. the first 4 bytes of zipped data, and then when you read and make sure it is the same).

EDIT: btw, I think the 4-6 first are ALWAYS the same when compressing with zlib.

Share this post


Link to post
Share on other sites
Rather than read though all that code [wink], take a look at the source of my SimpleArchive project, which does basically what you have described. I used this page as my reference for making the library. It works fine both ways, so you can start comparing code (mines heavily commented) so you can get a better idea of what you need to aim for. Good luck!

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