source: git/src/img.c @ 0da6e60

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 0da6e60 was 0da6e60, checked in by Olly Betts <olly@…>, 24 years ago

Pushed .pos parsing code down from diffpos.c to img.c so all .3d file
reading programs can potentially benefit.

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

  • Property mode set to 100644
File size: 24.7 KB
RevLine 
[0da6e60]1/* img.c
[d1b1380]2 * Routines for reading and writing Survex ".3d" image files
[bd1913f]3 * Copyright (C) 1993-2001 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"
31#ifdef IMG_HOSTED
[d69255f]32# include "debug.h"
[d1b1380]33# include "filelist.h"
[d69255f]34# include "filename.h"
35# include "message.h"
36# include "useful.h"
[a420b49]37# define TIMENA msg(/*Date and time not available.*/108)
38# define TIMEFMT msg(/*%a,%Y.%m.%d %H:%M:%S %Z*/107)
[d1b1380]39#else
[72af530]40# define INT32_T long
[d1b1380]41# define TIMENA "Time not available."
42# define TIMEFMT "%a,%Y.%m.%d %H:%M:%S %Z"
43# define EXT_SVX_3D "3d"
44# define xosmalloc(L) malloc((L))
[72af530]45# define xosrealloc(L,S) realloc((L),(S))
[d1b1380]46# define osfree(P) free((P))
47# define ossizeof(T) sizeof(T)
[72af530]48/* in IMG_HOSTED mode, this tests if a filename refers to a directory */
[d1b1380]49# define fDirectory(X) 0
50/* open file FNM with mode MODE, maybe using path PTH and/or extension EXT */
51/* path isn't used in img.c, but EXT is */
52# define fopenWithPthAndExt(PTH,FNM,EXT,MODE,X) fopen(FNM,MODE)
53# define fFalse 0
54# define fTrue 1
55# define bool int
56/* dummy do {...} while(0) hack to permit stuff like
57 * if (s) fputsnl(s,fh); else exit(1);
58 * to work as intended
59 */
[23f7ea7]60# define fputsnl(S, FH) do {fputs((S), (FH)); putc('\n', (FH));} while(0)
[d69255f]61# define ASSERT(X)
[d1b1380]62
[a420b49]63static long
64get32(FILE *fh)
65{
[ad9a5cd]66   long w = getc(fh);
[a420b49]67   w |= (long)getc(fh) << 8l;
68   w |= (long)getc(fh) << 16l;
69   w |= (long)getc(fh) << 24l;
70   return w;
[d1b1380]71}
72
[a420b49]73static void
74put32(long w, FILE *fh)
75{
76   putc((char)(w), fh);
77   putc((char)(w >> 8l), fh);
78   putc((char)(w >> 16l), fh);
79   putc((char)(w >> 24l), fh);
[d1b1380]80}
[5c3c61a]81
82#endif
83
[dd1d6369]84#ifdef HAVE_ROUND
85# include <math.h>
86extern double round(double); /* prototype is often missing... */
87# define my_round round
88#else
89static double
90my_round(double x) {
91   if (x >= 0.0) return floor(x + 0.5);
92   return ceil(x - 0.5);
93}
94#endif
95
[d69255f]96unsigned int img_output_version = 3;
[5c3c61a]97
[23f7ea7]98#define TMPBUFLEN 256
99static char tmpbuf[TMPBUFLEN];
[5c3c61a]100
[72af530]101#ifdef IMG_HOSTED
[5c3c61a]102static enum {
103   IMG_NONE = 0,
[759fb47]104   IMG_FILENOTFOUND = /*Couldn't open data file `%s'*/24,
[5c3c61a]105   IMG_OUTOFMEMORY  = /*Out of memory %.0s*/38,
[759fb47]106   IMG_DIRECTORY    = /*Filename `%s' refers to directory*/44,
107   IMG_CANTOPENOUT  = /*Failed to open output file `%s'*/47,
[ad9a5cd]108   IMG_BADFORMAT    = /*Bad 3d image file `%s'*/106,
109   IMG_READERROR    = /*Error reading from file `%s'*/109,
[6c1c4f3]110   IMG_WRITEERROR   = /*Error writing to file `%s'*/110,
111   IMG_TOONEW       = /*File `%s' has a newer format than this program can understand*/114
[5c3c61a]112} img_errno = IMG_NONE;
113#else
114static img_errcode img_errno = IMG_NONE;
[c0563da]115#endif
[d1b1380]116
[0da6e60]117/* Attempt to string paste to ensure we are passed a literal string */
118#define LITLEN(S) (sizeof(S"") - 1)
119
[5c3c61a]120/* Read a line from a stream to a buffer. Any eol chars are removed
121 * from the file and the length of the string excluding '\0' is returned */
[a420b49]122static int
123getline(char *buf, size_t len, FILE *fh)
124{
[eb18f4d]125   size_t i = 0;
[a420b49]126   int ch;
[d1b1380]127
[a420b49]128   ch = getc(fh);
[647407d]129   while (ch != '\n' && ch != '\r' && ch != EOF && i < len - 1) {
[a420b49]130      buf[i++] = ch;
131      ch = getc(fh);
132   }
[647407d]133   if (ch == '\n' || ch == '\r') {
134      /* remove any further eol chars (for DOS text files) */
[a420b49]135      do {
136         ch = getc(fh);
137      } while (ch == '\n' || ch == '\r');
138      ungetc(ch, fh); /* we don't want it, so put it back */
139   }
140   buf[i] = '\0';
[5c3c61a]141   return i;
[d1b1380]142}
[c0563da]143
[a2ad284]144static char *
145getline_alloc(FILE *fh)
146{
147   int ch;
148   size_t i = 0;
149   size_t len = 16;
150   char *buf = xosmalloc(len);
151   if (!buf) return NULL;
152
153   ch = getc(fh);
154   while (ch != '\n' && ch != '\r' && ch != EOF) {
155      buf[i++] = ch;
156      if (i == len - 1) {
157         char *p;
158         len += len;
159         p = xosrealloc(buf, len);
160         if (!p) {
161            osfree(buf);
162            return NULL;
163         }
164         buf = p;
165      }
166      ch = getc(fh);
167   }
168   if (ch == '\n' || ch == '\r') {
169      /* remove any further eol chars (for DOS text files) */
170      do {
171         ch = getc(fh);
172      } while (ch == '\n' || ch == '\r');
173      ungetc(ch, fh); /* we don't want it, so put it back */
174   }
175   buf[i++] = '\0';   
176   return buf;
177}
178
[72af530]179#ifndef IMG_HOSTED
[a420b49]180img_errcode
181img_error(void)
182{
183   return img_errno;
[d1b1380]184}
185#else
[a420b49]186int
187img_error(void)
188{
189   return (int)img_errno;
[d1b1380]190}
191#endif
192
[a420b49]193img *
[a2ad284]194img_open_survey(const char *fnm, const char *survey)
[a420b49]195{
196   img *pimg;
[0da6e60]197   size_t len;
[a420b49]198
199   if (fDirectory(fnm)) {
200      img_errno = IMG_DIRECTORY;
201      return NULL;
202   }
[d1b1380]203
[a420b49]204   pimg = (img *)xosmalloc(ossizeof(img));
205   if (pimg == NULL) {
206      img_errno = IMG_OUTOFMEMORY;
207      return NULL;
208   }
[d1b1380]209
[23f7ea7]210   pimg->buf_len = 257;
[0ff23cb]211   pimg->label_buf = xosmalloc(pimg->buf_len);
212   if (!pimg->label_buf) {
[23f7ea7]213      osfree(pimg);
214      img_errno = IMG_OUTOFMEMORY;
215      return NULL;
216   }
217
[a420b49]218   pimg->fh = fopenWithPthAndExt("", fnm, EXT_SVX_3D, "rb", NULL);
219   if (pimg->fh == NULL) {
220      osfree(pimg);
221      img_errno = IMG_FILENOTFOUND;
222      return NULL;
223   }
[d1b1380]224
[0da6e60]225   pimg->fRead = fTrue; /* reading from this file */
226   img_errno = IMG_NONE;
227   pimg->start = ftell(pimg->fh);
228
229   pimg->flags = 0;
230
231   /* for version 3 we use label_buf to store the prefix for reuse */
232   pimg->label_len = 0;
233
234   pimg->survey = NULL;
235   pimg->survey_len = 0;
236
237   if (survey) {
238      len = strlen(survey);
239      if (len) {
240         if (survey[len - 1] == '.') len--;
241         if (len) {
242            char *p;
243            pimg->survey = osmalloc(len + 2);
244            memcpy(pimg->survey, survey, len);
245            /* Set title to leaf survey name */
246            pimg->survey[len] = '\0';
247            p = strchr(pimg->survey, '.');
248            if (p) p++; else p = pimg->survey;
249            strcpy(pimg->title, p);
250            pimg->survey[len] = '.';
251            pimg->survey[len + 1] = '\0';
252         }
253      }
254      pimg->survey_len = len;
255   }
256
257   /* [version -1] already skipped heading line, or there wasn't one
258    * [version 0] not in the middle of a 'LINE' command
259    * [version 3] not in the middle of turning a LINE into a MOVE
260    */
261   pimg->pending = 0;
262
263   len = strlen(fnm);
264   if (len > LITLEN(EXT_SVX_POS) + 1 &&
265       fnm[len - LITLEN(EXT_SVX_POS) - 1] == FNM_SEP_EXT &&
266       strcmp(fnm + len - LITLEN(EXT_SVX_POS), EXT_SVX_POS) == 0) {
267      pimg->version = -1;
268      pimg->title = baseleaf_from_fnm(fnm);
269      pimg->datestamp = osstrdup(msg(/*Date and time not available.*/108));
270      return pimg;
271   }
272
[23f7ea7]273   getline(tmpbuf, TMPBUFLEN, pimg->fh); /* id string */
274   if (strcmp(tmpbuf, "Survex 3D Image File") != 0) {
[a420b49]275      fclose(pimg->fh);
276      osfree(pimg);
277      img_errno = IMG_BADFORMAT;
278      return NULL;
279   }
[d1b1380]280
[23f7ea7]281   getline(tmpbuf, TMPBUFLEN, pimg->fh); /* file format version */
282   pimg->version = (tolower(*tmpbuf) == 'b'); /* binary file iff B/b prefix */
[a420b49]283   /* knock off the 'B' or 'b' if it's there */
[23f7ea7]284   if (strcmp(tmpbuf + pimg->version, "v0.01") == 0) {
[0da6e60]285      /* nothing special to do */
[6c1c4f3]286   } else if (pimg->version == 0 && tmpbuf[0] == 'v') {
287      if (tmpbuf[1] < '2' || tmpbuf[1] > '3' || tmpbuf[2] != '\0') {
288         fclose(pimg->fh);
289         osfree(pimg);
290         img_errno = IMG_TOONEW;
291         return NULL;   
292      }
[d69255f]293      pimg->version = tmpbuf[1] - '0';
[5c3c61a]294   } else {
[a420b49]295      fclose(pimg->fh);
296      osfree(pimg);
[647407d]297      img_errno = IMG_BADFORMAT;
[a420b49]298      return NULL;
299   }
[58ad9da]300
[a2ad284]301   pimg->title = getline_alloc(pimg->fh);
302   pimg->datestamp = getline_alloc(pimg->fh);
303   if (!pimg->title || !pimg->datestamp) {
304      osfree(pimg->title);
305      fclose(pimg->fh);
306      osfree(pimg);
307      img_errno = IMG_OUTOFMEMORY;
308      return NULL;
309   }
310
[a420b49]311   return pimg;
[d1b1380]312}
313
[f2588ca]314void
315img_rewind(img *pimg)
316{
317   fseek(pimg->fh, pimg->start, SEEK_SET);
[76bbb7c9]318
319   /* [version 0] not in the middle of a 'LINE' command
320    * [version 3] not in the middle of turning a LINE into a MOVE */
321   pimg->pending = 0;
[d69255f]322
323   img_errno = IMG_NONE;
[99cf51a]324
[5d7280f8]325   /* for version 3 we use label_buf to store the prefix for reuse */
[d69255f]326   pimg->label_len = 0;
[f2588ca]327}
328
[a420b49]329img *
[fe8e80e]330img_open_write(const char *fnm, char *title_buf, bool fBinary)
[a420b49]331{
332   time_t tm;
333   img *pimg;
[d1b1380]334
[d69255f]335   fBinary = fBinary;
336
[a420b49]337   if (fDirectory(fnm)) {
338      img_errno = IMG_DIRECTORY;
339      return NULL;
340   }
[d1b1380]341
[a420b49]342   pimg = (img *)xosmalloc(ossizeof(img));
343   if (pimg == NULL) {
344      img_errno = IMG_OUTOFMEMORY;
345      return NULL;
346   }
[d1b1380]347
[fe8e80e]348   pimg->buf_len = 257;
[0ff23cb]349   pimg->label_buf = xosmalloc(pimg->buf_len);
350   if (!pimg->label_buf) {
[fe8e80e]351      osfree(pimg);
352      img_errno = IMG_OUTOFMEMORY;
353      return NULL;
354   }
355
[a420b49]356   pimg->fh = fopen(fnm, "wb");
357   if (!pimg->fh) {
358      osfree(pimg);
359      img_errno = IMG_CANTOPENOUT;
360      return NULL;
361   }
[d1b1380]362
[a420b49]363   /* Output image file header */
364   fputs("Survex 3D Image File\n", pimg->fh); /* file identifier string */
[5c3c61a]365   if (img_output_version < 2) {
[d69255f]366      pimg->version = 1;
367      fputs("Bv0.01\n", pimg->fh); /* binary file format version number */
[5c3c61a]368   } else {
[d69255f]369      pimg->version = (img_output_version > 2) ? 3 : 2;
[5c3c61a]370      fprintf(pimg->fh, "v%d\n", pimg->version); /* file format version no. */
371   }
[fe8e80e]372   fputsnl(title_buf, pimg->fh);
[a420b49]373   tm = time(NULL);
374   if (tm == (time_t)-1) {
375      fputsnl(TIMENA, pimg->fh);
376   } else {
377      /* output current date and time in format specified */
[23f7ea7]378      strftime(tmpbuf, TMPBUFLEN, TIMEFMT, localtime(&tm));
379      fputsnl(tmpbuf, pimg->fh);
[a420b49]380   }
381   pimg->fRead = fFalse; /* writing to this file */
382   img_errno = IMG_NONE;
[d69255f]383
[5d7280f8]384   /* for version 3 we use label_buf to store the prefix for reuse */
[0ff23cb]385   pimg->label_buf[0] = '\0';
[d69255f]386   pimg->label_len = 0;
387
[ad9a5cd]388   /* Don't check for write errors now - let img_close() report them... */
[a420b49]389   return pimg;
[d1b1380]390}
391
[ad9a5cd]392static int
393read_coord(FILE *fh, img_point *pt)
394{
395   ASSERT(fh);
396   ASSERT(pt);
397   pt->x = get32(fh) / 100.0;
398   pt->y = get32(fh) / 100.0;
399   pt->z = get32(fh) / 100.0;
400   if (ferror(fh) || feof(fh)) {
401      img_errno = feof(fh) ? IMG_BADFORMAT : IMG_READERROR;
402      return 0;
403   }       
404   return 1;
405}
406
[a420b49]407int
[23f7ea7]408img_read_item(img *pimg, img_point *p)
[a420b49]409{
410   int result;
[95c3272]411   pimg->flags = 0;
[0ff23cb]412   pimg->label = pimg->label_buf;
[d69255f]413
414   if (pimg->version == 3) {
415      int opt;
[76bbb7c9]416      if (pimg->pending >= 0x80) {
417         *p = pimg->mv;
418         pimg->flags = (int)(pimg->pending) & 0x3f;
419         pimg->pending = 0;
[99cf51a]420         return img_LINE;
[76bbb7c9]421      }
[d69255f]422      again3: /* label to goto if we get a prefix */
423      opt = getc(pimg->fh);
[ad9a5cd]424      if (opt == EOF) {
425         img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
426         return img_BAD;
427      }
[d69255f]428      switch (opt >> 6) {
429       case 0:
430         if (opt == 0) {
431            if (!pimg->label_len) return img_STOP; /* end of data marker */
432            pimg->label_len = 0;
433            goto again3;
434         }
435         if (opt < 15) {
436            /* 1-14 mean trim that many levels from current prefix */
437            int c;
438            /* zero prefix using "0" */
439            if (pimg->label_len <= 16) {
440               img_errno = IMG_BADFORMAT;
441               return img_BAD;
442            }
443            c = pimg->label_len - 16;
444            opt &= 0x07;
[0ff23cb]445            while (pimg->label_buf[c] != '.' || --opt > 0) {
[d69255f]446               if (--c < 0) {
447                  /* zero prefix using "0" */
448                  img_errno = IMG_BADFORMAT;
449                  return img_BAD;
450               }
451            }
452            c++;
[0ff23cb]453            pimg->label_buf[c] = '\0';
[d69255f]454            pimg->label_len = c;
455            goto again3;
456         }
457         if (opt == 15) {
458            result = img_MOVE;
459            break;
460         }
461         /* 16-31 mean remove (n - 15) characters from the prefix */
462         pimg->label_len -= (opt - 15);
463         /* zero prefix using 0 */
464         if (pimg->label_len <= 0) {
465            img_errno = IMG_BADFORMAT;
466            return img_BAD;
467         }
468         goto again3;
469       case 1: case 2: {
470         char *q;
[ad9a5cd]471         long len = getc(pimg->fh);
472         if (len == EOF) {
473            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
474            return img_BAD;
475         }
[d69255f]476         if (len == 0xfe) {
477            len += get16(pimg->fh);
[ad9a5cd]478            if (feof(pimg->fh)) {
479               img_errno = IMG_BADFORMAT;
480               return img_BAD;
481            }
482            if (ferror(pimg->fh)) {
483               img_errno = IMG_READERROR;
484               return img_BAD;
485            }
[d69255f]486         } else if (len == 0xff) {
487            len = get32(pimg->fh);
[ad9a5cd]488            if (ferror(pimg->fh)) {
489               img_errno = IMG_READERROR;
490               return img_BAD;
491            }
492            if (feof(pimg->fh) || len < 0xfe + 0xffff) {
[d69255f]493               img_errno = IMG_BADFORMAT;
494               return img_BAD;
495            }
496         }
497
[0ff23cb]498         q = pimg->label_buf + pimg->label_len;
[d69255f]499         pimg->label_len += len;
500         if (pimg->label_len >= pimg->buf_len) {
[0ff23cb]501            pimg->label_buf = xosrealloc(pimg->label_buf, pimg->label_len + 1);
502            if (!pimg->label_buf) {
[d69255f]503               img_errno = IMG_OUTOFMEMORY;
504               return img_BAD;
505            }
506            pimg->buf_len = pimg->label_len + 1;
507         }
508         if (len && fread(q, len, 1, pimg->fh) != 1) {
[ad9a5cd]509            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]510            return img_BAD;
511         }
512         q[len] = '\0';
[76bbb7c9]513
514         result = opt & 0x40 ? img_LABEL : img_LINE;
515
516         if (pimg->survey_len) {
517            size_t l = pimg->survey_len;
[0ff23cb]518            const char *s = pimg->label_buf;
[76bbb7c9]519            if (result == img_LINE) {
520               if (strncmp(pimg->survey, s, l) != 0 ||
521                   !(s[l] == '.' || s[l] == '\0')) {
[ad9a5cd]522                  if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;                   
[76bbb7c9]523                  pimg->pending = 15;
524                  goto again3;
525               }
526            } else {
527               if (strncmp(pimg->survey, s, l + 1) != 0) {
528                  fseek(pimg->fh, 12, SEEK_CUR);
529                  goto again3;
530               }
531            }
[0ff23cb]532            pimg->label += l;
533            /* skip the dot if there */
534            if (*pimg->label) pimg->label++;
[76bbb7c9]535         }
536
537         if (result == img_LINE && pimg->pending) {
538            *p = pimg->mv;
[ad9a5cd]539            if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
[76bbb7c9]540            pimg->pending = opt;
541            return img_MOVE;
542         }
543         pimg->flags = (int)opt & 0x3f;
[d69255f]544         break;
545       }
546       default:
547         img_errno = IMG_BADFORMAT;
548         return img_BAD;
549      }
[ad9a5cd]550      if (!read_coord(pimg->fh, p)) return img_BAD;
[76bbb7c9]551      pimg->pending = 0;
[d69255f]552      return result;
553   } else if (pimg->version > 0) {
554      static long opt_lookahead = 0;
[ad9a5cd]555      static img_point pt = { 0.0, 0.0, 0.0 };
[a420b49]556      long opt;
557      again: /* label to goto if we get a cross */
[5d7280f8]558      pimg->label[0] = '\0';
[ad9a5cd]559
[5c3c61a]560      if (pimg->version == 1) {
[c4d4649]561         if (opt_lookahead) {
562            opt = opt_lookahead;
563            opt_lookahead = 0;
564         } else {
565            opt = get32(pimg->fh);
566         }
[5c3c61a]567      } else {
568         opt = getc(pimg->fh);
569      }
[ad9a5cd]570
571      if (feof(pimg->fh)) {
572         img_errno = IMG_BADFORMAT;
573         return img_BAD;
574      }
575      if (ferror(pimg->fh)) {
576         img_errno = IMG_READERROR;
577         return img_BAD;
578      }
579
[a420b49]580      switch (opt) {
[437caf3]581       case -1: case 0:
[a420b49]582         return img_STOP; /* end of data marker */
583       case 1:
[ad9a5cd]584         /* skip coordinates */
585         if (fseek(pimg->fh, 12, SEEK_CUR) == -1) {
586            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
587            return img_BAD;
588         }
[a420b49]589         goto again;
[23f7ea7]590       case 2: case 3: {
[fe8e80e]591         char *q;
[3a1f8da]592         int ch;
[437caf3]593         result = img_LABEL;
[3a1f8da]594         ch = getc(pimg->fh);
[d69255f]595         if (ch == EOF) {
[ad9a5cd]596            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]597            return img_BAD;
598         }
[3a1f8da]599         if (ch != '\\') ungetc(ch, pimg->fh);
[0ff23cb]600         fgets(pimg->label_buf, 257, pimg->fh);
[ad9a5cd]601         if (feof(pimg->fh)) {
602            img_errno = IMG_BADFORMAT;
603            return img_BAD;
604         }
605         if (ferror(pimg->fh)) {
606            img_errno = IMG_READERROR;
607            return img_BAD;
608         }
[0ff23cb]609         q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[d69255f]610         if (*q != '\n') {
611            img_errno = IMG_BADFORMAT;
612            return img_BAD;
613         }
[9968ebf]614         /* Ignore empty labels in some .3d files (caused by a bug) */
[0ff23cb]615         if (q == pimg->label_buf) goto again;
[fe8e80e]616         *q = '\0';
[509e099]617         pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[437caf3]618         if (opt == 2) goto done;
619         break;
[23f7ea7]620       }
[95c3272]621       case 6: case 7: {
[ad9a5cd]622         long len;
[23f7ea7]623         result = img_LABEL;
[ad9a5cd]624
[509e099]625         if (opt == 7)
626            pimg->flags = getc(pimg->fh);
627         else
628            pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[ad9a5cd]629
[23f7ea7]630         len = get32(pimg->fh);
[ad9a5cd]631
632         if (feof(pimg->fh)) {
633            img_errno = IMG_BADFORMAT;
634            return img_BAD;
635         }
636         if (ferror(pimg->fh)) {
637            img_errno = IMG_READERROR;
638            return img_BAD;
639         }
640
[9968ebf]641         /* Ignore empty labels in some .3d files (caused by a bug) */
642         if (len == 0) goto again;
[dd1d6369]643         if (len >= (long)pimg->buf_len) {
[0ff23cb]644            pimg->label_buf = xosrealloc(pimg->label_buf, len + 1);
645            if (!pimg->label_buf) {
[23f7ea7]646               img_errno = IMG_OUTOFMEMORY;
647               return img_BAD;
648            }
649            pimg->buf_len = len + 1;
650         }
[0ff23cb]651         if (fread(pimg->label_buf, len, 1, pimg->fh) != 1) {
[ad9a5cd]652            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]653            return img_BAD;
654         }
[23f7ea7]655         break;
656       }
[a420b49]657       case 4:
658         result = img_MOVE;
659         break;
660       case 5:
661         result = img_LINE;
662         break;
663       default:
[95c3272]664         switch ((int)opt & 0xc0) {
665          case 0x80:
666            pimg->flags = (int)opt & 0x3f;
667            result = img_LINE;
668            break;
669          case 0x40: {
670            char *q;
671            pimg->flags = (int)opt & 0x3f;
672            result = img_LABEL;
[0ff23cb]673            if (!fgets(pimg->label_buf, 257, pimg->fh)) {
[ad9a5cd]674               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]675               return img_BAD;
676            }
[0ff23cb]677            q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[9968ebf]678            /* Ignore empty-labels in some .3d files (caused by a bug) */
[0ff23cb]679            if (q == pimg->label_buf) goto again;
[d69255f]680            if (*q != '\n') {
681               img_errno = IMG_BADFORMAT;
682               return img_BAD;
683            }
[95c3272]684            *q = '\0';
685            break;
686          }
687          case 0xc0:
688            /* use this for an extra leg or station flag if we need it */
689          default:
[d69255f]690            img_errno = IMG_BADFORMAT;
[95c3272]691            return img_BAD;
692         }
[437caf3]693         break;
[a420b49]694      }
[ad9a5cd]695
696      if (!read_coord(pimg->fh, &pt)) return img_BAD;
[76bbb7c9]697
[ed0f5b6]698      if (result == img_LABEL && pimg->survey_len) {
699         if (strncmp(pimg->label_buf, pimg->survey, pimg->survey_len + 1) != 0)
[0ff23cb]700            goto again;
701         pimg->label += pimg->survey_len + 1;
702      }
[76bbb7c9]703
[a420b49]704      done:
[ad9a5cd]705      *p = pt;
[c4d4649]706
707      if (result == img_MOVE && pimg->version == 1) {
[d69255f]708         /* peek at next code and see if it's an old-style label */
[23f7ea7]709         opt_lookahead = get32(pimg->fh);
[ad9a5cd]710
711         if (feof(pimg->fh)) {
712            img_errno = IMG_BADFORMAT;
713            return img_BAD;
714         }
715         if (ferror(pimg->fh)) {
716            img_errno = IMG_READERROR;
717            return img_BAD;
718         }
719
[d69255f]720         if (opt_lookahead == 2) return img_read_item(pimg, p);
[c4d4649]721      }
[23f7ea7]722
[a420b49]723      return result;
[0da6e60]724   } else if (pimg->version == 0) {
[a420b49]725      ascii_again:
[5d7280f8]726      pimg->label[0] = '\0';
[a420b49]727      if (feof(pimg->fh)) return img_STOP;
[76bbb7c9]728      if (pimg->pending) {
729         pimg->pending = 0;
[a420b49]730         result = img_LINE;
731      } else {
732         /* Stop if nothing found */
[23f7ea7]733         if (fscanf(pimg->fh, "%s", tmpbuf) < 1) return img_STOP;
734         if (strcmp(tmpbuf, "move") == 0)
[a420b49]735            result = img_MOVE;
[23f7ea7]736         else if (strcmp(tmpbuf, "draw") == 0)
[a420b49]737            result = img_LINE;
[23f7ea7]738         else if (strcmp(tmpbuf, "line") == 0) {
[bd1913f]739            /* set flag to indicate to process second triplet as LINE */
[76bbb7c9]740            pimg->pending = 1;
[a420b49]741            result = img_MOVE;
[23f7ea7]742         } else if (strcmp(tmpbuf, "cross") == 0) {
[d69255f]743            if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]744               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[0ed0e16]745               return img_BAD;
[d69255f]746            }
[a420b49]747            goto ascii_again;
[23f7ea7]748         } else if (strcmp(tmpbuf, "name") == 0) {
[0da6e60]749            size_t off = 0;
750            pimg->label_buf[0] = '\0';
751            while (!feof(pimg->fh)) {
752               if (!fgets(pimg->label_buf + off, pimg->buf_len - off, pimg->fh)) {
[ad9a5cd]753                  img_errno = IMG_READERROR;
754                  return img_BAD;
755               }
[0da6e60]756
757               off += strlen(pimg->label_buf + off);
758               if (off && pimg->label_buf[off - 1] == '\n') {
759                  pimg->label_buf[off - 1] = '\0';
760                  break;
761               }
762               pimg->buf_len += pimg->buf_len;
763               pimg->label_buf = xosrealloc(pimg->label_buf, pimg->buf_len);
[ad9a5cd]764            }
[0da6e60]765
766            if (pimg->label[0] == '\\')
767               memmove(pimg->label, pimg->label + 1, off - 1);
768     
[a420b49]769            result = img_LABEL;
[d69255f]770         } else {
771            img_errno = IMG_BADFORMAT;
[a420b49]772            return img_BAD; /* unknown keyword */
[d69255f]773         }
[a420b49]774      }
[d1b1380]775
[d69255f]776      if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]777         img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
[fe8e80e]778         return img_BAD;
[d69255f]779      }
780
[0ff23cb]781      if (result == img_LABEL) {
782         if (pimg->survey_len &&
783          (strncmp(pimg->label_buf, pimg->survey, pimg->survey_len + 1) != 0))
784            goto ascii_again;
785         pimg->label += pimg->survey_len + 1;
786      }
[76bbb7c9]787
[a420b49]788      return result;
[0da6e60]789   } else {
790      /* version -1: .pos file */
791      size_t off = 0;
792      while (fscanf(pimg->fh, "(%lf,%lf,%lf ) ", &p->x, &p->y, &p->z) != 3) {
793         int ch;
794         if (ferror(pimg->fh)) {
795            img_errno = IMG_READERROR;
796            return img_BAD;
797         }
798         if (feof(pimg->fh)) return img_STOP;
799         if (pimg->pending) {
800            img_errno = IMG_BADFORMAT;
801            return img_BAD;
802         }
803         pimg->pending = 1;
804         /* ignore rest of line */
805         do {
806            ch = getc(pimg->fh);
807         } while (ch != '\n' && ch != '\r' && ch != EOF);
808      }
809
810      pimg->label_buf[0] = '\0';
811      while (!feof(pimg->fh)) {
812         if (!fgets(pimg->label_buf + off, pimg->buf_len - off, pimg->fh)) {
813            img_errno = IMG_READERROR;
814            return img_BAD;
815         }
816
817         off += strlen(pimg->label_buf + off);
818         if (off && pimg->label_buf[off - 1] == '\n') {
819            pimg->label_buf[off - 1] = '\0';
820            break;
821         }
822         pimg->buf_len += pimg->buf_len;
823         pimg->label_buf = xosrealloc(pimg->label_buf, pimg->buf_len);
824      }
825
826      if (pimg->label[0] == '\\')
827         memmove(pimg->label, pimg->label + 1, off - 1);
828     
829      return img_LABEL;
[a420b49]830   }
[d1b1380]831}
832
[ad9a5cd]833static int
[d69255f]834write_v3label(img *pimg, int opt, const char *s)
835{
836   size_t len, n, dot;
837
838   /* find length of common prefix */
839   dot = 0;
[0ff23cb]840   for (len = 0; s[len] == pimg->label_buf[len] && s[len] != '\0'; len++) {
[d69255f]841      if (s[len] == '.') dot = len + 1;
842   }
843
844   ASSERT(len <= pimg->label_len);
845   n = pimg->label_len - len;
846   if (len == 0) {
847      if (pimg->label_len) putc(0, pimg->fh);
848   } else if (n <= 16) {
849      if (n) putc(n + 15, pimg->fh);
850   } else if (dot == 0) {
851      if (pimg->label_len) putc(0, pimg->fh);
[99cf51a]852      len = 0;
[d69255f]853   } else {
[0ff23cb]854      const char *p = pimg->label_buf + dot;
[d69255f]855      n = 1;
856      for (len = pimg->label_len - dot - 17; len; len--) {
857         if (*p++ == '.') n++;
858      }
859      if (n <= 14) {
860         putc(n, pimg->fh);
861         len = dot;
862      } else {
863         if (pimg->label_len) putc(0, pimg->fh);
864         len = 0;
865      }
866   }
867
868   n = strlen(s + len);
869   putc(opt, pimg->fh);
870   if (n < 0xfe) {
871      putc(n, pimg->fh);
872   } else if (n < 0xffff + 0xfe) {
873      putc(0xfe, pimg->fh);
874      put16(n - 0xfe, pimg->fh);
875   } else {
876      putc(0xff, pimg->fh);
877      put32(n, pimg->fh);
878   }
879   fwrite(s + len, n, 1, pimg->fh);
880
881   n += len;
882   pimg->label_len = n;
883   if (n >= pimg->buf_len) {
[0ff23cb]884      char *p = xosrealloc(pimg->label_buf, n + 1);
[ad9a5cd]885      if (!p) return 0; /* FIXME: distinguish out of memory... */
886      pimg->label_buf = p;
887      pimg->buf_len = n + 1;
[d69255f]888   }
[0ff23cb]889   memcpy(pimg->label_buf + len, s + len, n - len + 1);
[ad9a5cd]890
891   return !ferror(pimg->fh);
[d69255f]892}
893
[a420b49]894void
[95c3272]895img_write_item(img *pimg, int code, int flags, const char *s,
[a9f5117]896               double x, double y, double z)
[a420b49]897{
[647407d]898   if (!pimg) return;
[d69255f]899   if (pimg->version == 3) {
900      int opt = 0;
901      switch (code) {
902       case img_LABEL:
903         write_v3label(pimg, 0x40 | flags, s);
904         opt = 0;
905         break;
906       case img_MOVE:
907         opt = 15;
908         break;
909       case img_LINE:
910         write_v3label(pimg, 0x80 | flags, s ? s : "");
911         opt = 0;
912         break;
913       default: /* ignore for now */
914         return;
915      }
916      if (opt) putc(opt, pimg->fh);
917      /* Output in cm */
[dd1d6369]918      put32((INT32_T)my_round(x * 100.0), pimg->fh);
919      put32((INT32_T)my_round(y * 100.0), pimg->fh);
920      put32((INT32_T)my_round(z * 100.0), pimg->fh);
[d69255f]921   } else {
[23f7ea7]922      size_t len;
[badeec8]923      INT32_T opt = 0;
[d69255f]924      ASSERT(pimg->version > 0);
[a420b49]925      switch (code) {
[437caf3]926       case img_LABEL:
927         if (pimg->version == 1) {
928            /* put a move before each label */
[95c3272]929            img_write_item(pimg, img_MOVE, 0, NULL, x, y, z);
[437caf3]930            put32(2, pimg->fh);
[0ed0e16]931            fputsnl(s, pimg->fh);
[437caf3]932            return;
933         }
[23f7ea7]934         len = strlen(s);
[af56069]935         if (len > 255 || strchr(s, '\n')) {
[23f7ea7]936            /* long label - not in early incarnations of v2 format, but few
937             * 3d files will need these, so better not to force incompatibility
938             * with a new version I think... */
[95c3272]939            putc(7, pimg->fh);
940            putc(flags, pimg->fh);
[23f7ea7]941            put32(len, pimg->fh);
942            fputs(s, pimg->fh);
943         } else {
[95c3272]944            putc(0x40 | (flags & 0x3f), pimg->fh);
[23f7ea7]945            fputsnl(s, pimg->fh);
946         }
[437caf3]947         opt = 0;
[23f7ea7]948         break;
[a420b49]949       case img_MOVE:
950         opt = 4;
951         break;
952       case img_LINE:
[5c3c61a]953         if (pimg->version > 1) {
[d69255f]954            opt = 0x80 | (flags & 0x3f);
[437caf3]955            break;
[5c3c61a]956         }
[437caf3]957         opt = 5;
[a420b49]958         break;
[437caf3]959       default: /* ignore for now */
960         return;
[a420b49]961      }
[437caf3]962      if (pimg->version == 1) {
963         put32(opt, pimg->fh);
964      } else {
965         if (opt) putc(opt, pimg->fh);
[a420b49]966      }
[d69255f]967      /* Output in cm */
[dd1d6369]968      put32((INT32_T)my_round(x * 100.0), pimg->fh);
969      put32((INT32_T)my_round(y * 100.0), pimg->fh);
970      put32((INT32_T)my_round(z * 100.0), pimg->fh);
[a420b49]971   }
[d1b1380]972}
973
[ad9a5cd]974int
[a420b49]975img_close(img *pimg)
976{
[ad9a5cd]977   int result = 1;
[dbb4e19]978   if (pimg) {
979      if (pimg->fh) {
[76bbb7c9]980         if (pimg->fRead) {
981            osfree(pimg->survey);
[a2ad284]982            osfree(pimg->title);
983            osfree(pimg->datestamp);
[76bbb7c9]984         } else {
985            /* write end of data marker */
[d69255f]986            switch (pimg->version) {
987             case 1:
[5c3c61a]988               put32((INT32_T)-1, pimg->fh);
[d69255f]989               break;
990             case 2:
991               putc(0, pimg->fh);
992               break;
993             case 3:
994               if (pimg->label_len) putc(0, pimg->fh);
[437caf3]995               putc(0, pimg->fh);
[d69255f]996               break;
[5c3c61a]997            }
998         }
[ad9a5cd]999         if (ferror(pimg->fh)) result = 0;
1000         if (fclose(pimg->fh)) result = 0;
1001         img_errno = pimg->fRead ? IMG_READERROR : IMG_WRITEERROR;
[dbb4e19]1002      }
[0ff23cb]1003      osfree(pimg->label_buf);
[dbb4e19]1004      osfree(pimg);
[a420b49]1005   }
[ad9a5cd]1006   return result;
[d1b1380]1007}
Note: See TracBrowser for help on using the repository browser.