#include <stream.h>
#include <fstream.h>
#include <string.h>
#include <stdio.h>

#define HXD_DLM "SC"

class HexDumper
{
	int outWidth, curByte;
	istream* input;
	ostream* output;

	void nxt();
public:
	HexDumper(istream& in)					{ curByte = 0; input = &in; }
	HexDumper(ostream& out, int ow = 60)	{ curByte = 0; output = &out; outWidth = ow; }

	int putMarker(char*);
	int putComponent(char*, char*);
	int putComponent(char*, int**);
	int putComponent(char*, unsigned long);

	int getMarker(char*, int = 0);
	int getComponent(char*, char**);
	int getComponent(char*, int**);
	int getComponent(char*, unsigned long*);
};

void HexDumper::nxt()
{
	curByte++;
	if((curByte * 3) > outWidth)
	{	*output << "\n";
		curByte = 0;
	}
}
	
int HexDumper::putMarker(char* key)
{
	if(!output)
		return(0);
	ostream& strm = *output;
	char kb[3];
	strncpy(kb, key, 3);
#ifdef HP
	strm << " " << form("%02s", kb); nxt();
#else
	char buf[10];
	sprintf(buf, "%02s", kb);
	strm << " " << buf; nxt();
#endif
	return(strm.good());
}

int HexDumper::putComponent(char* key, char* value)
{
	if(!output)
		return(0);

	ostream& strm = *output;

	strm << " " << key; nxt();
	while(*value)
#ifdef HP
	{	strm << " " << form("%02X", *value++);
#else
	{	char buf[10];
		sprintf(buf, "%02X", *value++);
		strm << " " << buf;
#endif
		nxt();
	}
	strm << " " << HXD_DLM; nxt();
	return(strm.good());
}

int HexDumper::putComponent(char* key, int** value)
{
	if(!output)
		return(0);

	ostream& strm = *output;

	strm << " " << key; nxt();
	while(*value)
	{	for(int i = 0; i < 2 /* sizeof(int) */ * 8; i += 8)
#ifdef HP
		{	strm << " " << form("%02X", ((**value & (0xFF << i)) >> i) & 0x000000FF);
#else
		{	char buf[10];
			sprintf(buf, "%02X", ((**value & (0xFF << i)) >> i) & 0x000000FF);
			strm << " " << buf;
#endif
			nxt();
		}
		value++;
	}
	strm << " " << HXD_DLM; nxt();
	return(strm.good());
}

int HexDumper::putComponent(char* key, unsigned long value)
{
	if(!output)
		return(0);

	ostream& strm = *output;

	strm << " " << key; nxt();
	for(int i = 0; i < sizeof(unsigned long) * 8; i += 8)
#ifdef HP
	{	strm << " " << form("%02x",((value & (0xFF << i)) >> i) & 0x000000FF);
#else
	{	char buf[10];
		sprintf(buf, "%02X", ((value & (0xFF << i)) >> i) & 0x000000FF);
		strm << " " << buf;
#endif
		nxt();
	}
	strm << " " << HXD_DLM; nxt();
	return(strm.good());
}

// codes: 0 read always, 1 read if matching, 2 read if not matching, 3 read never

int HexDumper::getMarker(char* key, int code)
{
	if(!input)
		return(0);
	istream& strm = *input;
	char buf[100];
	strm >> buf;
	int rc = strcmp(buf, key) ? 0 : 1;
	if((code == 1 && !rc) || (code == 2 && rc) || (code == 3))
	{
#ifndef __GNUG__
		for(int i = 2; i >= 0; i--)
			strm.putback(buf[i]);
#else
		streampos p = strm.tellg();
		strm.seekg(p - 2);
#endif
	}
	return(rc);
}

int HexDumper::getComponent(char* key, char** value)
{
	if(!input)
		return(0);

	istream& strm = *input;
	char buf[100];
	int x = 0, i = 0;

	strm >> buf;
	if(strcmp(buf, key))
	{
cerr << "invalid key: " << buf << " (" << key << " expected)!\n";
		return(0);
	}
	strm >> buf;
	while(strcmp(buf, HXD_DLM))
	{	sscanf(buf, "%x", &x);
		(*value)[i++] = x;
		strm >> buf;
	}
	(*value)[i] = '\0';
	return(1);
}

int HexDumper::getComponent(char* key, int** value)
{
	if(!input)
		return(0);

	istream& strm = *input;
	char buf[100];
	int x, i = 0;

	strm >> buf;
	if(strcmp(buf, key))
	{
cerr << "invalid key: " << buf << " (" << key << " expected)!\n";
		return(0);
	}
	strm >> buf;
	while(*value && strcmp(buf, HXD_DLM))
	{	**value = 0;
		i = 0;
		while(i < 2 /* sizeof(int) */ * 8 && strcmp(buf, HXD_DLM))
		{	sscanf(buf, "%x", &x);
			**value |= (x << i);
			i += 8;
			strm >> buf;
		}
		value++;
	}
	while(strcmp(buf, HXD_DLM))
		strm >> buf;
	return(1);
}

int HexDumper::getComponent(char* key, unsigned long* value)
{
	if(!input)
		return(0);

	istream& strm = *input;
	char buf[100];
	int x, i = 0;

	strm >> buf;
	if(strcmp(buf, key))
	{
cerr << "invalid key: " << buf << " (" << key << " expected)!\n";
		return(0);
	}
	strm >> buf;
	*value = 0L;
	while(strcmp(buf, HXD_DLM) && i < /* sizeof(unsigned long) * 8 */ 32)
	{	sscanf(buf, "%x", &x);
		*value |= (x << i);
		i += 8;
		strm >> buf;
	}
	while(strcmp(buf, HXD_DLM))
		strm >> buf;
	return(1);
}

#ifdef HXD_DEBUG

#define HXD_EOI "G0"
#define HXD_DLG "G1"
#define HXD_CTR "G2"
#define HXD_NAM "G3"
#define HXD_IID "G4"
#define HXD_GEO "G5"
#define HXD_STY "G6"

main()
{
	char* aStr = new char[30];
	strcpy(aStr, "hallo halli!");
	int a = 0x111, b = 0x222, c = 0x333, d = 0x444;
	unsigned long l = 0x12345670;

	int* ip[5];
	ip[0] = &a; ip[1] = &b; ip[2] = &c; ip[3] = &d; ip[5] = NULL;

	cout << "Fmt test start...\n";

	ofstream out("dum.txt");
	HexDumper od(out);

	cout << sizeof(char) << " / " << sizeof(int) << " / " << sizeof(unsigned long) << "\n";

	od.putComponent(HXD_NAM, aStr);
	od.putComponent(HXD_GEO, ip);
	od.putComponent(HXD_STY, l);

	out << "\n";
	out.close();

//	aStr = "nix";
	strcpy(aStr, "nix");
	a = b = c = d = 0;
	l = 0L;

	ifstream in("dum.txt");
	HexDumper id(in);

	id.getMarker(HXD_STY, 1);

	id.getComponent(HXD_NAM, &aStr);
	id.getComponent(HXD_GEO, ip);
	id.getComponent(HXD_STY, &l);

	in.close();

	cout << aStr << "\n" << form("%x, %x, %x, %x\n%lx\n", a, b, c, d, l) << "\n";

	cout << "Test end.\n";
}

#endif
