source: git/src/img.c @ 081ef63

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

Sorted out rounding of coordinates going into .3d files.

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

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