/*
 * Softcam plugin to VDR (C++)
 *
 * This code is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
 */

#include "stdafx.h"
#include <ctype.h>
#include <string.h>

#include "vdr/tools.h"

#include "common.h"
#include "misc.h"

#include "asprintf.h"

// -----------------------------------------------------------------------------

void LogText(const char *head, const char *format, ...)
{
	va_list ap;
	va_start(ap,format);
	char *txt;
	vasprintf(&txt,format,ap);
	va_end(ap);
//	esyslog("%s: %s",head,txt);
	d(printf("%s: %s\n",head,txt))
	free(txt);
}

#define PER_LINE 16

void HexDump(const unsigned char *buffer, int n, bool hideMess )
{
  if (!hideMess) printf("dump: n=%d/0x%04x\n",n,n);
  for(int i=0; i<n;) {
    printf("  %04x: ",i);
    for(int l=0 ; l<PER_LINE && i<n ; l++) printf("%02x ",buffer[i++]);
    printf("\n");
    }
}

const char *HexStr(char *str, const unsigned char *mem, int len)
{
	for(int i=0 ; i<len ; i++) sprintf(&str[i*2],"%02X",mem[i]);
	return str;
}

const char *HexStrSpaced(char *str, const unsigned char *mem, int len)
{
  for(int i=0 ; i<len ; i++) sprintf(&str[i*3],"%02X ",mem[i]);
  return str;
}

static int HexDigit(int asc)
{
	if(asc>='A') return toupper(asc)-'A'+10;
	return asc-'0';
}

int GetChar(const char * &line, int *store, int count)
{
	line=skipspace(line);
	const char *sline=line;
	*store=0;
	while(count) {
		if(line[0]==0 || !isalnum(line[0])) break;
		*store<<=8; *store+=line[0];
		line++; count--;
	}
	if(!count && (!*line || isspace(*line) || *line==';')) return sline-line;
	*store=0;
	line=sline;
	return 0;
}

static int GetHexBase(const char * &line, unsigned char *store, int count, bool fixedLen, bool asc)
{
	line=skipspace(line);
	const char *sline=line;
	unsigned char *sstore=store;
	int scount=count;
	while(count) {
		if(line[0]==0 || line[1]==0 || !isxdigit(line[0]) || !isxdigit(line[1])) break;
		if(asc) {
			*store++=line[0]; *store++=line[1];
		}
		else {
			int d1=HexDigit(line[0]);
			int d0=HexDigit(line[1]);
			*store++=(d1<<4) + d0;
		}
		line+=2; count--;
	}
	if(asc) *store=0; // make sure strings are NULL terminated
	if((!count || (!fixedLen && count!=scount)) &&
		(!*line || isspace(*line) || *line==';' || *line==']' || *line=='/') ) return scount-count;
	memset(sstore,0,scount);
	line=sline;
	return 0;
}

int GetHex(const char * &line, unsigned char *store, int count, bool fixedLen)
{
	return GetHexBase(line,store,count,fixedLen,false);
}

unsigned long long Bin2LongLong(unsigned char *mem, int len)
{
	unsigned long long k=0;
	for(int i=0 ; i<len ; i++) { k<<=8; k+=mem[i]; }
	return k;
}

void RotateBytes(unsigned char *out, const unsigned char *in, int n)
{
	// loop is executed atleast once, so it's not a good idea to
	// call with n=0 !!
	out+=n;
	do { *(--out)=*(in++); } while(--n);
}

void RotateBytes(unsigned char *in, int n)
{
	// loop is executed atleast once, so it's not a good idea to
	// call with n=0 !!
	unsigned char *e=in+n-1;
	do {
		unsigned char temp=*in;
		*in++=*e;
		*e-- =temp;
	} while(in<e);
}

bool CheckNull(const unsigned char *data, int len)
{
	while(--len>=0) if(data[len]) return false;
	return true;
}

unsigned char XorSum(const unsigned char *mem, int len)
{
	unsigned char cs=0;
	while(len>0) { cs ^= *mem++; len--; }
	return cs;
}

// crc stuff taken from linux-2.6.0/lib/crc32.c
/*
 * There are multiple 16-bit CRC polynomials in common use, but this is
 * *the* standard CRC-32 polynomial, first popularized by Ethernet.
 * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
 */
#define CRCPOLY_LE 0xedb88320

unsigned int crc32_le(unsigned int crc, unsigned char const *p, int len)
{
	crc^=0xffffffff; // zlib mod
	while(len--) {
		crc^=*p++;
		for(int i=0; i<8; i++)
			crc=(crc&1) ? (crc>>1)^CRCPOLY_LE : (crc>>1);
	}
	crc^=0xffffffff; // zlib mod
	return crc;
}

// -- cSimpleListBase --------------------------------------------------------------

cSimpleListBase::cSimpleListBase(void)
{
	first=last=0; count=0;
}

cSimpleListBase::~cSimpleListBase()
{
	Clear();
}

void cSimpleListBase::Add(cSimpleItem *Item, cSimpleItem *After)
{
	if(After) {
		Item->next=After->next;
		After->next=Item;
	}
	else {
		Item->next=0;
		if(last) last->next=Item;
		else first=Item;
	}
	if(!Item->next) last=Item;
	count++;
}

void cSimpleListBase::Ins(cSimpleItem *Item)
{
	Item->next=first;
	first=Item;
	count++;
}

void cSimpleListBase::Del(cSimpleItem *Item, bool Del)
{
	if(first==Item) {
		first=Item->next;
		if(!first) last=0;
	}
	else {
		cSimpleItem *item=first;
		while(item) {
			if(item->next==Item) {
				item->next=Item->next;
				if(!item->next) last=item;
				break;
			}
			item=item->next;
		}
	}
	count--;
	if(Del) delete Item;
}

void cSimpleListBase::Clear(void)
{
	while(first) Del(first);
	first=last=0; count=0;
}
