/* xbm.c * portable bitmap format (xbm) decoder * (c) 2002 Petr 'Brain' Kulhavy * This file is a part of the Links program, released under GPL */ #include "cfg.h" #ifdef G #include "links.h" #include #include #include #define XBM_BUFFER_LEN 1024 #define min(a,b) (ab?a:b) struct xbm_decoder{ int width, height; /* rozmery obrazku */ int partnum; /* buffer skoncil uprostred cisla */ int *numdest; /* kam se ma ukladat to cislo kdyz je partnum */ int in_data_block; /* jsme v bloku dat (uz jsme precetli otviraci slozenou zavorku) */ int image_pos; /* pixelova pozice v cimg->buffer */ int pixels; /* velikost cimg->buffer v pixelech */ int state; /* stav automatu na zrani komentaru */ int actual_eight; /* aktualni cislo, ktere se ma putnout do cimg */ unsigned char barvicky[6]; /* 0-2 background, 3-5 foreground */ /* * stavy: * 0 - mimo komentar * 1 - za 1. lomitkem * 2 - za 1. lomitkem a hvezdickou * 3 - za 2. hvezdickou */ int buffer_pos; /* delka platnych dat v bufferu */ unsigned char buffer[XBM_BUFFER_LEN]; }; extern int get_foreground(int rgb); unsigned char *my_memmem(unsigned char *h, int hl, unsigned char *n, int nl) { for (;hl>=nl;hl--,h++) if (*h==*n&&!memcmp(h,n,nl))return h; return NULL; } void xbm_start(struct cached_image *cimg) { struct xbm_decoder *deco; unsigned short r,g,b; deco=mem_alloc(sizeof(struct xbm_decoder)); if (!deco){img_end(cimg);return;} cimg->decoder=deco; deco->state=0; deco->width=-1; deco->height=-1; deco->buffer_pos=0; deco->partnum=0; deco->in_data_block=0; round_color_sRGB_to_48(&r,&g,&b,cimg->background_color); deco->barvicky[0]=apply_gamma_single_16_to_8(r,display_red_gamma); deco->barvicky[1]=apply_gamma_single_16_to_8(g,display_green_gamma); deco->barvicky[2]=apply_gamma_single_16_to_8(b,display_blue_gamma); round_color_sRGB_to_48(&r,&g,&b,get_foreground(cimg->background_color)); deco->barvicky[3]=apply_gamma_single_16_to_8(r,display_red_gamma); deco->barvicky[4]=apply_gamma_single_16_to_8(g,display_green_gamma); deco->barvicky[5]=apply_gamma_single_16_to_8(b,display_blue_gamma); } /* vrati cislo, nebo -1, kdyz to neni cislo, a nastavi p a l na posledni necislici */ static inline int __read_num(unsigned char **p,int *l,int *partnum,int *digits, int *base) { static int a=-1; static int b=10; static int d=0; int retval; *partnum=0; dalsi_runda: if (!(*l))return a; **p=tolower(**p); if (b==10&&((**p)<'0'||(**p)>'9'))return a; /* tohle neni cislo, to si strc nekam... */ if (b==16&&((**p)<'a'||(**p>'f'))&&((**p)<'0'||(**p)>'9'))return a; if (a==-1)a=0; for (;*l&&(((**p)>='0'&&(**p)<='9')||(b==16&&(**p)>='a'&&(**p)<='f'));(*l)--,(*p)++){d++;a*=b;a+=((**p)>='a'?10+(**p)-'a':(**p)-'0');} if (b==10&&!a&&(*l)&&((**p)|32)=='x'){b=16;d=0;(*p)++;(*l)--;goto dalsi_runda;} retval=a; if (!*l)*partnum=1; else a=-1,*base=b,b=10,*digits=d,d=0; return retval; } static inline void __skip_space_tab(unsigned char **p, int *l) { for (;*l&&(**p==' '||**p==9);(*l)--,(*p)++); } static inline void __skip_whitespace(unsigned char **p, int *l) { for (;*l&&((**p)>'9'||(**p)<'0');(*l)--,(*p)++); } static inline void put_eight(struct cached_image *cimg,int bits) { struct xbm_decoder *deco=(struct xbm_decoder *)cimg->decoder; int a; for (a=0;aimage_pospixels;a++,deco->image_pos++) { memcpy(cimg->buffer+deco->image_pos*3,deco->barvicky+((deco->actual_eight)&1)*3,3); deco->actual_eight>>=1; } } /* opravdovy dekoder xbm, data jsou bez komentaru */ /* length is always !=NULL */ void xbm_decode(struct cached_image *cimg, unsigned char *data, int length) { struct xbm_decoder *deco=(struct xbm_decoder *)cimg->decoder; /* okurky v decu ;-) */ int a; int must_return=0; restart_again: if (must_return&&!length)return; must_return=0; a=min(length,XBM_BUFFER_LEN-deco->buffer_pos); memcpy(deco->buffer+deco->buffer_pos,data,a); length-=a; deco->buffer_pos+=a; if (!deco->buffer_pos)return; /* z toho nic plodnyho nevznikne */ data+=a; if (!deco->in_data_block&&deco->partnum) { unsigned char *p; int a; int b,d; p=deco->buffer; a=deco->buffer_pos; *(deco->numdest)=__read_num(&p,&a,&(deco->partnum),&d,&b); /* p i a ukazuje na 1. neciselnej znak (at uz za mezerama bylo cislo nebo nebylo) */ memmove(deco->buffer,p,a); deco->buffer_pos=a; if (deco->partnum){must_return=1;goto restart_again;} /* zase konec bufferu */ } if (deco->width<0||deco->height<0) /* decoding header */ { unsigned char *p,*q; int *d; int a; int base, digits; p=my_memmem(deco->buffer,deco->buffer_pos,"width",5); q=my_memmem(deco->buffer,deco->buffer_pos,"height",6); if (!p&&!q) /* sezereme zacatek */ { int a=deco->buffer_pos>5?deco->buffer_pos:0; /* nesmime ukrast kus width/height */ memmove(deco->buffer,deco->buffer+deco->buffer_pos-a,deco->buffer_pos-a); /* sezereme to pred width/height */ deco->buffer_pos-=a; must_return=1; goto restart_again; } p=p&&q?min(p,q):max(p,q); /* bereme vetsi, protoze ten 2. je NULL */ memmove(deco->buffer,p,(deco->buffer_pos)+(deco->buffer)-p); /* sezereme to pred width/height */ deco->buffer_pos-=p-deco->buffer; /* deco->buffer zacina height/width */ if (deco->buffer[0]=='w'){p=deco->buffer+5;d=&(deco->width);} else {p=deco->buffer+6;d=&(deco->height);} a=deco->buffer_pos+deco->buffer-p; __skip_space_tab(&p,&a); if (!a){must_return=1;goto restart_again;} /* v bufferu je: width/height, whitespace, konec */ *d=__read_num(&p,&a,&(deco->partnum),&digits, &base); if (deco->partnum)deco->numdest=d,must_return=1; /* p i a ukazuje na 1. neciselnej znak (at uz za mezerama bylo cislo nebo nebylo) */ memmove(deco->buffer,p,a); deco->buffer_pos=a; goto restart_again; } else /* decoding data */ { unsigned char *p; int a; int d,b; if (!deco->in_data_block) { p=memchr(deco->buffer,'{',deco->buffer_pos); if (!p){deco->buffer_pos=0;must_return=1;goto restart_again;} /* sezerem celej blok a cekame na zavorku */ cimg->width=deco->width; cimg->height=deco->height; cimg->buffer_bytes_per_pixel=3; cimg->red_gamma=display_red_gamma; cimg->green_gamma=display_green_gamma; cimg->blue_gamma=display_blue_gamma; cimg->strip_optimized=0; header_dimensions_known(cimg); deco->in_data_block=1; p++; memmove(deco->buffer,p,deco->buffer_pos+deco->buffer-p); /* sezereme to pred width/height */ deco->buffer_pos-=p-deco->buffer; deco->image_pos=0; deco->pixels=deco->width*deco->height; } p=deco->buffer; a=deco->buffer_pos; if (!deco->partnum) __skip_whitespace(&p,&a); deco->actual_eight=__read_num(&p,&a,&(deco->partnum),&d,&b); memmove(deco->buffer,p,a); deco->buffer_pos=a; if (deco->partnum)must_return=1; else put_eight(cimg,(b==16&&d>2)||(b==10&&deco->actual_eight>255)?16:8); if (deco->image_pos>=deco->pixels) {img_end(cimg);return;} goto restart_again; } } /* skip comments and call real decoding function */ void xbm_restart(struct cached_image *cimg, unsigned char *data, int length) { struct xbm_decoder *deco=(struct xbm_decoder*)cimg->decoder; cycle_again: if (!length)return; switch(deco->state) { case 0: /* mimo komentar */ { unsigned char *p; p=memchr(data,'/',length); if (!p){xbm_decode(cimg, data, length);return;} xbm_decode(cimg, data, p-data); data=p+1; /* preskocim lomitko */ length-=p-data+1; deco->state=1; goto cycle_again; } case 1: /* za 1. lomitkem */ { if (*data=='*'){deco->state=2;data++;length--;goto cycle_again;} /* zacal komentar */ xbm_decode(cimg, "/", 1); deco->state=0; /* to nebyl komentar */ goto cycle_again; } case 2: /* za lomeno hvezdicka (uvnitr komentare) */ { unsigned char *p; p=memchr(data,'*',length); if (!p)return; /* furt komentar */ data=p+1; /* preskocim hvezdicku */ length-=p-data+1; deco->state=3; goto cycle_again; } case 3: /* za 2. hvezdickou */ { if (*data=='/'){data++;length--;deco->state=0;goto cycle_again;} /* skoncil komentar */ deco->state=2; data++; length--; goto cycle_again; } } } #endif /* G */