source: git/src/img.c @ 1da3ccc

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 1da3ccc was 6c1c4f3, checked in by Olly Betts <olly@…>, 24 years ago

Distinguish between a "bad" .3d file and one which has a newer
revision of the format than we understand.

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

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