
/********************************************************************** 
  bdecode.c - Copyright (C) 2004 - r00t
  This program 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, or (at your option)
  any later version.
              
  This program 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.
 ***********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
//#include <string.h>
#include <assert.h>

void safe_print(char *s);
int get(void);



#define TIGER_BASE32SIZE    39
#define BASE32_LOOKUP_MAX 43




static unsigned char *base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

int bitziGetBase32EncodeLength(int rawLength)
{
    return ((rawLength * 8) / 5) + ((rawLength % 5) != 0) + 1;
}

int bitziGetBase32DecodeLength(int base32Length)
{
    return ((base32Length * 5) / 8);
}

void bitziEncodeBase32(const unsigned char *buffer,
                       unsigned int         bufLen,
                       char                *base32Buffer)
{
    unsigned int   i, index;
    unsigned char  word;

    for(i = 0, index = 0; i < bufLen;)
    {
        /* Is the current word going to span a byte boundary? */
        if (index > 3)
        {
            word = (buffer[i] & (0xFF >> index));
            index = (index + 5) % 8;
            word <<= index;
            if (i < bufLen - 1)
                word |= buffer[i + 1] >> (8 - index);

            i++;
        }
        else
        {
            word = (buffer[i] >> (8 - (index + 5))) & 0x1F;
            index = (index + 5) % 8;
            if (index == 0)
               i++;
        }

        assert(word < 32);
        *(base32Buffer++) = (char)base32Chars[word];
    }

    *base32Buffer = 0;
}



void error(char *msg, int c){
	char d[2]="\0\0";
	fprintf(stderr,"\n%s: '%c'\n",msg,c);
	while (!(feof(stdin)) && ((d[0]=get())!=EOF) ){
		safe_print(d);
	}

	exit(1);
}

int ctoi(char c){
	switch (c){
	case '0': return 0;
	case '1': return 1;
	case '2': return 2;
	case '3': return 3;
	case '4': return 4;
	case '5': return 5;
	case '6': return 6;
	case '7': return 7;
	case '8': return 8;
	case '9': return 9;
	}
	error("invalid arg to ctoi()!",c);
	/* notreached */
	return -1;
}

void tab(int ln){
	int i;
	for (i=0;i<ln;i++) printf(" ");
}

void safe_print(char *s){
	char *t;
	printf("'");
	for (t=s;*t!=0;t++){
		if (isprint(*t)&&(*t!='\\')){
			printf("%c",*t);
		} else {
			printf("\\%2X",(*t)&255);
		}
	}
	printf("'\n");
}

int get(void){
	int c;
	c=getchar();
	/*if (isprint(c)){
		printf("r: %c\n",c);
	} else {
		printf("r: (%i)\n",c);
	}*/
	return c;
}


int main(int argc, char **argv){

	int c;
	int lv=0;
	unsigned long long int tmp;
	char *tmps;
	int len;
	
	while (!(feof(stdin)) && ((c=get())!=EOF) ){
		switch (c){
		case 'l':
			tab(lv);printf("l{\n");
			lv++;
			break;
		case 'd':
			tab(lv);printf("d{\n");
			lv++;
			break;
		case 'e':
			lv--;
			tab(lv);printf("}\n");
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			//tab(lv);printf("string:\n");
			tmp=ctoi(c);
			while ((c=get()) && (c>='0') && (c<='9')){
				tmp*=10;
				tmp+=ctoi(c);
			}
			if (c!=':'){
				error("no : at end of string length!",c);
			}
			len=tmp;
			tmps=malloc(len+1);
			tmps[len]=0;
			//tab(lv);printf("length: %i\n",len);
			for (tmp=0;tmp<len;tmp++){
				c=get();
				tmps[tmp]=c;
				//printf("string: char %i of %i: %c\n",tmp,len,c);
			}
			if (feof(stdin)) error("EOF in string!",'.');
			if (len<1024){
				tab(lv);printf("s[%i]=",len);
				safe_print(tmps);
			} else {
				tab(lv);printf("hashes: 20*%i=%i (%i=0)\n",len/20,len,len%20);
				for (tmp=0;tmp<len/20;tmp++){
					char b32out[128];
					bitziEncodeBase32(tmps+20*tmp,20,b32out);
					tab(lv);printf("- %s\n",b32out);
				}
			}
			free(tmps);
			break;
		case 'i':
			//tab(lv);printf("integer:\n");
			tmp=0;
			while ((c=get()) && (c>='0') && (c<='9')){
				tmp*=10;
				tmp+=ctoi(c);
			}
			if (c!='e') error("no e at end of int!",c);
			//tab(lv);printf("value: %i\n",tmp);
			tab(lv);printf("i=%lli\n",tmp);
			break;
		default:
			error("unknown command in input stream!",c);
			break;
		}

	} /* while */
	printf("end!\n");

	return 0;
}

