source: git/src/img.c @ 82be646

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

Enhanced img to read arbitrarily long title and datestamp.

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

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