]> www.wagner.pp.ru Git - oss/fgis.git/blob - lib/epp_loaded.c
First checked in version
[oss/fgis.git] / lib / epp_loaded.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <epp.h>
5 #include "epp_private.h"
6 #define row_buffer ((unsigned char **)epp->cache)
7
8
9
10 /*
11  * Opens file in read-write mode and loads raster into memory 
12  * Returns pointer to newly created structure or NULL on error
13  */
14
15 EPP *load_epp(char *filename)
16 {
17   FILE *f;
18   f=fopen(filename,"rb+");
19   if (!f) {
20     map_error=ME_NO_FILE;
21     return NULL;
22   }
23   return fload_epp(f);
24 }
25
26 /*
27  * Reads file from given stream into memory. Returns 0 if Ok, -1 if
28  * something wrong
29  */
30
31 int do_load_epp(EPP *epp)
32 { char **row,**rr;
33   int i,j,k,nrows;
34   unsigned short *width;
35   unsigned short *new_widthtable=NULL; /* if we have to create widthtable 
36                                   on the fly, we would keep it here */
37   int *counttab;
38   unsigned short int *pixel;
39   int oldpos;
40
41   if(!epp->widthtable) { 
42      new_widthtable=calloc(epp->lr-epp->fr,sizeof(short int));
43      
44   }
45   /* 
46     If we want to have read-write access, we should have read access
47      first. Switching from write-only to read-write access requires
48      reset_epp
49    */
50   if(!(epp->mode&MAP_INPUT)) {
51         map_error=ME_INVALID_MODE;
52         return -1;
53   }
54   /*
55     We use pointer where cache is otherwise kept
56    */
57   if (epp->mode&MAP_CACHED) { 
58      free_cache(epp);
59   }
60   /*
61      Create array of pointers to file rows
62    */
63   if ((epp->cache=calloc(epp->lr-epp->fr,sizeof(char *)))==NULL) {
64        map_error=ME_OUT_OF_MEMORY;return -1;
65   }
66   /*
67       Allocate table of frequencies.
68    */
69    /* Note, count of pixels with value==offsite not stored here! */
70    epp->counttable=calloc(1<<epp->kind,sizeof(int));
71    counttab=epp->counttable;
72    if (epp->counttable==NULL) {
73       map_error=ME_OUT_OF_MEMORY;
74       return -1;
75    }
76   /*
77      Allocate and read
78    */
79   /* We are assuming that file is fresh from fopen_epp or reset_epp */
80   nrows=epp->lr-epp->fr;
81   if (epp->widthtable) {
82      width=epp->widthtable;
83   } else {
84      width=new_widthtable;
85   }
86   for(row=epp->cache,i=epp->fr,k=1;i<epp->lr;width++,i++,row++,k++)
87    { if((*row=malloc(*width))==NULL)
88      { for(rr=epp->cache;rr<row;rr++) free(*rr);
89        free(epp->cache);
90        free(epp->counttable);
91        map_error=ME_OUT_OF_MEMORY;
92        return 0;
93      }
94      if (EndLineProc) (*EndLineProc)(i,k,nrows);
95      oldpos=epp->filepos;
96      get_row(epp); 
97      if (new_widthtable) {
98        *width=epp->filepos-oldpos;
99      }
100      memcpy(*row,epp->packed_buffer,*width);
101      for (j=epp->fc,pixel=epp->row;j<epp->lc;j++,pixel++) {
102        counttab[*pixel]++;
103      }  
104    }
105   /* find out what is actual maximum minimum of file */
106   for (i=(1<<epp->kind)-1;i>0&&(counttab[i]==0||i==epp->offsite);i--);
107   epp->max=i;
108   for (i=0;i<epp->max&&(counttab[i]==0||i==epp->offsite);i++);
109   epp->min=i; 
110   fseek(epp->F,128L,SEEK_SET);
111   epp->filepos=128;
112   epp->currentline=epp->fr-1;
113   epp->modified=0;
114   epp->mode=MAP_INPUT|MAP_OUTPUT|MAP_LOADED;
115   epp->position=position_loaded;
116   return 0;
117 }
118 /*
119  * Recieves stream and loads epp-file from it
120  *
121  */
122 EPP *fload_epp(FILE *f) 
123 { EPP *epp;
124   epp=fopen_epp(f);
125   if (!epp) {
126     fclose(f);
127     return NULL;
128   }
129   /* do_load return non-zero on error */
130   if (do_load_epp(epp)) {
131      close_epp(epp);
132      return NULL;
133   }
134   return epp;
135 }
136
137 int load_new_epp(EPP *epp) 
138 {
139   if (epp->mode!=MAP_OUTPUT) {
140      map_error=ME_INVALID_MODE;
141      return -1;
142   }
143   reset_epp(epp);
144   if (do_load_epp(epp)) {
145     close_epp(epp);
146     return -1;
147   }
148   return 0;
149 }
150  
151 void save_row(EPP *epp)
152 {  int oldsize,newsize,l=epp->currentline-epp->fr;
153    
154    if (!epp->modified) return;
155     
156    epp->mode|=MAP_MODIFIED;
157    oldsize=epp->widthtable[l];
158    newsize=pack_buffer(epp);
159    if (oldsize != newsize) { 
160       free(row_buffer[l]);
161       row_buffer[l]=malloc(newsize);
162       epp->widthtable[l]=newsize;
163    }  
164    memcpy(row_buffer[l],epp->packed_buffer,newsize);
165    epp->modified=0;
166 }   
167 /*
168  * Writes loaded file back. Uses stream stored in F field.
169  * Returns 0 on success, -1 on failure 
170  * Calls EndLineProc after saving each row.
171  */
172
173 int save_epp(EPP *epp)
174
175     char **row;
176     unsigned short *width;
177     int i,k,nrows;
178     if (!(epp->mode&MAP_LOADED)) {
179         map_error=ME_INVALID_MODE;
180         return -1;
181     }
182     save_row(epp);
183     /* If file wasn't modified, don't save. See touch_epp macro in epp.h */
184     if (!(epp->mode&MAP_MODIFIED)) {
185        map_error=0;
186        return 0;
187     }
188     fseek(epp->F,128L,SEEK_SET);
189     epp->filepos=128;
190     nrows=epp->lr-epp->fr;
191     map_error=ME_WRITE_ERROR;
192     for(i=epp->fr,row=epp->cache,width=epp->widthtable,k=1;
193             i<epp->lr; row++,width++,i++,k++) { 
194         if (EndLineProc) (*EndLineProc)(i,k,nrows);
195         if (fwrite(*row,1,*width,epp->F)!=*width) 
196             return -1; 
197         epp->filepos+=*width;
198     }
199     epp->currentline=epp->lr;
200     update_header(epp);
201     epp->position(epp,epp->fr);
202     map_error=0;     
203     return 0;
204 }
205 /*
206  * Writes epp file to given stream and makes this stream default
207  * Copies header by hand and then calls save_epp
208  *
209  */
210 int fsave_epp_as(EPP *epp,FILE *f)
211 { EPPHEADER h;
212   
213   fread(&h,128,1,epp->F);
214   fclose(epp->F);
215   epp->F=f;
216   fseek(f,0L,SEEK_SET);
217   if (fwrite(&h,128,1,f)!=128) return 1;
218   touch_epp(epp);
219   return save_epp(epp);
220 }
221 /*
222  * Wrapper around fsave_epp_as, which opens stream to pass there
223  *
224  */
225
226 int save_epp_as(EPP *epp,char *newname)
227 {FILE *f;
228  f=fopen(newname,"w+");
229  if (!f) return 1;
230  return fsave_epp_as(epp,f);
231 }
232 /*
233  * position_loaded - sets current line of epp to given row. 
234  * To be stored in position field of EPP structure.
235  * Takes care of saving row, if modified and unpacks neccesary row 
236  * temporary substituting pointer to it into packed_buffer field.
237  */
238 void position_loaded(EPP *epp,int row)
239
240   unsigned char *tmp; /* to keep packed buffer */
241
242   if (row==epp->currentline) return;
243   save_row(epp); /* save row does nothing if row isn't modified */
244   tmp=epp->packed_buffer;
245   epp->packed_buffer=row_buffer[row-epp->fr];
246   unpack_buffer(epp);
247   epp->modified=0;
248   epp->packed_buffer=tmp;
249   epp->currentline=row;
250   map_error=0;
251
252 /*
253  * epp_expand - converts loaded 8-bit file into 16-bit one
254  * by appending packed string of zeros to each row
255  * return 0 on succes -1 of failure.
256  * errors:
257  *    ME_INVALID_MODE - file is not loaded
258  *    ME_INVALID_FILE - file already have maximum depth
259  *    ME_OUT_OF_MEMORY - no comments
260  */ 
261  
262 int epp_expand (EPP *epp) 
263 { unsigned char *tail; /* here prepaired packed tail is kept*/
264                        /* ATTENCTION, packtail is VERY poisoneuos fish*/
265   int tail_length;
266   unsigned char *byteptr, 
267       **row;/* pointer to pointer to current packed row */
268   int i;
269   unsigned short *width; /* pointer to current element of widthtable */
270   EPPHEADER h;
271   /* check if passed file is suitable for expanding */
272   if (!(epp->mode&MAP_LOADED)) {
273      map_error=ME_INVALID_MODE;
274      return -1;
275   }
276   if (epp->kind==16) {
277      /* nowhere to expand */
278      map_error=ME_INVALID_FILE;
279      return -1;
280   }    
281   
282   /* any error, which occurs further, should be ME_OUT_OF_MEMORY*/
283   map_error=ME_OUT_OF_MEMORY;
284   
285   /* prepare packed tail */
286   tail_length=((epp->lc-epp->fc+254)/255)*2;
287   tail=malloc(tail_length);
288   if (!tail) return -1;
289   for (i=epp->lc-epp->fc,byteptr=tail;i>0;i-=255) {
290     int count=i>255?255:i;
291     *(byteptr++)=count;
292     *(byteptr++)=0;
293   }
294   /* reallocate rows */
295   
296   for (i=epp->fc,width=epp->widthtable,row=row_buffer;
297            i<epp->lc;i++,row++,width++) {
298      unsigned char *tmp=realloc(*row,*width+tail_length);
299      if (!tmp) {
300         /* realloc fails, trying to restore status quo */
301         for (i--,width--;i>=epp->fc;i--,width--)
302             *width-=tail_length;
303         return -1;
304      }
305      /* fill newly allocated memory */
306      memcpy(tmp+*width,tail,tail_length);
307      /* store new row ptr and new width */
308      *row=tmp;
309      *width+=tail_length;
310      /* Width overflow is not checked, becouse packed string of zeros
311        couldn't overflow even most lengthly 8-bit row */
312   }
313   /* fix epp->kind value */
314   epp->kind+=8;
315   /* and write it to disk immediately, becouse no one cares about
316      updating this field in header, but this function */
317   fseek(epp->F,0,SEEK_SET);
318   fread(&h,128,1,epp->F);
319   /* read errors are not checked, becouse thay are quite improbable */
320   h.kind=swapshort(epp->kind);
321   fseek(epp->F,0,SEEK_SET);
322   fwrite(&h,128,1,epp->F);
323   /* Now we are ready to exit successifully */
324   map_error=0;
325   return 0;
326 }  
327