source: git/src/img.c @ 65472a2

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 65472a2 was 47e4a2e, checked in by Olly Betts <olly@…>, 23 years ago

free pimg->label_buf *before* pimg, not after...

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

  • Property mode set to 100644
File size: 37.6 KB
Line 
1/* img.c
2 * Routines for reading and writing Survex ".3d" image files
3 * Copyright (C) 1993-2002 Olly Betts
4 *
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.
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
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
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
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <time.h>
28#include <ctype.h>
29
30#include "img.h"
31
32#ifdef IMG_HOSTED
33# include "debug.h"
34# include "filelist.h"
35# include "filename.h"
36# include "message.h"
37# include "useful.h"
38# define TIMENA msg(/*Date and time not available.*/108)
39# define TIMEFMT msg(/*%a,%Y.%m.%d %H:%M:%S %Z*/107)
40#else
41# define INT32_T long
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))
46# define xosrealloc(L,S) realloc((L),(S))
47# define osfree(P) free((P))
48# define ossizeof(T) sizeof(T)
49/* in IMG_HOSTED mode, this tests if a filename refers to a directory */
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 */
61# define fputsnl(S, FH) do {fputs((S), (FH)); putc('\n', (FH));} while(0)
62# define ASSERT(X)
63
64static long
65get32(FILE *fh)
66{
67   long w = getc(fh);
68   w |= (long)getc(fh) << 8l;
69   w |= (long)getc(fh) << 16l;
70   w |= (long)getc(fh) << 24l;
71   return w;
72}
73
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);
81}
82
83#endif
84
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
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
113unsigned int img_output_version = 3;
114
115#ifdef IMG_HOSTED
116static enum {
117   IMG_NONE = 0,
118   IMG_FILENOTFOUND = /*Couldn't open data file `%s'*/24,
119   IMG_OUTOFMEMORY  = /*Out of memory %.0s*/38,
120   IMG_DIRECTORY    = /*Filename `%s' refers to directory*/44,
121   IMG_CANTOPENOUT  = /*Failed to open output file `%s'*/47,
122   IMG_BADFORMAT    = /*Bad 3d image file `%s'*/106,
123   IMG_READERROR    = /*Error reading from file `%s'*/109,
124   IMG_WRITEERROR   = /*Error writing to file `%s'*/110,
125   IMG_TOONEW       = /*File `%s' has a newer format than this program can understand*/114
126} img_errno = IMG_NONE;
127#else
128static img_errcode img_errno = IMG_NONE;
129#endif
130
131#define FILEID "Survex 3D Image File"
132
133#define EXT_PLT "plt"
134#define EXT_XYZ "xyz"
135
136/* Attempt to string paste to ensure we are passed a literal string */
137#define LITLEN(S) (sizeof(S"") - 1)
138
139static char *
140my_strdup(const char *str)
141{
142   char *p;
143   size_t len = strlen(str) + 1;
144   p = xosmalloc(len);
145   if (p) memcpy(p, str, len);
146   return p;
147}
148
149static char *
150getline_alloc(FILE *fh)
151{
152   int ch;
153   size_t i = 0;
154   size_t len = 16;
155   char *buf = xosmalloc(len);
156   if (!buf) return NULL;
157
158   ch = getc(fh);
159   while (ch != '\n' && ch != '\r' && ch != EOF) {
160      buf[i++] = ch;
161      if (i == len - 1) {
162         char *p;
163         len += len;
164         p = xosrealloc(buf, len);
165         if (!p) {
166            osfree(buf);
167            return NULL;
168         }
169         buf = p;
170      }
171      ch = getc(fh);
172   }
173   if (ch == '\n' || ch == '\r') {
174      int otherone = ch ^ ('\n' ^ '\r');
175      ch = getc(fh);
176      /* if it's not the other eol character, put it back */
177      if (ch != otherone) ungetc(ch, fh);
178   }
179   buf[i++] = '\0';
180   return buf;
181}
182
183#ifndef IMG_HOSTED
184img_errcode
185img_error(void)
186{
187   return img_errno;
188}
189#else
190int
191img_error(void)
192{
193   return (int)img_errno;
194}
195#endif
196
197static bool
198check_label_space(img *pimg, size_t len)
199{
200   if (len > pimg->buf_len) {
201      char *b = xosrealloc(pimg->label_buf, len);
202      if (!b) return fFalse;
203      pimg->label = (pimg->label - pimg->label_buf) + b;
204      pimg->label_buf = b;
205      pimg->buf_len = len;
206   }
207   return fTrue;
208}
209
210img *
211img_open_survey(const char *fnm, const char *survey)
212{
213   img *pimg;
214   size_t len;
215   char buf[LITLEN(FILEID) + 1];
216   int ch;
217
218   if (fDirectory(fnm)) {
219      img_errno = IMG_DIRECTORY;
220      return NULL;
221   }
222
223   pimg = (img *)xosmalloc(ossizeof(img));
224   if (pimg == NULL) {
225      img_errno = IMG_OUTOFMEMORY;
226      return NULL;
227   }
228
229   pimg->buf_len = 257;
230   pimg->label_buf = xosmalloc(pimg->buf_len);
231   if (!pimg->label_buf) {
232      osfree(pimg);
233      img_errno = IMG_OUTOFMEMORY;
234      return NULL;
235   }
236
237   pimg->fh = fopenWithPthAndExt("", fnm, EXT_SVX_3D, "rb", NULL);
238   if (pimg->fh == NULL) {
239      osfree(pimg->label_buf);
240      osfree(pimg);
241      img_errno = IMG_FILENOTFOUND;
242      return NULL;
243   }
244
245   pimg->fRead = fTrue; /* reading from this file */
246   img_errno = IMG_NONE;
247
248   pimg->flags = 0;
249
250   /* for version 3 we use label_buf to store the prefix for reuse */
251   /* for version -2, 0 value indicates we haven't entered a survey yet */
252   /* for version -4, we store the last station here to detect whether
253    * we MOVE or LINE */
254   pimg->label_len = 0;
255   pimg->label_buf[0] = '\0';
256
257   pimg->survey = NULL;
258   pimg->survey_len = 0;
259
260   pimg->title = pimg->datestamp = NULL;
261   if (survey) {
262      len = strlen(survey);
263      if (len) {
264         if (survey[len - 1] == '.') len--;
265         if (len) {
266            char *p;
267            pimg->survey = osmalloc(len + 2);
268            memcpy(pimg->survey, survey, len);
269            /* Set title to leaf survey name */
270            pimg->survey[len] = '\0';
271            p = strchr(pimg->survey, '.');
272            if (p) p++; else p = pimg->survey;
273            pimg->title = my_strdup(p);
274            if (!pimg->title) {
275               img_errno = IMG_OUTOFMEMORY;
276               goto error;
277            }
278            pimg->survey[len] = '.';
279            pimg->survey[len + 1] = '\0';
280         }
281      }
282      pimg->survey_len = len;
283   }
284
285   /* [version -2, -3, -4] pending IMG_LINE or IMG_MOVE - both have 4 added
286    * [version -1] already skipped heading line, or there wasn't one
287    * [version 0] not in the middle of a 'LINE' command
288    * [version 3] not in the middle of turning a LINE into a MOVE
289    */
290   pimg->pending = 0;
291
292   len = strlen(fnm);
293   if (len > LITLEN(EXT_SVX_POS) + 1 &&
294       fnm[len - LITLEN(EXT_SVX_POS) - 1] == FNM_SEP_EXT &&
295       my_strcasecmp(fnm + len - LITLEN(EXT_SVX_POS), EXT_SVX_POS) == 0) {
296pos_file:
297      pimg->version = -1;
298      if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm);
299      pimg->datestamp = my_strdup(TIMENA);
300      if (!pimg->datestamp) {
301         img_errno = IMG_OUTOFMEMORY;
302         goto error;
303      }
304      pimg->start = 0;
305      return pimg;
306   }
307
308   if (len > LITLEN(EXT_PLT) + 1 &&
309       fnm[len - LITLEN(EXT_PLT) - 1] == FNM_SEP_EXT &&
310       my_strcasecmp(fnm + len - LITLEN(EXT_PLT), EXT_PLT) == 0) {
311      long fpos;
312plt_file:
313      pimg->version = -2;
314      pimg->start = 0;
315      if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm);
316      pimg->datestamp = my_strdup(TIMENA);
317      if (!pimg->datestamp) {
318         img_errno = IMG_OUTOFMEMORY;
319         goto error;
320      }
321      while (1) {
322         int ch = getc(pimg->fh);
323         switch (ch) {
324          case '\x1a':
325            fseek(pimg->fh, -1, SEEK_CUR);
326            /* FALL THRU */
327          case EOF:
328            pimg->start = ftell(pimg->fh);
329            return pimg;
330          case 'N': {
331            char *line, *q;
332            fpos = ftell(pimg->fh) - 1;
333            if (!pimg->survey) {
334               /* FIXME : if there's only one survey in the file, it'd be nice
335                * to use its description as the title here...
336                */
337               ungetc('N', pimg->fh);
338               pimg->start = fpos;
339               return pimg;
340            }
341            line = getline_alloc(pimg->fh);
342            if (!line) {
343               img_errno = IMG_OUTOFMEMORY;
344               goto error;
345            }
346            len = 0;
347            while (line[len] > 32) ++len;
348            if (pimg->survey_len != len ||
349                memcmp(line, pimg->survey, len) != 0) {
350               osfree(line);
351               continue;
352            }
353            q = strchr(line + len, 'C');
354            if (q && q[1]) {
355                osfree(pimg->title);
356                pimg->title = my_strdup(q + 1);
357            } else if (!pimg->title) {
358                pimg->title = my_strdup(pimg->label);
359            }
360            osfree(line);
361            if (!pimg->title) {
362                img_errno = IMG_OUTOFMEMORY;
363                goto error;
364            }
365            if (!pimg->start) pimg->start = fpos;
366            fseek(pimg->fh, pimg->start, SEEK_SET);
367            return pimg;
368          }
369          case 'M': case 'D':
370            pimg->start = ftell(pimg->fh) - 1;
371            break;
372         }
373         while (ch != '\n' && ch != '\r') {
374            ch = getc(pimg->fh);
375         }
376      }
377   }
378
379   if (len > LITLEN(EXT_XYZ) + 1 &&
380       fnm[len - LITLEN(EXT_XYZ) - 1] == FNM_SEP_EXT &&
381       my_strcasecmp(fnm + len - LITLEN(EXT_XYZ), EXT_XYZ) == 0) {
382      long fpos;
383      char *line;
384xyz_file:
385      line = getline_alloc(pimg->fh);
386      if (!line) {
387         img_errno = IMG_OUTOFMEMORY;
388         goto error;
389      }
390      /* FIXME: reparse date? */
391      len = strlen(line);
392      if (len > 59) line[59] = '\0';
393      if (len > 45) {
394         pimg->datestamp = my_strdup(line + 45);
395      } else {
396         pimg->datestamp = my_strdup(TIMENA);
397      }
398      if (strncmp(line, "  Cave Survey Data Processed by CMAP ",
399                  LITLEN("  Cave Survey Data Processed by CMAP ")) == 0) {
400         len = 0;
401      } else {
402         if (len > 45) {
403            line[45] = '\0';
404            len = 45;
405         }
406         while (len > 2 && line[len - 1] == ' ') --len;
407         if (len > 2) {
408            line[len] = '\0';
409            pimg->title = my_strdup(line + 2);
410         }
411      }
412      if (len <= 2) pimg->title = baseleaf_from_fnm(fnm);
413      osfree(line);
414      if (!pimg->datestamp || !pimg->title) {
415         img_errno = IMG_OUTOFMEMORY;
416         goto error;
417      }
418      line = getline_alloc(pimg->fh);
419      if (!line) {
420         img_errno = IMG_OUTOFMEMORY;
421         goto error;
422      }
423      if (line[0] != ' ' || (line[1] != 'S' && line[1] != 'O')) {
424         img_errno = IMG_BADFORMAT;
425         goto error;
426      }
427      if (line[1] == 'S') {
428         pimg->version = -3; /* Station format */
429      } else {
430         pimg->version = -4; /* Shot format */
431      }
432      osfree(line);
433      line = getline_alloc(pimg->fh);
434      if (!line) {
435         img_errno = IMG_OUTOFMEMORY;
436         goto error;
437      }
438      if (line[0] != ' ' || line[1] != '-') {
439         img_errno = IMG_BADFORMAT;
440         goto error;
441      }
442      osfree(line);
443      pimg->start = ftell(pimg->fh);
444      return pimg;
445   }
446
447   if (fread(buf, LITLEN(FILEID) + 1, 1, pimg->fh) != 1 ||
448       memcmp(buf, FILEID"\n", LITLEN(FILEID)) != 0) {
449      if (buf[1] == ' ') {
450         if (buf[0] == ' ') {
451            /* Looks like a CMAP .xyz file ... */
452            rewind(pimg->fh);
453            goto xyz_file;
454         } else if (strchr("ZSNF", buf[0])) {
455            /* Looks like a Compass .plt file ... */
456            /* Almost certainly it'll start "Z " */
457            rewind(pimg->fh);
458            goto plt_file;
459         }
460      }
461      if (buf[0] == '(') {
462         /* Looks like a Survex .pos file ... */
463         rewind(pimg->fh);
464         goto pos_file;
465      }
466      img_errno = IMG_BADFORMAT;
467      goto error;
468   }
469
470   /* check file format version */
471   ch = getc(pimg->fh);
472   pimg->version = 0;
473   if (tolower(ch) == 'b') {
474      /* binary file iff B/b prefix */
475      pimg->version = 1;
476      ch = getc(pimg->fh);
477   }
478   if (ch != 'v') {
479      img_errno = IMG_BADFORMAT;
480      goto error;
481   }
482   ch = getc(pimg->fh);
483   if (ch == '0') {
484      if (fread(buf, 4, 1, pimg->fh) != 1 || memcmp(buf, ".01\n", 4) != 0) {
485         img_errno = IMG_BADFORMAT;
486         goto error;
487      }
488      /* nothing special to do */
489   } else if (pimg->version == 0) {
490      if (ch < '2' || ch > '3' || getc(pimg->fh) != '\n') {
491         img_errno = IMG_TOONEW;
492         goto error;
493      }
494      pimg->version = ch - '0';
495   } else {
496      img_errno = IMG_BADFORMAT;
497      goto error;
498   }
499
500   if (!pimg->title)
501       pimg->title = getline_alloc(pimg->fh);
502   else
503       osfree(getline_alloc(pimg->fh));
504   pimg->datestamp = getline_alloc(pimg->fh);
505   if (!pimg->title || !pimg->datestamp) {
506      img_errno = IMG_OUTOFMEMORY;
507      error:
508      osfree(pimg->title);
509      osfree(pimg->datestamp);
510      fclose(pimg->fh);
511      osfree(pimg);
512      return NULL;
513   }
514
515   pimg->start = ftell(pimg->fh);
516
517   return pimg;
518}
519
520int
521img_rewind(img *pimg)
522{
523   if (!pimg->fRead) {
524      img_errno = IMG_WRITEERROR;
525      return 0;
526   }
527   if (fseek(pimg->fh, pimg->start, SEEK_SET) != 0) {
528      img_errno = IMG_READERROR;
529      return 0;
530   }
531   clearerr(pimg->fh);
532   /* [version -1] already skipped heading line, or there wasn't one
533    * [version 0] not in the middle of a 'LINE' command
534    * [version 3] not in the middle of turning a LINE into a MOVE */
535   pimg->pending = 0;
536
537   img_errno = IMG_NONE;
538
539   /* for version 3 we use label_buf to store the prefix for reuse */
540   /* for version -2, 0 value indicates we haven't entered a survey yet */
541   /* for version -4, we store the last station here to detect whether
542    * we MOVE or LINE */
543   pimg->label_len = 0;
544   return 1;
545}
546
547img *
548img_open_write(const char *fnm, char *title_buf, bool fBinary)
549{
550   time_t tm;
551   img *pimg;
552
553   fBinary = fBinary;
554
555   if (fDirectory(fnm)) {
556      img_errno = IMG_DIRECTORY;
557      return NULL;
558   }
559
560   pimg = (img *)xosmalloc(ossizeof(img));
561   if (pimg == NULL) {
562      img_errno = IMG_OUTOFMEMORY;
563      return NULL;
564   }
565
566   pimg->buf_len = 257;
567   pimg->label_buf = xosmalloc(pimg->buf_len);
568   if (!pimg->label_buf) {
569      osfree(pimg);
570      img_errno = IMG_OUTOFMEMORY;
571      return NULL;
572   }
573
574   pimg->fh = fopen(fnm, "wb");
575   if (!pimg->fh) {
576      osfree(pimg->label_buf);
577      osfree(pimg);
578      img_errno = IMG_CANTOPENOUT;
579      return NULL;
580   }
581
582   /* Output image file header */
583   fputs("Survex 3D Image File\n", pimg->fh); /* file identifier string */
584   if (img_output_version < 2) {
585      pimg->version = 1;
586      fputs("Bv0.01\n", pimg->fh); /* binary file format version number */
587   } else {
588      pimg->version = (img_output_version > 2) ? 3 : 2;
589      fprintf(pimg->fh, "v%d\n", pimg->version); /* file format version no. */
590   }
591   fputsnl(title_buf, pimg->fh);
592   tm = time(NULL);
593   if (tm == (time_t)-1) {
594      fputsnl(TIMENA, pimg->fh);
595   } else {
596      char date[256];
597      /* output current date and time in format specified */
598      strftime(date, 256, TIMEFMT, localtime(&tm));
599      fputsnl(date, pimg->fh);
600   }
601   pimg->fRead = fFalse; /* writing to this file */
602   img_errno = IMG_NONE;
603
604   /* for version 3 we use label_buf to store the prefix for reuse */
605   pimg->label_buf[0] = '\0';
606   pimg->label_len = 0;
607
608   /* Don't check for write errors now - let img_close() report them... */
609   return pimg;
610}
611
612static void
613read_xyz_station_coords(img_point *pt, const char *line)
614{
615   char num[12];
616   memcpy(num, line + 6, 9);
617   num[9] = '\0';
618   pt->x = atof(num) / METRES_PER_FOOT;
619   memcpy(num, line + 15, 9);
620   pt->y = atof(num) / METRES_PER_FOOT;
621   memcpy(num, line + 24, 8);
622   num[8] = '\0';
623   pt->z = atof(num) / METRES_PER_FOOT;
624}
625
626static void
627read_xyz_shot_coords(img_point *pt, const char *line)
628{
629   char num[12];
630   memcpy(num, line + 40, 10);
631   num[10] = '\0';
632   pt->x = atof(num) / METRES_PER_FOOT;
633   memcpy(num, line + 50, 10);
634   pt->y = atof(num) / METRES_PER_FOOT;
635   memcpy(num, line + 60, 9);
636   num[9] = '\0';
637   pt->z = atof(num) / METRES_PER_FOOT;
638}
639
640static void
641subtract_xyz_shot_deltas(img_point *pt, const char *line)
642{
643   char num[12];
644   memcpy(num, line + 15, 9);
645   num[9] = '\0';
646   pt->x -= atof(num) / METRES_PER_FOOT;
647   memcpy(num, line + 24, 8);
648   num[8] = '\0';
649   pt->y -= atof(num) / METRES_PER_FOOT;
650   memcpy(num, line + 32, 8);
651   pt->z -= atof(num) / METRES_PER_FOOT;
652}
653
654static int
655read_coord(FILE *fh, img_point *pt)
656{
657   ASSERT(fh);
658   ASSERT(pt);
659   pt->x = get32(fh) / 100.0;
660   pt->y = get32(fh) / 100.0;
661   pt->z = get32(fh) / 100.0;
662   if (ferror(fh) || feof(fh)) {
663      img_errno = feof(fh) ? IMG_BADFORMAT : IMG_READERROR;
664      return 0;
665   }
666   return 1;
667}
668
669static int
670skip_coord(FILE *fh)
671{
672    return (fseek(fh, 12, SEEK_CUR) == 0);
673}
674
675int
676img_read_item(img *pimg, img_point *p)
677{
678   int result;
679   pimg->flags = 0;
680
681   if (pimg->version == 3) {
682      int opt;
683      if (pimg->pending >= 0x80) {
684         *p = pimg->mv;
685         pimg->flags = (int)(pimg->pending) & 0x3f;
686         pimg->pending = 0;
687         return img_LINE;
688      }
689      again3: /* label to goto if we get a prefix */
690      pimg->label = pimg->label_buf;
691      opt = getc(pimg->fh);
692      if (opt == EOF) {
693         img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
694         return img_BAD;
695      }
696      switch (opt >> 6) {
697       case 0:
698         if (opt == 0) {
699            if (!pimg->label_len) return img_STOP; /* end of data marker */
700            pimg->label_len = 0;
701            goto again3;
702         }
703         if (opt < 15) {
704            /* 1-14 mean trim that many levels from current prefix */
705            int c;
706            if (pimg->label_len <= 16) {
707               /* zero prefix using "0" */
708               img_errno = IMG_BADFORMAT;
709               return img_BAD;
710            }
711            c = pimg->label_len - 16 - 1;
712            while (pimg->label_buf[c] != '.' || --opt > 0) {
713               if (--c < 0) {
714                  /* zero prefix using "0" */
715                  img_errno = IMG_BADFORMAT;
716                  return img_BAD;
717               }
718            }
719            c++;
720            pimg->label_len = c;
721            goto again3;
722         }
723         if (opt == 15) {
724            result = img_MOVE;
725            break;
726         }
727         /* 16-31 mean remove (n - 15) characters from the prefix */
728         /* zero prefix using 0 */
729         if (pimg->label_len <= (size_t)(opt - 15)) {
730            img_errno = IMG_BADFORMAT;
731            return img_BAD;
732         }
733         pimg->label_len -= (opt - 15);
734         goto again3;
735       case 1: case 2: {
736         char *q;
737         long len = getc(pimg->fh);
738         if (len == EOF) {
739            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
740            return img_BAD;
741         }
742         if (len == 0xfe) {
743            len += get16(pimg->fh);
744            if (feof(pimg->fh)) {
745               img_errno = IMG_BADFORMAT;
746               return img_BAD;
747            }
748            if (ferror(pimg->fh)) {
749               img_errno = IMG_READERROR;
750               return img_BAD;
751            }
752         } else if (len == 0xff) {
753            len = get32(pimg->fh);
754            if (ferror(pimg->fh)) {
755               img_errno = IMG_READERROR;
756               return img_BAD;
757            }
758            if (feof(pimg->fh) || len < 0xfe + 0xffff) {
759               img_errno = IMG_BADFORMAT;
760               return img_BAD;
761            }
762         }
763
764         if (!check_label_space(pimg, pimg->label_len + len + 1)) {
765            img_errno = IMG_OUTOFMEMORY;
766            return img_BAD;
767         }
768         q = pimg->label_buf + pimg->label_len;
769         pimg->label_len += len;
770         if (len && fread(q, len, 1, pimg->fh) != 1) {
771            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
772            return img_BAD;
773         }
774         q[len] = '\0';
775
776         result = opt & 0x40 ? img_LABEL : img_LINE;
777
778         if (pimg->survey_len) {
779            size_t l = pimg->survey_len;
780            const char *s = pimg->label_buf;
781            if (result == img_LINE) {
782               if (strncmp(pimg->survey, s, l) != 0 ||
783                   !(s[l] == '.' || s[l] == '\0')) {
784                  if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
785                  pimg->pending = 15;
786                  goto again3;
787               }
788            } else {
789               if (strncmp(pimg->survey, s, l + 1) != 0) {
790                  if (!skip_coord(pimg->fh)) return img_BAD;
791                  pimg->pending = 0;
792                  goto again3;
793               }
794            }
795            pimg->label += l;
796            /* skip the dot if there */
797            if (*pimg->label) pimg->label++;
798         }
799
800         if (result == img_LINE && pimg->pending) {
801            *p = pimg->mv;
802            if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
803            pimg->pending = opt;
804            return img_MOVE;
805         }
806         pimg->flags = (int)opt & 0x3f;
807         break;
808       }
809       default:
810         img_errno = IMG_BADFORMAT;
811         return img_BAD;
812      }
813      if (!read_coord(pimg->fh, p)) return img_BAD;
814      pimg->pending = 0;
815      return result;
816   }
817
818   pimg->label = pimg->label_buf;
819
820   if (pimg->version > 0) {
821      static long opt_lookahead = 0;
822      static img_point pt = { 0.0, 0.0, 0.0 };
823      long opt;
824      again: /* label to goto if we get a cross */
825      pimg->label[0] = '\0';
826
827      if (pimg->version == 1) {
828         if (opt_lookahead) {
829            opt = opt_lookahead;
830            opt_lookahead = 0;
831         } else {
832            opt = get32(pimg->fh);
833         }
834      } else {
835         opt = getc(pimg->fh);
836      }
837
838      if (feof(pimg->fh)) {
839         img_errno = IMG_BADFORMAT;
840         return img_BAD;
841      }
842      if (ferror(pimg->fh)) {
843         img_errno = IMG_READERROR;
844         return img_BAD;
845      }
846
847      switch (opt) {
848       case -1: case 0:
849         return img_STOP; /* end of data marker */
850       case 1:
851         /* skip coordinates */
852         if (!skip_coord(pimg->fh)) {
853            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
854            return img_BAD;
855         }
856         goto again;
857       case 2: case 3: {
858         char *q;
859         int ch;
860         result = img_LABEL;
861         ch = getc(pimg->fh);
862         if (ch == EOF) {
863            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
864            return img_BAD;
865         }
866         if (ch != '\\') ungetc(ch, pimg->fh);
867         fgets(pimg->label_buf, 257, pimg->fh);
868         if (feof(pimg->fh)) {
869            img_errno = IMG_BADFORMAT;
870            return img_BAD;
871         }
872         if (ferror(pimg->fh)) {
873            img_errno = IMG_READERROR;
874            return img_BAD;
875         }
876         q = pimg->label_buf + strlen(pimg->label_buf) - 1;
877         if (*q != '\n') {
878            img_errno = IMG_BADFORMAT;
879            return img_BAD;
880         }
881         /* Ignore empty labels in some .3d files (caused by a bug) */
882         if (q == pimg->label_buf) goto again;
883         *q = '\0';
884         pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
885         if (opt == 2) goto done;
886         break;
887       }
888       case 6: case 7: {
889         long len;
890         result = img_LABEL;
891
892         if (opt == 7)
893            pimg->flags = getc(pimg->fh);
894         else
895            pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
896
897         len = get32(pimg->fh);
898
899         if (feof(pimg->fh)) {
900            img_errno = IMG_BADFORMAT;
901            return img_BAD;
902         }
903         if (ferror(pimg->fh)) {
904            img_errno = IMG_READERROR;
905            return img_BAD;
906         }
907
908         /* Ignore empty labels in some .3d files (caused by a bug) */
909         if (len == 0) goto again;
910         if (!check_label_space(pimg, len + 1)) {
911            img_errno = IMG_OUTOFMEMORY;
912            return img_BAD;
913         }
914         if (fread(pimg->label_buf, len, 1, pimg->fh) != 1) {
915            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
916            return img_BAD;
917         }
918         pimg->label_buf[len] = '\0';
919         break;
920       }
921       case 4:
922         result = img_MOVE;
923         break;
924       case 5:
925         result = img_LINE;
926         break;
927       default:
928         switch ((int)opt & 0xc0) {
929          case 0x80:
930            pimg->flags = (int)opt & 0x3f;
931            result = img_LINE;
932            break;
933          case 0x40: {
934            char *q;
935            pimg->flags = (int)opt & 0x3f;
936            result = img_LABEL;
937            if (!fgets(pimg->label_buf, 257, pimg->fh)) {
938               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
939               return img_BAD;
940            }
941            q = pimg->label_buf + strlen(pimg->label_buf) - 1;
942            /* Ignore empty-labels in some .3d files (caused by a bug) */
943            if (q == pimg->label_buf) goto again;
944            if (*q != '\n') {
945               img_errno = IMG_BADFORMAT;
946               return img_BAD;
947            }
948            *q = '\0';
949            break;
950          }
951          case 0xc0:
952            /* use this for an extra leg or station flag if we need it */
953          default:
954            img_errno = IMG_BADFORMAT;
955            return img_BAD;
956         }
957         break;
958      }
959
960      if (!read_coord(pimg->fh, &pt)) return img_BAD;
961
962      if (result == img_LABEL && pimg->survey_len) {
963         if (strncmp(pimg->label_buf, pimg->survey, pimg->survey_len + 1) != 0)
964            goto again;
965         pimg->label += pimg->survey_len + 1;
966      }
967
968      done:
969      *p = pt;
970
971      if (result == img_MOVE && pimg->version == 1) {
972         /* peek at next code and see if it's an old-style label */
973         opt_lookahead = get32(pimg->fh);
974
975         if (feof(pimg->fh)) {
976            img_errno = IMG_BADFORMAT;
977            return img_BAD;
978         }
979         if (ferror(pimg->fh)) {
980            img_errno = IMG_READERROR;
981            return img_BAD;
982         }
983
984         if (opt_lookahead == 2) return img_read_item(pimg, p);
985      }
986
987      return result;
988   } else if (pimg->version == 0) {
989      ascii_again:
990      pimg->label[0] = '\0';
991      if (feof(pimg->fh)) return img_STOP;
992      if (pimg->pending) {
993         pimg->pending = 0;
994         result = img_LINE;
995      } else {
996         char cmd[7];
997         /* Stop if nothing found */
998         if (fscanf(pimg->fh, "%6s", cmd) < 1) return img_STOP;
999         if (strcmp(cmd, "move") == 0)
1000            result = img_MOVE;
1001         else if (strcmp(cmd, "draw") == 0)
1002            result = img_LINE;
1003         else if (strcmp(cmd, "line") == 0) {
1004            /* set flag to indicate to process second triplet as LINE */
1005            pimg->pending = 1;
1006            result = img_MOVE;
1007         } else if (strcmp(cmd, "cross") == 0) {
1008            if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
1009               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
1010               return img_BAD;
1011            }
1012            goto ascii_again;
1013         } else if (strcmp(cmd, "name") == 0) {
1014            size_t off = 0;
1015            int ch = getc(pimg->fh);
1016            if (ch == ' ') ch = getc(pimg->fh);
1017            while (ch != ' ') {
1018               if (ch == '\n' || ch == EOF) {
1019                  img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
1020                  return img_BAD;
1021               }
1022               if (off == pimg->buf_len) {
1023                  if (!check_label_space(pimg, pimg->buf_len * 2)) {
1024                     img_errno = IMG_OUTOFMEMORY;
1025                     return img_BAD;
1026                  }
1027               }
1028               pimg->label_buf[off++] = ch;
1029               ch = getc(pimg->fh);
1030            }
1031            pimg->label_buf[off] = '\0';
1032
1033            pimg->label = pimg->label_buf;
1034            if (pimg->label[0] == '\\') pimg->label++;
1035
1036            result = img_LABEL;
1037         } else {
1038            img_errno = IMG_BADFORMAT;
1039            return img_BAD; /* unknown keyword */
1040         }
1041      }
1042
1043      if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
1044         img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
1045         return img_BAD;
1046      }
1047
1048      if (result == img_LABEL && pimg->survey_len) {
1049         if (strncmp(pimg->label, pimg->survey, pimg->survey_len + 1) != 0)
1050            goto ascii_again;
1051         pimg->label += pimg->survey_len + 1;
1052      }
1053
1054      return result;
1055   } else if (pimg->version == -1) {
1056      /* version -1: .pos file */
1057      size_t off;
1058      pimg->flags = img_SFLAG_UNDERGROUND; /* default flags */
1059      againpos:
1060      off = 0;
1061      while (fscanf(pimg->fh, "(%lf,%lf,%lf ) ", &p->x, &p->y, &p->z) != 3) {
1062         int ch;
1063         if (ferror(pimg->fh)) {
1064            img_errno = IMG_READERROR;
1065            return img_BAD;
1066         }
1067         if (feof(pimg->fh)) return img_STOP;
1068         if (pimg->pending) {
1069            img_errno = IMG_BADFORMAT;
1070            return img_BAD;
1071         }
1072         pimg->pending = 1;
1073         /* ignore rest of line */
1074         do {
1075            ch = getc(pimg->fh);
1076         } while (ch != '\n' && ch != '\r' && ch != EOF);
1077      }
1078
1079      pimg->label_buf[0] = '\0';
1080      while (!feof(pimg->fh)) {
1081         char *b;
1082         if (!fgets(pimg->label_buf + off, pimg->buf_len - off, pimg->fh)) {
1083            img_errno = IMG_READERROR;
1084            return img_BAD;
1085         }
1086
1087         off += strlen(pimg->label_buf + off);
1088         if (off && pimg->label_buf[off - 1] == '\n') {
1089            pimg->label_buf[off - 1] = '\0';
1090            break;
1091         }
1092         if (!check_label_space(pimg, pimg->buf_len * 2)) {
1093            img_errno = IMG_OUTOFMEMORY;
1094            return img_BAD;
1095         }
1096      }
1097
1098      pimg->label = pimg->label_buf;
1099
1100      if (pimg->label[0] == '\\') pimg->label++;
1101
1102      if (pimg->survey_len) {
1103         size_t l = pimg->survey_len + 1;
1104         if (strncmp(pimg->survey, pimg->label, l) != 0) goto againpos;
1105         pimg->label += l;
1106      }
1107
1108      return img_LABEL;
1109   } else if (pimg->version == -2) {
1110      /* version -2: Compass .plt file */
1111      if (pimg->pending > 0) {
1112         /* -1 signals we've entered the first survey we want to
1113          * read, and need to fudge lots if the first action is 'D'...
1114          */
1115         /* pending MOVE or LINE */
1116         int r = pimg->pending - 4;
1117         pimg->pending = 0;
1118         pimg->flags = 0;
1119         pimg->label[pimg->label_len] = '\0';
1120         return r;
1121      }
1122
1123      while (1) {
1124         char *line;
1125         char *q;
1126         size_t len = 0;
1127         int ch = getc(pimg->fh);
1128
1129         switch (ch) {
1130            case '\x1a': case EOF: /* Don't insist on ^Z at end of file */
1131               return img_STOP;
1132            case 'X': case 'F': case 'S':
1133               /* bounding boX (marks end of survey), Feature survey, or
1134                * new Section - skip to next survey */
1135               if (pimg->survey) return img_STOP;
1136skip_to_N:
1137               while (1) {
1138                  do {
1139                     ch = getc(pimg->fh);
1140                  } while (ch != '\n' && ch != '\r' && ch != EOF);
1141                  while (ch == '\n' || ch == '\r') ch = getc(pimg->fh);
1142                  if (ch == 'N') break;
1143                  if (ch == '\x1a' || ch == EOF) return img_STOP;
1144               }
1145               /* FALLTHRU */
1146            case 'N':
1147               line = getline_alloc(pimg->fh);
1148               if (!line) {
1149                  img_errno = IMG_OUTOFMEMORY;
1150                  return img_BAD;
1151               }
1152               while (line[len] > 32) ++len;
1153               if (pimg->survey && pimg->label_len == 0)
1154                  pimg->pending = -1;
1155               if (!check_label_space(pimg, len + 1)) {
1156                  osfree(line);
1157                  img_errno = IMG_OUTOFMEMORY;
1158                  return img_BAD;
1159               }
1160               pimg->label_len = len;
1161               pimg->label = pimg->label_buf;
1162               memcpy(pimg->label, line, len);
1163               pimg->label[len] = '\0';
1164               osfree(line);
1165               break;
1166            case 'M': case 'D': {
1167               /* Move or Draw */
1168               long fpos = -1;
1169               if (pimg->survey && pimg->label_len == 0) {
1170                  /* We're only holding onto this line in case the first line
1171                   * of the 'N' is a 'D', so skip it for now...
1172                   */
1173                  goto skip_to_N;
1174               }
1175               if (ch == 'D' && pimg->pending == -1) {
1176                  fpos = ftell(pimg->fh) - 1;
1177                  fseek(pimg->fh, pimg->start, SEEK_SET);
1178                  ch = getc(pimg->fh);
1179                  pimg->pending = 0;
1180               }
1181               line = getline_alloc(pimg->fh);
1182               if (!line) {
1183                  img_errno = IMG_OUTOFMEMORY;
1184                  return img_BAD;
1185               }
1186               /* Compass store coordinates as North, East, Up = (y,x,z)! */
1187               if (sscanf(line, "%lf%lf%lf", &p->y, &p->x, &p->z) != 3) {
1188                  osfree(line);
1189                  if (ferror(pimg->fh)) {
1190                     img_errno = IMG_READERROR;
1191                  } else {
1192                     img_errno = IMG_BADFORMAT;
1193                  }
1194                  return img_BAD;
1195               }
1196               p->x /= METRES_PER_FOOT;
1197               p->y /= METRES_PER_FOOT;
1198               p->z /= METRES_PER_FOOT;
1199               q = strchr(line, 'S');
1200               if (!q) {
1201                  osfree(line);
1202                  img_errno = IMG_BADFORMAT;
1203                  return img_BAD;
1204               }
1205               ++q;
1206               len = 0;
1207               while (q[len] > ' ') {
1208                  /* change dots to spaces.  spaces aren't legal in compass
1209                   * station names, while dots are the survey level separator
1210                   * in Survex */
1211                  if (q[len] == '.') q[len] = ' ';
1212                  ++len;
1213               }
1214               q[len] = '\0';
1215               len += 2; /* '.' and '\0' */
1216               if (!check_label_space(pimg, pimg->label_len + len)) {
1217                  img_errno = IMG_OUTOFMEMORY;
1218                  return img_BAD;
1219               }
1220               pimg->label = pimg->label_buf;
1221               pimg->label[pimg->label_len] = '.';
1222               memcpy(pimg->label + pimg->label_len + 1, q, len - 1);
1223               osfree(line);
1224               pimg->flags = img_SFLAG_UNDERGROUND; /* default flags */
1225               if (fpos != -1) {
1226                  fseek(pimg->fh, fpos, SEEK_SET);
1227               } else {
1228                  pimg->pending = (ch == 'M' ? img_MOVE : img_LINE) + 4;
1229               }
1230               return img_LABEL;
1231            }
1232            default:
1233               img_errno = IMG_BADFORMAT;
1234               return img_BAD;
1235         }
1236      }
1237   } else {
1238      /* version -3 or -4: CMAP .xyz file */
1239      char *line = NULL;
1240      char *q;
1241      size_t len;
1242
1243      if (pimg->pending) {
1244         /* pending MOVE or LINE or LABEL or STOP */
1245         int r = pimg->pending - 4;
1246         /* Set label to empty - don't use "" as we adjust label relative
1247          * to label_buf when label_buf is reallocated. */
1248         pimg->label = pimg->label_buf + strlen(pimg->label_buf);
1249         pimg->flags = 0;
1250         if (r == img_LABEL) {
1251            /* nasty magic */
1252            read_xyz_shot_coords(p, pimg->label_buf + 16);
1253            subtract_xyz_shot_deltas(p, pimg->label_buf + 16);
1254            pimg->pending = img_STOP + 4;
1255            return img_MOVE;
1256         }
1257       
1258         pimg->pending = 0;
1259
1260         if (r == img_STOP) {
1261            /* nasty magic */
1262            read_xyz_shot_coords(p, pimg->label_buf + 16);
1263            return img_LINE;
1264         }
1265         
1266         return r;
1267      }
1268
1269      pimg->label = pimg->label_buf;
1270      do {
1271         osfree(line);
1272         if (feof(pimg->fh)) return img_STOP;
1273         line = getline_alloc(pimg->fh);
1274         if (!line) {
1275            img_errno = IMG_OUTOFMEMORY;
1276            return img_BAD;
1277         }
1278      } while (line[0] == ' ' || line[0] == '\0');
1279      if (line[0] == '\x1a') return img_STOP;
1280
1281      len = strlen(line);
1282      if (pimg->version == -3) {
1283         /* station variant */
1284         if (len < 37) {
1285            osfree(line);
1286            img_errno = IMG_BADFORMAT;
1287            return img_BAD;
1288         }
1289         memcpy(pimg->label, line, 6);
1290         q = memchr(pimg->label, ' ', 6);
1291         if (!q) q = pimg->label + 6;
1292         *q = '\0';
1293         /* change dots to spaces.  spaces aren't legal in CMAP
1294          * station names, while dots are the survey level separator
1295          * in Survex */
1296         while (--q >= pimg->label) if (*q == '.') *q = ' ';
1297
1298         read_xyz_station_coords(p, line);
1299         
1300         /* FIXME: look at prev for lines (line + 32, 5) */
1301         /* FIXME: duplicate stations... */
1302         return img_LABEL;
1303      } else {
1304         /* Shot variant */
1305         char old[8], new[8];
1306         if (len < 61) {
1307            osfree(line);
1308            img_errno = IMG_BADFORMAT;
1309            return img_BAD;
1310         }
1311         
1312         memcpy(old, line, 7);
1313         q = memchr(old, ' ', 7);
1314         if (!q) q = old + 7;
1315         *q = '\0';
1316         /* change dots to spaces.  spaces aren't legal in CMAP
1317          * station names, while dots are the survey level separator
1318          * in Survex */
1319         while (--q > old) if (*q == '.') *q = ' ';
1320         
1321         memcpy(new, line + 7, 7);
1322         q = memchr(new, ' ', 7);
1323         if (!q) q = new + 7;
1324         *q = '\0';
1325         /* change dots to spaces.  spaces aren't legal in CMAP
1326          * station names, while dots are the survey level separator
1327          * in Survex */
1328         while (--q > new) if (*q == '.') *q = ' ';
1329         
1330         pimg->flags = img_SFLAG_UNDERGROUND;
1331
1332         if (strcmp(old, new) == 0) {
1333            pimg->pending = img_MOVE + 4;
1334            read_xyz_shot_coords(p, line);
1335            strcpy(pimg->label, new);
1336            osfree(line);
1337            return img_LABEL;
1338         }
1339         
1340         if (strcmp(old, pimg->label) == 0) {
1341            pimg->pending = img_LINE + 4;
1342            read_xyz_shot_coords(p, line);
1343            strcpy(pimg->label, new);
1344            osfree(line);
1345            return img_LABEL;
1346         }
1347         
1348         pimg->pending = img_LABEL + 4;
1349         read_xyz_shot_coords(p, line);
1350         strcpy(pimg->label, new);
1351         memcpy(pimg->label + 16, line, 70);
1352
1353         osfree(line);
1354         return img_LABEL;
1355      }
1356   }
1357}
1358
1359static int
1360write_v3label(img *pimg, int opt, const char *s)
1361{
1362   size_t len, n, dot;
1363
1364   /* find length of common prefix */
1365   dot = 0;
1366   for (len = 0; s[len] == pimg->label_buf[len] && s[len] != '\0'; len++) {
1367      if (s[len] == '.') dot = len + 1;
1368   }
1369
1370   ASSERT(len <= pimg->label_len);
1371   n = pimg->label_len - len;
1372   if (len == 0) {
1373      if (pimg->label_len) putc(0, pimg->fh);
1374   } else if (n <= 16) {
1375      if (n) putc(n + 15, pimg->fh);
1376   } else if (dot == 0) {
1377      if (pimg->label_len) putc(0, pimg->fh);
1378      len = 0;
1379   } else {
1380      const char *p = pimg->label_buf + dot;
1381      n = 1;
1382      for (len = pimg->label_len - dot - 17; len; len--) {
1383         if (*p++ == '.') n++;
1384      }
1385      if (n <= 14) {
1386         putc(n, pimg->fh);
1387         len = dot;
1388      } else {
1389         if (pimg->label_len) putc(0, pimg->fh);
1390         len = 0;
1391      }
1392   }
1393
1394   n = strlen(s + len);
1395   putc(opt, pimg->fh);
1396   if (n < 0xfe) {
1397      putc(n, pimg->fh);
1398   } else if (n < 0xffff + 0xfe) {
1399      putc(0xfe, pimg->fh);
1400      put16(n - 0xfe, pimg->fh);
1401   } else {
1402      putc(0xff, pimg->fh);
1403      put32(n, pimg->fh);
1404   }
1405   fwrite(s + len, n, 1, pimg->fh);
1406
1407   n += len;
1408   pimg->label_len = n;
1409   if (!check_label_space(pimg, n + 1))
1410      return 0; /* FIXME: distinguish out of memory... */
1411   memcpy(pimg->label_buf + len, s + len, n - len + 1);
1412
1413   return !ferror(pimg->fh);
1414}
1415
1416void
1417img_write_item(img *pimg, int code, int flags, const char *s,
1418               double x, double y, double z)
1419{
1420   if (!pimg) return;
1421   if (pimg->version == 3) {
1422      int opt = 0;
1423      switch (code) {
1424       case img_LABEL:
1425         write_v3label(pimg, 0x40 | flags, s);
1426         opt = 0;
1427         break;
1428       case img_MOVE:
1429         opt = 15;
1430         break;
1431       case img_LINE:
1432         write_v3label(pimg, 0x80 | flags, s ? s : "");
1433         opt = 0;
1434         break;
1435       default: /* ignore for now */
1436         return;
1437      }
1438      if (opt) putc(opt, pimg->fh);
1439      /* Output in cm */
1440      put32((INT32_T)my_round(x * 100.0), pimg->fh);
1441      put32((INT32_T)my_round(y * 100.0), pimg->fh);
1442      put32((INT32_T)my_round(z * 100.0), pimg->fh);
1443   } else {
1444      size_t len;
1445      INT32_T opt = 0;
1446      ASSERT(pimg->version > 0);
1447      switch (code) {
1448       case img_LABEL:
1449         if (pimg->version == 1) {
1450            /* put a move before each label */
1451            img_write_item(pimg, img_MOVE, 0, NULL, x, y, z);
1452            put32(2, pimg->fh);
1453            fputsnl(s, pimg->fh);
1454            return;
1455         }
1456         len = strlen(s);
1457         if (len > 255 || strchr(s, '\n')) {
1458            /* long label - not in early incarnations of v2 format, but few
1459             * 3d files will need these, so better not to force incompatibility
1460             * with a new version I think... */
1461            putc(7, pimg->fh);
1462            putc(flags, pimg->fh);
1463            put32(len, pimg->fh);
1464            fputs(s, pimg->fh);
1465         } else {
1466            putc(0x40 | (flags & 0x3f), pimg->fh);
1467            fputsnl(s, pimg->fh);
1468         }
1469         opt = 0;
1470         break;
1471       case img_MOVE:
1472         opt = 4;
1473         break;
1474       case img_LINE:
1475         if (pimg->version > 1) {
1476            opt = 0x80 | (flags & 0x3f);
1477            break;
1478         }
1479         opt = 5;
1480         break;
1481       default: /* ignore for now */
1482         return;
1483      }
1484      if (pimg->version == 1) {
1485         put32(opt, pimg->fh);
1486      } else {
1487         if (opt) putc(opt, pimg->fh);
1488      }
1489      /* Output in cm */
1490      put32((INT32_T)my_round(x * 100.0), pimg->fh);
1491      put32((INT32_T)my_round(y * 100.0), pimg->fh);
1492      put32((INT32_T)my_round(z * 100.0), pimg->fh);
1493   }
1494}
1495
1496int
1497img_close(img *pimg)
1498{
1499   int result = 1;
1500   if (pimg) {
1501      if (pimg->fh) {
1502         if (pimg->fRead) {
1503            osfree(pimg->survey);
1504            osfree(pimg->title);
1505            osfree(pimg->datestamp);
1506         } else {
1507            /* write end of data marker */
1508            switch (pimg->version) {
1509             case 1:
1510               put32((INT32_T)-1, pimg->fh);
1511               break;
1512             case 2:
1513               putc(0, pimg->fh);
1514               break;
1515             case 3:
1516               if (pimg->label_len) putc(0, pimg->fh);
1517               putc(0, pimg->fh);
1518               break;
1519            }
1520         }
1521         if (ferror(pimg->fh)) result = 0;
1522         if (fclose(pimg->fh)) result = 0;
1523         if (!result) img_errno = pimg->fRead ? IMG_READERROR : IMG_WRITEERROR;
1524      }
1525      osfree(pimg->label_buf);
1526      osfree(pimg);
1527   }
1528   return result;
1529}
Note: See TracBrowser for help on using the repository browser.