source: git/src/img.c @ 27bd06b

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 27bd06b was 27bd06b, checked in by Olly Betts <olly@…>, 23 years ago

.plt files typically start "Z " so use that to auto-detect filetype.

Fixed handling of --survey.

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

  • Property mode set to 100644
File size: 30.7 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') {
[4ebc557]173      int otherone = ch ^ ('\n' ^ '\r');
174      ch = getc(fh);
175      /* if it's not the other eol character, put it back */
176      if (ch != otherone) ungetc(ch, fh);
[a2ad284]177   }
[421b7d2]178   buf[i++] = '\0';
[a2ad284]179   return buf;
180}
181
[72af530]182#ifndef IMG_HOSTED
[a420b49]183img_errcode
184img_error(void)
185{
186   return img_errno;
[d1b1380]187}
188#else
[a420b49]189int
190img_error(void)
191{
192   return (int)img_errno;
[d1b1380]193}
194#endif
195
[d4d3655]196static bool
197check_label_space(img *pimg, size_t len)
198{
199   if (len > pimg->buf_len) {
200      char *b = xosrealloc(pimg->label_buf, len);
201      if (!b) return fFalse;
202      pimg->label = (pimg->label - pimg->label_buf) + b;
203      pimg->label_buf = b;
204      pimg->buf_len = len;
205   }
206   return fTrue;
207}
208
[a420b49]209img *
[a2ad284]210img_open_survey(const char *fnm, const char *survey)
[a420b49]211{
212   img *pimg;
[0da6e60]213   size_t len;
[7d27e36]214   char buf[LITLEN(FILEID) + 1];
215   int ch;
[a420b49]216
217   if (fDirectory(fnm)) {
218      img_errno = IMG_DIRECTORY;
219      return NULL;
220   }
[d1b1380]221
[a420b49]222   pimg = (img *)xosmalloc(ossizeof(img));
223   if (pimg == NULL) {
224      img_errno = IMG_OUTOFMEMORY;
225      return NULL;
226   }
[d1b1380]227
[23f7ea7]228   pimg->buf_len = 257;
[0ff23cb]229   pimg->label_buf = xosmalloc(pimg->buf_len);
230   if (!pimg->label_buf) {
[23f7ea7]231      osfree(pimg);
232      img_errno = IMG_OUTOFMEMORY;
233      return NULL;
234   }
235
[a420b49]236   pimg->fh = fopenWithPthAndExt("", fnm, EXT_SVX_3D, "rb", NULL);
237   if (pimg->fh == NULL) {
238      osfree(pimg);
239      img_errno = IMG_FILENOTFOUND;
240      return NULL;
241   }
[d1b1380]242
[0da6e60]243   pimg->fRead = fTrue; /* reading from this file */
244   img_errno = IMG_NONE;
245
246   pimg->flags = 0;
247
248   /* for version 3 we use label_buf to store the prefix for reuse */
[4ebc557]249   /* for version -2, 0 value indicates we haven't entered a survey yet */
[0da6e60]250   pimg->label_len = 0;
251
252   pimg->survey = NULL;
253   pimg->survey_len = 0;
254
[58f02ae]255   pimg->title = NULL;
[0da6e60]256   if (survey) {
257      len = strlen(survey);
258      if (len) {
259         if (survey[len - 1] == '.') len--;
260         if (len) {
261            char *p;
262            pimg->survey = osmalloc(len + 2);
263            memcpy(pimg->survey, survey, len);
264            /* Set title to leaf survey name */
265            pimg->survey[len] = '\0';
266            p = strchr(pimg->survey, '.');
267            if (p) p++; else p = pimg->survey;
[7d27e36]268            pimg->title = my_strdup(p);
269            if (!pimg->title) {
270               img_errno = IMG_OUTOFMEMORY;
271               goto error;
272            }
[0da6e60]273            pimg->survey[len] = '.';
274            pimg->survey[len + 1] = '\0';
275         }
276      }
277      pimg->survey_len = len;
278   }
279
[ad4eaf3f]280   /* [version -2] pending IMG_LINE ('D') or IMG_MOVE ('M')
281    * [version -1] already skipped heading line, or there wasn't one
[0da6e60]282    * [version 0] not in the middle of a 'LINE' command
283    * [version 3] not in the middle of turning a LINE into a MOVE
284    */
285   pimg->pending = 0;
286
287   len = strlen(fnm);
288   if (len > LITLEN(EXT_SVX_POS) + 1 &&
289       fnm[len - LITLEN(EXT_SVX_POS) - 1] == FNM_SEP_EXT &&
[ad4eaf3f]290       my_strcasecmp(fnm + len - LITLEN(EXT_SVX_POS), EXT_SVX_POS) == 0) {
[0da6e60]291      pimg->version = -1;
[984f49e]292      if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm);
[7d27e36]293      pimg->datestamp = my_strdup(TIMENA);
294      if (!pimg->datestamp) {
295         img_errno = IMG_OUTOFMEMORY;
296         goto error;
297      }
[58f02ae]298      pimg->start = 0;
[0da6e60]299      return pimg;
300   }
[5757725]301
[ad4eaf3f]302   if (len > LITLEN(EXT_PLT) + 1 &&
303       fnm[len - LITLEN(EXT_PLT) - 1] == FNM_SEP_EXT &&
304       my_strcasecmp(fnm + len - LITLEN(EXT_PLT), EXT_PLT) == 0) {
[4ebc557]305      long fpos;
[27bd06b]306plt_file:
[ad4eaf3f]307      pimg->version = -2;
[4ebc557]308      pimg->start = 0;
[984f49e]309      if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm);
[ad4eaf3f]310      pimg->datestamp = my_strdup(TIMENA);
311      if (!pimg->datestamp) {
312         img_errno = IMG_OUTOFMEMORY;
313         goto error;
314      }
[4ebc557]315      while (1) {
316         int ch = getc(pimg->fh);
317         switch (ch) {
318          case '\x1a':
319            fseek(pimg->fh, -1, SEEK_CUR);
320            /* FALL THRU */
321          case EOF:
322            pimg->start = ftell(pimg->fh);
323            return pimg;
324          case 'N': {
325            char *line, *q;
326            fpos = ftell(pimg->fh) - 1;
327            if (!pimg->survey) {
328               /* FIXME : if there's only one survey in the file, it'd be nice
329                * to use its description as the title here...
330                */
[0d922fc]331               ungetc('N', pimg->fh);
[4ebc557]332               pimg->start = fpos;
[984f49e]333               return pimg;
334            }
[4ebc557]335            line = getline_alloc(pimg->fh);
[0d922fc]336            len = 0;
[4ebc557]337            while (line[len] > 32) ++len;
338            if (pimg->survey_len != len ||
339                memcmp(line, pimg->survey, len) != 0) {
[ad4eaf3f]340               osfree(line);
[4ebc557]341               continue;
[ad4eaf3f]342            }
[4ebc557]343            q = strchr(line + len, 'C');
344            if (q && q[1]) {
345                osfree(pimg->title);
346                pimg->title = osstrdup(q + 1);
347            } else if (!pimg->title) {
348                pimg->title = osstrdup(pimg->label);
349            }
350            osfree(line);
351            if (!pimg->title) {
352                img_errno = IMG_OUTOFMEMORY;
353                goto error;
354            }
355            if (!pimg->start) pimg->start = fpos;
[27bd06b]356            fseek(pimg->fh, pimg->start, SEEK_SET);
[4ebc557]357            return pimg;
358          }
359          case 'M': case 'D':
360            pimg->start = ftell(pimg->fh) - 1;
361            break;
[984f49e]362         }
[4ebc557]363         while (ch != '\n' && ch != '\r') {
364            ch = getc(pimg->fh);
[984f49e]365         }
366      }
[ad4eaf3f]367   }
[0da6e60]368
[7d27e36]369   if (fread(buf, LITLEN(FILEID) + 1, 1, pimg->fh) != 1 ||
370       memcmp(buf, FILEID"\n", LITLEN(FILEID)) != 0) {
[27bd06b]371      if (buf[0] == 'Z' && buf[1] == ' ') {
372         /* Looks like a Compass .plt file ... */
373         rewind(pimg->fh);
374         goto plt_file;
375      }
[a420b49]376      img_errno = IMG_BADFORMAT;
[58f02ae]377      goto error;
[a420b49]378   }
[d1b1380]379
[7d27e36]380   /* check file format version */
381   ch = getc(pimg->fh);
382   pimg->version = 0;
383   if (tolower(ch) == 'b') {
384      /* binary file iff B/b prefix */
385      pimg->version = 1;
386      ch = getc(pimg->fh);
387   }
388   if (ch != 'v') {
389      img_errno = IMG_BADFORMAT;
390      goto error;
391   }
392   ch = getc(pimg->fh);
393   if (ch == '0') {
394      if (fread(buf, 4, 1, pimg->fh) != 1 || memcmp(buf, ".01\n", 4) != 0) {
395         img_errno = IMG_BADFORMAT;
396         goto error;
397      }
[0da6e60]398      /* nothing special to do */
[7d27e36]399   } else if (pimg->version == 0) {
400      if (ch < '2' || ch > '3' || getc(pimg->fh) != '\n') {
[6c1c4f3]401         img_errno = IMG_TOONEW;
[58f02ae]402         goto error;
[6c1c4f3]403      }
[7d27e36]404      pimg->version = ch - '0';
[5c3c61a]405   } else {
[647407d]406      img_errno = IMG_BADFORMAT;
[58f02ae]407      goto error;
[a420b49]408   }
[421b7d2]409
[4d3dfdf]410   if (!pimg->title)
411       pimg->title = getline_alloc(pimg->fh);
412   else
413       osfree(getline_alloc(pimg->fh));
[a2ad284]414   pimg->datestamp = getline_alloc(pimg->fh);
415   if (!pimg->title || !pimg->datestamp) {
[58f02ae]416      img_errno = IMG_OUTOFMEMORY;
417      error:
[a2ad284]418      osfree(pimg->title);
[984f49e]419      osfree(pimg->datestamp);
[a2ad284]420      fclose(pimg->fh);
421      osfree(pimg);
422      return NULL;
423   }
424
[58f02ae]425   pimg->start = ftell(pimg->fh);
[421b7d2]426
[a420b49]427   return pimg;
[d1b1380]428}
429
[9f3e5df]430int
[f2588ca]431img_rewind(img *pimg)
432{
[9f3e5df]433   if (!pimg->fRead) {
434      img_errno = IMG_WRITEERROR;
435      return 0;
436   }
437   if (fseek(pimg->fh, pimg->start, SEEK_SET) != 0) {
438      img_errno = IMG_READERROR;
439      return 0;
440   }
[58f02ae]441   clearerr(pimg->fh);
442   /* [version -1] already skipped heading line, or there wasn't one
443    * [version 0] not in the middle of a 'LINE' command
[76bbb7c9]444    * [version 3] not in the middle of turning a LINE into a MOVE */
[4ebc557]445   pimg->pending = 0;
[d69255f]446
447   img_errno = IMG_NONE;
[99cf51a]448
[5d7280f8]449   /* for version 3 we use label_buf to store the prefix for reuse */
[4ebc557]450   /* for version -2, 0 value indicates we haven't entered a survey yet */
[d69255f]451   pimg->label_len = 0;
[9f3e5df]452   return 1;
[f2588ca]453}
454
[a420b49]455img *
[fe8e80e]456img_open_write(const char *fnm, char *title_buf, bool fBinary)
[a420b49]457{
458   time_t tm;
459   img *pimg;
[d1b1380]460
[d69255f]461   fBinary = fBinary;
462
[a420b49]463   if (fDirectory(fnm)) {
464      img_errno = IMG_DIRECTORY;
465      return NULL;
466   }
[d1b1380]467
[a420b49]468   pimg = (img *)xosmalloc(ossizeof(img));
469   if (pimg == NULL) {
470      img_errno = IMG_OUTOFMEMORY;
471      return NULL;
472   }
[d1b1380]473
[fe8e80e]474   pimg->buf_len = 257;
[0ff23cb]475   pimg->label_buf = xosmalloc(pimg->buf_len);
476   if (!pimg->label_buf) {
[fe8e80e]477      osfree(pimg);
478      img_errno = IMG_OUTOFMEMORY;
479      return NULL;
480   }
481
[a420b49]482   pimg->fh = fopen(fnm, "wb");
483   if (!pimg->fh) {
484      osfree(pimg);
485      img_errno = IMG_CANTOPENOUT;
486      return NULL;
487   }
[d1b1380]488
[a420b49]489   /* Output image file header */
490   fputs("Survex 3D Image File\n", pimg->fh); /* file identifier string */
[5c3c61a]491   if (img_output_version < 2) {
[d69255f]492      pimg->version = 1;
493      fputs("Bv0.01\n", pimg->fh); /* binary file format version number */
[5c3c61a]494   } else {
[d69255f]495      pimg->version = (img_output_version > 2) ? 3 : 2;
[5c3c61a]496      fprintf(pimg->fh, "v%d\n", pimg->version); /* file format version no. */
497   }
[fe8e80e]498   fputsnl(title_buf, pimg->fh);
[a420b49]499   tm = time(NULL);
500   if (tm == (time_t)-1) {
501      fputsnl(TIMENA, pimg->fh);
502   } else {
[7d27e36]503      char date[256];
[a420b49]504      /* output current date and time in format specified */
[7d27e36]505      strftime(date, 256, TIMEFMT, localtime(&tm));
506      fputsnl(date, pimg->fh);
[a420b49]507   }
508   pimg->fRead = fFalse; /* writing to this file */
509   img_errno = IMG_NONE;
[d69255f]510
[5d7280f8]511   /* for version 3 we use label_buf to store the prefix for reuse */
[0ff23cb]512   pimg->label_buf[0] = '\0';
[d69255f]513   pimg->label_len = 0;
514
[ad9a5cd]515   /* Don't check for write errors now - let img_close() report them... */
[a420b49]516   return pimg;
[d1b1380]517}
518
[ad9a5cd]519static int
520read_coord(FILE *fh, img_point *pt)
521{
522   ASSERT(fh);
523   ASSERT(pt);
524   pt->x = get32(fh) / 100.0;
525   pt->y = get32(fh) / 100.0;
526   pt->z = get32(fh) / 100.0;
527   if (ferror(fh) || feof(fh)) {
528      img_errno = feof(fh) ? IMG_BADFORMAT : IMG_READERROR;
529      return 0;
[421b7d2]530   }
[ad9a5cd]531   return 1;
532}
533
[4d3dfdf]534static int
535skip_coord(FILE *fh)
536{
537    return (fseek(fh, 12, SEEK_CUR) == 0);
538}
539
[a420b49]540int
[23f7ea7]541img_read_item(img *pimg, img_point *p)
[a420b49]542{
543   int result;
[95c3272]544   pimg->flags = 0;
[d69255f]545
546   if (pimg->version == 3) {
547      int opt;
[76bbb7c9]548      if (pimg->pending >= 0x80) {
549         *p = pimg->mv;
550         pimg->flags = (int)(pimg->pending) & 0x3f;
551         pimg->pending = 0;
[421b7d2]552         return img_LINE;
[76bbb7c9]553      }
[d69255f]554      again3: /* label to goto if we get a prefix */
[4d3dfdf]555      pimg->label = pimg->label_buf;
[d69255f]556      opt = getc(pimg->fh);
[ad9a5cd]557      if (opt == EOF) {
558         img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
559         return img_BAD;
560      }
[d69255f]561      switch (opt >> 6) {
562       case 0:
563         if (opt == 0) {
564            if (!pimg->label_len) return img_STOP; /* end of data marker */
565            pimg->label_len = 0;
566            goto again3;
567         }
568         if (opt < 15) {
569            /* 1-14 mean trim that many levels from current prefix */
570            int c;
571            if (pimg->label_len <= 16) {
[4d3dfdf]572               /* zero prefix using "0" */
[d69255f]573               img_errno = IMG_BADFORMAT;
574               return img_BAD;
575            }
[4b156b3]576            c = pimg->label_len - 16 - 1;
[0ff23cb]577            while (pimg->label_buf[c] != '.' || --opt > 0) {
[d69255f]578               if (--c < 0) {
579                  /* zero prefix using "0" */
580                  img_errno = IMG_BADFORMAT;
581                  return img_BAD;
582               }
583            }
584            c++;
585            pimg->label_len = c;
586            goto again3;
587         }
588         if (opt == 15) {
589            result = img_MOVE;
590            break;
591         }
592         /* 16-31 mean remove (n - 15) characters from the prefix */
593         /* zero prefix using 0 */
[ad4eaf3f]594         if (pimg->label_len <= (size_t)(opt - 15)) {
[d69255f]595            img_errno = IMG_BADFORMAT;
596            return img_BAD;
597         }
[d245d71]598         pimg->label_len -= (opt - 15);
[d69255f]599         goto again3;
600       case 1: case 2: {
601         char *q;
[ad9a5cd]602         long len = getc(pimg->fh);
603         if (len == EOF) {
604            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
605            return img_BAD;
606         }
[d69255f]607         if (len == 0xfe) {
608            len += get16(pimg->fh);
[ad9a5cd]609            if (feof(pimg->fh)) {
610               img_errno = IMG_BADFORMAT;
611               return img_BAD;
612            }
613            if (ferror(pimg->fh)) {
614               img_errno = IMG_READERROR;
615               return img_BAD;
616            }
[d69255f]617         } else if (len == 0xff) {
618            len = get32(pimg->fh);
[ad9a5cd]619            if (ferror(pimg->fh)) {
620               img_errno = IMG_READERROR;
621               return img_BAD;
622            }
623            if (feof(pimg->fh) || len < 0xfe + 0xffff) {
[d69255f]624               img_errno = IMG_BADFORMAT;
625               return img_BAD;
626            }
627         }
628
[6dd3a20]629         if (!check_label_space(pimg, pimg->label_len + len + 1)) {
[d4d3655]630            img_errno = IMG_OUTOFMEMORY;
631            return img_BAD;
[d69255f]632         }
[d4d3655]633         q = pimg->label_buf + pimg->label_len;
[6dd3a20]634         pimg->label_len += len;
[d69255f]635         if (len && fread(q, len, 1, pimg->fh) != 1) {
[ad9a5cd]636            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]637            return img_BAD;
638         }
639         q[len] = '\0';
[76bbb7c9]640
641         result = opt & 0x40 ? img_LABEL : img_LINE;
642
643         if (pimg->survey_len) {
644            size_t l = pimg->survey_len;
[0ff23cb]645            const char *s = pimg->label_buf;
[76bbb7c9]646            if (result == img_LINE) {
647               if (strncmp(pimg->survey, s, l) != 0 ||
648                   !(s[l] == '.' || s[l] == '\0')) {
[421b7d2]649                  if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
[76bbb7c9]650                  pimg->pending = 15;
[421b7d2]651                  goto again3;
[76bbb7c9]652               }
653            } else {
654               if (strncmp(pimg->survey, s, l + 1) != 0) {
[4d3dfdf]655                  if (!skip_coord(pimg->fh)) return img_BAD;
656                  pimg->pending = 0;
[76bbb7c9]657                  goto again3;
658               }
659            }
[0ff23cb]660            pimg->label += l;
661            /* skip the dot if there */
662            if (*pimg->label) pimg->label++;
[76bbb7c9]663         }
664
665         if (result == img_LINE && pimg->pending) {
666            *p = pimg->mv;
[ad9a5cd]667            if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
[76bbb7c9]668            pimg->pending = opt;
669            return img_MOVE;
670         }
671         pimg->flags = (int)opt & 0x3f;
[d69255f]672         break;
673       }
674       default:
675         img_errno = IMG_BADFORMAT;
676         return img_BAD;
677      }
[ad9a5cd]678      if (!read_coord(pimg->fh, p)) return img_BAD;
[76bbb7c9]679      pimg->pending = 0;
[d69255f]680      return result;
[4d3dfdf]681   }
682
683   pimg->label = pimg->label_buf;
684
685   if (pimg->version > 0) {
[d69255f]686      static long opt_lookahead = 0;
[ad9a5cd]687      static img_point pt = { 0.0, 0.0, 0.0 };
[a420b49]688      long opt;
689      again: /* label to goto if we get a cross */
[5d7280f8]690      pimg->label[0] = '\0';
[ad9a5cd]691
[5c3c61a]692      if (pimg->version == 1) {
[c4d4649]693         if (opt_lookahead) {
694            opt = opt_lookahead;
695            opt_lookahead = 0;
696         } else {
697            opt = get32(pimg->fh);
698         }
[5c3c61a]699      } else {
[421b7d2]700         opt = getc(pimg->fh);
[5c3c61a]701      }
[ad9a5cd]702
703      if (feof(pimg->fh)) {
704         img_errno = IMG_BADFORMAT;
705         return img_BAD;
706      }
707      if (ferror(pimg->fh)) {
708         img_errno = IMG_READERROR;
709         return img_BAD;
710      }
711
[a420b49]712      switch (opt) {
[437caf3]713       case -1: case 0:
[a420b49]714         return img_STOP; /* end of data marker */
715       case 1:
[ad9a5cd]716         /* skip coordinates */
[4d3dfdf]717         if (!skip_coord(pimg->fh)) {
[ad9a5cd]718            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
719            return img_BAD;
720         }
[a420b49]721         goto again;
[23f7ea7]722       case 2: case 3: {
[fe8e80e]723         char *q;
[3a1f8da]724         int ch;
[437caf3]725         result = img_LABEL;
[3a1f8da]726         ch = getc(pimg->fh);
[d69255f]727         if (ch == EOF) {
[ad9a5cd]728            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]729            return img_BAD;
730         }
[3a1f8da]731         if (ch != '\\') ungetc(ch, pimg->fh);
[0ff23cb]732         fgets(pimg->label_buf, 257, pimg->fh);
[421b7d2]733         if (feof(pimg->fh)) {
[ad9a5cd]734            img_errno = IMG_BADFORMAT;
735            return img_BAD;
736         }
[421b7d2]737         if (ferror(pimg->fh)) {
[ad9a5cd]738            img_errno = IMG_READERROR;
739            return img_BAD;
740         }
[0ff23cb]741         q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[d69255f]742         if (*q != '\n') {
743            img_errno = IMG_BADFORMAT;
744            return img_BAD;
745         }
[9968ebf]746         /* Ignore empty labels in some .3d files (caused by a bug) */
[0ff23cb]747         if (q == pimg->label_buf) goto again;
[fe8e80e]748         *q = '\0';
[509e099]749         pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[437caf3]750         if (opt == 2) goto done;
751         break;
[23f7ea7]752       }
[95c3272]753       case 6: case 7: {
[ad9a5cd]754         long len;
[23f7ea7]755         result = img_LABEL;
[ad9a5cd]756
[509e099]757         if (opt == 7)
758            pimg->flags = getc(pimg->fh);
759         else
760            pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[ad9a5cd]761
[23f7ea7]762         len = get32(pimg->fh);
[ad9a5cd]763
764         if (feof(pimg->fh)) {
765            img_errno = IMG_BADFORMAT;
766            return img_BAD;
767         }
768         if (ferror(pimg->fh)) {
769            img_errno = IMG_READERROR;
770            return img_BAD;
771         }
772
[9968ebf]773         /* Ignore empty labels in some .3d files (caused by a bug) */
774         if (len == 0) goto again;
[d4d3655]775         if (!check_label_space(pimg, len + 1)) {
776            img_errno = IMG_OUTOFMEMORY;
777            return img_BAD;
[23f7ea7]778         }
[0ff23cb]779         if (fread(pimg->label_buf, len, 1, pimg->fh) != 1) {
[ad9a5cd]780            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]781            return img_BAD;
782         }
[23f7ea7]783         break;
784       }
[a420b49]785       case 4:
786         result = img_MOVE;
787         break;
788       case 5:
789         result = img_LINE;
790         break;
791       default:
[95c3272]792         switch ((int)opt & 0xc0) {
793          case 0x80:
794            pimg->flags = (int)opt & 0x3f;
795            result = img_LINE;
796            break;
797          case 0x40: {
798            char *q;
799            pimg->flags = (int)opt & 0x3f;
800            result = img_LABEL;
[0ff23cb]801            if (!fgets(pimg->label_buf, 257, pimg->fh)) {
[ad9a5cd]802               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]803               return img_BAD;
804            }
[0ff23cb]805            q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[9968ebf]806            /* Ignore empty-labels in some .3d files (caused by a bug) */
[0ff23cb]807            if (q == pimg->label_buf) goto again;
[d69255f]808            if (*q != '\n') {
809               img_errno = IMG_BADFORMAT;
810               return img_BAD;
811            }
[95c3272]812            *q = '\0';
813            break;
814          }
815          case 0xc0:
816            /* use this for an extra leg or station flag if we need it */
817          default:
[d69255f]818            img_errno = IMG_BADFORMAT;
[95c3272]819            return img_BAD;
820         }
[437caf3]821         break;
[a420b49]822      }
[ad9a5cd]823
824      if (!read_coord(pimg->fh, &pt)) return img_BAD;
[76bbb7c9]825
[ed0f5b6]826      if (result == img_LABEL && pimg->survey_len) {
827         if (strncmp(pimg->label_buf, pimg->survey, pimg->survey_len + 1) != 0)
[0ff23cb]828            goto again;
829         pimg->label += pimg->survey_len + 1;
830      }
[76bbb7c9]831
[a420b49]832      done:
[ad9a5cd]833      *p = pt;
[c4d4649]834
835      if (result == img_MOVE && pimg->version == 1) {
[d69255f]836         /* peek at next code and see if it's an old-style label */
[23f7ea7]837         opt_lookahead = get32(pimg->fh);
[ad9a5cd]838
839         if (feof(pimg->fh)) {
840            img_errno = IMG_BADFORMAT;
841            return img_BAD;
842         }
843         if (ferror(pimg->fh)) {
844            img_errno = IMG_READERROR;
845            return img_BAD;
846         }
847
[d69255f]848         if (opt_lookahead == 2) return img_read_item(pimg, p);
[c4d4649]849      }
[23f7ea7]850
[a420b49]851      return result;
[0da6e60]852   } else if (pimg->version == 0) {
[a420b49]853      ascii_again:
[5d7280f8]854      pimg->label[0] = '\0';
[a420b49]855      if (feof(pimg->fh)) return img_STOP;
[76bbb7c9]856      if (pimg->pending) {
857         pimg->pending = 0;
[a420b49]858         result = img_LINE;
859      } else {
[7d27e36]860         char cmd[7];
[a420b49]861         /* Stop if nothing found */
[7d27e36]862         if (fscanf(pimg->fh, "%6s", cmd) < 1) return img_STOP;
863         if (strcmp(cmd, "move") == 0)
[a420b49]864            result = img_MOVE;
[7d27e36]865         else if (strcmp(cmd, "draw") == 0)
[a420b49]866            result = img_LINE;
[7d27e36]867         else if (strcmp(cmd, "line") == 0) {
[bd1913f]868            /* set flag to indicate to process second triplet as LINE */
[76bbb7c9]869            pimg->pending = 1;
[a420b49]870            result = img_MOVE;
[7d27e36]871         } else if (strcmp(cmd, "cross") == 0) {
[d69255f]872            if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]873               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[0ed0e16]874               return img_BAD;
[d69255f]875            }
[a420b49]876            goto ascii_again;
[7d27e36]877         } else if (strcmp(cmd, "name") == 0) {
[0da6e60]878            size_t off = 0;
[58f02ae]879            int ch = getc(pimg->fh);
880            if (ch == ' ') ch = getc(pimg->fh);
881            while (ch != ' ') {
882               if (ch == '\n' || ch == EOF) {
883                  img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
[ad9a5cd]884                  return img_BAD;
885               }
[58f02ae]886               if (off == pimg->buf_len) {
[d4d3655]887                  if (!check_label_space(pimg, pimg->buf_len * 2)) {
[9b56f4d]888                     img_errno = IMG_OUTOFMEMORY;
889                     return img_BAD;
890                  }
[0da6e60]891               }
[58f02ae]892               pimg->label_buf[off++] = ch;
893               ch = getc(pimg->fh);
[ad9a5cd]894            }
[58f02ae]895            pimg->label_buf[off] = '\0';
896
897            pimg->label = pimg->label_buf;
898            if (pimg->label[0] == '\\') pimg->label++;
[0da6e60]899
[a420b49]900            result = img_LABEL;
[d69255f]901         } else {
902            img_errno = IMG_BADFORMAT;
[a420b49]903            return img_BAD; /* unknown keyword */
[d69255f]904         }
[a420b49]905      }
[d1b1380]906
[d69255f]907      if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]908         img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
[fe8e80e]909         return img_BAD;
[d69255f]910      }
911
[58f02ae]912      if (result == img_LABEL && pimg->survey_len) {
913         if (strncmp(pimg->label, pimg->survey, pimg->survey_len + 1) != 0)
[0ff23cb]914            goto ascii_again;
915         pimg->label += pimg->survey_len + 1;
916      }
[76bbb7c9]917
[a420b49]918      return result;
[ad4eaf3f]919   } else if (pimg->version == -1) {
[0da6e60]920      /* version -1: .pos file */
[58f02ae]921      size_t off;
[5eea574]922      pimg->flags = img_SFLAG_UNDERGROUND; /* default flags */
[58f02ae]923      againpos:
924      off = 0;
[0da6e60]925      while (fscanf(pimg->fh, "(%lf,%lf,%lf ) ", &p->x, &p->y, &p->z) != 3) {
926         int ch;
927         if (ferror(pimg->fh)) {
928            img_errno = IMG_READERROR;
929            return img_BAD;
930         }
931         if (feof(pimg->fh)) return img_STOP;
932         if (pimg->pending) {
933            img_errno = IMG_BADFORMAT;
934            return img_BAD;
935         }
936         pimg->pending = 1;
937         /* ignore rest of line */
938         do {
939            ch = getc(pimg->fh);
940         } while (ch != '\n' && ch != '\r' && ch != EOF);
941      }
942
943      pimg->label_buf[0] = '\0';
944      while (!feof(pimg->fh)) {
[9b56f4d]945         char *b;
[0da6e60]946         if (!fgets(pimg->label_buf + off, pimg->buf_len - off, pimg->fh)) {
947            img_errno = IMG_READERROR;
948            return img_BAD;
949         }
950
951         off += strlen(pimg->label_buf + off);
952         if (off && pimg->label_buf[off - 1] == '\n') {
953            pimg->label_buf[off - 1] = '\0';
954            break;
955         }
[d4d3655]956         if (!check_label_space(pimg, pimg->buf_len * 2)) {
[9b56f4d]957            img_errno = IMG_OUTOFMEMORY;
958            return img_BAD;
959         }
[0da6e60]960      }
961
[58f02ae]962      pimg->label = pimg->label_buf;
963
[421b7d2]964      if (pimg->label[0] == '\\') pimg->label++;
[58f02ae]965
966      if (pimg->survey_len) {
967         size_t l = pimg->survey_len + 1;
968         if (strncmp(pimg->survey, pimg->label, l) != 0) goto againpos;
969         pimg->label += l;
970      }
971
[0da6e60]972      return img_LABEL;
[ad4eaf3f]973   } else {
974      /* version -2: Compass .plt file */
[4ebc557]975      if (pimg->pending > 0) {
976         /* -1 signals we've entered the first survey we want to
977          * read, and need to fudge lots if the first action is 'D'...
978          */
979         /* pending MOVE or LINE */
[984f49e]980         int r = pimg->pending - 4;
[ad4eaf3f]981         pimg->pending = 0;
982         pimg->flags = 0;
[f710a3f]983         pimg->label[pimg->label_len] = '\0';
[ad4eaf3f]984         return r;
985      }
986
987      while (1) {
[4ebc557]988         char *line;
[ad4eaf3f]989         char *q;
990         size_t len = 0;
[4ebc557]991         int ch = getc(pimg->fh);
992
993         switch (ch) {
994            case '\x1a': case EOF: /* Don't insist on ^Z at end of file */
995               return img_STOP;
[27bd06b]996            case 'X': case 'F': case 'S':
997               /* bounding boX (marks end of survey), Feature survey, or
998                * new Section - skip to next survey */
999               if (pimg->survey) return img_STOP;
1000skip_to_N:
1001               while (1) {
1002                  do {
1003                     ch = getc(pimg->fh);
1004                  } while (ch != '\n' && ch != '\r' && ch != EOF);
1005                  while (ch == '\n' || ch == '\r') ch = getc(pimg->fh);
1006                  if (ch == 'N') break;
1007                  if (ch == '\x1a' || ch == EOF) return img_STOP;
1008               }
1009               /* FALLTHRU */
[4ebc557]1010            case 'N':
1011               line = getline_alloc(pimg->fh);
1012               while (line[len] > 32) ++len;
1013               if (pimg->survey && pimg->label_len == 0)
1014                  pimg->pending = -1;
1015               if (!check_label_space(pimg, len + 1)) {
1016                  osfree(line);
1017                  img_errno = IMG_OUTOFMEMORY;
1018                  return img_BAD;
1019               }
1020               pimg->label_len = len;
1021               pimg->label = pimg->label_buf;
1022               memcpy(pimg->label, line, len);
1023               pimg->label[len] = '\0';
1024               osfree(line);
1025               break;
1026            case 'M': case 'D': {
[ad4eaf3f]1027               /* Move or Draw */
[4ebc557]1028               long fpos = -1;
[27bd06b]1029               if (pimg->survey && pimg->label_len == 0) {
[4ebc557]1030                  /* We're only holding onto this line in case the first line
[27bd06b]1031                   * of the 'N' is a 'D', so skip it for now...
[4ebc557]1032                   */
[27bd06b]1033                  goto skip_to_N;
[4ebc557]1034               }
1035               if (ch == 'D' && pimg->pending == -1) {
1036                  fpos = ftell(pimg->fh) - 1;
1037                  fseek(pimg->fh, pimg->start, SEEK_SET);
1038                  ch = getc(pimg->fh);
[0d922fc]1039                  pimg->pending = 0;
[4ebc557]1040               }
1041               line = getline_alloc(pimg->fh);
1042               if (sscanf(line, "%lf %lf %lf", &p->x, &p->y, &p->z) != 3) {
[ad4eaf3f]1043                  osfree(line);
1044                  if (ferror(pimg->fh)) {
1045                     img_errno = IMG_READERROR;
1046                  } else {
1047                     img_errno = IMG_BADFORMAT;
1048                  }
1049                  return img_BAD;
1050               }
1051               q = strchr(line, 'S');
1052               if (!q) {
1053                  osfree(line);
[5757725]1054                  img_errno = IMG_BADFORMAT;
[ad4eaf3f]1055                  return img_BAD;
1056               }
1057               ++q;
1058               len = 0;
1059               while (q[len] > ' ') ++len;
1060               q[len] = '\0';
[f710a3f]1061               len += 2; /* '.' and '\0' */
[d4d3655]1062               if (!check_label_space(pimg, pimg->label_len + len)) {
1063                  img_errno = IMG_OUTOFMEMORY;
1064                  return img_BAD;
[ad4eaf3f]1065               }
1066               pimg->label = pimg->label_buf;
[f710a3f]1067               pimg->label[pimg->label_len] = '.';
1068               memcpy(pimg->label + pimg->label_len + 1, q, len - 1);
[ad4eaf3f]1069               osfree(line);
1070               pimg->flags = img_SFLAG_UNDERGROUND; /* default flags */
[0d922fc]1071               if (fpos != -1) {
1072                  fseek(pimg->fh, fpos, SEEK_SET);
1073               } else {
1074                  pimg->pending = (ch == 'M' ? img_MOVE : img_LINE) + 4;
1075               }
[ad4eaf3f]1076               return img_LABEL;
[4ebc557]1077            }
[ad4eaf3f]1078            default:
1079               img_errno = IMG_BADFORMAT;
1080               return img_BAD;
1081         }
1082      }
[a420b49]1083   }
[d1b1380]1084}
1085
[ad9a5cd]1086static int
[d69255f]1087write_v3label(img *pimg, int opt, const char *s)
1088{
1089   size_t len, n, dot;
1090
1091   /* find length of common prefix */
1092   dot = 0;
[0ff23cb]1093   for (len = 0; s[len] == pimg->label_buf[len] && s[len] != '\0'; len++) {
[d69255f]1094      if (s[len] == '.') dot = len + 1;
1095   }
1096
1097   ASSERT(len <= pimg->label_len);
1098   n = pimg->label_len - len;
1099   if (len == 0) {
1100      if (pimg->label_len) putc(0, pimg->fh);
1101   } else if (n <= 16) {
1102      if (n) putc(n + 15, pimg->fh);
1103   } else if (dot == 0) {
1104      if (pimg->label_len) putc(0, pimg->fh);
[99cf51a]1105      len = 0;
[d69255f]1106   } else {
[0ff23cb]1107      const char *p = pimg->label_buf + dot;
[d69255f]1108      n = 1;
1109      for (len = pimg->label_len - dot - 17; len; len--) {
1110         if (*p++ == '.') n++;
1111      }
1112      if (n <= 14) {
1113         putc(n, pimg->fh);
1114         len = dot;
1115      } else {
1116         if (pimg->label_len) putc(0, pimg->fh);
1117         len = 0;
1118      }
1119   }
1120
1121   n = strlen(s + len);
1122   putc(opt, pimg->fh);
1123   if (n < 0xfe) {
1124      putc(n, pimg->fh);
1125   } else if (n < 0xffff + 0xfe) {
1126      putc(0xfe, pimg->fh);
1127      put16(n - 0xfe, pimg->fh);
1128   } else {
1129      putc(0xff, pimg->fh);
1130      put32(n, pimg->fh);
1131   }
1132   fwrite(s + len, n, 1, pimg->fh);
1133
1134   n += len;
1135   pimg->label_len = n;
[d4d3655]1136   if (!check_label_space(pimg, n + 1))
1137      return 0; /* FIXME: distinguish out of memory... */
[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;
[0d922fc]1250         if (!result) 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.