/* * unzlog.c * * Desempaquetador del zlog * * Historia: * 23/11/2015 Creación. * 03/12/2015 Primera version completamente funcional [v1.0]. * 11/12/2014 Avanzo el numero de version para igualar con zlog.c [v1.2] * 14/12/2014 Avanzo el numero de version para igualar con zlog.c [v1.3] * * Autor: Dario Rodriguez dario@softhome.net * (c) 2015 SICOSOFT */ #include #include #include #include #include #include #include #include #define MAXTMPBUF 4096 #define MAXOUTBUF 256 /*#define DEBUG*/ /*#define LOWLEVELDEBUG*/ #ifdef DEBUG #include int dprintf(char *format,...) { va_list a; char mybuf[2096]; va_start(a,format); vsnprintf(mybuf,sizeof(mybuf),format,a);mybuf[sizeof(mybuf)-1]='\0';va_end(a);fprintf(stderr,"ERROR: %s\n",mybuf); return 0; } #define DPRINTF(a) dprintf##a #else #define DPRINTF(a) #endif static int zlog_unpackblock(char *inbuf, int inbufsize, char *outbuf, int outbufsize, int *nprocessed); int main(int argc, char *argv[]) { char inbuf[MAXTMPBUF]; char outbuf[MAXOUTBUF]; int usedinbuf; int in,out; int nread; int nunpacked; int nprocessed; int nbyte; if(argc<3 || strcmp(argv[argc-1],"--help")==0) { fprintf(stderr,"Syntax: %s infile.zlog outfile.log\n",argv[0]); return(1); } in=-1,out=-1; if((in=open(argv[1],O_RDONLY))==-1 || (out=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0644))==-1) { if(in==-1) fprintf(stderr,"ERROR: couldn't open %s for reading\n",argv[1]); else fprintf(stderr,"ERROR: couldn't open %s for writing\n",argv[2]); if(in!=-1) close(in),in=-1; return(2); } usedinbuf=0; nbyte=0; while((nread=read(in,inbuf+usedinbuf,sizeof(inbuf)-usedinbuf))>0 || usedinbuf>0) { nread=(nread<=0)?0:nread; usedinbuf+=nread; if((nunpacked=zlog_unpackblock(inbuf,usedinbuf,outbuf,sizeof(outbuf),&nprocessed))>=0) { if(write(out,outbuf,nunpacked)!=nunpacked) { fprintf(stderr,"ERROR: short write at byte %i, len %i\n",nbyte,nunpacked); break; /* short write */ } } else { fprintf(stderr,"E"); nprocessed=1; } memmove(inbuf,inbuf+nprocessed,usedinbuf-nprocessed); usedinbuf-=nprocessed; nbyte+=nprocessed; } close(in); close(out); return(0); } /* Packing format: 1 byte: segmentsdatasize (n+m+k) 1 byte: segment1 unpacked len (seg1size) 1 byte: segment2 unpacked len (seg2size) 1 byte: segment3 unpacked len (seg3size) n bytes: segment1data, unpack until seg1size unpacked in buffer m bytes: segment2data, unpack until added seg2size unpacked in buffer k bytes: segment3data, unpack until added seg2size unpacked in buffer 1 byte: segmentsdatasize (n+m+k), it is repeated to be able to "rewind" lines How to unpack segment1data: For each nibble (first high nibble, then low nibble): 0-13 represents the corresponding character in "0123456789/ :" 14 and 15 requires two nibbles to decode: 14:0-12 the second number is repetitions-3 of previous character 14:13-15 are the strings "Mon ","Tue ","Wed " 15:0-15 are the strings "Thu ","Fri ","Sat ","Sun ","Jan ","Feb ","Mar ","Apr ","May ","Jun ","Jul ","Aug ","Sep ","Oct ","Nov ","Dec " How to unpack segment2data: Each tuple of 3 bytes is expanded to a tuple of 4 bytes: aaaaaabb bbbbcccc ccdddddd -> 00aaaaaa 00bbbbbb 00cccccc 00dddddd Each expanded byte is decoded as follows: 0-62: represent the corresponding character in " 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 63: the following two expanded bytes are encoded as "count-1""data", as in: 00ccccdd 00dddddd How to unpack segment3data: Each byte has its nibbles swapped. */ static int zlog_unpackblock(char *inbuf, int inbufsize, char *outbuf, int outbufsize, int *nprocessed) { static char encoded[]={"0123456789/ :"}; static char *staticstr[]={"Mon ","Tue ","Wed ","Thu ","Fri ","Sat ","Sun ","Jan ","Feb ","Mar ","Apr ","May ","Jun ","Jul ","Aug ","Sep ","Oct ","Nov ","Dec ",NULL}; static char seg2encoded[]={" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"}; int l; int csize; int seg1origsize,seg2origsize,seg3origsize; int i; int ooff; int nibble; int nextnibble; int sub; int count; int c; unsigned char *in=inbuf; char *ptr; int tuple[4]; int tmptuple[3]; char fillingtmptuple; int tmptuplei; if(inbufsize<5) { DPRINTF(("main: not enough data")); return(-1); /* not enough data */ } l=in[0]; csize=(((int)in[1])+in[2]+in[3]); if(inbufsize<(1+3+l+1) || in[1+3+l]!=l || csize>255) { DPRINTF(("main: format error, inbufsize/navmarkers/csize")); return(-1); /* format error */ } if(outbufsize>4)&0xf):in[i]&0xf; i+=sub; /* si estamos en el nibble 1, el siguiente esta en el siguiente byte */ sub=1-sub; /* cambiamos de 1 a 0 y viceversa */ if(nibble<=13) outbuf[ooff++]=encoded[nibble]; else if((nibble==14 || nibble==15) && (i+sub)<(4+l)) { /* lo del i+sub es para comprobar que el siguiente nibble no esta fuera del buffer */ nextnibble=(sub==0)?((in[i]>>4)&0xf):in[i]&0xf; i+=sub; /* si estamos en el nibble 1, el siguiente esta en el siguiente byte */ sub=1-sub; /* cambiamos de 1 a 0 y viceversa */ if(nibble==14 && nextnibble<=12) { if(ooff==0) { DPRINTF(("seg1: there is no previous character to repeat")); return(-1); /* encoding format error: there is no previous character to repeat */ } if((ooff+(nextnibble+3))>seg1origsize) { DPRINTF(("seg1: encoded data is too large for seg1 char repeat")); return(-1); /* encoding format error: encoded data is too large */ } c=outbuf[ooff-1]; for(count=(nextnibble+3);count>0;count--) outbuf[ooff++]=c; } else { ptr=(nibble==14)?staticstr[nextnibble-13]:staticstr[3+nextnibble]; if((ooff+4)>seg1origsize) { DPRINTF(("seg1: encoded data is too large for seg1 static string")); return(-1); /* encoding format error: encoded data is too large */ } memcpy(outbuf+ooff,ptr,4),ooff+=4; } } else return(-1); /* encoding format error */ } if(sub==1) i++; /* next segment starts in a byte boundary */ if(ooff!=seg1origsize) { DPRINTF(("seg1: unpacked size is not expected size")); return(-1); /* encoding format error: seg1 unpacked size is not the expected size */ } /* unpack segment2 */ for(sub=4,fillingtmptuple=0;ooff<(seg1origsize+seg2origsize);) { if(sub==4) { if((i+3)>(4+l)) break; /* we have less than 3 bytes left in packed data */ sub=0; tuple[0]=((in[i]>>2)&0x3f); tuple[1]=((in[i]&0x3)<<4)|((in[i+1]>>4)&0xf); tuple[2]=((in[i+1]&0xf)<<2)|((in[i+2]>>6)&0x3); tuple[3]=((in[i+2])&0x3f); i+=3; } if(fillingtmptuple==1 && tmptuplei<3) { tmptuple[tmptuplei++]=tuple[sub]; sub++; if(tmptuplei==3) { fillingtmptuple=0; count=(tmptuple[1]>>2)&0xf; c=((tmptuple[1]<<6)&0xc0)|tmptuple[2]; if((ooff+count)>(seg1origsize+seg2origsize)) { DPRINTF(("seg2: encoded data is too large for seg2 char repeat")); return(-1); /* encoding format error: encoded data is too large */ } for(count++;count>0;count--) outbuf[ooff++]=c; } } else if(tuple[sub]<63) { outbuf[ooff++]=seg2encoded[tuple[sub]]; sub++; } else { fillingtmptuple=1; tmptuplei=0; tmptuple[tmptuplei++]=tuple[sub]; sub++; } } if(ooff!=(seg1origsize+seg2origsize)) { DPRINTF(("seg2: unpacked size is not expected size (%i<%i)",ooff,(seg1origsize+seg2origsize))); return(-1); /* encoding format error: seg2 unpacked size is not the expected size */ } /* unpack segment 3 */ for(;i<(4+l) && ooff<(seg1origsize+seg2origsize+seg3origsize);) { c=in[i]; outbuf[ooff++]=((c<<4)|(c>>4))&0xff; i++; } if(ooff!=(seg1origsize+seg2origsize+seg3origsize)) { DPRINTF(("seg2: unpacked size is not expected size (%i<%i)",ooff,(seg1origsize+seg2origsize+seg3origsize))); return(-1); /* encoding format error: seg2 unpacked size is not the expected size */ } *nprocessed=l+5; #ifdef LOWLEVELDEBUG { unsigned long sum=0; for(i=0;i