GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/formatText.c Lines: 1 164 0.6 %
Date: 2017-05-26 Branches: 0 134 0.0 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "nrrd.h"
25
#include "privateNrrd.h"
26
27
static int
28
_nrrdFormatText_available(void) {
29
30
4
  return AIR_TRUE;
31
}
32
33
static int
34
_nrrdFormatText_nameLooksLike(const char *fname) {
35
36
  return (airEndsWith(fname, NRRD_EXT_TEXT)
37
          || airEndsWith(fname, ".text")
38
          || airEndsWith(fname, ".ascii"));
39
}
40
41
static int
42
_nrrdFormatText_fitsInto(const Nrrd *nrrd, const NrrdEncoding *encoding,
43
                         int useBiff) {
44
  static const char me[]="_nrrdFormatText_fitsInto";
45
46
  AIR_UNUSED(encoding);
47
  /* encoding ignored- always ascii */
48
  if (!(1  == nrrd->dim || 2 == nrrd->dim)) {
49
    biffMaybeAddf(useBiff, NRRD, "%s: dimension is %d, not 1 or 2",
50
                  me, nrrd->dim);
51
    return AIR_FALSE;
52
  }
53
  if (nrrdTypeBlock == nrrd->type) {
54
    biffMaybeAddf(useBiff, NRRD, "%s: can't save blocks to plain text", me);
55
    return AIR_FALSE;
56
  }
57
  /* NOTE: type of array not guaranteed to survive */
58
  return AIR_TRUE;
59
}
60
61
static int
62
_nrrdFormatText_contentStartsLike(NrrdIoState *nio) {
63
  float oneFloat;
64
65
  return (NRRD_COMMENT_CHAR == nio->line[0]
66
          || airParseStrF(&oneFloat, nio->line, _nrrdTextSep, 1));
67
}
68
69
static int
70
_nrrdFormatText_read(FILE *file, Nrrd *nrrd, NrrdIoState *nio) {
71
  static const char me[]="_nrrdFormatText_read";
72
  const char *fs;
73
  char *errS;
74
  unsigned int plen, llen;
75
  size_t line, sx, sy, size[NRRD_DIM_MAX];
76
  int nret, fidx, settwo = 0, gotOnePerAxis = AIR_FALSE;
77
  /* fl: first line, al: all lines */
78
  airArray *flArr, *alArr;
79
  float *fl, *al, oneFloat;
80
  airPtrPtrUnion appu;
81
82
  if (!_nrrdFormatText_contentStartsLike(nio)) {
83
    biffAddf(NRRD, "%s: this doesn't look like a %s file", me,
84
             nrrdFormatText->name);
85
    return 1;
86
  }
87
88
  /* this goofiness is just to leave the nrrd as we found it
89
     (specifically, nrrd->dim) when we hit an error */
90
#define UNSETTWO if (settwo) nrrd->dim = settwo
91
92
  /* we only get here with the first line already in nio->line */
93
  line = 1;
94
  llen = AIR_CAST(unsigned int, strlen(nio->line));
95
96
  if (0 == nrrd->dim) {
97
    settwo = nrrd->dim;
98
    nrrd->dim = 2;
99
  }
100
  /* first, we get through comments */
101
  while (NRRD_COMMENT_CHAR == nio->line[0]) {
102
    nio->pos = 1;
103
    nio->pos += AIR_CAST(int, strspn(nio->line + nio->pos, _nrrdFieldSep));
104
    fidx = _nrrdReadNrrdParseField(nio, AIR_FALSE);
105
    /* could we parse anything? */
106
    if (!fidx) {
107
      /* being unable to parse a comment as a nrrd field is not
108
         any kind of error */
109
      goto plain;
110
    }
111
    if (nrrdField_comment == fidx) {
112
      fidx = 0;
113
      goto plain;
114
    }
115
    fs = airEnumStr(nrrdField, fidx);
116
    if (!_nrrdFieldValidInText[fidx]) {
117
      if (1 <= nrrdStateVerboseIO) {
118
        fprintf(stderr, "(%s: field \"%s\" not allowed in plain text "
119
                "--> plain comment)\n", me, fs);
120
      }
121
      fidx = 0;
122
      goto plain;
123
    }
124
    /* when reading plain text, we simply ignore repetitions of a field */
125
    if ((nrrdField_keyvalue == fidx || !nio->seen[fidx])
126
        && nrrdFieldInfoParse[fidx](file, nrrd, nio, AIR_TRUE)) {
127
      errS = biffGetDone(NRRD);
128
      if (1 <= nrrdStateVerboseIO) {
129
        fprintf(stderr, "%s: %s", me, errS);
130
        fprintf(stderr, "(%s: malformed field \"%s\" --> plain comment)\n",
131
                me, fs);
132
      }
133
      if (nrrdField_dimension == fidx) {
134
        /* "# dimension: 0" lead nrrd->dim being set to 0 */
135
        nrrd->dim = 2;
136
      }
137
      free(errS);
138
      fidx = 0;
139
      goto plain;
140
    }
141
    if (nrrdField_dimension == fidx) {
142
      if (!(1 == nrrd->dim || 2 == nrrd->dim)) {
143
        if (1 <= nrrdStateVerboseIO) {
144
          fprintf(stderr, "(%s: plain text dimension can only be 1 or 2; "
145
                  "resetting to 2)\n", me);
146
        }
147
        nrrd->dim = 2;
148
      }
149
      if (1 == nrrd->dim && gotOnePerAxis) {
150
        fprintf(stderr, "(%s: already parsed per-axis field, can't reset "
151
                "dimension to 1; resetting to 2)\n", me);
152
        nrrd->dim = 2;
153
      }
154
    }
155
    if (_nrrdFieldOnePerAxis[fidx]) {
156
      gotOnePerAxis = AIR_TRUE;
157
    }
158
    nio->seen[fidx] = AIR_TRUE;
159
  plain:
160
    if (!fidx) {
161
      if (nrrdCommentAdd(nrrd, nio->line + 1)) {
162
        biffAddf(NRRD, "%s: couldn't add comment", me);
163
        UNSETTWO; return 1;
164
      }
165
    }
166
    if (_nrrdOneLine(&llen, nio, file)) {
167
      biffAddf(NRRD, "%s: error getting a line", me);
168
      UNSETTWO; return 1;
169
    }
170
    if (!llen) {
171
      biffAddf(NRRD, "%s: hit EOF before any numbers parsed", me);
172
      UNSETTWO; return 1;
173
    }
174
    line++;
175
  }
176
177
  /* we supposedly have a line of numbers, see how many there are */
178
  if (!airParseStrF(&oneFloat, nio->line, _nrrdTextSep, 1)) {
179
    char stmp[AIR_STRLEN_SMALL];
180
    biffAddf(NRRD, "%s: couldn't parse a single number on line %s", me,
181
             airSprintSize_t(stmp, line));
182
    UNSETTWO; return 1;
183
  }
184
  appu.f = &fl;
185
  flArr = airArrayNew(appu.v, NULL, sizeof(float), _NRRD_TEXT_INCR);
186
  if (!flArr) {
187
    biffAddf(NRRD, "%s: couldn't create array for first line values", me);
188
    UNSETTWO; return 1;
189
  }
190
  for (sx=1; 1; sx++) {
191
    /* there is obviously a limit to the number of numbers that can
192
       be parsed from a single finite line of input text */
193
    airArrayLenSet(flArr, AIR_CAST(unsigned int, sx));
194
    if (!flArr->data) {
195
      char stmp[AIR_STRLEN_SMALL];
196
      biffAddf(NRRD, "%s: couldn't alloc space for %s values", me,
197
               airSprintSize_t(stmp, sx));
198
      UNSETTWO; return 1;
199
    }
200
    if (sx > airParseStrF(fl, nio->line, _nrrdTextSep, AIR_CAST(unsigned int, sx))) {
201
      /* We asked for sx ints and got less.  We know that we successfully
202
         got one value, so we did succeed in parsing sx-1 values */
203
      sx--;
204
      break;
205
    }
206
  }
207
  flArr = airArrayNuke(flArr);
208
  if (1 == nrrd->dim && 1 != sx) {
209
    char stmp[AIR_STRLEN_SMALL];
210
    biffAddf(NRRD, "%s: wanted 1-D nrrd, but got %s values on 1st line", me,
211
             airSprintSize_t(stmp, sx));
212
    UNSETTWO; return 1;
213
  }
214
  /* else sx == 1 when nrrd->dim == 1 */
215
216
  /* now see how many more lines there are */
217
  appu.f = &al;
218
  alArr = airArrayNew(appu.v, NULL, sx*sizeof(float), _NRRD_TEXT_INCR);
219
  if (!alArr) {
220
    biffAddf(NRRD, "%s: couldn't create data buffer", me);
221
    UNSETTWO; return 1;
222
  }
223
  sy = 0;
224
  while (llen) {
225
    airArrayLenIncr(alArr, 1);
226
    if (!alArr->data) {
227
      char stmp[AIR_STRLEN_SMALL];
228
      biffAddf(NRRD, "%s: couldn't create scanline of %s values", me,
229
               airSprintSize_t(stmp, sx));
230
      UNSETTWO; return 1;
231
    }
232
    plen = airParseStrF(al + sy*sx, nio->line, _nrrdTextSep, AIR_CAST(unsigned int, sx));
233
    if (sx > plen) {
234
      char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL];
235
      biffAddf(NRRD, "%s: could only parse %d values (not %s) on line %s",
236
               me, plen, airSprintSize_t(stmp1, sx),
237
               airSprintSize_t(stmp2, line));
238
      UNSETTWO; return 1;
239
    }
240
    sy++;
241
    line++;
242
    if (_nrrdOneLine(&llen, nio, file)) {
243
      biffAddf(NRRD, "%s: error getting a line", me);
244
      UNSETTWO; return 1;
245
    }
246
  }
