2 /* I don't know what it means, but otherwise fileno function is not declared
9 /* Even more strange define. It is neccesary to access ftruncate function */
15 # include "epp_private.h"
16 int Create16bit=0; /* if non-zero, all created EPP files would be 16 bit*/
18 EPP *creat_epp(char *pathname,int first_col,int first_row,int last_col,
19 int last_row, double AXLeft,double AYTop, double AXRight,
20 double AYBottom, int scale, int base, int offsite)
21 /* creating epp file from scratch. All fields which are not defined as
22 parameters, are filled by default values. Kind depends of global variable
25 f=fopen(pathname,"wb+");
26 if (f==NULL) {map_error=ME_CREATE_ERROR;return NULL;}
27 return fcreat_epp(f,first_col,first_row,last_col,last_row,AXLeft,AYTop,
28 AXRight,AYBottom,scale,base,offsite);
32 EPP *fcreat_epp(FILE* f,int first_col,int first_row,int last_col,
33 int last_row, double AXLeft,double AYTop, double AXRight,
34 double AYBottom, int scale, int base, int offsite)
39 unsigned short int *r;
41 if ((epp=malloc(sizeof(EPP)))==NULL) {fclose(f);map_error=ME_OUT_OF_MEMORY;
43 h.fcx=swapdouble(epp->XLeft=AXLeft);
44 h.lcx=swapdouble(epp->XRight=AXRight);
45 h.lry=swapdouble(epp->YBottom=AYBottom);
46 h.fry=swapdouble(epp->YTop=AYTop);
47 h.fc=swapshort(epp->fc=first_col);
48 h.fr=swapshort(epp->fr=first_row);
49 h.lc=swapshort(epp->lc=last_col);epp->lc++;
50 h.lr=swapshort(epp->lr=last_row);epp->lr++;
51 h.scale=swapshort(scale==0?100:scale);
52 h.base=swapshort(base);
53 h.offsite=swapshort(epp->offsite=offsite);
54 epp->width=last_col-first_col+2;
55 if ((epp->row=calloc(epp->width+1,sizeof(short)))==NULL)
56 {free(epp);fclose(f);map_error=ME_OUT_OF_MEMORY;return NULL;}
59 for(r=epp->row,i=0;i<=epp->width;*(r++)=offsite,i++);
60 if((epp->widthtable=calloc(epp->lr-epp->fr,sizeof(short)))==NULL)
61 {free(epp->row);free(epp);fclose(f);map_error=ME_OUT_OF_MEMORY;return NULL;}
62 if ((epp->packed_buffer=malloc(epp->width*4/3))==NULL)
63 { free(epp->row);if (epp->widthtable!=NULL) free(epp->widthtable);
64 fclose(f);free(epp);map_error=ME_OUT_OF_MEMORY;return NULL;}
67 epp->position=position_output;
68 h.kind=swapshort(epp->kind=Create16bit?16:8);
70 h.sfact=swapdouble(epp->cell_area=fabs(AXRight-AXLeft)/(last_col-first_col+1)*
71 fabs(AYBottom-AYTop)/(last_row-first_row+1));
72 memset(h.comment,32,' ');
75 epp->currentline=epp->fr;
80 EPP *creat_epp_as(char *pathname,EPP *pattern)
82 f=fopen(pathname,"wb+");
83 if (f==NULL) {map_error=ME_CREATE_ERROR;return NULL;}
84 return fcreat_epp_as(f,pattern);
86 EPP *fcreat_epp_as(FILE *f,EPP *pattern)
87 /* creates new epp file, copiing a most header fields from given file */
90 get_epp_header(pattern,&h);
91 epp=fcreat_epp(f,h.fc,h.fr,h.lc,h.lr,
92 pattern->XLeft,pattern->YTop,pattern->XRight,
93 pattern->YBottom,h.scale,h.base,h.offsite);
96 setcomment(epp,strncpy(cmt,h.comment,32));
100 void setcomment(EPP *epp,char *comment)
101 /* change comment of epp file, which was open by creat_epp or creat_epp_as */
104 if((epp->mode & MAP_OUTPUT) == 0)
105 { map_error=ME_INVALID_MODE; return; }
106 fseek(epp->F,0L,SEEK_SET);
107 fread(&h,128,1,epp->F);
108 strncpy(h.comment,comment,32);
109 for(i=strlen(comment);i<32;i++) h.comment[i]=' ';
110 fseek(epp->F,0L,SEEK_SET);
111 fwrite(&h,128,1,epp->F);
112 fseek(epp->F,epp->filepos,SEEK_SET);
114 void change_epp_header(EPP *epp,EPPHEADER h)
117 fseek(epp->F,0L,SEEK_SET);
118 fread(&fh,128,1,epp->F);
119 fh.fcx=swapdouble(h.fcx);
120 fh.lcx=swapdouble(h.lcx);
121 fh.fry=swapdouble(h.fry);
122 fh.lry=swapdouble(h.lry);
123 fh.base=swapshort(h.base);
124 fh.scale=swapshort(h.scale);
125 fh.offsite=swapshort(epp->offsite=h.offsite);
126 fh.sfact=swapdouble(h.sfact);
127 fh.coord_sys=h.coord_sys;
128 fh.area_unit=h.area_unit;
129 memcpy(h.comment,fh.comment,32);
130 fseek(epp->F,0L,SEEK_SET);
131 fwrite(&fh,128,1,epp->F);
132 fseek(epp->F,epp->filepos,SEEK_SET);
135 int shift_epp(EPP *epp,int new_fr,int new_fc)
136 {int new_lr,new_lc,result;
138 new_lr=epp->lr-epp->fr+new_fr;
139 new_lc=epp->lc-epp->fc+new_fc;
140 if ((new_fr<-32767)||(new_fc<-32767)||(new_lc>32768)||(new_lc>32768))
142 if (epp->mode & MAP_OUTPUT)
144 fseek(epp->F,0,SEEK_SET);
145 fread(&h,128,1,epp->F);
146 h.fc=swapshort(epp->fc=new_fc);
147 h.fr=swapshort(epp->fr=new_fr);
148 h.lr=swapshort((epp->lr=new_lr)-1);
149 h.lc=swapshort((epp->lc=new_lc)-1);
150 fseek(epp->F,0,SEEK_SET);
151 result=(fwrite(&h,128,1,epp->F)==128);
152 fseek(epp->F,epp->filepos,SEEK_SET);
165 void reset_epp(EPP *epp)
166 /* reopens epp file for reading. if file was in create mode, fills all non-filled
168 { if (epp->mode==MAP_OUTPUT)
169 { update_header(epp);
171 fseek(epp->F,128L,SEEK_SET);
173 epp->currentline=epp->fr-1;
174 epp->position=position_input;
176 else (*epp->position)(epp,epp->fr);
179 * update_header - writes changes into header and writes width table.
180 * for write-only files also fills all unfilled rows by offsite.
181 * Modifies following field in file header:
182 * 1. access_ptr (to point to newly written width table)
185 * 4. offsite (so we can play with its value)
186 * 5. date and time stamp
188 void update_header(EPP *epp)/* writes changes into header */
191 unsigned short int *r;
199 /* For write-only file fill rest of it by offsite */
200 if(epp->mode==MAP_OUTPUT) {
202 for (r=epp->row,i=0;i<epp->width;*(r++)=epp->offsite,i++);
203 for (i=epp->currentline;i<epp->lr;i++){put_row(epp);}
206 /* width table should be aligned to 128 byte boundary */
207 if((i=(epp->filepos % 128))) fwrite(&h,128-i,1,epp->F);
208 table_offset=ftell(epp->F);
210 fwrite(epp->widthtable,epp->lr-epp->fr,sizeof(short),epp->F);
212 fwt=calloc(epp->lr-epp->fr,sizeof(short));
213 swab(epp->widthtable,fwt,epp->lr-epp->fr);
214 fwrite(fwt,epp->lr-epp->fr,sizeof(short),epp->F);
217 if ((i=(ftell(epp->F)%128))) fwrite(&h,128-i,1,epp->F);
218 /* I don't know how old software would behave if file size is
219 not multiplication of 128, so write few bytes of junk */
220 if ((i=(ftell(epp->F)%128))) fwrite(&h,128-i,1,epp->F);
221 /* Truncate file here.*/
222 ftruncate(fileno(epp->F),ftell(epp->F));
223 /* Now we are ready to write header. */
224 fseek(epp->F,0,SEEK_SET);
225 fread(&h,128,1,epp->F);
226 h.access_ptr=swaplong(table_offset / 128);
227 h.offsite=swapshort(epp->offsite);
228 h.maxclass=swapshort(epp->max);
229 h.minclass=swapshort(epp->min);
230 /* correct date/time values */
232 t=localtime(×ec);
233 sprintf(h.date,"%02d/%02d/%02d",t->tm_mon+1,t->tm_mday,t->tm_year);
234 for(i=strlen(h.date);i<16;h.date[i++]=' ');
235 sprintf(h.time,"%02d:%02d:%02d",t->tm_hour,t->tm_min,t->tm_sec);
236 for(i=strlen(h.time);i<8;h.time[i++]=' ');
237 fseek(epp->F,0L,SEEK_SET);
238 fwrite(&h,128,1,epp->F);
240 epp->currentline=epp->fr-1;
243 * Perform actual eppl packing algoritm. Fetch each second byte from
244 * source row, so pack_buffer can call it twice for 16-bit files
245 * row is row buffer to pack (may be pointer to second byte of actual
246 * row buffer) bufpos - stores offset in epp->packed_buffer, where to
247 * start packing. On exit it contains offset of next byte after last packed
250 void pack_row(unsigned char *row,int *bufpos,EPP *epp)
252 register unsigned char c, *dest, *i;
253 register unsigned char *stop;
254 register unsigned char *j, *k;
255 stop=row+((epp->width-1)<<1);
256 dest=epp->packed_buffer+(*bufpos);
260 while((j<stop)&&(c<255)&&(*i==*j))
263 { *(dest++)=c;*(dest++)=*i;
267 { for(j=i+2;(j<stop-2)&&(c<255)&&(*j!=*(j+2));
269 if ((j==stop-2)&&(c<255)) {j+=2;c++;}
273 for (k=i;k<j;k+=2) *(dest++)=*k;
277 *bufpos=(int)dest-(int)(epp->packed_buffer);
280 * Stores content of epp->row into epp->packed_buffer by calling
281 * pack_row epp->kind/8 times.
282 * Updates width table.
284 int pack_buffer(EPP *epp)
286 if (!(epp->mode & MAP_OUTPUT)) {map_error=ME_INVALID_MODE; return 0;}
288 /* Intel architecture - first byte of short is LSB. store it first */
289 pack_row((unsigned char *)epp->row,&bufpos,epp);
291 pack_row(((unsigned char *)epp->row)+1,&bufpos,epp);
293 /* Sparc architecture - store second byte of short first, first byte last*/
294 pack_row(((unsigned char *)epp->row)+1,&bufpos,epp);
296 pack_row(((unsigned char *)epp->row),&bufpos,epp);
298 /* update width table */
299 epp->widthtable[epp->currentline-epp->fr]=bufpos;
303 * Packs and writes row
306 void put_row(EPP *epp)
308 if (!(epp->mode & MAP_OUTPUT)) {
309 map_error=ME_INVALID_MODE;
313 if (fwrite(epp->packed_buffer,1,l,epp->F)!=l) {
314 map_error=ME_WRITE_ERROR;
321 * Positions write-only file. To be stored in position field of EPP structure.
322 * If row > current fills all rows between current and given by offsite.
324 void position_output(EPP *epp,int row)
329 if (row==epp->currentline)
331 if (!epp_contains(epp,epp->fc,row)) {
332 map_error=ME_POINT_OUTSIDE; return;
334 if (row<epp->currentline) {
335 map_error=ME_INVALID_PUT;
338 /* store current row */
341 if (map_error) return;
342 /* fill row buffer with offsite */
343 for (r=epp->row,i=epp->fc;i<epp->lc;i++,r++)*r=epp->offsite;
344 while (epp->currentline<row) {
346 if (map_error) return;
348 /* Here we are - buffer filled with offsite and prevouis rows are written */
351 * Recieves write-only file, writing to which is just finished,
352 * and writes it into filename as
354 * Doesn't even try to unpack high byte
356 void fast_convert_to_8bit(EPP *source,char *filename)
361 short *swapped_bytes;
364 int i,j,nrows,access_ptr;
365 if (source->mode!=MAP_OUTPUT) {
366 map_error=ME_INVALID_MODE;
370 fseek(source->F,0L,SEEK_SET);
371 fread(&h,128,1,source->F);
373 if (source->offsite>255&&source->offsite!=65535) {
374 h.offsite=swapshort(source->offsite & 0xff);
376 dest=fopen(filename,"w+");
378 map_error=ME_WRITE_ERROR;
381 fwrite(&h,128,1,dest);
382 nrows=source->lr-source->fr;
383 for(i=source->fr,j=0;i<source->lr;i++,j++) {
385 (*EndLineProc)(i,j+1,nrows);
386 fread(source->packed_buffer,source->widthtable[j],1,source->F);
388 unpack_row((unsigned char *)source->row,&bufpos,source);
389 source->widthtable[j]=bufpos;
390 fwrite(source->packed_buffer,bufpos,1,dest);
393 /* This is assignment, not condition */
394 if((i=ftell(dest) % 128)) fwrite(&h,128-i,1,dest);
395 access_ptr=ftell(dest)/128;
397 fwrite(source->widthtable,nrows,2,dest);
399 swapped_bytes=malloc(nrows*2);
400 swab(source->widthtable,swapped_bytes,nrows*2);
401 fwrite(swapped_bytes,nrows,2,dest);
403 fseek(dest,0L,SEEK_SET);
404 fread(&h,128,1,dest);
405 h.access_ptr=swaplong(access_ptr);
406 fseek(dest,0L,SEEK_SET);
407 fwrite(&h,128,1,dest);
412 /* fills given cell by value. File must be in create mode. if line is not
413 current, does nothing if line above current or fills all lines between current
414 and specified by offsite
416 void epp_put(EPP *epp,int x,int y,int value)
418 unsigned short *pixel;
420 if (!(epp->mode&MAP_OUTPUT)){
421 map_error=ME_INVALID_MODE; return ;
424 if (!epp_contains(epp,x,y)) {
425 map_error=ME_POINT_OUTSIDE; return;
428 if (epp->currentline!=y) {
429 (*epp->position)(epp,y);
431 if (epp->counttable) {
432 /* if we are supporting counting of cell values*/
433 pixel=epp->row+(x-epp->fc);
434 /* # maintain table */
435 epp->counttable[*pixel]--;
436 epp->counttable[value]++;
438 /* # check if maximum or minimum changed */
439 if (value>epp->max&&value!=epp->offsite) {
442 while ((epp->max==epp->offsite||!epp->counttable[epp->max])&&
446 if (value<epp->min&&value!=epp->offsite) {
449 while ((epp->min==epp->offsite||!epp->counttable[epp->min])&&
454 /* we can only change max/min if value is outside them */
455 epp->row[x-epp->fc]=value;
456 if (value!=epp->offsite) {
457 if ((unsigned)value>epp->max) epp->max=value;
458 if ((unsigned)value<epp->min) epp->min=value;
463 /* fills range of adjanced cells in same row with same value
464 In create mode complains, if row is above current.
465 If any point of specified range is outside physical file limits,
466 complains and does nothing.
468 void epp_putline(EPP *epp,int x1,int x2,int y,int value)
470 unsigned short *pixel;
472 if (!(epp->mode&MAP_OUTPUT)){
473 map_error=ME_INVALID_MODE; return ;
477 /* Positioning to desired row */
478 if (epp->currentline!=y) {
479 (*epp->position)(epp,y);
481 /* return if row is invalid */
482 if (map_error) return;
483 /* if line exceeds file limits, truncate it */
484 if (x1<epp->fc) x1=epp->fc;
485 if (x2>=epp->lc) x2=epp->lc-1;
486 /* if nothing left, return error */
488 map_error=ME_POINT_OUTSIDE;
491 if (epp->counttable) {
492 /* if we are supporting counting of cell values*/
493 for (pixel=epp->row+(x1-epp->fc),i=x1;i<=x2;i++,pixel++) {
494 /* # maintain table */
495 epp->counttable[*pixel]--;
498 epp->counttable[value]+=x2-x1+1;
499 /* # check if maximum or minimum changed */
500 if (value>epp->max&&value!=epp->offsite) {
503 while ((epp->max==epp->offsite||!epp->counttable[epp->max])&&
507 if (value<epp->min&&value!=epp->offsite) {
510 while ((epp->min==epp->offsite||!epp->counttable[epp->min])&&
515 /* we can only change max/min if value is outside them */
516 for (pixel=epp->row+(x1-epp->fc),i=x1;i<=x2;i++,pixel++) {
519 if (value!=epp->offsite) {
520 if ((unsigned)value>epp->max) epp->max=value;
521 if ((unsigned)value<epp->min) epp->min=value;