source: git/src/img.c @ ee11c6a7

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 ee11c6a7 was d4d3655, checked in by Olly Betts <olly@…>, 23 years ago

Factored out "enlarge label buffer if necessary" code into check_label_space()

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

  • Property mode set to 100644
File size: 29.7 KB
RevLine 
[0da6e60]1/* img.c
[d1b1380]2 * Routines for reading and writing Survex ".3d" image files
[ad4eaf3f]3 * Copyright (C) 1993-2002 Olly Betts
[846746e]4 *
[89231c4]5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
[846746e]9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
[d1b1380]18 */
19
[a420b49]20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
[d1b1380]24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <time.h>
28#include <ctype.h>
29
[72af530]30#include "img.h"
[7d27e36]31
[72af530]32#ifdef IMG_HOSTED
[d69255f]33# include "debug.h"
[d1b1380]34# include "filelist.h"
[d69255f]35# include "filename.h"
36# include "message.h"
37# include "useful.h"
[a420b49]38# define TIMENA msg(/*Date and time not available.*/108)
39# define TIMEFMT msg(/*%a,%Y.%m.%d %H:%M:%S %Z*/107)
[d1b1380]40#else
[72af530]41# define INT32_T long
[d1b1380]42# define TIMENA "Time not available."
43# define TIMEFMT "%a,%Y.%m.%d %H:%M:%S %Z"
44# define EXT_SVX_3D "3d"
45# define xosmalloc(L) malloc((L))
[72af530]46# define xosrealloc(L,S) realloc((L),(S))
[d1b1380]47# define osfree(P) free((P))
48# define ossizeof(T) sizeof(T)
[72af530]49/* in IMG_HOSTED mode, this tests if a filename refers to a directory */
[d1b1380]50# define fDirectory(X) 0
51/* open file FNM with mode MODE, maybe using path PTH and/or extension EXT */
52/* path isn't used in img.c, but EXT is */
53# define fopenWithPthAndExt(PTH,FNM,EXT,MODE,X) fopen(FNM,MODE)
54# define fFalse 0
55# define fTrue 1
56# define bool int
57/* dummy do {...} while(0) hack to permit stuff like
58 * if (s) fputsnl(s,fh); else exit(1);
59 * to work as intended
60 */
[23f7ea7]61# define fputsnl(S, FH) do {fputs((S), (FH)); putc('\n', (FH));} while(0)
[d69255f]62# define ASSERT(X)
[d1b1380]63
[a420b49]64static long
65get32(FILE *fh)
66{
[ad9a5cd]67   long w = getc(fh);
[a420b49]68   w |= (long)getc(fh) << 8l;
69   w |= (long)getc(fh) << 16l;
70   w |= (long)getc(fh) << 24l;
71   return w;
[d1b1380]72}
73
[a420b49]74static void
75put32(long w, FILE *fh)
76{
77   putc((char)(w), fh);
78   putc((char)(w >> 8l), fh);
79   putc((char)(w >> 16l), fh);
80   putc((char)(w >> 24l), fh);
[d1b1380]81}
[5c3c61a]82
83#endif
84
[dd1d6369]85#ifdef HAVE_ROUND
86# include <math.h>
87extern double round(double); /* prototype is often missing... */
88# define my_round round
89#else
90static double
91my_round(double x) {
92   if (x >= 0.0) return floor(x + 0.5);
93   return ceil(x - 0.5);
94}
95#endif
96
[ad4eaf3f]97/* portable case insensitive string compare */
98#if defined(strcasecmp) || defined(HAVE_STRCASECMP)
99# define my_strcasecmp strcasecmp
100#else
101/* What about top bit set chars? */
102int my_strcasecmp(const char *s1, const char *s2) {
103   register c1, c2;
104   do {
105      c1 = *s1++;
106      c2 = *s2++;
107   } while (c1 && toupper(c1) == toupper(c2));
108   /* now calculate real difference */
109   return c1 - c2;
110}
111#endif
112
[d69255f]113unsigned int img_output_version = 3;
[5c3c61a]114
[72af530]115#ifdef IMG_HOSTED
[5c3c61a]116static enum {
117   IMG_NONE = 0,
[759fb47]118   IMG_FILENOTFOUND = /*Couldn't open data file `%s'*/24,
[5c3c61a]119   IMG_OUTOFMEMORY  = /*Out of memory %.0s*/38,
[759fb47]120   IMG_DIRECTORY    = /*Filename `%s' refers to directory*/44,
121   IMG_CANTOPENOUT  = /*Failed to open output file `%s'*/47,
[ad9a5cd]122   IMG_BADFORMAT    = /*Bad 3d image file `%s'*/106,
123   IMG_READERROR    = /*Error reading from file `%s'*/109,
[6c1c4f3]124   IMG_WRITEERROR   = /*Error writing to file `%s'*/110,
125   IMG_TOONEW       = /*File `%s' has a newer format than this program can understand*/114
[5c3c61a]126} img_errno = IMG_NONE;
127#else
128static img_errcode img_errno = IMG_NONE;
[c0563da]129#endif
[d1b1380]130
[7d27e36]131#define FILEID "Survex 3D Image File"
132
[ad4eaf3f]133#define EXT_PLT "plt"
134
[0da6e60]135/* Attempt to string paste to ensure we are passed a literal string */
136#define LITLEN(S) (sizeof(S"") - 1)
137
[7d27e36]138static char *
139my_strdup(const char *str)
[a420b49]140{
[7d27e36]141   char *p;
142   size_t len = strlen(str) + 1;
143   p = xosmalloc(len);
144   if (p) memcpy(p, str, len);
145   return p;
[d1b1380]146}
[c0563da]147
[a2ad284]148static char *
149getline_alloc(FILE *fh)
150{
151   int ch;
152   size_t i = 0;
153   size_t len = 16;
154   char *buf = xosmalloc(len);
155   if (!buf) return NULL;
156
157   ch = getc(fh);
158   while (ch != '\n' && ch != '\r' && ch != EOF) {
159      buf[i++] = ch;
160      if (i == len - 1) {
161         char *p;
162         len += len;
163         p = xosrealloc(buf, len);
164         if (!p) {
165            osfree(buf);
166            return NULL;
167         }
168         buf = p;
169      }
170      ch = getc(fh);
171   }
172   if (ch == '\n' || ch == '\r') {
173      /* remove any further eol chars (for DOS text files) */
174      do {
175         ch = getc(fh);
176      } while (ch == '\n' || ch == '\r');
177      ungetc(ch, fh); /* we don't want it, so put it back */
178   }
[421b7d2]179   buf[i++] = '\0';
[a2ad284]180   return buf;
181}
182
[72af530]183#ifndef IMG_HOSTED
[a420b49]184img_errcode
185img_error(void)
186{
187   return img_errno;
[d1b1380]188}
189#else
[a420b49]190int
191img_error(void)
192{
193   return (int)img_errno;
[d1b1380]194}
195#endif
196
[d4d3655]197static bool
198check_label_space(img *pimg, size_t len)
199{
200   if (len > pimg->buf_len) {
201      char *b = xosrealloc(pimg->label_buf, len);
202      if (!b) return fFalse;
203      pimg->label = (pimg->label - pimg->label_buf) + b;
204      pimg->label_buf = b;
205      pimg->buf_len = len;
206   }
207   return fTrue;
208}
209
[a420b49]210img *
[a2ad284]211img_open_survey(const char *fnm, const char *survey)
[a420b49]212{
213   img *pimg;
[0da6e60]214   size_t len;
[7d27e36]215   char buf[LITLEN(FILEID) + 1];
216   int ch;
[a420b49]217
218   if (fDirectory(fnm)) {
219      img_errno = IMG_DIRECTORY;
220      return NULL;
221   }
[d1b1380]222
[a420b49]223   pimg = (img *)xosmalloc(ossizeof(img));
224   if (pimg == NULL) {
225      img_errno = IMG_OUTOFMEMORY;
226      return NULL;
227   }
[d1b1380]228
[23f7ea7]229   pimg->buf_len = 257;
[0ff23cb]230   pimg->label_buf = xosmalloc(pimg->buf_len);
231   if (!pimg->label_buf) {
[23f7ea7]232      osfree(pimg);
233      img_errno = IMG_OUTOFMEMORY;
234      return NULL;
235   }
236
[a420b49]237   pimg->fh = fopenWithPthAndExt("", fnm, EXT_SVX_3D, "rb", NULL);
238   if (pimg->fh == NULL) {
239      osfree(pimg);
240      img_errno = IMG_FILENOTFOUND;
241      return NULL;
242   }
[d1b1380]243
[0da6e60]244   pimg->fRead = fTrue; /* reading from this file */
245   img_errno = IMG_NONE;
246
247   pimg->flags = 0;
248
249   /* for version 3 we use label_buf to store the prefix for reuse */
250   pimg->label_len = 0;
251
252   pimg->survey = NULL;
253   pimg->survey_len = 0;
254
[58f02ae]255   pimg->title = NULL;
[0da6e60]256   if (survey) {
257      len = strlen(survey);
258      if (len) {
259         if (survey[len - 1] == '.') len--;
260         if (len) {
261            char *p;
262            pimg->survey = osmalloc(len + 2);
263            memcpy(pimg->survey, survey, len);
264            /* Set title to leaf survey name */
265            pimg->survey[len] = '\0';
266            p = strchr(pimg->survey, '.');
267            if (p) p++; else p = pimg->survey;
[7d27e36]268            pimg->title = my_strdup(p);
269            if (!pimg->title) {
270               img_errno = IMG_OUTOFMEMORY;
271               goto error;
272            }
[0da6e60]273            pimg->survey[len] = '.';
274            pimg->survey[len + 1] = '\0';
275         }
276      }
277      pimg->survey_len = len;
278   }
279
[ad4eaf3f]280   /* [version -2] pending IMG_LINE ('D') or IMG_MOVE ('M')
281    * [version -1] already skipped heading line, or there wasn't one
[0da6e60]282    * [version 0] not in the middle of a 'LINE' command
283    * [version 3] not in the middle of turning a LINE into a MOVE
284    */
285   pimg->pending = 0;
286
287   len = strlen(fnm);
288   if (len > LITLEN(EXT_SVX_POS) + 1 &&
289       fnm[len - LITLEN(EXT_SVX_POS) - 1] == FNM_SEP_EXT &&
[ad4eaf3f]290       my_strcasecmp(fnm + len - LITLEN(EXT_SVX_POS), EXT_SVX_POS) == 0) {
[0da6e60]291      pimg->version = -1;
[984f49e]292      if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm);
[7d27e36]293      pimg->datestamp = my_strdup(TIMENA);
294      if (!pimg->datestamp) {
295         img_errno = IMG_OUTOFMEMORY;
296         goto error;
297      }
[58f02ae]298      pimg->start = 0;
[0da6e60]299      return pimg;
300   }
[5757725]301
[ad4eaf3f]302   if (len > LITLEN(EXT_PLT) + 1 &&
303       fnm[len - LITLEN(EXT_PLT) - 1] == FNM_SEP_EXT &&
304       my_strcasecmp(fnm + len - LITLEN(EXT_PLT), EXT_PLT) == 0) {
305      char *line = NULL;
[f710a3f]306
[ad4eaf3f]307      pimg->version = -2;
[984f49e]308      if (!pimg->survey) pimg->title = baseleaf_from_fnm(fnm);
[ad4eaf3f]309      pimg->datestamp = my_strdup(TIMENA);
310      if (!pimg->datestamp) {
311         img_errno = IMG_OUTOFMEMORY;
312         goto error;
313      }
314      do {
[984f49e]315         do {
316            osfree(line);
317            line = getline_alloc(pimg->fh);
318            if (!line) {
319               img_errno = IMG_OUTOFMEMORY;
320               goto error;
321            }
322            if (line[0] == '\x1a') {
323               osfree(line);
324               pimg->pending = img_STOP + 4;
325               return pimg;
326            }
327            if (feof(pimg->fh)) {
[ad4eaf3f]328               osfree(line);
329               img_errno = IMG_BADFORMAT;
[984f49e]330               goto error;
[ad4eaf3f]331            }
[984f49e]332         } while (line[0] != 'N');
[f710a3f]333
[984f49e]334         len = 1;
335         while (line[len] > 32) ++len;
336      } while (pimg->survey && (pimg->survey_len != len - 1 ||
337               memcmp(line + 1, pimg->survey, pimg->survey_len) != 0));
[f710a3f]338
[d4d3655]339      if (!check_label_space(pimg, len)) {
340         img_errno = IMG_OUTOFMEMORY;
341         goto error;
[f710a3f]342      }
[d4d3655]343
[984f49e]344      --len;
[f710a3f]345      pimg->label_len = len;
346      pimg->label = pimg->label_buf;
347      memcpy(pimg->label, line + 1, len);
348      pimg->label[len] = '\0';
[984f49e]349      if (pimg->survey) {
[5757725]350         char *q = strchr(line + len, 'C');
[984f49e]351         if (q && q[1]) {
352            osfree(pimg->title);
353            pimg->title = osstrdup(q + 1);
354         } else if (!pimg->title) {
355            pimg->title = osstrdup(pimg->label);
356         }
357         if (!pimg->title) {
358            img_errno = IMG_OUTOFMEMORY;
359            goto error;
360         }
361      }
[ad4eaf3f]362      osfree(line);
363      pimg->start = 0;
364      return pimg;
365   }
[0da6e60]366
[7d27e36]367   if (fread(buf, LITLEN(FILEID) + 1, 1, pimg->fh) != 1 ||
368       memcmp(buf, FILEID"\n", LITLEN(FILEID)) != 0) {
[a420b49]369      img_errno = IMG_BADFORMAT;
[58f02ae]370      goto error;
[a420b49]371   }
[d1b1380]372
[7d27e36]373   /* check file format version */
374   ch = getc(pimg->fh);
375   pimg->version = 0;
376   if (tolower(ch) == 'b') {
377      /* binary file iff B/b prefix */
378      pimg->version = 1;
379      ch = getc(pimg->fh);
380   }
381   if (ch != 'v') {
382      img_errno = IMG_BADFORMAT;
383      goto error;
384   }
385   ch = getc(pimg->fh);
386   if (ch == '0') {
387      if (fread(buf, 4, 1, pimg->fh) != 1 || memcmp(buf, ".01\n", 4) != 0) {
388         img_errno = IMG_BADFORMAT;
389         goto error;
390      }
[0da6e60]391      /* nothing special to do */
[7d27e36]392   } else if (pimg->version == 0) {
393      if (ch < '2' || ch > '3' || getc(pimg->fh) != '\n') {
[6c1c4f3]394         img_errno = IMG_TOONEW;
[58f02ae]395         goto error;
[6c1c4f3]396      }
[7d27e36]397      pimg->version = ch - '0';
[5c3c61a]398   } else {
[647407d]399      img_errno = IMG_BADFORMAT;
[58f02ae]400      goto error;
[a420b49]401   }
[421b7d2]402
[4d3dfdf]403   if (!pimg->title)
404       pimg->title = getline_alloc(pimg->fh);
405   else
406       osfree(getline_alloc(pimg->fh));
[a2ad284]407   pimg->datestamp = getline_alloc(pimg->fh);
408   if (!pimg->title || !pimg->datestamp) {
[58f02ae]409      img_errno = IMG_OUTOFMEMORY;
410      error:
[a2ad284]411      osfree(pimg->title);
[984f49e]412      osfree(pimg->datestamp);
[a2ad284]413      fclose(pimg->fh);
414      osfree(pimg);
415      return NULL;
416   }
417
[58f02ae]418   pimg->start = ftell(pimg->fh);
[421b7d2]419
[a420b49]420   return pimg;
[d1b1380]421}
422
[9f3e5df]423int
[f2588ca]424img_rewind(img *pimg)
425{
[9f3e5df]426   if (!pimg->fRead) {
427      img_errno = IMG_WRITEERROR;
428      return 0;
429   }
430   if (fseek(pimg->fh, pimg->start, SEEK_SET) != 0) {
431      img_errno = IMG_READERROR;
432      return 0;
433   }
[58f02ae]434   clearerr(pimg->fh);
435   /* [version -1] already skipped heading line, or there wasn't one
436    * [version 0] not in the middle of a 'LINE' command
[76bbb7c9]437    * [version 3] not in the middle of turning a LINE into a MOVE */
[984f49e]438   pimg->pending = 0; /* FIXME: consider rewind on .plt with survey matching nothing ... */
[d69255f]439
440   img_errno = IMG_NONE;
[99cf51a]441
[5d7280f8]442   /* for version 3 we use label_buf to store the prefix for reuse */
[d69255f]443   pimg->label_len = 0;
[9f3e5df]444   return 1;
[f2588ca]445}
446
[a420b49]447img *
[fe8e80e]448img_open_write(const char *fnm, char *title_buf, bool fBinary)
[a420b49]449{
450   time_t tm;
451   img *pimg;
[d1b1380]452
[d69255f]453   fBinary = fBinary;
454
[a420b49]455   if (fDirectory(fnm)) {
456      img_errno = IMG_DIRECTORY;
457      return NULL;
458   }
[d1b1380]459
[a420b49]460   pimg = (img *)xosmalloc(ossizeof(img));
461   if (pimg == NULL) {
462      img_errno = IMG_OUTOFMEMORY;
463      return NULL;
464   }
[d1b1380]465
[fe8e80e]466   pimg->buf_len = 257;
[0ff23cb]467   pimg->label_buf = xosmalloc(pimg->buf_len);
468   if (!pimg->label_buf) {
[fe8e80e]469      osfree(pimg);
470      img_errno = IMG_OUTOFMEMORY;
471      return NULL;
472   }
473
[a420b49]474   pimg->fh = fopen(fnm, "wb");
475   if (!pimg->fh) {
476      osfree(pimg);
477      img_errno = IMG_CANTOPENOUT;
478      return NULL;
479   }
[d1b1380]480
[a420b49]481   /* Output image file header */
482   fputs("Survex 3D Image File\n", pimg->fh); /* file identifier string */
[5c3c61a]483   if (img_output_version < 2) {
[d69255f]484      pimg->version = 1;
485      fputs("Bv0.01\n", pimg->fh); /* binary file format version number */
[5c3c61a]486   } else {
[d69255f]487      pimg->version = (img_output_version > 2) ? 3 : 2;
[5c3c61a]488      fprintf(pimg->fh, "v%d\n", pimg->version); /* file format version no. */
489   }
[fe8e80e]490   fputsnl(title_buf, pimg->fh);
[a420b49]491   tm = time(NULL);
492   if (tm == (time_t)-1) {
493      fputsnl(TIMENA, pimg->fh);
494   } else {
[7d27e36]495      char date[256];
[a420b49]496      /* output current date and time in format specified */
[7d27e36]497      strftime(date, 256, TIMEFMT, localtime(&tm));
498      fputsnl(date, pimg->fh);
[a420b49]499   }
500   pimg->fRead = fFalse; /* writing to this file */
501   img_errno = IMG_NONE;
[d69255f]502
[5d7280f8]503   /* for version 3 we use label_buf to store the prefix for reuse */
[0ff23cb]504   pimg->label_buf[0] = '\0';
[d69255f]505   pimg->label_len = 0;
506
[ad9a5cd]507   /* Don't check for write errors now - let img_close() report them... */
[a420b49]508   return pimg;
[d1b1380]509}
510
[ad9a5cd]511static int
512read_coord(FILE *fh, img_point *pt)
513{
514   ASSERT(fh);
515   ASSERT(pt);
516   pt->x = get32(fh) / 100.0;
517   pt->y = get32(fh) / 100.0;
518   pt->z = get32(fh) / 100.0;
519   if (ferror(fh) || feof(fh)) {
520      img_errno = feof(fh) ? IMG_BADFORMAT : IMG_READERROR;
521      return 0;
[421b7d2]522   }
[ad9a5cd]523   return 1;
524}
525
[4d3dfdf]526static int
527skip_coord(FILE *fh)
528{
529    return (fseek(fh, 12, SEEK_CUR) == 0);
530}
531
[a420b49]532int
[23f7ea7]533img_read_item(img *pimg, img_point *p)
[a420b49]534{
535   int result;
[95c3272]536   pimg->flags = 0;
[d69255f]537
538   if (pimg->version == 3) {
539      int opt;
[76bbb7c9]540      if (pimg->pending >= 0x80) {
541         *p = pimg->mv;
542         pimg->flags = (int)(pimg->pending) & 0x3f;
543         pimg->pending = 0;
[421b7d2]544         return img_LINE;
[76bbb7c9]545      }
[d69255f]546      again3: /* label to goto if we get a prefix */
[4d3dfdf]547      pimg->label = pimg->label_buf;
[d69255f]548      opt = getc(pimg->fh);
[ad9a5cd]549      if (opt == EOF) {
550         img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
551         return img_BAD;
552      }
[d69255f]553      switch (opt >> 6) {
554       case 0:
555         if (opt == 0) {
556            if (!pimg->label_len) return img_STOP; /* end of data marker */
557            pimg->label_len = 0;
558            goto again3;
559         }
560         if (opt < 15) {
561            /* 1-14 mean trim that many levels from current prefix */
562            int c;
563            if (pimg->label_len <= 16) {
[4d3dfdf]564               /* zero prefix using "0" */
[d69255f]565               img_errno = IMG_BADFORMAT;
566               return img_BAD;
567            }
[4b156b3]568            c = pimg->label_len - 16 - 1;
[0ff23cb]569            while (pimg->label_buf[c] != '.' || --opt > 0) {
[d69255f]570               if (--c < 0) {
571                  /* zero prefix using "0" */
572                  img_errno = IMG_BADFORMAT;
573                  return img_BAD;
574               }
575            }
576            c++;
577            pimg->label_len = c;
578            goto again3;
579         }
580         if (opt == 15) {
581            result = img_MOVE;
582            break;
583         }
584         /* 16-31 mean remove (n - 15) characters from the prefix */
585         /* zero prefix using 0 */
[ad4eaf3f]586         if (pimg->label_len <= (size_t)(opt - 15)) {
[d69255f]587            img_errno = IMG_BADFORMAT;
588            return img_BAD;
589         }
[d245d71]590         pimg->label_len -= (opt - 15);
[d69255f]591         goto again3;
592       case 1: case 2: {
593         char *q;
[ad9a5cd]594         long len = getc(pimg->fh);
595         if (len == EOF) {
596            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
597            return img_BAD;
598         }
[d69255f]599         if (len == 0xfe) {
600            len += get16(pimg->fh);
[ad9a5cd]601            if (feof(pimg->fh)) {
602               img_errno = IMG_BADFORMAT;
603               return img_BAD;
604            }
605            if (ferror(pimg->fh)) {
606               img_errno = IMG_READERROR;
607               return img_BAD;
608            }
[d69255f]609         } else if (len == 0xff) {
610            len = get32(pimg->fh);
[ad9a5cd]611            if (ferror(pimg->fh)) {
612               img_errno = IMG_READERROR;
613               return img_BAD;
614            }
615            if (feof(pimg->fh) || len < 0xfe + 0xffff) {
[d69255f]616               img_errno = IMG_BADFORMAT;
617               return img_BAD;
618            }
619         }
620
621         pimg->label_len += len;
[d4d3655]622         if (!check_label_space(pimg, pimg->label_len + 1)) {
623            img_errno = IMG_OUTOFMEMORY;
624            return img_BAD;
[d69255f]625         }
[d4d3655]626         q = pimg->label_buf + pimg->label_len;
[d69255f]627         if (len && fread(q, len, 1, pimg->fh) != 1) {
[ad9a5cd]628            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]629            return img_BAD;
630         }
631         q[len] = '\0';
[76bbb7c9]632
633         result = opt & 0x40 ? img_LABEL : img_LINE;
634
635         if (pimg->survey_len) {
636            size_t l = pimg->survey_len;
[0ff23cb]637            const char *s = pimg->label_buf;
[76bbb7c9]638            if (result == img_LINE) {
639               if (strncmp(pimg->survey, s, l) != 0 ||
640                   !(s[l] == '.' || s[l] == '\0')) {
[421b7d2]641                  if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
[76bbb7c9]642                  pimg->pending = 15;
[421b7d2]643                  goto again3;
[76bbb7c9]644               }
645            } else {
646               if (strncmp(pimg->survey, s, l + 1) != 0) {
[4d3dfdf]647                  if (!skip_coord(pimg->fh)) return img_BAD;
648                  pimg->pending = 0;
[76bbb7c9]649                  goto again3;
650               }
651            }
[0ff23cb]652            pimg->label += l;
653            /* skip the dot if there */
654            if (*pimg->label) pimg->label++;
[76bbb7c9]655         }
656
657         if (result == img_LINE && pimg->pending) {
658            *p = pimg->mv;
[ad9a5cd]659            if (!read_coord(pimg->fh, &(pimg->mv))) return img_BAD;
[76bbb7c9]660            pimg->pending = opt;
661            return img_MOVE;
662         }
663         pimg->flags = (int)opt & 0x3f;
[d69255f]664         break;
665       }
666       default:
667         img_errno = IMG_BADFORMAT;
668         return img_BAD;
669      }
[ad9a5cd]670      if (!read_coord(pimg->fh, p)) return img_BAD;
[76bbb7c9]671      pimg->pending = 0;
[d69255f]672      return result;
[4d3dfdf]673   }
674
675   pimg->label = pimg->label_buf;
676
677   if (pimg->version > 0) {
[d69255f]678      static long opt_lookahead = 0;
[ad9a5cd]679      static img_point pt = { 0.0, 0.0, 0.0 };
[a420b49]680      long opt;
681      again: /* label to goto if we get a cross */
[5d7280f8]682      pimg->label[0] = '\0';
[ad9a5cd]683
[5c3c61a]684      if (pimg->version == 1) {
[c4d4649]685         if (opt_lookahead) {
686            opt = opt_lookahead;
687            opt_lookahead = 0;
688         } else {
689            opt = get32(pimg->fh);
690         }
[5c3c61a]691      } else {
[421b7d2]692         opt = getc(pimg->fh);
[5c3c61a]693      }
[ad9a5cd]694
695      if (feof(pimg->fh)) {
696         img_errno = IMG_BADFORMAT;
697         return img_BAD;
698      }
699      if (ferror(pimg->fh)) {
700         img_errno = IMG_READERROR;
701         return img_BAD;
702      }
703
[a420b49]704      switch (opt) {
[437caf3]705       case -1: case 0:
[a420b49]706         return img_STOP; /* end of data marker */
707       case 1:
[ad9a5cd]708         /* skip coordinates */
[4d3dfdf]709         if (!skip_coord(pimg->fh)) {
[ad9a5cd]710            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
711            return img_BAD;
712         }
[a420b49]713         goto again;
[23f7ea7]714       case 2: case 3: {
[fe8e80e]715         char *q;
[3a1f8da]716         int ch;
[437caf3]717         result = img_LABEL;
[3a1f8da]718         ch = getc(pimg->fh);
[d69255f]719         if (ch == EOF) {
[ad9a5cd]720            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]721            return img_BAD;
722         }
[3a1f8da]723         if (ch != '\\') ungetc(ch, pimg->fh);
[0ff23cb]724         fgets(pimg->label_buf, 257, pimg->fh);
[421b7d2]725         if (feof(pimg->fh)) {
[ad9a5cd]726            img_errno = IMG_BADFORMAT;
727            return img_BAD;
728         }
[421b7d2]729         if (ferror(pimg->fh)) {
[ad9a5cd]730            img_errno = IMG_READERROR;
731            return img_BAD;
732         }
[0ff23cb]733         q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[d69255f]734         if (*q != '\n') {
735            img_errno = IMG_BADFORMAT;
736            return img_BAD;
737         }
[9968ebf]738         /* Ignore empty labels in some .3d files (caused by a bug) */
[0ff23cb]739         if (q == pimg->label_buf) goto again;
[fe8e80e]740         *q = '\0';
[509e099]741         pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[437caf3]742         if (opt == 2) goto done;
743         break;
[23f7ea7]744       }
[95c3272]745       case 6: case 7: {
[ad9a5cd]746         long len;
[23f7ea7]747         result = img_LABEL;
[ad9a5cd]748
[509e099]749         if (opt == 7)
750            pimg->flags = getc(pimg->fh);
751         else
752            pimg->flags = img_SFLAG_UNDERGROUND; /* no flags given... */
[ad9a5cd]753
[23f7ea7]754         len = get32(pimg->fh);
[ad9a5cd]755
756         if (feof(pimg->fh)) {
757            img_errno = IMG_BADFORMAT;
758            return img_BAD;
759         }
760         if (ferror(pimg->fh)) {
761            img_errno = IMG_READERROR;
762            return img_BAD;
763         }
764
[9968ebf]765         /* Ignore empty labels in some .3d files (caused by a bug) */
766         if (len == 0) goto again;
[d4d3655]767         if (!check_label_space(pimg, len + 1)) {
768            img_errno = IMG_OUTOFMEMORY;
769            return img_BAD;
[23f7ea7]770         }
[0ff23cb]771         if (fread(pimg->label_buf, len, 1, pimg->fh) != 1) {
[ad9a5cd]772            img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]773            return img_BAD;
774         }
[23f7ea7]775         break;
776       }
[a420b49]777       case 4:
778         result = img_MOVE;
779         break;
780       case 5:
781         result = img_LINE;
782         break;
783       default:
[95c3272]784         switch ((int)opt & 0xc0) {
785          case 0x80:
786            pimg->flags = (int)opt & 0x3f;
787            result = img_LINE;
788            break;
789          case 0x40: {
790            char *q;
791            pimg->flags = (int)opt & 0x3f;
792            result = img_LABEL;
[0ff23cb]793            if (!fgets(pimg->label_buf, 257, pimg->fh)) {
[ad9a5cd]794               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[d69255f]795               return img_BAD;
796            }
[0ff23cb]797            q = pimg->label_buf + strlen(pimg->label_buf) - 1;
[9968ebf]798            /* Ignore empty-labels in some .3d files (caused by a bug) */
[0ff23cb]799            if (q == pimg->label_buf) goto again;
[d69255f]800            if (*q != '\n') {
801               img_errno = IMG_BADFORMAT;
802               return img_BAD;
803            }
[95c3272]804            *q = '\0';
805            break;
806          }
807          case 0xc0:
808            /* use this for an extra leg or station flag if we need it */
809          default:
[d69255f]810            img_errno = IMG_BADFORMAT;
[95c3272]811            return img_BAD;
812         }
[437caf3]813         break;
[a420b49]814      }
[ad9a5cd]815
816      if (!read_coord(pimg->fh, &pt)) return img_BAD;
[76bbb7c9]817
[ed0f5b6]818      if (result == img_LABEL && pimg->survey_len) {
819         if (strncmp(pimg->label_buf, pimg->survey, pimg->survey_len + 1) != 0)
[0ff23cb]820            goto again;
821         pimg->label += pimg->survey_len + 1;
822      }
[76bbb7c9]823
[a420b49]824      done:
[ad9a5cd]825      *p = pt;
[c4d4649]826
827      if (result == img_MOVE && pimg->version == 1) {
[d69255f]828         /* peek at next code and see if it's an old-style label */
[23f7ea7]829         opt_lookahead = get32(pimg->fh);
[ad9a5cd]830
831         if (feof(pimg->fh)) {
832            img_errno = IMG_BADFORMAT;
833            return img_BAD;
834         }
835         if (ferror(pimg->fh)) {
836            img_errno = IMG_READERROR;
837            return img_BAD;
838         }
839
[d69255f]840         if (opt_lookahead == 2) return img_read_item(pimg, p);
[c4d4649]841      }
[23f7ea7]842
[a420b49]843      return result;
[0da6e60]844   } else if (pimg->version == 0) {
[a420b49]845      ascii_again:
[5d7280f8]846      pimg->label[0] = '\0';
[a420b49]847      if (feof(pimg->fh)) return img_STOP;
[76bbb7c9]848      if (pimg->pending) {
849         pimg->pending = 0;
[a420b49]850         result = img_LINE;
851      } else {
[7d27e36]852         char cmd[7];
[a420b49]853         /* Stop if nothing found */
[7d27e36]854         if (fscanf(pimg->fh, "%6s", cmd) < 1) return img_STOP;
855         if (strcmp(cmd, "move") == 0)
[a420b49]856            result = img_MOVE;
[7d27e36]857         else if (strcmp(cmd, "draw") == 0)
[a420b49]858            result = img_LINE;
[7d27e36]859         else if (strcmp(cmd, "line") == 0) {
[bd1913f]860            /* set flag to indicate to process second triplet as LINE */
[76bbb7c9]861            pimg->pending = 1;
[a420b49]862            result = img_MOVE;
[7d27e36]863         } else if (strcmp(cmd, "cross") == 0) {
[d69255f]864            if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]865               img_errno = feof(pimg->fh) ? IMG_BADFORMAT : IMG_READERROR;
[0ed0e16]866               return img_BAD;
[d69255f]867            }
[a420b49]868            goto ascii_again;
[7d27e36]869         } else if (strcmp(cmd, "name") == 0) {
[0da6e60]870            size_t off = 0;
[58f02ae]871            int ch = getc(pimg->fh);
872            if (ch == ' ') ch = getc(pimg->fh);
873            while (ch != ' ') {
874               if (ch == '\n' || ch == EOF) {
875                  img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
[ad9a5cd]876                  return img_BAD;
877               }
[58f02ae]878               if (off == pimg->buf_len) {
[d4d3655]879                  if (!check_label_space(pimg, pimg->buf_len * 2)) {
[9b56f4d]880                     img_errno = IMG_OUTOFMEMORY;
881                     return img_BAD;
882                  }
[0da6e60]883               }
[58f02ae]884               pimg->label_buf[off++] = ch;
885               ch = getc(pimg->fh);
[ad9a5cd]886            }
[58f02ae]887            pimg->label_buf[off] = '\0';
888
889            pimg->label = pimg->label_buf;
890            if (pimg->label[0] == '\\') pimg->label++;
[0da6e60]891
[a420b49]892            result = img_LABEL;
[d69255f]893         } else {
894            img_errno = IMG_BADFORMAT;
[a420b49]895            return img_BAD; /* unknown keyword */
[d69255f]896         }
[a420b49]897      }
[d1b1380]898
[d69255f]899      if (fscanf(pimg->fh, "%lf%lf%lf", &p->x, &p->y, &p->z) < 3) {
[ad9a5cd]900         img_errno = ferror(pimg->fh) ? IMG_READERROR : IMG_BADFORMAT;
[fe8e80e]901         return img_BAD;
[d69255f]902      }
903
[58f02ae]904      if (result == img_LABEL && pimg->survey_len) {
905         if (strncmp(pimg->label, pimg->survey, pimg->survey_len + 1) != 0)
[0ff23cb]906            goto ascii_again;
907         pimg->label += pimg->survey_len + 1;
908      }
[76bbb7c9]909
[a420b49]910      return result;
[ad4eaf3f]911   } else if (pimg->version == -1) {
[0da6e60]912      /* version -1: .pos file */
[58f02ae]913      size_t off;
[5eea574]914      pimg->flags = img_SFLAG_UNDERGROUND; /* default flags */
[58f02ae]915      againpos:
916      off = 0;
[0da6e60]917      while (fscanf(pimg->fh, "(%lf,%lf,%lf ) ", &p->x, &p->y, &p->z) != 3) {
918         int ch;
919         if (ferror(pimg->fh)) {
920            img_errno = IMG_READERROR;
921            return img_BAD;
922         }
923         if (feof(pimg->fh)) return img_STOP;
924         if (pimg->pending) {
925            img_errno = IMG_BADFORMAT;
926            return img_BAD;
927         }
928         pimg->pending = 1;
929         /* ignore rest of line */
930         do {
931            ch = getc(pimg->fh);
932         } while (ch != '\n' && ch != '\r' && ch != EOF);
933      }
934
935      pimg->label_buf[0] = '\0';
936      while (!feof(pimg->fh)) {
[9b56f4d]937         char *b;
[0da6e60]938         if (!fgets(pimg->label_buf + off, pimg->buf_len - off, pimg->fh)) {
939            img_errno = IMG_READERROR;
940            return img_BAD;
941         }
942
943         off += strlen(pimg->label_buf + off);
944         if (off && pimg->label_buf[off - 1] == '\n') {
945            pimg->label_buf[off - 1] = '\0';
946            break;
947         }
[d4d3655]948         if (!check_label_space(pimg, pimg->buf_len * 2)) {
[9b56f4d]949            img_errno = IMG_OUTOFMEMORY;
950            return img_BAD;
951         }
[0da6e60]952      }
953
[58f02ae]954      pimg->label = pimg->label_buf;
955
[421b7d2]956      if (pimg->label[0] == '\\') pimg->label++;
[58f02ae]957
958      if (pimg->survey_len) {
959         size_t l = pimg->survey_len + 1;
960         if (strncmp(pimg->survey, pimg->label, l) != 0) goto againpos;
961         pimg->label += l;
962      }
963
[0da6e60]964      return img_LABEL;
[ad4eaf3f]965   } else {
966      /* version -2: Compass .plt file */
967      if (pimg->pending) {
[984f49e]968         /* pending MOVE or LINE or STOP */
969         int r = pimg->pending - 4;
[ad4eaf3f]970         pimg->pending = 0;
971         pimg->flags = 0;
[f710a3f]972         pimg->label[pimg->label_len] = '\0';
[ad4eaf3f]973         return r;
974      }
975
976      while (1) {
977         char *line = getline_alloc(pimg->fh);
978         char *q;
979         size_t len = 0;
980
981         switch (line[0]) {
982            case 'M': case 'D':
983               /* Move or Draw */
984               if (sscanf(line + 1, "%lf %lf %lf", &p->x, &p->y, &p->z) != 3) {
985                  osfree(line);
986                  if (ferror(pimg->fh)) {
987                     img_errno = IMG_READERROR;
988                  } else {
989                     img_errno = IMG_BADFORMAT;
990                  }
991                  return img_BAD;
992               }
993               q = strchr(line, 'S');
994               if (!q) {
995                  osfree(line);
[5757725]996                  img_errno = IMG_BADFORMAT;
[ad4eaf3f]997                  return img_BAD;
998               }
999               ++q;
1000               len = 0;
1001               while (q[len] > ' ') ++len;
1002               q[len] = '\0';
[f710a3f]1003               len += 2; /* '.' and '\0' */
[d4d3655]1004               if (!check_label_space(pimg, pimg->label_len + len)) {
1005                  img_errno = IMG_OUTOFMEMORY;
1006                  return img_BAD;
[ad4eaf3f]1007               }
1008               pimg->label = pimg->label_buf;
[f710a3f]1009               pimg->label[pimg->label_len] = '.';
1010               memcpy(pimg->label + pimg->label_len + 1, q, len - 1);
[984f49e]1011               pimg->pending = (line[0] == 'M' ? img_MOVE : img_LINE) + 4;
[ad4eaf3f]1012               osfree(line);
1013               pimg->flags = img_SFLAG_UNDERGROUND; /* default flags */
1014               return img_LABEL;
1015            case 'X': case 'F': case 'S':
1016               /* bounding boX (marks end of survey), Feature survey, or
1017                * new Section - skip to next survey */
1018               do {
[984f49e]1019                  do {
[ad4eaf3f]1020                     osfree(line);
[984f49e]1021                     line = getline_alloc(pimg->fh);
1022                     if (!line) {
1023                        img_errno = IMG_OUTOFMEMORY;
1024                        return img_BAD;
1025                     }
1026                     if (line[0] == '\x1a') {
1027                        osfree(line);
1028                        return img_STOP;
1029                     }
1030                     if (feof(pimg->fh)) {
1031                        osfree(line);
1032                        img_errno = IMG_BADFORMAT;
1033                        return img_BAD;
1034                     }
1035                  } while (line[0] != 'N');
1036
1037                  len = 1;
1038                  while (line[len] > 32) ++len;
1039               } while (pimg->survey && (pimg->survey_len != len - 1 ||
1040                        memcmp(line + 1, pimg->survey, pimg->survey_len) != 0));
[f710a3f]1041
[d4d3655]1042               if (!check_label_space(pimg, len)) {
1043                  img_errno = IMG_OUTOFMEMORY;
1044                  return img_BAD;
[f710a3f]1045               }
1046               --len;
1047               pimg->label_len = len;
1048               pimg->label = pimg->label_buf;
1049               memcpy(pimg->label, line + 1, len);
1050               pimg->label[len] = '\0';
1051
[ad4eaf3f]1052               osfree(line);
1053               break;
1054            default:
1055               osfree(line);
1056               img_errno = IMG_BADFORMAT;
1057               return img_BAD;
1058         }
1059      }
[a420b49]1060   }
[d1b1380]1061}
1062
[ad9a5cd]1063static int
[d69255f]1064write_v3label(img *pimg, int opt, const char *s)
1065{
1066   size_t len, n, dot;
1067
1068   /* find length of common prefix */
1069   dot = 0;
[0ff23cb]1070   for (len = 0; s[len] == pimg->label_buf[len] && s[len] != '\0'; len++) {
[d69255f]1071      if (s[len] == '.') dot = len + 1;
1072   }
1073
1074   ASSERT(len <= pimg->label_len);
1075   n = pimg->label_len - len;
1076   if (len == 0) {
1077      if (pimg->label_len) putc(0, pimg->fh);
1078   } else if (n <= 16) {
1079      if (n) putc(n + 15, pimg->fh);
1080   } else if (dot == 0) {
1081      if (pimg->label_len) putc(0, pimg->fh);
[99cf51a]1082      len = 0;
[d69255f]1083   } else {
[0ff23cb]1084      const char *p = pimg->label_buf + dot;
[d69255f]1085      n = 1;
1086      for (len = pimg->label_len - dot - 17; len; len--) {
1087         if (*p++ == '.') n++;
1088      }
1089      if (n <= 14) {
1090         putc(n, pimg->fh);
1091         len = dot;
1092      } else {
1093         if (pimg->label_len) putc(0, pimg->fh);
1094         len = 0;
1095      }
1096   }
1097
1098   n = strlen(s + len);
1099   putc(opt, pimg->fh);
1100   if (n < 0xfe) {
1101      putc(n, pimg->fh);
1102   } else if (n < 0xffff + 0xfe) {
1103      putc(0xfe, pimg->fh);
1104      put16(n - 0xfe, pimg->fh);
1105   } else {
1106      putc(0xff, pimg->fh);
1107      put32(n, pimg->fh);
1108   }
1109   fwrite(s + len, n, 1, pimg->fh);
1110
1111   n += len;
1112   pimg->label_len = n;
[d4d3655]1113   if (!check_label_space(pimg, n + 1))
1114      return 0; /* FIXME: distinguish out of memory... */
[0ff23cb]1115   memcpy(pimg->label_buf + len, s + len, n - len + 1);
[ad9a5cd]1116
1117   return !ferror(pimg->fh);
[d69255f]1118}
1119
[a420b49]1120void
[95c3272]1121img_write_item(img *pimg, int code, int flags, const char *s,
[a9f5117]1122               double x, double y, double z)
[a420b49]1123{
[647407d]1124   if (!pimg) return;
[d69255f]1125   if (pimg->version == 3) {
1126      int opt = 0;
1127      switch (code) {
1128       case img_LABEL:
1129         write_v3label(pimg, 0x40 | flags, s);
1130         opt = 0;
1131         break;
1132       case img_MOVE:
1133         opt = 15;
1134         break;
1135       case img_LINE:
1136         write_v3label(pimg, 0x80 | flags, s ? s : "");
1137         opt = 0;
1138         break;
1139       default: /* ignore for now */
1140         return;
1141      }
1142      if (opt) putc(opt, pimg->fh);
1143      /* Output in cm */
[dd1d6369]1144      put32((INT32_T)my_round(x * 100.0), pimg->fh);
1145      put32((INT32_T)my_round(y * 100.0), pimg->fh);
1146      put32((INT32_T)my_round(z * 100.0), pimg->fh);
[d69255f]1147   } else {
[23f7ea7]1148      size_t len;
[badeec8]1149      INT32_T opt = 0;
[d69255f]1150      ASSERT(pimg->version > 0);
[a420b49]1151      switch (code) {
[437caf3]1152       case img_LABEL:
1153         if (pimg->version == 1) {
1154            /* put a move before each label */
[95c3272]1155            img_write_item(pimg, img_MOVE, 0, NULL, x, y, z);
[437caf3]1156            put32(2, pimg->fh);
[0ed0e16]1157            fputsnl(s, pimg->fh);
[437caf3]1158            return;
1159         }
[23f7ea7]1160         len = strlen(s);
[af56069]1161         if (len > 255 || strchr(s, '\n')) {
[23f7ea7]1162            /* long label - not in early incarnations of v2 format, but few
1163             * 3d files will need these, so better not to force incompatibility
1164             * with a new version I think... */
[95c3272]1165            putc(7, pimg->fh);
1166            putc(flags, pimg->fh);
[23f7ea7]1167            put32(len, pimg->fh);
1168            fputs(s, pimg->fh);
1169         } else {
[95c3272]1170            putc(0x40 | (flags & 0x3f), pimg->fh);
[23f7ea7]1171            fputsnl(s, pimg->fh);
1172         }
[437caf3]1173         opt = 0;
[23f7ea7]1174         break;
[a420b49]1175       case img_MOVE:
1176         opt = 4;
1177         break;
1178       case img_LINE:
[421b7d2]1179         if (pimg->version > 1) {
[d69255f]1180            opt = 0x80 | (flags & 0x3f);
[437caf3]1181            break;
[421b7d2]1182         }
[437caf3]1183         opt = 5;
[a420b49]1184         break;
[437caf3]1185       default: /* ignore for now */
1186         return;
[a420b49]1187      }
[437caf3]1188      if (pimg->version == 1) {
1189         put32(opt, pimg->fh);
1190      } else {
1191         if (opt) putc(opt, pimg->fh);
[a420b49]1192      }
[d69255f]1193      /* Output in cm */
[dd1d6369]1194      put32((INT32_T)my_round(x * 100.0), pimg->fh);
1195      put32((INT32_T)my_round(y * 100.0), pimg->fh);
1196      put32((INT32_T)my_round(z * 100.0), pimg->fh);
[a420b49]1197   }
[d1b1380]1198}
1199
[ad9a5cd]1200int
[a420b49]1201img_close(img *pimg)
1202{
[ad9a5cd]1203   int result = 1;
[dbb4e19]1204   if (pimg) {
1205      if (pimg->fh) {
[76bbb7c9]1206         if (pimg->fRead) {
1207            osfree(pimg->survey);
[a2ad284]1208            osfree(pimg->title);
1209            osfree(pimg->datestamp);
[76bbb7c9]1210         } else {
1211            /* write end of data marker */
[d69255f]1212            switch (pimg->version) {
1213             case 1:
[5c3c61a]1214               put32((INT32_T)-1, pimg->fh);
[d69255f]1215               break;
1216             case 2:
1217               putc(0, pimg->fh);
1218               break;
1219             case 3:
1220               if (pimg->label_len) putc(0, pimg->fh);
[437caf3]1221               putc(0, pimg->fh);
[d69255f]1222               break;
[5c3c61a]1223            }
1224         }
[ad9a5cd]1225         if (ferror(pimg->fh)) result = 0;
1226         if (fclose(pimg->fh)) result = 0;
1227         img_errno = pimg->fRead ? IMG_READERROR : IMG_WRITEERROR;
[dbb4e19]1228      }
[0ff23cb]1229      osfree(pimg->label_buf);
[dbb4e19]1230      osfree(pimg);
[a420b49]1231   }
[ad9a5cd]1232   return result;
[d1b1380]1233}
Note: See TracBrowser for help on using the repository browser.