247
  /*
248
  fprintf(stderr, "%s: nrrd->dim = %d, sx = %d; sy = %d\n",
249
          me, nrrd->dim, sx, sy);
250
  */
251
252
  if (!( 1 == nrrd->dim || 2 == nrrd->dim )) {
253
    fprintf(stderr, "%s: PANIC about to save, but dim = %d\n", me, nrrd->dim);
254
    exit(1);
255
  }
256
  if (1 == nrrd->dim) {
257
    size[0] = sy;
258
  } else {
259
    size[0] = sx;
260
    size[1] = sy;
261
  }
262
263
  if (nio->oldData
264
      && nio->oldDataSize == (size_t)(nrrdTypeSize[nrrdTypeFloat]*sx*sy)) {
265
    nret = nrrdWrap_nva(nrrd, nio->oldData, nrrdTypeFloat, nrrd->dim, size);
266
  } else {
267
    nret = nrrdMaybeAlloc_nva(nrrd, nrrdTypeFloat, nrrd->dim, size);
268
  }
269
  if (nret) {
270
    biffAddf(NRRD, "%s: couldn't create nrrd for plain text data", me);
271
    UNSETTWO; return 1;
272
  }
273
  memcpy(nrrd->data, al, sx*sy*sizeof(float));
274
275
  alArr = airArrayNuke(alArr);
