#include "NibStr.h"

#include <set_error.h>

extern "C" {
#ifdef SYSV
	#include <string.h>
	#define bcopy(from, to, len) (memcpy((to), (from), (len)))
#else
	#include <strings.h>
#endif
}

void NibStr::insert( unsigned long offset, const NibStr & replacement) {

	unsigned long o = 0;
	unsigned long l = replacement.length();

	while (l >= 16) {
		poke(offset+o, (unsigned long long) replacement.peek(o, 16), 16);
		o += 16;
		l -= 16;
	}
	
	if (l) {
		poke(offset+o, (unsigned long long) replacement.peek(o,l), l);
	}
}

void NibStr::poke (unsigned long offset, unsigned long long val, int nibs) {
		
	if (nibs == 0) return;
	
	char * a = adr + (offset >> 1);
	
	bool nflag = (offset & 1)? true : false;
	
	int cnt = nibs - 1;
	do {
		if (nflag) {
			char c = *(a) & 0x0f;
			c |= (val << 4) & 0xf0;
			*(a) = c;
			
			nflag = false;
			a++;
		} else {
			char c = *(a) & 0xf0;
			c |= val & 0x0f;
			*(a) = c;
			
			nflag = true;
		}
		
		val >>= 4;
		
	} while (cnt--);
}

unsigned long long NibStr::peek (unsigned long offset, int nibs) const {
	
	if (nibs == 0) return 0;
	
	offset += nibs-1;
	
	const char * a = adr + (offset >> 1);
	bool nflag = (offset & 1)? true : false;
	unsigned long long v = 0;
	int cnt = nibs - 1;
	do {
		v <<= 4;
		if (nflag) {
			v |= ((*(a) & 0xf0) >> 4);
			nflag = false;
		} else {
			v |= (*(a) & 0x0f);
			nflag = true;
			a--;
		}
	} while (cnt--);
	
	return v;
}


NibStr NibStr::operator+ (const NibStr & rv) const {
	NibStr res(length()+rv.length());

	if (!res.fail) {
		bcopy ( adr, res.adr, len );
		
		if (even) {
			
			if (rv.length()) {
				bcopy ( rv.adr, res.adr+len, rv.len );
			}
			res.even = false;
			if (rv.even) res.even = true;
		} else {
			
			if (rv.length() > 0) {
				char * s = rv.adr;
				char * d = res.adr + len - 1;
	
				bool nflag = true;
				char val = *s++;
				int cnt = rv.length() - 1;
				do {
					if (nflag) {
						char c = *(d) & 0x0f;
						c |= (val << 4) & 0xf0;
						*(d) = c;
						
						nflag = false;
						d++;
					} else {
						char c = *(d) & 0xf0;
						c |= (val >> 4) & 0x0f;
						*(d) = c;
						
						val = *s++;
						nflag = true;
					}		
				} while (cnt--);
			}
			
			res.even = true;
			if (rv.even) res.even = false;
		}
	}
	return res;
}

NibStr NibStr::operator+= (const NibStr & rv) {
	
	unsigned long newlen = (length() + rv.length() + 1) >> 1;
	if (newlen > alloc_len) {
		if (rv.len < 64*1024 && rv.len < len) {
			expand();
			if (alloc_len < newlen) {
				set_error("NibStr::operator+= ","unable to allocate more memory");
				return *this;
			}
		} else {
			char * nadr = new char[newlen+1];
			if (nadr == 0) {
				fail = -1;
				set_error("NibStr::operator+= ","unable to allocate more memory");
				return *this;
			}
			
			bcopy(adr, nadr, len+1);
			if (alloc_len) delete [] adr;
			adr = nadr;
			alloc_len = newlen;
		}
	}
	
	if (even) {	
		if (rv.length()) {
			bcopy ( rv.adr, adr+len, rv.len+1 );
		}
		len = newlen;
		even = false;
		if (rv.even) even = true;
	} else {
		if (rv.length() > 0) {
			char * s = rv.adr;
			char * d = adr + len - 1;
			bool nflag = true;
			char val = *s++;
			int cnt = rv.length() - 1;
			do {
				if (nflag) {
					char c = *(d) & 0x0f;
					c |= (val << 4) & 0xf0;
					*(d) = c;
						
					nflag = false;
					d++;
				} else {
					char c = *(d) & 0xf0;
					c |= (val >> 4) & 0x0f;
					*(d) = c;
					
					val = *s++;
					nflag = true;
				}		
			} while (cnt--);
		}
		len = newlen;
		*(adr+len) = 0;
		even = true;
		if (rv.even) even = false;
	}
	return *this;
}


#include <Bstream.h>

BOstream & operator<< (BOstream & out, const NibStr & n) {
	out << n.even;
	return operator<< (out, (Str &)n );
}


BIstream & operator>> (BIstream & in, NibStr & n) {
	in >> n.even;
	return operator>> (in, (Str &)n);
}



syntax highlighted by Code2HTML, v. 0.9.1