source: git/src/img.c @ 9478ea4

RELEASE/1.0RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernloglog-selectstereostereo-2025walls-datawalls-data-hanging-as-warningwarn-only-for-hanging-survey
Last change on this file since 9478ea4 was 9f3e5df, checked in by Olly Betts <olly@…>, 23 years ago

img_rewind now returns int instead of void

git-svn-id: file:///home/survex-svn/survex/trunk@1807 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 30.3 KB
RevLine 
[0da6e60]1/* img.c
[d1b1380]2 * Routines for reading and writing Survex ".3d" image files
[ad4eaf3f]3 * Copyright (C) 1993-2002 Olly Betts
[846746e]4 *
[89231c4]5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
[846746e]9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
[d1b1380]18 */
19
[a420b49]20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
[d1b1380]24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <time.h>
28#include <ctype.h>
29
[72af530]30#include "img.h"
[7d27e36]31
[72af530]32#ifdef IMG_HOSTED
[d69255f]33# include "debug.h"
[d1b1380]34# include "filelist.h"
[d69255f]35# include "filename.h"
36# include "message.h"
37# include "useful.h"
[a420b49]38# define TIMENA msg(/*Date and time not available.*/108)
39# define TIMEFMT msg(/*%a,%Y.%m.%d %H:%M:%S %Z*/107)
[d1b1380]40#else
[72af530]41# define INT32_T long
[d1b1380]42# define TIMENA "Time not available."
43# define TIMEFMT "%a,%Y.%m.%d %H:%M:%S %Z"
44# define EXT_SVX_3D "3d"
45# define xosmalloc(L) malloc((L))
[72af530]46# define xosrealloc(L,S) realloc((L),(S))
[d1b1380]47# define osfree(P) free((P))
48# define ossizeof(T) sizeof(T)
[72af530]49/* in IMG_HOSTED mode, this tests if a filename refers to a directory */
[d1b1380]50# define fDirectory(X) 0
51/* open file FNM with mode MODE, maybe using path PTH and/or extension EXT */
52/* path isn't used in img.c, but EXT is */
53# define fopenWithPthAndExt(PTH,FNM,EXT,MODE,X) fopen(FNM,MODE)
54# define fFalse 0
55# define fTrue 1
56# define bool int
57/* dummy do {...} while(0) hack to permit stuff like
58 * if (s) fputsnl(s,fh); else exit(1);
59 * to work as intended
60 */
[23f7ea7]61# define fputsnl(S, FH) do {fputs((S), (FH)); putc('\n', (FH));} while(0)
[d69255f]62# define ASSERT(X)
[d1b1380]63
[a420b49]64static long
65get32(FILE *fh)
66{
[ad9a5cd]67   long w = getc(fh);
[a420b49]68   w |= (long)getc(fh) << 8l;
69   w |= (long)getc(fh) << 16l;
70   w |= (long)getc(fh) << 24l;
71   return w;
[d1b1380]72}
73
[a420b49]74static void
75put32(long w, FILE *fh)
76{
77   putc((char)(w), fh);
78   putc((char)(w >> 8l), fh);
79   putc((char)(w >> 16l), fh);
80   putc((char)(w >> 24l), fh);
[d1b1380]81}
[5c3c61a]82
83#endif
84
[dd1d6369]85#ifdef HAVE_ROUND
86# include <math.h>
87extern double round(double); /* prototype is often missing... */
88# define my_round round
89#else
90static double
91my_round(double x) {
92   if (x >= 0.0) return floor(x + 0.5);
93   return ceil(x - 0.5);
94}
95#endif
96
[ad4eaf3f]97/* portable case insensitive string compare */
98#if defined(strcasecmp) || defined(HAVE_STRCASECMP)
99# define my_strcasecmp strcasecmp
100#else
101/* What about top bit set chars? */
102int my_strcasecmp(const char *s1, const char *s2) {
103   register c1, c2;
104   do {
105      c1 = *s1++;
106      c2 = *s2++;
107   } while (c1 && toupper(c1) == toupper(c2));
108   /* now calculate real difference */
109   return c1 - c2;
110}
111#endif
112
[d69255f]113unsigned int img_output_version = 3;
[5c3c61a]114
[72af530]115#ifdef IMG_HOSTED
[5c3c61a]116static enum {
117   IMG_NONE = 0,
[759fb47]118   IMG_FILENOTFOUND = /*Couldn't open data file `%s'*/24,
[5c3c61a]119   IMG_OUTOFMEMORY  = /*Out of memory %.0s*/38,
[759fb47]120   IMG_DIRECTORY    = /*Filename `%s' refers to directory*/44,
121   IMG_CANTOPENOUT  = /*Failed to open output file `%s'*/47,
[ad9a5cd]122   IMG_BADFORMAT    = /*Bad 3d image file `%s'*/106,
123   IMG_READERROR    = /*Error reading from file `%s'*/109,
[6c1c4f3]124   IMG_WRITEERROR   = /*Error writing to file `%s'*/110,
125   IMG_TOONEW       = /*File `%s' has a newer format than this program can understand*/114
[5c3c61a]126} img_errno = IMG_NONE;
127#else
128static img_errcode img_errno = IMG_NONE;
[c0563da]129#endif
[d1b1380]130
[7d27e36]131#define FILEID "Survex 3D Image File"
132
[ad4eaf3f]133#define EXT_PLT "plt"
134
[0da6e60]135/* Attempt to string paste to ensure we are passed a literal string */
136#define LITLEN(S) (sizeof(S"") - 1)
137
[7d27e36]138static char *
139my_strdup(const char *str)
[a420b49]140{
[7d27e36]141   char *p;
142   size_t len = strlen(str) + 1;
143   p = xosmalloc(len);
144   if (p) memcpy(p, str, len);
145   return p;
[d1b1380]146}
[c0563da]147
[a2ad284]148static char *
149getline_alloc(FILE *fh)
150{
151   int ch;
152   size_t i = 0;
153   size_t len = 16;
154   char *buf = xosmalloc(len);
155   if (!buf) return NULL;
156
157   ch = getc(fh);
158   while (ch != '\n' && ch != '\r' && ch != EOF) {
159      buf[i++] = ch;
160      if (i == len - 1) {
161         char *p;
162         len += len;
163         p = xosrealloc(buf, len);
164         if (!p) {
165            osfree(buf);
166            return NULL;
167         }
168         buf = p;
169      }
170      ch = getc(fh);
171   }
172   if (ch == '\n' || ch == '\r') {
173      /* remove any further eol chars (for DOS text files) */
174      do {
175         ch = getc(fh);
176      } while (ch == '\n' || ch == '\r');
177      ungetc(ch, fh); /* we don't want it, so put it back */
178   }
[421b7d2]179   buf[i++] = '\0';
[a2ad284]180   return buf;
181}
182
[72af530]183#ifndef IMG_HOSTED
[a420b49]184img_errcode
185img_error(void)
186{
187   return img_errno;
[d1b1380]188}
189#else
[a420b49]190int
191img_error(void)
192{
193   return (int)img_errno;
[d1b1380]194}
195#endif
196
[a420b49]197img *
[a2ad284]198img_open_survey(const char *fnm, const char *survey)
[a420b49]199{
200   img *pimg;
[0da6e60]201   size_t len;
[7d27e36]202   char buf[LITLEN(FILEID) + 1];
203   int ch;
[a420b49]204
205   if (fDirectory(fnm)) {
206      img_errno = IMG_DIRECTORY;
207      return NULL;
208   }
[d1b1380]209
[a420b49]210   pimg = (img *)xosmalloc(ossizeof(img));
211   if (pimg == NULL) {
212      img_errno = IMG_OUTOFMEMORY;
213      return NULL;
214   }
[d1b1380]215
[23f7ea7]216   pimg->buf_len = 257;
[0ff23cb]217   pimg->label_buf = xosmalloc(pimg->buf_len);
218   if (!pimg->label_buf) {
[23f7ea7]219      osfree(pimg);
220      img_errno = IMG_OUTOFMEMORY;
221      return NULL;
222   }
223
[a420b49]224   pimg->fh = fopenWithPthAndExt("", fnm, EXT_SVX_3D, "rb", NULL);
225   if (pimg->fh == NULL) {
226      osfree(pimg);
227      img_errno = IMG_FILENOTFOUND;
228      return NULL;
229   }
[d1b1380]230
[0da6e60]231   pimg->fRead = fTrue; /* reading from this file */
232   img_errno = IMG_NONE;
233
234   pimg->flags = 0;
235
236   /* for version 3 we use label_buf to store the prefix for reuse */
237   pimg->label_len = 0;
238
239   pimg->survey = NULL;
240   pimg->survey_len = 0;
241
[58f02ae]242   pimg->title = NULL;
[0da6e60]243   if (survey) {
244      len = strlen(survey);
245      if (len) {
246         if (survey[len - 1] == '.') len--;
247         if (len) {
248            char *p;
249            pimg->survey = osmalloc(len + 2);
250            memcpy(pimg->survey, survey, len);
251            /* Set title to leaf survey name */
252            pimg->survey[len] = '\0';
253            p = strchr(pimg->survey, '.');
254            if (p) p++; else p = pimg->survey;
[7d27e36]255            pimg->title = my_strdup(p);
256            if (!pimg->title) {
257               img_errno = IMG_OUTOFMEMORY;
258               goto error;
259            }
[0da6e60]260            pimg->survey[len] = '.';
261            pimg->survey[len + 1] = '\0';
262         }
263      }
264      pimg->survey_len = len;
265   }
266
[ad4eaf3f]267   /* [version -2] pending IMG_LINE ('D') or IMG_MOVE ('M')
268    * [version -1] already skipped heading line, or there wasn't one
[0da6e60]269    * [version 0] not in the middle of a 'LINE' command
270    * [version 3] not in the middle of turning a LINE into a MOVE
271    */
272   pimg->pending = 0;
273
274   len = strlen(fnm);
275   if (len > LITLEN(EXT_SVX_POS) + 1 &&
276       fnm[len - LITLEN(EXT_SVX_POS) - 1] == FNM_SEP_EXT &&
[ad4eaf3f]277       my_strcasecmp(fnm + len - LITLEN(EXT_SVX_POS), EXT_SVX_POS) == 0) {
[0da6e60]278      pimg->version = -1;
[984f49e]279      if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm);
[7d27e36]280      pimg->datestamp = my_strdup(TIMENA);
281      if (!pimg->datestamp) {
282         img_errno = IMG_OUTOFMEMORY;
283         goto error;
284      }
[58f02ae]285      pimg->start = 0;
[0da6e60]286      return pimg;
287   }
[5757725]288
[ad4eaf3f]289   if (len > LITLEN(EXT_PLT) + 1 &&
290       fnm[len - LITLEN(EXT_PLT) - 1] == FNM_SEP_EXT &&
291       my_strcasecmp(fnm + len - LITLEN(EXT_PLT), EXT_PLT) == 0) {
292      char *line = NULL;
[f710a3f]293
[ad4eaf3f]294      pimg->version = -2;
[984f49e]295      if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm);
[ad4eaf3f]296      pimg->datestamp = my_strdup(TIMENA);
297      if (!pimg->datestamp) {
298         img_errno = IMG_OUTOFMEMORY;
299         goto error;
300      }
301      do {
[984f49e]302         do {
303            osfree(line);
304            line = getline_alloc(pimg->fh);
305            if (!line) {
306               img_errno = IMG_OUTOFMEMORY;
307               goto error;
308            }
309            if (line[0] == '\x1a') {
310               osfree(line);
311               pimg->pending = img_STOP + 4;
312               return pimg;
313            }
314            if (feof(pimg->fh)) {
[ad4eaf3f]315               osfree(line);
316               img_errno = IMG_BADFORMAT;
[984f49e]317               goto error;
[ad4eaf3f]318            }
[984f49e]319         } while (line[0] != 'N');
[f710a3f]320
[984f49e]321         len = 1;
322         while (line[len] > 32) ++len;
323      } while (pimg->survey && (pimg->survey_len != len - 1 ||
324               memcmp(line + 1, pimg->survey, pimg->survey_len) != 0));
[f710a3f]325
[5757725]326      if (len > pimg->buf_len) {
[f710a3f]327         char *b = xosrealloc(pimg->label_buf, len);
328         if (!b) {
329            img_errno = IMG_OUTOFMEMORY;
[984f49e]330            goto error;
[f710a3f]331         }
332         pimg->label_buf = b;
333         pimg->buf_len = len;
334      }
[984f49e]335      --len;
[f710a3f]336      pimg->label_len = len;
337      pimg->label = pimg->label_buf;
338      memcpy(pimg->label, line + 1, len);
339      pimg->label[len] = '\0';
[984f49e]340      if (pimg->survey) {
[5757725]341         char *q = strchr(line + len, 'C');
[984f49e]342         if (q && q[1]) {
343            osfree(pimg->title);
344            pimg->title = osstrdup(q + 1);
345         } else if (!pimg->title) {
346            pimg->title = osstrdup(pimg->label);
347         }
348         if (!pimg->title) {
349            img_errno = IMG_OUTOFMEMORY;
350            goto error;
351         }
352      }
[ad4eaf3f]353      osfree(line);
354      pimg->start = 0;
355      return pimg;
356   }
[0da6e60]357
[7d27e36]358   if (fread(buf, LITLEN(FILEID) + 1, 1, pimg->fh) != 1 ||
359       memcmp(buf, FILEID"\n", LITLEN(FILEID)) != 0) {
[a420b49]360      img_errno = IMG_BADFORMAT;
[58f02ae]361      goto error;
[a420b49]362   }
[d1b1380]363
[7d27e36]364   /* check file format version */
365   ch = getc(pimg->fh);
366   pimg->version = 0;
367   if (tolower(ch) == 'b') {
368      /* binary file iff B/b prefix */
369      pimg->version = 1;
370      ch = getc(pimg->fh);
371   }
372   if (ch != 'v') {
373      img_errno = IMG_BADFORMAT;
374      goto error;
375   }
376   ch = getc(pimg->fh);
377   if (ch == '0') {
378      if (fread(buf, 4, 1, pimg->fh) != 1 || memcmp(buf, ".01\n", 4) != 0) {
379         img_errno = IMG_BADFORMAT;
380         goto error;
381      }
[0da6e60]382      /* nothing special to do */
[7d27e36]383   } else if (pimg->version == 0) {
384      if (ch < '2' || ch > '3' || getc(pimg->fh) != '\n') {
[6c1c4f3]385         img_errno = IMG_TOONEW;
[58f02ae]386         goto error;
[6c1c4f3]387      }
[7d27e36]388      pimg->version = ch - '0';
[5c3c61a]389   } else {
[647407d]390      img_errno = IMG_BADFORMAT;
[58f02ae]391      goto error;
[a420b49]392   }
[421b7d2]393
[4d3dfdf]394   if (!pimg->title)
395       pimg->title = getline_alloc(pimg->fh);
396   else
397       osfree(getline_alloc(pimg->fh));
[a2ad284]398   pimg->datestamp = getline_alloc(pimg->fh);
399   if (!pimg->title || !pimg->datestamp) {
[58f02ae]400      img_errno = IMG_OUTOFMEMORY;
401      error:
[a2ad284]402      osfree(pimg->title);
[984f49e]403      osfree(pimg->datestamp);
[a2ad284]404      fclose(pimg->fh);
405      osfree(pimg);
406      return NULL;
407   }
408
[58f02ae]409   pimg->start = ftell(pimg->fh);
[421b7d2]410
[a420b49]411   return pimg;
[d1b1380]412}
413
[9f3e5df]414int
[f2588ca]415img_rewind(img *pimg)
416{
[9f3e5df]417   if (!pimg->fRead) {
418      img_errno = IMG_WRITEERROR;
419      return 0;
420   }
421   if (fseek(pimg->fh, pimg->start, SEEK_SET) != 0) {
422      img_errno = IMG_READERROR;
423      return 0;
424   }
[58f02ae]425   clearerr(pimg->fh);
426   /* [version -1] already skipped heading line, or there wasn't one
427    * [version 0] not in the middle of a 'LINE' command
[76bbb7c9]428    * [version 3] not in the middle of turning a LINE into a MOVE */
[984f49e]429   pimg->pending = 0; /* FIXME: consider rewind on .plt with survey matching nothing ... */
[d69255f]430
431   img_errno = IMG_NONE;
[99cf51a]432
[5d7280f8]433   /* for version 3 we use label_buf to store the prefix for reuse */
[d69255f]434   pimg->label_len = 0;
[9f3e5df]435   return 1;
[f2588ca]436}
437
[a420b49]438img *
[fe8e80e]439img_open_write(const char *fnm, char *title_buf, bool fBinary)
[a420b49]440{
441   time_t tm;
442   img *pimg;
[d1b1380]443
[d69255f]444   fBinary = fBinary;
445
[a420b49]446   if (fDirectory(fnm)) {
447      img_errno = IMG_DIRECTORY;
448      return NULL;
449   }
[d1b1380]450
[a420b49]451   pimg = (img *)xosmalloc(ossizeof(img));
452   if (pimg == NULL) {
453      img_errno = IMG_OUTOFMEMORY;
454      return NULL;
455   }
[d1b1380]456
[fe8e80e]457   pimg->buf_len = 257;
[0ff23cb]458   pimg->label_buf = xosmalloc(pimg->buf_len);
459   if (!pimg->label_buf) {
[fe8e80e]460      osfree(pimg);
461      img_errno = IMG_OUTOFMEMORY;
462      return NULL;
463   }
464
[a420b49]465   pimg->fh = fopen(fnm, "wb");
466   if (!pimg->fh) {
467      osfree(pimg);
468      img_errno = IMG_CANTOPENOUT;
469      return NULL;
470   }
[d1b1380]471
[a420b49]472   /* Output image file header */
473   fputs("Survex 3D Image File\n", pimg->fh); /* file identifier string */
[5c3c61a]474   if (img_output_version < 2) {
[d69255f]475      pimg->version = 1;
476      fputs("Bv0.01\n", pimg->fh); /* binary file format version number */
[5c3c61a]477   } else {
[d69255f]478      pimg->version = (img_output_version > 2) ? 3 : 2;
[5c3c61a]479      fprintf(pimg->fh, "v%d\n", pimg->version); /* file format version no. */
480   }
[fe8e80e]481   fputsnl(title_buf, pimg->fh);
[a420b49]482   tm = time(NULL);
483   if (tm == (time_t)-1) {
484      fputsnl(TIMENA, pimg->fh);
485   } else {
[7d27e36]486      char date[256];
[a420b49]487      /* output current date and time in format specified */
[7d27e36]488      strftime(date, 256, TIMEFMT, localtime(&tm));
489      fputsnl(date, pimg->fh);
[a420b49]490   }
491   pimg->fRead = fFalse; /* writing to this file */
492   img_errno = IMG_NONE;
[d69255f]493
[5d7280f8]494   /* for version 3 we use label_buf to store the prefix for reuse */
[0ff23cb]495   pimg->label_buf[0] = '\0';
[d69255f]496   pimg->label_len = 0;
497
[ad9a5cd]498   /* Don't check for write errors now - let img_close() report them... */
[a420b49]499   return pimg;
[d1b1380]500}
501
[ad9a5cd]502static int
503read_coord(FILE *fh, img_point *pt)
504{
505   ASSERT(fh);
506   ASSERT(pt);
507   pt->x = get32(fh) / 100.0;
508   pt->y = get32(fh) / 100.0;
509   pt->z = get32(fh) / 100.0;
510   if (ferror(fh) || feof(fh)) {
511      img_errno = feof(fh) ? IMG_BADFORMAT : IMG_READERROR;
512      return 0;
[421b7d2]513   }
[ad9a5cd]514   return 1;
515}
516
[4d3dfdf]517static int
518skip_coord(FILE *fh)
519{
520    return (fseek(fh, 12, SEEK_CUR) == 0);
521}
522
[a420b49]523int
[23f7ea7]524img_read_item(img *pimg, img_point *p)
[a420b49]525{
526   int result;
[95c3272]527   pimg->flags = 0;
[d69255f]528
529   if (pimg->version == 3) {
530      int opt;
[76bbb7c9]531      if (pimg->pending >= 0x80) {
532         *p = pimg->mv;
533         pimg->flags = (int)(pimg->pending) & 0x3f;
534         pimg->pending = 0;
[421b7d2]535         return img_LINE;
[76bbb7c9]536      }
[d69255f]537      again3: /* label to goto if we get a prefix */
[4d3dfdf]538      pimg->label = pimg->label_buf;
[d69255f]539      opt = getc(pimg->fh);
[ad9a5cd]540      if (opt == EOF) {
541         img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
542         return img_BAD;
543      }
[d69255f]544      switch (opt >> 6) {
545       case 0:
546         if (opt == 0) {
547            if (!pimg->label_len) return img_STOP; /* end of data marker */
548            pimg->label_len = 0;
549            goto again3;
550         }
551         if (opt < 15) {
552            /* 1-14 mean trim that many levels from current prefix */
553            int c;
554            if (pimg->label_len <= 16) {
[4d3dfdf]555               /* zero prefix using "0" */
[d69255f]556               img_errno = IMG_BADFORMAT;
557               return img_BAD;
558            }
[4b156b3]559            c = pimg->label_len - 16 - 1;
[0ff23cb]560            while (pimg->label_buf[c] != '.' || --opt > 0) {
[d69255f]561               if (--c < 0) {
562                  /* zero prefix using "0" */
563                  img_errno = IMG_BADFORMAT;
564                  return img_BAD;
565               }
566            }
567            c++;
568            pimg->label_len = c;
569            goto again3;
570         }
571         if (opt == 15) {
572            result = img_MOVE;
573            break;
574         }
575         /* 16-31 mean remove (n - 15) characters from the prefix */
576         /* zero prefix using 0 */
[ad4eaf3f]577         if (pimg->label_len <= (size_t)(opt - 15)) {
[d69255f]578            img_errno = IMG_BADFORMAT;
579            return img_BAD;
580         }
[d245d71]581         pimg->label_len -= (opt - 15);
[d69255f]582         goto again3;
583       case 1: case 2: {
584         char *q;
[ad9a5cd]585         long len = getc(pimg->fh);
586         if (len == EOF) {
587            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
588            return img_BAD;
589         }
[d69255f]590         if (len == 0xfe) {
591            len += get16(pimg->fh);
[ad9a5cd]592            if (feof(pimg->fh)) {
593               img_errno = IMG_BADFORMAT;
594               return img_BAD;
595            }
596            if (ferror(pimg->fh)) {
597               img_errno = IMG_READERROR;
598               return img_BAD;
599            }
[d69255f]600         } else if (len == 0xff) {
601            len = get32(pimg->fh);
[ad9a5cd]602            if (ferror(pimg->fh)) {
603               img_errno = IMG_READERROR;
604               return img_BAD;
605            }
606            if (feof(pimg->fh) || len < 0xfe + 0xffff) {
[d69255f]607               img_errno = IMG_BADFORMAT;
608               return img_BAD;
609            }
610         }
611
[0ff23cb]612         q = pimg->label_buf + pimg->label_len;
[d69255f]613         pimg->label_len += len;
614         if (pimg->label_len >= pimg->buf_len) {
[58f02ae]615            char *b = xosrealloc(pimg->label_buf, pimg->label_len + 1);
616            if (!b) {
[d69255f]617               img_errno = IMG_OUTOFMEMORY;
618               return img_BAD;
619            }
[58f02ae]620            q = (q - pimg->label_buf) + b;
621            pimg->label = pimg->label_buf = b;
[d69255f]622            pimg->buf_len = pimg->label_len + 1;
623         }
624         if (len && fread(q, len, 1, pimg->fh) != 1) {
[ad9a5cd]625            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]626            return img_BAD;
627         }
628         q[len] = '\0';
[76bbb7c9]629
630         result = opt & 0x40 ? img_LABEL : img_LINE;
631
632         if (pimg->survey_len) {
633            size_t l = pimg->survey_len;
[0ff23cb]634            const char *s = pimg->label_buf;
[76bbb7c9]635            if (result == img_LINE) {
636               if (strncmp(pimg->survey, s, l) != 0 ||
637                   !(s[l] == '.' || s[l] == '\0')) {
[421b7d2]638                  if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
[76bbb7c9]639                  pimg->pending = 15;
[421b7d2]640                  goto again3;
[76bbb7c9]641               }
642            } else {
643               if (strncmp(pimg->survey, s, l + 1) != 0) {
[4d3dfdf]644                  if (!skip_coord(pimg->fh)) return img_BAD;
645                  pimg->pending = 0;
[76bbb7c9]646                  goto again3;
647               }
648            }
[0ff23cb]649            pimg->label += l;
650            /* skip the dot if there */
651            if (*pimg->label) pimg->label++;
[76bbb7c9]652         }
653
654         if (result == img_LINE && pimg->pending) {
655            *p = pimg->mv;
[ad9a5cd]656            if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
[76bbb7c9]657            pimg->pending = opt;
658            return img_MOVE;
659         }
660         pimg->flags = (int)opt & 0x3f;
[d69255f]661         break;
662       }
663       default:
664         img_errno = IMG_BADFORMAT;
665         return img_BAD;
666      }
[ad9a5cd]667      if (!read_coord(pimg->fh, p)) return img_BAD;
[76bbb7c9]668      pimg->pending = 0;
[d69255f]669      return result;
[4d3dfdf]670   }
671
672   pimg->label = pimg->label_buf;
673
674   if (pimg->version > 0) {
[d69255f]675      static long opt_lookahead = 0;
[ad9a5cd]676      static img_point pt = { 0.0, 0.0, 0.0 };
[a420b49]677      long opt;
678      again: /* label to goto if we get a cross */
[5d7280f8]679      pimg->label[0] = '\0';
[ad9a5cd]680
[5c3c61a]681      if (pimg->version == 1) {
[c4d4649]682         if (opt_lookahead) {
683            opt = opt_lookahead;
684            opt_lookahead = 0;
685         } else {
686            opt = get32(pimg->fh);
687         }
[5c3c61a]688      } else {
[421b7d2]689         opt = getc(pimg->fh);
[5c3c61a]690      }
[ad9a5cd]691
692      if (feof(pimg->fh)) {
693         img_errno = IMG_BADFORMAT;
694         return img_BAD;
695      }
696      if (ferror(pimg->fh)) {
697         img_errno = IMG_READERROR;
698         return img_BAD;
699      }
700
[a420b49]701      switch (opt) {
[437caf3]702       case -1: case 0:
[a420b49]703         return img_STOP; /* end of data marker */
704       case 1:
[ad9a5cd]705         /* skip coordinates */
[4d3dfdf]706         if (!skip_coord(pimg->fh)) {
[ad9a5cd]707            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
708            return img_BAD;
709         }
[a420b49]710         goto again;
[23f7ea7]711       case 2: case 3: {
[fe8e80e]712         char *q;
[3a1f8da]713         int ch;
[437caf3]714         result = img_LABEL;
[3a1f8da]715         ch = getc(pimg->fh);
[d69255f]716         if (ch == EOF) {
[ad9a5cd]717            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]718            return img_BAD;
719         }
[3a1f8da]720         if (ch != '\\') ungetc(ch, pimg->fh);
[0ff23cb]721         fgets(pimg->label_buf, 257, pimg->fh);
[421b7d2]722         if (feof(pimg->fh)) {
[ad9a5cd]723            img_errno = IMG_BADFORMAT;
724            return img_BAD;
725         }
[421b7d2]726         if (ferror(pimg->fh)) {
[ad9a5cd]727            img_errno = IMG_READERROR;
728            return img_BAD;
729         }
[0ff23cb]730         q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[d69255f]731         if (*q != '\n') {
732            img_errno = IMG_BADFORMAT;
733            return img_BAD;
734         }
[9968ebf]735         /* Ignore empty labels in some .3d files (caused by a bug) */
[0ff23cb]736         if (q == pimg->label_buf) goto again;
[fe8e80e]737         *q = '\0';
[509e099]738         pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[437caf3]739         if (opt == 2) goto done;
740         break;
[23f7ea7]741       }
[95c3272]742       case 6: case 7: {
[ad9a5cd]743         long len;
[23f7ea7]744         result = img_LABEL;
[ad9a5cd]745
[509e099]746         if (opt == 7)
747            pimg->flags = getc(pimg->fh);
748         else
749            pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[ad9a5cd]750
[23f7ea7]751         len = get32(pimg->fh);
[ad9a5cd]752
753         if (feof(pimg->fh)) {
754            img_errno = IMG_BADFORMAT;
755            return img_BAD;
756         }
757         if (ferror(pimg->fh)) {
758            img_errno = IMG_READERROR;
759            return img_BAD;
760         }
761
[9968ebf]762         /* Ignore empty labels in some .3d files (caused by a bug) */
763         if (len == 0) goto again;
[dd1d6369]764         if (len >= (long)pimg->buf_len) {
[9b56f4d]765            char *b = xosrealloc(pimg->label_buf, len + 1);
766            if (!b) {
[23f7ea7]767               img_errno = IMG_OUTOFMEMORY;
768               return img_BAD;
769            }
[9b56f4d]770            pimg->label = pimg->label_buf = b;
[23f7ea7]771            pimg->buf_len = len + 1;
772         }
[0ff23cb]773         if (fread(pimg->label_buf, len, 1, pimg->fh) != 1) {
[ad9a5cd]774            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]775            return img_BAD;
776         }
[23f7ea7]777         break;
778       }
[a420b49]779       case 4:
780         result = img_MOVE;
781         break;
782       case 5:
783         result = img_LINE;
784         break;
785       default:
[95c3272]786         switch ((int)opt & 0xc0) {
787          case 0x80:
788            pimg->flags = (int)opt & 0x3f;
789            result = img_LINE;
790            break;
791          case 0x40: {
792            char *q;
793            pimg->flags = (int)opt & 0x3f;
794            result = img_LABEL;
[0ff23cb]795            if (!fgets(pimg->label_buf, 257, pimg->fh)) {
[ad9a5cd]796               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]797               return img_BAD;
798            }
[0ff23cb]799            q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[9968ebf]800            /* Ignore empty-labels in some .3d files (caused by a bug) */
[0ff23cb]801            if (q == pimg->label_buf) goto again;
[d69255f]802            if (*q != '\n') {
803               img_errno = IMG_BADFORMAT;
804               return img_BAD;
805            }
[95c3272]806            *q = '\0';
807            break;
808          }
809          case 0xc0:
810            /* use this for an extra leg or station flag if we need it */
811          default:
[d69255f]812            img_errno = IMG_BADFORMAT;
[95c3272]813            return img_BAD;
814         }
[437caf3]815         break;
[a420b49]816      }
[ad9a5cd]817
818      if (!read_coord(pimg->fh, &pt)) return img_BAD;
[76bbb7c9]819
[ed0f5b6]820      if (result == img_LABEL && pimg->survey_len) {
821         if (strncmp(pimg->label_buf, pimg->survey, pimg->survey_len + 1) != 0)
[0ff23cb]822            goto again;
823         pimg->label += pimg->survey_len + 1;
824      }
[76bbb7c9]825
[a420b49]826      done:
[ad9a5cd]827      *p = pt;
[c4d4649]828
829      if (result == img_MOVE && pimg->version == 1) {
[d69255f]830         /* peek at next code and see if it's an old-style label */
[23f7ea7]831         opt_lookahead = get32(pimg->fh);
[ad9a5cd]832
833         if (feof(pimg->fh)) {
834            img_errno = IMG_BADFORMAT;
835            return img_BAD;
836         }
837         if (ferror(pimg->fh)) {
838            img_errno = IMG_READERROR;
839            return img_BAD;
840         }
841
[d69255f]842         if (opt_lookahead == 2) return img_read_item(pimg, p);
[c4d4649]843      }
[23f7ea7]844
[a420b49]845      return result;
[0da6e60]846   } else if (pimg->version == 0) {
[a420b49]847      ascii_again:
[5d7280f8]848      pimg->label[0] = '\0';
[a420b49]849      if (feof(pimg->fh)) return img_STOP;
[76bbb7c9]850      if (pimg->pending) {
851         pimg->pending = 0;
[a420b49]852         result = img_LINE;
853      } else {
[7d27e36]854         char cmd[7];
[a420b49]855         /* Stop if nothing found */
[7d27e36]856         if (fscanf(pimg->fh, "%6s", cmd) < 1) return img_STOP;
857         if (strcmp(cmd, "move") == 0)
[a420b49]858            result = img_MOVE;
[7d27e36]859         else if (strcmp(cmd, "draw") == 0)
[a420b49]860            result = img_LINE;
[7d27e36]861         else if (strcmp(cmd, "line") == 0) {
[bd1913f]862            /* set flag to indicate to process second triplet as LINE */
[76bbb7c9]863            pimg->pending = 1;
[a420b49]864            result = img_MOVE;
[7d27e36]865         } else if (strcmp(cmd, "cross") == 0) {
[d69255f]866            if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]867               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[0ed0e16]868               return img_BAD;
[d69255f]869            }
[a420b49]870            goto ascii_again;
[7d27e36]871         } else if (strcmp(cmd, "name") == 0) {
[0da6e60]872            size_t off = 0;
[58f02ae]873            int ch = getc(pimg->fh);
874            if (ch == ' ') ch = getc(pimg->fh);
875            while (ch != ' ') {
876               if (ch == '\n' || ch == EOF) {
877                  img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
[ad9a5cd]878                  return img_BAD;
879               }
[58f02ae]880               if (off == pimg->buf_len) {
[9b56f4d]881                  char *b;
882                  b = xosrealloc(pimg->label_buf, pimg->buf_len * 2);
883                  if (!b) {
884                     img_errno = IMG_OUTOFMEMORY;
885                     return img_BAD;
886                  }
887                  pimg->label_buf = b;
888                  pimg->buf_len *= 2;
[0da6e60]889               }
[58f02ae]890               pimg->label_buf[off++] = ch;
891               ch = getc(pimg->fh);
[ad9a5cd]892            }
[58f02ae]893            pimg->label_buf[off] = '\0';
894
895            pimg->label = pimg->label_buf;
896            if (pimg->label[0] == '\\') pimg->label++;
[0da6e60]897
[a420b49]898            result = img_LABEL;
[d69255f]899         } else {
900            img_errno = IMG_BADFORMAT;
[a420b49]901            return img_BAD; /* unknown keyword */
[d69255f]902         }
[a420b49]903      }
[d1b1380]904
[d69255f]905      if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]906         img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
[fe8e80e]907         return img_BAD;
[d69255f]908      }
909
[58f02ae]910      if (result == img_LABEL && pimg->survey_len) {
911         if (strncmp(pimg->label, pimg->survey, pimg->survey_len + 1) != 0)
[0ff23cb]912            goto ascii_again;
913         pimg->label += pimg->survey_len + 1;
914      }
[76bbb7c9]915
[a420b49]916      return result;
[ad4eaf3f]917   } else if (pimg->version == -1) {
[0da6e60]918      /* version -1: .pos file */
[58f02ae]919      size_t off;
[5eea574]920      pimg->flags = img_SFLAG_UNDERGROUND; /* default flags */
[58f02ae]921      againpos:
922      off = 0;
[0da6e60]923      while (fscanf(pimg->fh, "(%lf,%lf,%lf ) ", &p->x, &p->y, &p->z) != 3) {
924         int ch;
925         if (ferror(pimg->fh)) {
926            img_errno = IMG_READERROR;
927            return img_BAD;
928         }
929         if (feof(pimg->fh)) return img_STOP;
930         if (pimg->pending) {
931            img_errno = IMG_BADFORMAT;
932            return img_BAD;
933         }
934         pimg->pending = 1;
935         /* ignore rest of line */
936         do {
937            ch = getc(pimg->fh);
938         } while (ch != '\n' && ch != '\r' && ch != EOF);
939      }
940
941      pimg->label_buf[0] = '\0';
942      while (!feof(pimg->fh)) {
[9b56f4d]943         char *b;
[0da6e60]944         if (!fgets(pimg->label_buf + off, pimg->buf_len - off, pimg->fh)) {
945            img_errno = IMG_READERROR;
946            return img_BAD;
947         }
948
949         off += strlen(pimg->label_buf + off);
950         if (off && pimg->label_buf[off - 1] == '\n') {
951            pimg->label_buf[off - 1] = '\0';
952            break;
953         }
[9b56f4d]954         b = xosrealloc(pimg->label_buf, pimg->buf_len * 2);
955         if (!b) {
956            img_errno = IMG_OUTOFMEMORY;
957            return img_BAD;
958         }
959         pimg->label_buf = b;
960         pimg->buf_len *= 2;
[0da6e60]961      }
962
[58f02ae]963      pimg->label = pimg->label_buf;
964
[421b7d2]965      if (pimg->label[0] == '\\') pimg->label++;
[58f02ae]966
967      if (pimg->survey_len) {
968         size_t l = pimg->survey_len + 1;
969         if (strncmp(pimg->survey, pimg->label, l) != 0) goto againpos;
970         pimg->label += l;
971      }
972
[0da6e60]973      return img_LABEL;
[ad4eaf3f]974   } else {
975      /* version -2: Compass .plt file */
976      if (pimg->pending) {
[984f49e]977         /* pending MOVE or LINE or STOP */
978         int r = pimg->pending - 4;
[ad4eaf3f]979         pimg->pending = 0;
980         pimg->flags = 0;
[f710a3f]981         pimg->label[pimg->label_len] = '\0';
[ad4eaf3f]982         return r;
983      }
984
985      while (1) {
986         char *line = getline_alloc(pimg->fh);
987         char *q;
988         size_t len = 0;
989
990         switch (line[0]) {
991            case 'M': case 'D':
992               /* Move or Draw */
993               if (sscanf(line + 1, "%lf %lf %lf", &p->x, &p->y, &p->z) != 3) {
994                  osfree(line);
995                  if (ferror(pimg->fh)) {
996                     img_errno = IMG_READERROR;
997                  } else {
998                     img_errno = IMG_BADFORMAT;
999                  }
1000                  return img_BAD;
1001               }
1002               q = strchr(line, 'S');
1003               if (!q) {
1004                  osfree(line);
[5757725]1005                  img_errno = IMG_BADFORMAT;
[ad4eaf3f]1006                  return img_BAD;
1007               }
1008               ++q;
1009               len = 0;
1010               while (q[len] > ' ') ++len;
1011               q[len] = '\0';
[f710a3f]1012               len += 2; /* '.' and '\0' */
[5757725]1013               if (pimg->label_len + len > pimg->buf_len) {
[f710a3f]1014                  char *b = xosrealloc(pimg->label_buf, pimg->label_len + len);
[ad4eaf3f]1015                  if (!b) {
1016                     img_errno = IMG_OUTOFMEMORY;
1017                     return img_BAD;
1018                  }
1019                  pimg->label_buf = b;
[f710a3f]1020                  pimg->buf_len = pimg->label_len + len;
[ad4eaf3f]1021               }
1022               pimg->label = pimg->label_buf;
[f710a3f]1023               pimg->label[pimg->label_len] = '.';
1024               memcpy(pimg->label + pimg->label_len + 1, q, len - 1);
[984f49e]1025               pimg->pending = (line[0] == 'M' ? img_MOVE : img_LINE) + 4;
[ad4eaf3f]1026               osfree(line);
1027               pimg->flags = img_SFLAG_UNDERGROUND; /* default flags */
1028               return img_LABEL;
1029            case 'X': case 'F': case 'S':
1030               /* bounding boX (marks end of survey), Feature survey, or
1031                * new Section - skip to next survey */
1032               do {
[984f49e]1033                  do {
[ad4eaf3f]1034                     osfree(line);
[984f49e]1035                     line = getline_alloc(pimg->fh);
1036                     if (!line) {
1037                        img_errno = IMG_OUTOFMEMORY;
1038                        return img_BAD;
1039                     }
1040                     if (line[0] == '\x1a') {
1041                        osfree(line);
1042                        return img_STOP;
1043                     }
1044                     if (feof(pimg->fh)) {
1045                        osfree(line);
1046                        img_errno = IMG_BADFORMAT;
1047                        return img_BAD;
1048                     }
1049                  } while (line[0] != 'N');
1050
1051                  len = 1;
1052                  while (line[len] > 32) ++len;
1053               } while (pimg->survey && (pimg->survey_len != len - 1 ||
1054                        memcmp(line + 1, pimg->survey, pimg->survey_len) != 0));
[f710a3f]1055
1056               if (len > pimg->buf_len) {
1057                  char *b = xosrealloc(pimg->label_buf, len);
1058                  if (!b) {
1059                     img_errno = IMG_OUTOFMEMORY;
1060                     return img_BAD;
1061                  }
1062                  pimg->label_buf = b;
1063                  pimg->buf_len = len;
1064               }
1065               --len;
1066               pimg->label_len = len;
1067               pimg->label = pimg->label_buf;
1068               memcpy(pimg->label, line + 1, len);
1069               pimg->label[len] = '\0';
1070
[ad4eaf3f]1071               osfree(line);
1072               break;
1073            default:
1074               osfree(line);
1075               img_errno = IMG_BADFORMAT;
1076               return img_BAD;
1077         }
1078      }
[a420b49]1079   }
[d1b1380]1080}
1081
[ad9a5cd]1082static int
[d69255f]1083write_v3label(img *pimg, int opt, const char *s)
1084{
1085   size_t len, n, dot;
1086
1087   /* find length of common prefix */
1088   dot = 0;
[0ff23cb]1089   for (len = 0; s[len] == pimg->label_buf[len] && s[len] != '\0'; len++) {
[d69255f]1090      if (s[len] == '.') dot = len + 1;
1091   }
1092
1093   ASSERT(len <= pimg->label_len);
1094   n = pimg->label_len - len;
1095   if (len == 0) {
1096      if (pimg->label_len) putc(0, pimg->fh);
1097   } else if (n <= 16) {
1098      if (n) putc(n + 15, pimg->fh);
1099   } else if (dot == 0) {
1100      if (pimg->label_len) putc(0, pimg->fh);
[99cf51a]1101      len = 0;
[d69255f]1102   } else {
[0ff23cb]1103      const char *p = pimg->label_buf + dot;
[d69255f]1104      n = 1;
1105      for (len = pimg->label_len - dot - 17; len; len--) {
1106         if (*p++ == '.') n++;
1107      }
1108      if (n <= 14) {
1109         putc(n, pimg->fh);
1110         len = dot;
1111      } else {
1112         if (pimg->label_len) putc(0, pimg->fh);
1113         len = 0;
1114      }
1115   }
1116
1117   n = strlen(s + len);
1118   putc(opt, pimg->fh);
1119   if (n < 0xfe) {
1120      putc(n, pimg->fh);
1121   } else if (n < 0xffff + 0xfe) {
1122      putc(0xfe, pimg->fh);
1123      put16(n - 0xfe, pimg->fh);
1124   } else {
1125      putc(0xff, pimg->fh);
1126      put32(n, pimg->fh);
1127   }
1128   fwrite(s + len, n, 1, pimg->fh);
1129
1130   n += len;
1131   pimg->label_len = n;
1132   if (n >= pimg->buf_len) {
[0ff23cb]1133      char *p = xosrealloc(pimg->label_buf, n + 1);
[ad9a5cd]1134      if (!p) return 0; /* FIXME: distinguish out of memory... */
1135      pimg->label_buf = p;
1136      pimg->buf_len = n + 1;
[d69255f]1137   }
[0ff23cb]1138   memcpy(pimg->label_buf + len, s + len, n - len + 1);
[ad9a5cd]1139
1140   return !ferror(pimg->fh);
[d69255f]1141}
1142
[a420b49]1143void
[95c3272]1144img_write_item(img *pimg, int code, int flags, const char *s,
[a9f5117]1145               double x, double y, double z)
[a420b49]1146{
[647407d]1147   if (!pimg) return;
[d69255f]1148   if (pimg->version == 3) {
1149      int opt = 0;
1150      switch (code) {
1151       case img_LABEL:
1152         write_v3label(pimg, 0x40 | flags, s);
1153         opt = 0;
1154         break;
1155       case img_MOVE:
1156         opt = 15;
1157         break;
1158       case img_LINE:
1159         write_v3label(pimg, 0x80 | flags, s ? s : "");
1160         opt = 0;
1161         break;
1162       default: /* ignore for now */
1163         return;
1164      }
1165      if (opt) putc(opt, pimg->fh);
1166      /* Output in cm */
[dd1d6369]1167      put32((INT32_T)my_round(x * 100.0), pimg->fh);
1168      put32((INT32_T)my_round(y * 100.0), pimg->fh);
1169      put32((INT32_T)my_round(z * 100.0), pimg->fh);
[d69255f]1170   } else {
[23f7ea7]1171      size_t len;
[badeec8]1172      INT32_T opt = 0;
[d69255f]1173      ASSERT(pimg->version > 0);
[a420b49]1174      switch (code) {
[437caf3]1175       case img_LABEL:
1176         if (pimg->version == 1) {
1177            /* put a move before each label */
[95c3272]1178            img_write_item(pimg, img_MOVE, 0, NULL, x, y, z);
[437caf3]1179            put32(2, pimg->fh);
[0ed0e16]1180            fputsnl(s, pimg->fh);
[437caf3]1181            return;
1182         }
[23f7ea7]1183         len = strlen(s);
[af56069]1184         if (len > 255 || strchr(s, '\n')) {
[23f7ea7]1185            /* long label - not in early incarnations of v2 format, but few
1186             * 3d files will need these, so better not to force incompatibility
1187             * with a new version I think... */
[95c3272]1188            putc(7, pimg->fh);
1189            putc(flags, pimg->fh);
[23f7ea7]1190            put32(len, pimg->fh);
1191            fputs(s, pimg->fh);
1192         } else {
[95c3272]1193            putc(0x40 | (flags & 0x3f), pimg->fh);
[23f7ea7]1194            fputsnl(s, pimg->fh);
1195         }
[437caf3]1196         opt = 0;
[23f7ea7]1197         break;
[a420b49]1198       case img_MOVE:
1199         opt = 4;
1200         break;
1201       case img_LINE:
[421b7d2]1202         if (pimg->version > 1) {
[d69255f]1203            opt = 0x80 | (flags & 0x3f);
[437caf3]1204            break;
[421b7d2]1205         }
[437caf3]1206         opt = 5;
[a420b49]1207         break;
[437caf3]1208       default: /* ignore for now */
1209         return;
[a420b49]1210      }
[437caf3]1211      if (pimg->version == 1) {
1212         put32(opt, pimg->fh);
1213      } else {
1214         if (opt) putc(opt, pimg->fh);
[a420b49]1215      }
[d69255f]1216      /* Output in cm */
[dd1d6369]1217      put32((INT32_T)my_round(x * 100.0), pimg->fh);
1218      put32((INT32_T)my_round(y * 100.0), pimg->fh);
1219      put32((INT32_T)my_round(z * 100.0), pimg->fh);
[a420b49]1220   }
[d1b1380]1221}
1222
[ad9a5cd]1223int
[a420b49]1224img_close(img *pimg)
1225{
[ad9a5cd]1226   int result = 1;
[dbb4e19]1227   if (pimg) {
1228      if (pimg->fh) {
[76bbb7c9]1229         if (pimg->fRead) {
1230            osfree(pimg->survey);
[a2ad284]1231            osfree(pimg->title);
1232            osfree(pimg->datestamp);
[76bbb7c9]1233         } else {
1234            /* write end of data marker */
[d69255f]1235            switch (pimg->version) {
1236             case 1:
[5c3c61a]1237               put32((INT32_T)-1, pimg->fh);
[d69255f]1238               break;
1239             case 2:
1240               putc(0, pimg->fh);
1241               break;
1242             case 3:
1243               if (pimg->label_len) putc(0, pimg->fh);
[437caf3]1244               putc(0, pimg->fh);
[d69255f]1245               break;
[5c3c61a]1246            }
1247         }
[ad9a5cd]1248         if (ferror(pimg->fh)) result = 0;
1249         if (fclose(pimg->fh)) result = 0;
1250         img_errno = pimg->fRead ? IMG_READERROR : IMG_WRITEERROR;
[dbb4e19]1251      }
[0ff23cb]1252      osfree(pimg->label_buf);
[dbb4e19]1253      osfree(pimg);
[a420b49]1254   }
[ad9a5cd]1255   return result;
[d1b1380]1256}
Note: See TracBrowser for help on using the repository browser.