source: git/src/img.c @ 35001ee

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 35001ee was 4d3dfdf, checked in by Olly Betts <olly@…>, 24 years ago

Fixed --survey filtering in img.c and added testcase to diffpos.tst

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

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