276
  return 0;
277
}
278
279
static int
280
_nrrdFormatText_write(FILE *file, const Nrrd *nrrd, NrrdIoState *nio) {
281
  char cmt[AIR_STRLEN_SMALL], buff[AIR_STRLEN_SMALL];
282
  size_t I;
283
  int i, x, y, sx, sy;
284
  void *data;
285
  float val;
286
287
  sprintf(cmt, "%c ", NRRD_COMMENT_CHAR);
288
  if (!nio->bareText) {
289
    if (1 == nrrd->dim) {
290
      _nrrdFprintFieldInfo(file, cmt, nrrd, nio, nrrdField_dimension,
291
                           AIR_FALSE);
292
    }
293
    for (i=1; i<=NRRD_FIELD_MAX; i++) {
294
      if (_nrrdFieldValidInText[i]
295
          && nrrdField_dimension != i  /* dimension is handled above */
296
          && _nrrdFieldInteresting(nrrd, nio, i)) {
297
        _nrrdFprintFieldInfo(file, cmt, nrrd, nio, i, AIR_FALSE);
298
      }
299
    }
300
    if (nrrdKeyValueSize(nrrd)) {
301
      unsigned int kvi;
302
      for (kvi=0; kvi<nrrd->kvpArr->len; kvi++) {
303
        _nrrdKeyValueWrite(file, NULL, "#",
304
                           nrrd->kvp[0 + 2*kvi],
305
                           nrrd->kvp[1 + 2*kvi]);
306
      }
307
    }
308
  }
309
310
  if (1 == nrrd->dim) {
311
    sx = 1;
312
    sy = AIR_CAST(int, nrrd->axis[0].size);
313
  }
314
  else {
315
    sx = AIR_CAST(int, nrrd->axis[0].size);
316
    sy = AIR_CAST(int, nrrd->axis[1].size);
317
  }
318
  data = nrrd->data;
319
  I = 0;
320
  for (y=0; y<sy; y++) {
321
    for (x=0; x<sx; x++) {
322
      val = nrrdFLookup[nrrd->type](data, I);
323
      nrrdSprint[nrrdTypeFloat](buff, &val);
324
      if (x) fprintf(file, " ");
325
      fprintf(file, "%s", buff);
326
      I++;
327
    }
328
    fprintf(file, "\n");
329
  }
330
331
  return 0;
332
}
333
334
const NrrdFormat
335
_nrrdFormatText = {
336
  "text",
337
  AIR_FALSE,  /* isImage */
338
  AIR_TRUE,   /* readable */
339
  AIR_FALSE,  /* usesDIO */
340
  _nrrdFormatText_available,
341
  _nrrdFormatText_nameLooksLike,
342
  _nrrdFormatText_fitsInto,
343
  _nrrdFormatText_contentStartsLike,
344
  _nrrdFormatText_read,
345
  _nrrdFormatText_write
346
};
347
348
const NrrdFormat *const
349
nrrdFormatText = &_nrrdFormatText;