Example #1
0
int
main(int argc, char *argv[]) {
    int aret;
    char *me;

    AIR_UNUSED(argc);
    me = argv[0];
    aret = airSanity();
    if (airInsane_not == aret) {
        char stmp[AIR_STRLEN_SMALL];
        fprintf(stderr, "%s: air sanity check passed.\n", me);
        fprintf(stderr, "\n");
        fprintf(stderr, "airMyEndian() == %d\n", airMyEndian());
        fprintf(stderr, "AIR_QNANHIBIT == %d\n", AIR_QNANHIBIT);
        fprintf(stderr, "AIR_DIO == %d\n", AIR_DIO);
        fprintf(stderr, "sizeof(size_t) = %s\n",
                airSprintSize_t(stmp, sizeof(size_t)));
        fprintf(stderr, "sizeof(void*) = %s\n",
                airSprintSize_t(stmp, sizeof(void*)));
        return 0;
    }
    /* else */
    fprintf(stderr, "%s: air sanity check FAILED:\n%s\n",
            me, airInsaneErr(aret));
    return 1;
}
Example #2
0
unsigned int
nrrdCRC32(const Nrrd *nin, int endian) {
  size_t nn;

  /* NULL nrrd or data */
  if (!nin
      || !(nin->data)
      || !(nn = nrrdElementSize(nin)*nrrdElementNumber(nin))
      || airEnumValCheck(airEndian, endian)) {
    return 0;
  }

  return airCRC32(AIR_CAST(const unsigned char *, nin->data),
                  nn, nrrdElementSize(nin),
                  endian == airMyEndian() ? AIR_FALSE : AIR_TRUE);
}
Example #3
0
int
unrrdu_cksumMain(int argc, const char **argv, const char *me,
                 hestParm *hparm) {
  hestOpt *opt = NULL;
  char *err, **inS;
  airArray *mop;
  int pret, endian, printend;
  unsigned int ni, ninLen;

  mop = airMopNew();
  hestOptAdd(&opt, "en,endian", "end", airTypeEnum, 1, 1, &endian,
             airEnumStr(airEndian, airMyEndian()),
             "Endianness in which to compute CRC; \"little\" for Intel and "
             "friends; \"big\" for everyone else. "
             "Defaults to endianness of this machine",
             NULL, airEndian);
  hestOptAdd(&opt, "pen,printendian", "bool", airTypeBool, 1, 1, &printend,
             "false",
             "whether or not to indicate after the CRC value the endianness "
             "with which the CRC was computed; doing so clarifies "
             "that the CRC result depends on endianness and may remove "
             "confusion in comparing results on platforms of different "
             "endianness");
  hestOptAdd(&opt, NULL, "nin1", airTypeString, 1, -1, &inS, NULL,
             "input nrrd(s)", &ninLen);
  airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways);

  USAGE(_unrrdu_cksumInfoL);
  PARSE();
  airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways);

  for (ni=0; ni<ninLen; ni++) {
    if (unrrdu_cksumDoit(me, inS[ni], endian, printend, stdout)) {
      airMopAdd(mop, err = biffGetDone(me), airFree, airMopAlways);
      fprintf(stderr, "%s: trouble with \"%s\":\n%s",
              me, inS[ni], err);
      /* continue working on the remaining files */
    }
  }

  airMopOkay(mop);
  return 0;
}
Example #4
0
int
_nrrdFormatVTK_read(FILE *file, Nrrd *nrrd, NrrdIoState *nio) {
  static const char me[]="_nrrdReadVTK";
  char *three[3];
  int sx, sy, sz, ret, N;
  double xm=0.0, ym=0.0, zm=0.0, xs=1.0, ys=1.0, zs=1.0;
  airArray *mop;
  unsigned int llen;

  if (!_nrrdFormatVTK_contentStartsLike(nio)) {
    biffAddf(NRRD, "%s: this doesn't look like a %s file", me,
             nrrdFormatVTK->name);
    return 1;
  }

#define GETLINE(what)                                        \
  do {                                                       \
    ret = _nrrdOneLine(&llen, nio, file);                    \
  } while (!ret && (1 == llen));                             \
  if (ret || !llen) {                                        \
    biffAddf(NRRD, "%s: couldn't get " #what " line", me);   \
    return 1;                                                \
  }

  /* read in content */
  GETLINE(content);
  if (strcmp(NRRD_UNKNOWN, nio->line)) {
    if (!(nrrd->content = airStrdup(nio->line))) {
      biffAddf(NRRD, "%s: couldn't read or copy content string", me);
      return 1;
    }
  }
  GETLINE(encoding); airToUpper(nio->line);
  if (!strcmp("ASCII", nio->line)) {
    nio->encoding = nrrdEncodingAscii;
  } else if (!strcmp("BINARY", nio->line)) {
    nio->encoding = nrrdEncodingRaw;
  } else {
    biffAddf(NRRD, "%s: encoding \"%s\" wasn't \"ASCII\" or \"BINARY\"",
             me, nio->line);
    return 1;
  }
  GETLINE(DATASET); airToUpper(nio->line);
  if (!strstr(nio->line, "STRUCTURED_POINTS")) {
    biffAddf(NRRD,
             "%s: sorry, only STRUCTURED_POINTS data is nrrd-ready", me);
    return 1;
  }
  GETLINE(DIMENSIONS); airToUpper(nio->line);
  if (!strstr(nio->line, "DIMENSIONS")
      || 3 != sscanf(nio->line, "DIMENSIONS %d %d %d", &sx, &sy, &sz)) {
    biffAddf(NRRD, "%s: couldn't parse DIMENSIONS line (\"%s\")",
             me, nio->line);
    return 1;
  }
  GETLINE(next); airToUpper(nio->line);
  while (!strstr(nio->line, "POINT_DATA")) {
    if (strstr(nio->line, "ORIGIN")) {
      if (3 != sscanf(nio->line, "ORIGIN %lf %lf %lf", &xm, &ym, &zm)) {
        biffAddf(NRRD, "%s: couldn't parse ORIGIN line (\"%s\")",
                 me, nio->line);
        return 1;
      }
    } else if (strstr(nio->line, "SPACING")) {
      if (3 != sscanf(nio->line, "SPACING %lf %lf %lf",
                      &xs, &ys, &zs)) {
        biffAddf(NRRD, "%s: couldn't parse SPACING line (\"%s\")",
                 me, nio->line);
        return 1;
      }
    } else if (strstr(nio->line, "ASPECT_RATIO")) {
      if (3 != sscanf(nio->line, "ASPECT_RATIO %lf %lf %lf",
                      &xs, &ys, &zs)) {
        biffAddf(NRRD, "%s: couldn't parse ASPECT_RATIO line (\"%s\")",
                 me, nio->line);
        return 1;
      }
    }
    GETLINE(next); airToUpper(nio->line);
  }
  if (1 != sscanf(nio->line, "POINT_DATA %d", &N)) {
    biffAddf(NRRD, "%s: couldn't parse POINT_DATA line (\"%s\")",
             me, nio->line);
    return 1;
  }
  if (N != sx*sy*sz) {
    biffAddf(NRRD,
             "%s: product of sizes (%d*%d*%d == %d) != # elements (%d)",
             me, sx, sy, sz, sx*sy*sz, N);
    return 1;
  }
  GETLINE(attribute declaration);
  mop = airMopNew();
  if (3 != airParseStrS(three, nio->line, AIR_WHITESPACE, 3, AIR_FALSE)) {
    biffAddf(NRRD,
             "%s: didn't see three words in attribute declaration \"%s\"",
             me, nio->line);
    return 1;
  }
  airMopAdd(mop, three[0], airFree, airMopAlways);
  airMopAdd(mop, three[1], airFree, airMopAlways);
  airMopAdd(mop, three[2], airFree, airMopAlways);
  airToLower(three[2]);
  if (!strcmp(three[2], "bit")) {
    if (nrrdEncodingAscii == nio->encoding) {
      fprintf(stderr, "%s: WARNING: \"bit\"-type data will be read in as "
              "unsigned char\n", me);
      nrrd->type = nrrdTypeUChar;
    } else {
      biffAddf(NRRD, "%s: can't read in \"bit\"-type data as BINARY", me);
      return 1;
    }
  } else if (!strcmp(three[2], "unsigned_char")) {
    nrrd->type = nrrdTypeUChar;
  } else if (!strcmp(three[2], "char")) {
    nrrd->type = nrrdTypeChar;
  } else if (!strcmp(three[2], "unsigned_short")) {
    nrrd->type = nrrdTypeUShort;
  } else if (!strcmp(three[2], "short")) {
    nrrd->type = nrrdTypeShort;
  } else if (!strcmp(three[2], "unsigned_int")) {
    nrrd->type = nrrdTypeUInt;
  } else if (!strcmp(three[2], "int")) {
    nrrd->type = nrrdTypeInt;
  } else if (!strcmp(three[2], "float")) {
    nrrd->type = nrrdTypeFloat;
  } else if (!strcmp(three[2], "double")) {
    nrrd->type = nrrdTypeDouble;
  } else {
    /* "unsigned_long" and "long" fall in here- I don't know what
       the VTK people mean by these types, since always mean different
       things on 32-bit versus 64-bit architectures */
    biffAddf(NRRD, "%s: type \"%s\" not recognized", me, three[2]);
    airMopError(mop); return 1;
  }
  airToUpper(three[0]);
  if (!strncmp("SCALARS", three[0], strlen("SCALARS"))) {
    GETLINE(LOOKUP_TABLE); airToUpper(nio->line);
    if (strcmp(nio->line, "LOOKUP_TABLE DEFAULT")) {
      biffAddf(NRRD,
               "%s: sorry, can only deal with default LOOKUP_TABLE", me);
      airMopError(mop); return 1;
    }
    nrrd->dim = 3;
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSize,
                       AIR_CAST(size_t, sx),
                       AIR_CAST(size_t, sy),
                       AIR_CAST(size_t, sz));
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSpacing, xs, ys, zs);
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoMin, xm, ym, zm);
  } else if (!strncmp("VECTORS", three[0], strlen("VECTORS"))) {
    nrrd->dim = 4;
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSize,
                       AIR_CAST(size_t, 3),
                       AIR_CAST(size_t, sx),
                       AIR_CAST(size_t, sy),
                       AIR_CAST(size_t, sz));
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSpacing, AIR_NAN, xs, ys, zs);
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoMin, AIR_NAN, xm, ym, zm);
    nrrd->axis[0].kind = nrrdKind3Vector;
  } else if (!strncmp("TENSORS", three[0], strlen("TENSORS"))) {
    nrrd->dim = 4;
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSize,
                       AIR_CAST(size_t, 9),
                       AIR_CAST(size_t, sx),
                       AIR_CAST(size_t, sy),
                       AIR_CAST(size_t, sz));
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoSpacing, AIR_NAN, xs, ys, zs);
    nrrdAxisInfoSet_va(nrrd, nrrdAxisInfoMin, AIR_NAN, xm, ym, zm);
    nrrd->axis[0].kind = nrrdKind3DMatrix;
  } else {
    biffAddf(NRRD,
             "%s: sorry, can only deal with SCALARS, VECTORS, and TENSORS "
             "currently, so couldn't parse attribute declaration \"%s\"",
             me, nio->line);
    airMopError(mop); return 1;
  }
  if (!nio->skipData) {
    if (_nrrdCalloc(nrrd, nio, file)) {
      biffAddf(NRRD, "%s: couldn't allocate memory for data", me);
      return 1;
    }
    if (nio->encoding->read(file, nrrd->data, nrrdElementNumber(nrrd),
                            nrrd, nio)) {
      biffAddf(NRRD, "%s:", me);
      return 1;
    }
    if (1 < nrrdElementSize(nrrd)
        && nio->encoding->endianMatters
        && airMyEndian() != airEndianBig) {
      /* encoding exposes endianness, and its big, but we aren't */
      nrrdSwapEndian(nrrd);
    }
  } else {
    nrrd->data = NULL;
  }

  airMopOkay(mop);
  return 0;
}
Example #5
0
/* this strongly assumes that nrrdFitsInFormat() was true */
int
_nrrdFormatVTK_write(FILE *file, const Nrrd *_nrrd, NrrdIoState *nio) {
  static const char me[]="_nrrdFormatVTK_write";
  int i, sx, sy, sz, sax;
  double xs, ys, zs, xm, ym, zm;
  char type[AIR_STRLEN_MED], name[AIR_STRLEN_SMALL];
  Nrrd *nrrd;
  airArray *mop;

  /* HEY: should this copy be done more conservatively */
  mop = airMopNew();
  airMopAdd(mop, nrrd=nrrdNew(), (airMopper)nrrdNuke, airMopAlways);
  if (nrrdCopy(nrrd, _nrrd)) {
    biffAddf(NRRD, "%s: couldn't make private copy", me);
    airMopError(mop); return 1;
  }
  if (!( 3 == nrrd->dim ||
         (4 == nrrd->dim && (3 == nrrd->axis[0].size ||
                             9 == nrrd->axis[0].size)) )) {
    biffAddf(NRRD, "%s: doesn't seem to be scalar, vector, or matrix", me);
    airMopError(mop); return 1;
  }
  sax = nrrd->dim - 3;
  xs = nrrd->axis[sax+0].spacing;
  ys = nrrd->axis[sax+1].spacing;
  zs = nrrd->axis[sax+2].spacing;
  if (!( AIR_EXISTS(xs) && AIR_EXISTS(ys) && AIR_EXISTS(zs) )) {
    xs = ys = zs = 1.0;
  }
  xm = nrrd->axis[sax+0].min;
  ym = nrrd->axis[sax+1].min;
  zm = nrrd->axis[sax+2].min;
  if (!( AIR_EXISTS(xm) && AIR_EXISTS(ym) && AIR_EXISTS(zm) )) {
    xm = ym = zm = 0.0;
  }
  sx = AIR_CAST(int, nrrd->axis[sax+0].size);
  sy = AIR_CAST(int, nrrd->axis[sax+1].size);
  sz = AIR_CAST(int, nrrd->axis[sax+2].size);

  switch(nrrd->type) {
  case nrrdTypeUChar:
    strcpy(type, "unsigned_char");
    break;
  case nrrdTypeChar:
    strcpy(type, "char");
    break;
  case nrrdTypeUShort:
    strcpy(type, "unsigned_short");
    break;
  case nrrdTypeShort:
    strcpy(type, "short");
    break;
  case nrrdTypeUInt:
    strcpy(type, "unsigned_int");
    break;
  case nrrdTypeInt:
    strcpy(type, "int");
    break;
  case nrrdTypeFloat:
    strcpy(type, "float");
    break;
  case nrrdTypeDouble:
    strcpy(type, "double");
    break;
  default:
    biffAddf(NRRD, "%s: can't put %s-type nrrd into VTK", me,
             airEnumStr(nrrdType, nrrd->type));
    airMopError(mop); return 1;
  }
  fprintf(file, "%s\n", MAGIC3);
  /* there is a file-format-imposed limit on the length of the "content" */
  if (nrrd->content) {
    /* when the "250" below was previously "255", vtk didn't deal */
    for (i=0; i<=250 && nrrd->content[i]; i++) {
      fputc(nrrd->content[i], file);
    }
    fputc('\n', file);
  } else {
    fprintf(file, NRRD_UNKNOWN "\n");
  }
  if (nrrdEncodingRaw == nio->encoding) {
    fprintf(file, "BINARY\n");
  } else {
    fprintf(file, "ASCII\n");
  }
  fprintf(file, "DATASET STRUCTURED_POINTS\n");
  fprintf(file, "DIMENSIONS %d %d %d\n", sx, sy, sz);
  fprintf(file, "ORIGIN %g %g %g\n", xm, ym, zm);
  fprintf(file, "SPACING %g %g %g\n", xs, ys, zs);
  fprintf(file, "POINT_DATA %d\n", sx*sy*sz);
  airSrandMT(AIR_CAST(unsigned int, airTime()));
  sprintf(name, "nrrd%05d", airRandInt(100000));
  if (3 == nrrd->dim) {
    fprintf(file, "SCALARS %s %s\n", name, type);
    fprintf(file, "LOOKUP_TABLE default\n");
  } else {
    /* 4 == nrrd->dim */
    if (3 == nrrd->axis[0].size) {
      fprintf(file, "VECTORS %s %s\n", name, type);
    } else {
      fprintf(file, "TENSORS %s %s\n", name, type);
    }
  }
  if (1 < nrrdElementSize(nrrd)
      && nio->encoding->endianMatters
      && airMyEndian() != airEndianBig) {
    /* encoding exposes endianness, and we're not big, as req.d by VTK */
    nrrdSwapEndian(nrrd);
  }
  if (nio->encoding->write(file, nrrd->data, nrrdElementNumber(nrrd),
                           nrrd, nio)) {
    biffAddf(NRRD, "%s:", me);
    airMopError(mop); return 1;
  }

  airMopOkay(mop);
  return 0;
}
Example #6
0
/*
******** airSanity()
**
** Does run-time checks to see if the compile-time constants are correct.
** Returns a value from the airInsane* enum; airInsane_not means all
** the checks came back without detecting any problems.
*/
int
airSanity(void) {
  double nanValue, pinf, ninf;
  float nanF, pinfF, ninfF;
  unsigned int sign, expvalue, mant;
  int tmpI;
  char endian;
  unsigned char uc0, uc1;
  static int _airSanity=0;

  if (_airSanity) {
    return airInsane_not;
  }

  /* now that there is no more compile-time endian info, this is
     merely double checking that airMyEndian() works, and returns
     the constants (either 1234, pronounced "little endian", or
     4321, "big endian") that are defined in air.h */
  tmpI = 1;
  endian = !(*((char*)(&tmpI)));
  if (endian) {
    /* big endian */
    if (4321 != airMyEndian()) {
      return airInsane_endian;
    }
  } else {
    if (1234 != airMyEndian()) {
      return airInsane_endian;
    }
  }

  /* checks on sizes of uchar, float, int, double, airLLong */
  uc0 = 255;
  uc1 = AIR_CAST(unsigned char, AIR_INT(uc0) + 1); /* want to overflow */
  if (!( 255 == uc0 && 0 == uc1 )) {
    return airInsane_UCSize;
  }
  /* these justify the AIR_EXISTS_F and AIR_EXISTS_D macros */
  if (!( (sizeof(float) == sizeof(int)) && (4 == sizeof(int)) )) {
    return airInsane_FISize;
  }
  if (!( (sizeof(double) == sizeof(airLLong)) && (8 == sizeof(airLLong)) )) {
    return airInsane_DLSize;
  }

  /* run-time NaN checks */
  pinf = DBL_MAX;
  pinf = _airSanityHelper(pinf);
  pinf = _airSanityHelper(pinf);
  pinf = _airSanityHelper(pinf);
  if (AIR_EXISTS(pinf)) {
    return airInsane_pInfExists;
  }
  ninf = -pinf;
  if (AIR_EXISTS(ninf)) {
    return airInsane_nInfExists;
  }
  nanValue = pinf / pinf;
  if (AIR_EXISTS(nanValue)) {
    return airInsane_NaNExists;
  }
  nanF = (float)nanValue;
  pinfF = (float)pinf;
  ninfF = (float)ninf;
  airFPValToParts_f(&sign, &expvalue, &mant, nanF);
  mant >>= 22;
  if (AIR_QNANHIBIT != (int)mant) {
    return airInsane_QNaNHiBit;
  }

  if (!( airFP_QNAN == airFPClass_f(AIR_NAN)
         && airFP_QNAN == airFPClass_f(AIR_QNAN)
         /*
           As of July 4 2012 GLK decides that the signalling NaN tests are
           more trouble than they're worth: the signal-ness of the NaN is not
           preserved in double-float conversion for some platforms (so
           airFP_SNAN == airFPClass_d(AIR_SNAN) has never been enforced), and
           there are more platforms for which (apparently) passing AIR_SNAN to
           airFPClass_d changes it to a quiet NaN, which defeats the purpose
           of the test.  To summarize, given that:
           ** AIR_NAN and AIR_QNAN are checked here to be quiet NaN, after
              casting to both float and double,
           ** quiet NaN "hi bit" is tested above, and that
           ** quiet and signalling NaN are mutually exclusive,
           skipping the signalling NaN tests is unlikely to undermine knowing
           the correctness of the compile-time representation of NaNs.  So the
           following line is now commented out for all platforms.
         */
         /* && airFP_SNAN == airFPClass_f(AIR_SNAN) */
         && airFP_QNAN == airFPClass_d(AIR_NAN)
         && airFP_QNAN == airFPClass_d(AIR_QNAN) )) {
    return airInsane_AIR_NAN;
  }
  if (!(airFP_QNAN == airFPClass_f(nanF)
        && airFP_POS_INF == airFPClass_f(pinfF)
        && airFP_NEG_INF == airFPClass_f(ninfF))) {
    /* really, this is verifying that assigning from a double to a
       float maintains the FPClass for non-existent values */
    return airInsane_FltDblFPClass;
  }

  /* just make sure AIR_DIO is reasonably set
     (actually, this should be done by include/teemDio.h) */
  switch (AIR_DIO) {
  case 0: break;
  case 1: break;
  default:
    return airInsane_dio;
  }

  _airSanity = 1;
  return airInsane_not;
}
/*
** _nrrdSprintFieldInfo
**
** this prints "<prefix><field>: <info>" into *strP (after allocating it for
** big enough, usually with a stupidly big margin of error), in a form
** suitable to be written to NRRD or other image headers.  This will always
** print something (for valid inputs), even stupid <info>s like
** "(unknown endian)".  It is up to the caller to decide which fields
** are worth writing, via _nrrdFieldInteresting().
**
** NOTE: some of these fields make sense in non-NRRD files (e.g. all
** the per-axis information), but many only make sense in NRRD files.
** This is just one example of NRRD-format-specific stuff that is not
** in formatNRRD.c
*/
void
_nrrdSprintFieldInfo(char **strP, const char *prefix,
                     const Nrrd *nrrd, NrrdIoState *nio, int field) {
  static const char me[]="_nrrdSprintFieldInfo";
  char buff[AIR_STRLEN_MED], *fnb, stmp[AIR_STRLEN_SMALL],
    *strtmp=NULL;
  double colvec[NRRD_SPACE_DIM_MAX];
  const char *fs;
  unsigned int ii, dd,
    uintStrlen = 11,
    size_tStrlen = 33,
    doubleStrlen = 513;
  size_t fslen, fdlen, maxl;
  int endi;

  if (!( strP && prefix
         && nrrd
         && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)
         && AIR_IN_OP(nrrdField_unknown, field, nrrdField_last) )) {
    return;
  }
  /* As of Sun Dec  2 01:57:48 CST 2012 (revision 5832) the only
     places where this function is called is when it has been guarded
     by "if (_nrrdFieldInteresting())" (except for in formatText.c when
     its called on the dimension field, which is always interesting).
     So, the following:

     if (!_nrrdFieldInteresting(nrrd, nio, field)) {
       *strP = airStrdup("");
     }

     was redundant and confusingly created the appearance of a memory
     leak waiting to happen.  We now let the default switch statement
     set *strP to NULL (all the other cases set it), to smoke out
     errors in how this function is called */

  fs = airEnumStr(nrrdField, field);
  fslen = strlen(prefix) + strlen(fs) + strlen(": ") + 1;
  switch (field) {
  case nrrdField_comment:
  case nrrdField_keyvalue:
    fprintf(stderr, "%s: CONFUSION: why are you calling me on \"%s\"?\n", me,
            airEnumStr(nrrdField, nrrdField_comment));
    *strP = airStrdup("");
    break;
  case nrrdField_content:
    strtmp = airOneLinify(airStrdup(nrrd->content));
    *strP = AIR_CALLOC(fslen + strlen(strtmp), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, strtmp);
    airFree(strtmp); strtmp = NULL;
    break;
  case nrrdField_number:
    *strP = AIR_CALLOC(fslen + size_tStrlen, char);
    sprintf(*strP, "%s%s: %s", prefix, fs,
            airSprintSize_t(stmp, nrrdElementNumber(nrrd)));
    break;
  case nrrdField_type:
    *strP = AIR_CALLOC(fslen + strlen(airEnumStr(nrrdType, nrrd->type)), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdType, nrrd->type));
    break;
  case nrrdField_block_size:
    *strP = AIR_CALLOC(fslen + size_tStrlen, char);
    sprintf(*strP, "%s%s: %s", prefix, fs,
            airSprintSize_t(stmp, nrrd->blockSize));
    break;
  case nrrdField_dimension:
    *strP = AIR_CALLOC(fslen + uintStrlen, char);
    sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->dim);
    break;
  case nrrdField_space:
    *strP = AIR_CALLOC(fslen
                       + strlen(airEnumStr(nrrdSpace, nrrd->space)), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdSpace, nrrd->space));
    break;
  case nrrdField_space_dimension:
    *strP = AIR_CALLOC(fslen + uintStrlen, char);
    sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->spaceDim);
    break;
    /* ---- begin per-axis fields ---- */
  case nrrdField_sizes:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(size_tStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      sprintf(buff, " %s", airSprintSize_t(stmp, nrrd->axis[ii].size));
      strcat(*strP, buff);
    }
    break;
  case nrrdField_spacings:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].spacing);
      strcat(*strP, buff);
    }
    break;
  case nrrdField_thicknesses:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].thickness);
      strcat(*strP, buff);
    }
    break;
  case nrrdField_axis_mins:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].min);
      strcat(*strP, buff);
    }
    break;
  case nrrdField_axis_maxs:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].max);
      strcat(*strP, buff);
    }
    break;
  case nrrdField_space_directions:
    *strP = AIR_CALLOC(fslen
                       + nrrd->dim*nrrd->spaceDim*(doubleStrlen
                                                   + strlen("(,) ")), char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim,
                             nrrd->axis[ii].spaceDirection);
      if (ii < nrrd->dim-1) {
        strcat(*strP, " ");
      }
    }
    break;
  case nrrdField_centers:
    fdlen = 0;
    for (ii=0; ii<nrrd->dim; ii++) {
      fdlen += 1 + airStrlen(nrrd->axis[ii].center
                             ? airEnumStr(nrrdCenter, nrrd->axis[ii].center)
                             : NRRD_UNKNOWN);
    }
    *strP = AIR_CALLOC(fslen + fdlen, char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      sprintf(buff, " %s",
              (nrrd->axis[ii].center
               ? airEnumStr(nrrdCenter, nrrd->axis[ii].center)
               : NRRD_UNKNOWN));
      strcat(*strP, buff);
    }
    break;
  case nrrdField_kinds:
    fdlen = 0;
    for (ii=0; ii<nrrd->dim; ii++) {
      fdlen += 1 + airStrlen(nrrd->axis[ii].kind
                             ? airEnumStr(nrrdKind, nrrd->axis[ii].kind)
                             : NRRD_UNKNOWN);
    }
    *strP = AIR_CALLOC(fslen + fdlen, char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      sprintf(buff, " %s",
              (nrrd->axis[ii].kind
               ? airEnumStr(nrrdKind, nrrd->axis[ii].kind)
               : NRRD_UNKNOWN));
      strcat(*strP, buff);
    }
    break;
  case nrrdField_labels:
  case nrrdField_units:
#define LABEL_OR_UNITS (nrrdField_labels == field \
                        ? nrrd->axis[ii].label \
                        : nrrd->axis[ii].units)
    fdlen = 0;
    for (ii=0; ii<nrrd->dim; ii++) {
      /* The "2*" is because at worst every character needs escaping.
         The "+ 3" for the |" "| between each part */
      fdlen += 2*airStrlen(LABEL_OR_UNITS) + 3;
    }
    fdlen += 1; /* for '\0' */
    *strP = AIR_CALLOC(fslen + fdlen, char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      strcat(*strP, " \"");
      if (airStrlen(nrrd->axis[ii].label)) {
        _nrrdWriteEscaped(NULL, *strP, LABEL_OR_UNITS,
                          "\"", _NRRD_WHITESPACE_NOTAB);
      }
      strcat(*strP, "\"");
    }
#undef LABEL_OR_UNITS
    break;
    /* ---- end per-axis fields ---- */
  case nrrdField_min:
  case nrrdField_max:
    /* we're basically a no-op, now that these fields became meaningless */
    *strP = AIR_CALLOC(fslen + doubleStrlen, char);
    sprintf(*strP, "%s%s: 0.0", prefix, fs);
    strcat(*strP, buff);
    break;
  case nrrdField_old_min:
    *strP = AIR_CALLOC(fslen + doubleStrlen, char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    airSinglePrintf(NULL, buff, "%.17g", nrrd->oldMin);
    strcat(*strP, buff);
    break;
  case nrrdField_old_max:
    *strP = AIR_CALLOC(fslen + doubleStrlen, char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    airSinglePrintf(NULL, buff, "%.17g", nrrd->oldMax);
    strcat(*strP, buff);
    break;
  case nrrdField_endian:
    if (airEndianUnknown != nio->endian) {
      /* we know a specific endianness because either it was recorded as
         part of "unu make -h", or it was set (and data was possibly
         altered) as part of "unu save" */
      endi = nio->endian;
    } else {
      /* we record our current architecture's endian because we're
         going to writing out data */
      endi = airMyEndian();
    }
    *strP = AIR_CALLOC(fslen + strlen(airEnumStr(airEndian, endi)), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(airEndian, endi));
    break;
  case nrrdField_encoding:
    *strP = AIR_CALLOC(fslen + strlen(nio->encoding->name), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, nio->encoding->name);
    break;
  case nrrdField_line_skip:
    *strP = AIR_CALLOC(fslen + uintStrlen, char);
    sprintf(*strP, "%s%s: %d", prefix, fs, nio->lineSkip);
    break;
  case nrrdField_byte_skip:
    *strP = AIR_CALLOC(fslen + uintStrlen, char);
    sprintf(*strP, "%s%s: %ld", prefix, fs, nio->byteSkip);
    break;
  case nrrdField_sample_units:
    strtmp = airOneLinify(airStrdup(nrrd->sampleUnits));
    *strP = AIR_CALLOC(fslen + strlen(strtmp), char);
    sprintf(*strP, "%s%s: \"%s\"", prefix, fs, strtmp);
    airFree(strtmp); strtmp = NULL;
    break;
  case nrrdField_space_units:
    fdlen = 0;
    for (ii=0; ii<nrrd->spaceDim; ii++) {
      /* The "2*" is because at worst every character needs escaping.
         See note in formatNRRD.c about how even though its not part
         of the format, we have worst-case scenario of having to
         escape a space units which is nothing but ". The "+ 3" for
         the |" "| between each part */
      fdlen += 2*airStrlen(nrrd->spaceUnits[ii]) + 3;
    }
    fdlen += 1; /* for '\0' */
    *strP = AIR_CALLOC(fslen + fdlen, char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->spaceDim; ii++) {
      strcat(*strP, " \"");
      if (airStrlen(nrrd->spaceUnits[ii])) {
        _nrrdWriteEscaped(NULL, *strP, nrrd->spaceUnits[ii],
                          "\"", _NRRD_WHITESPACE_NOTAB);
      }
      strcat(*strP, "\"");
    }
    break;
  case nrrdField_space_origin:
    *strP = AIR_CALLOC(fslen + nrrd->spaceDim*(doubleStrlen
                                               + strlen("(,) ")), char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, nrrd->spaceOrigin);
    break;
  case nrrdField_measurement_frame:
    *strP = AIR_CALLOC(fslen + (nrrd->spaceDim*
                                nrrd->spaceDim*(doubleStrlen
                                                + strlen("(,) "))), char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    for (dd=0; dd<nrrd->spaceDim; dd++) {
      for (ii=0; ii<nrrd->spaceDim; ii++) {
        colvec[ii] = nrrd->measurementFrame[dd][ii];
      }
      _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, colvec);
      if (dd < nrrd->spaceDim-1) {
        strcat(*strP, " ");
      }
    }
    break;
  case nrrdField_data_file:
    /* NOTE: this comes last (nrrdField_data_file is the highest-valued
       member of the nrrdField* enum) because the "LIST" form of the
       data file specification requires that the following lines be
       the filenames */
    /* error checking elsewhere: assumes there is data file info */
    if (nio->dataFNFormat) {
      *strP = AIR_CALLOC(fslen + strlen(nio->dataFNFormat) + 4*uintStrlen,
                         char);
      if (nio->dataFileDim == nrrd->dim-1) {
        sprintf(*strP, "%s%s: %s %d %d %d", prefix, fs, nio->dataFNFormat,
                nio->dataFNMin, nio->dataFNMax, nio->dataFNStep);
      } else {
        sprintf(*strP, "%s%s: %s %d %d %d %u", prefix, fs, nio->dataFNFormat,
                nio->dataFNMin, nio->dataFNMax, nio->dataFNStep,
                nio->dataFileDim);
      }
    } else if (nio->dataFNArr->len > 1) {
Example #8
0
int
main(int argc, const char **argv) {
  /* stock variables */
  char me[] = BKEY;
  hestOpt *hopt=NULL;
  hestParm *hparm;
  airArray *mop;
  /* variables specific to this program */
  int negskip, progress;
  Nrrd *nref, *nin;
  size_t *size, ii, nn, tick, pad[2];
  unsigned int axi, refCRC, gotCRC, sizeNum;
  char *berr, *outS[2], stmp[AIR_STRLEN_SMALL], doneStr[AIR_STRLEN_SMALL];
  airRandMTState *rng;
  unsigned int seed, *rdata, printbytes;
  unsigned char *dataUC;
  double time0, time1;
  FILE *fout;

  /* start-up */
  mop = airMopNew();
  hparm = hestParmNew();
  airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
  /* learn things from hest */
  hestOptAdd(&hopt, "seed", "N", airTypeUInt, 1, 1, &seed, "42",
             "seed for RNG");
  hestOptAdd(&hopt, "s", "sz0", airTypeSize_t, 1, -1, &size, NULL,
             "sizes of desired output", &sizeNum);
  hestOptAdd(&hopt, "p", "pb pa", airTypeSize_t, 2, 2, pad, "0 0",
             "bytes of padding before, and after, the data segment "
             "in the written data");
  hestOptAdd(&hopt, "ns", "bool", airTypeInt, 0, 0, &negskip, NULL,
             "skipping should be relative to end of file");
  hestOptAdd(&hopt, "pb", "print", airTypeUInt, 1, 1, &printbytes, "0",
             "bytes to print at beginning and end of data, to help "
             "debug problems");
  hestOptAdd(&hopt, "o", "out.data out.nhdr", airTypeString, 2, 2,
             outS, NULL, "output filenames of data and header");
  hestParseOrDie(hopt, argc-1, argv+1, hparm, me, tskipInfo,
                 AIR_TRUE, AIR_TRUE, AIR_TRUE);
  airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
  airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways);

  /* generate reference nrrd data */
  nref = nrrdNew();
  airMopAdd(mop, nref, (airMopper)nrrdNuke, airMopAlways);
  if (nrrdMaybeAlloc_nva(nref, nrrdTypeUInt, sizeNum, size)) {
    airMopAdd(mop, berr=biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: error allocating data: %s\n", me, berr);
    airMopError(mop); return 1;
  }
  rng = airRandMTStateNew(seed);
  airMopAdd(mop, rng, (airMopper)airRandMTStateNix, airMopAlways);
  nn = nrrdElementNumber(nref);
  rdata = AIR_CAST(unsigned int *, nref->data);
  fprintf(stderr, "generating data: . . .       "); fflush(stderr);
  time0 = airTime();
  progress = AIR_FALSE;
  tick = nn/100;
  for (ii=0; ii<nn; ii++) {
    rdata[ii] = airUIrandMT_r(rng);
    if (ii && tick && !(ii % tick)) {
      time1 = airTime();
      if (time1 - time0 > 1.0) {
        /* if it took more than a second to do 1% of the thing,
           would be good to generate some progress indication */
        progress = AIR_TRUE;
      }
      if (progress) {
        fprintf(stderr, "%s", airDoneStr(0, ii, nn, doneStr)); fflush(stderr);
      }
    }
  }
  if (progress) {
    fprintf(stderr, "%s\n", airDoneStr(0, ii, nn, doneStr)); fflush(stderr);
  } else {
    fprintf(stderr, "\n");
  }
  fprintf(stderr, "finding reference (big-endian) CRC: "); fflush(stderr);
  refCRC = nrrdCRC32(nref, airEndianBig);
  fprintf(stderr, "%u\n", refCRC);

  /* write data, with padding */
  fprintf(stderr, "saving data . . . "); fflush(stderr);
  if (!(fout = fopen(outS[0], "wb" COMMIT))) {
    fprintf(stderr, "\n%s: couldn't open %s for writing: %s\n", me,
            outS[0], strerror(errno));
    airMopError(mop); return 1;
  }
  airMopAdd(mop, fout, (airMopper)airFclose, airMopAlways);
  for (ii=0; ii<pad[0]; ii++) {
    if (EOF == fputc(1, fout)) {
      fprintf(stderr, "\n%s: error doing pre-padding\n", me);
      airMopError(mop); return 1;
    }
  }
  if (nn != fwrite(nref->data, nrrdElementSize(nref), nn, fout)) {
    fprintf(stderr, "\n%s: error writing data\n", me);
    airMopError(mop); return 1;
  }
  for (ii=0; ii<pad[1]; ii++) {
    if (EOF == fputc(2, fout)) {
      fprintf(stderr, "\n%s: error doing post-padding\n", me);
      airMopError(mop); return 1;
    }
  }
  if (EOF == fflush(fout)) {
    fprintf(stderr, "\n%s: error fflushing data: %s\n", me,
            strerror(errno));
  }
  fprintf(stderr, "\n");
  if (printbytes) {
    size_t bi, rpb, nn;
    char stmp[AIR_STRLEN_SMALL];
    nn = nrrdElementSize(nref)*nrrdElementNumber(nref);
    rpb = AIR_MIN(printbytes, nn);
    dataUC = AIR_CAST(unsigned char *, nref->data);
    fprintf(stderr, "CORRECT %s bytes at beginning:\n",
            airSprintSize_t(stmp, rpb));
    for (bi=0; bi<rpb; bi++) {
      fprintf(stderr, "%x ", dataUC[bi]);
    }
    fprintf(stderr, "...\n");
    fprintf(stderr, "CORRECT %s bytes at end:\n",
            airSprintSize_t(stmp, rpb));
    fprintf(stderr, "...");
    for (bi=nn - rpb; bi<nn; bi++) {
      fprintf(stderr, " %x", dataUC[bi]);
    }
    fprintf(stderr, "\n");
  }
  airMopSingleOkay(mop, fout);
  airMopSingleOkay(mop, nref); nref = NULL;

  /* write header; for now just writing the header directly */
  fprintf(stderr, "writing header . . . \n");
  if (!(fout = fopen(outS[1], "w"))) {
    fprintf(stderr, "%s: couldn't open %s for writing: %s\n", me,
            outS[1], strerror(errno));
    airMopError(mop); return 1;
  }
  airMopAdd(mop, fout, (airMopper)airFclose, airMopAlways);
  fprintf(fout, "NRRD0005\n");
  fprintf(fout, "type: unsigned int\n");
  fprintf(fout, "dimension: %u\n", sizeNum);
  fprintf(fout, "sizes:");
  for (axi=0; axi<sizeNum; axi++) {
    fprintf(fout, " %s", airSprintSize_t(stmp, size[axi]));
  }
  fprintf(fout, "\n");
  fprintf(fout, "endian: %s\n", airEnumStr(airEndian, airMyEndian()));
  fprintf(fout, "encoding: %s\n", airEnumStr(nrrdEncodingType,
                                             nrrdEncodingTypeRaw));
  if (!negskip) {
    if (pad[0]) {
      fprintf(fout, "byte skip: %s\n", airSprintSize_t(stmp, pad[0]));
    }
  } else {
    fprintf(fout, "byte skip: -%s\n", airSprintSize_t(stmp, pad[1]+1));
  }
  fprintf(fout, "data file: %s\n", outS[0]);
  airMopSingleOkay(mop, fout);

  /* read it in, make sure it checks out */
  fprintf(stderr, "reading data . . . \n");
  nin = nrrdNew();
  airMopAdd(mop, nin, (airMopper)nrrdNuke, airMopAlways);
  if (nrrdLoad(nin, outS[1], NULL)) {
    airMopAdd(mop, berr=biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: error reading back in: %s\n", me, berr);
    airMopError(mop); return 1;
  }
  if (printbytes) {
    size_t bi, rpb, nn;
    char stmp[AIR_STRLEN_SMALL];
    nn = nrrdElementSize(nin)*nrrdElementNumber(nin);
    rpb = AIR_MIN(printbytes, nn);
    dataUC = AIR_CAST(unsigned char *, nin->data);
    fprintf(stderr, "FOUND %s bytes at beginning:\n",
            airSprintSize_t(stmp, rpb));
    for (bi=0; bi<rpb; bi++) {
      fprintf(stderr, "%x ", dataUC[bi]);
    }
    fprintf(stderr, "...\n");
    fprintf(stderr, "FOUND %s bytes at end:\n",
            airSprintSize_t(stmp, rpb));
    fprintf(stderr, "...");
    for (bi=nn - rpb; bi<nn; bi++) {
      fprintf(stderr, " %x", dataUC[bi]);
    }
    fprintf(stderr, "\n");
  }
  fprintf(stderr, "finding new CRC . . . \n");
  gotCRC = nrrdCRC32(nin, airEndianBig);
  if (refCRC != gotCRC) {
    fprintf(stderr, "%s: got CRC %u but wanted %u\n", me, gotCRC, refCRC);
    airMopError(mop); return 1;
  }
  fprintf(stderr, "(all ok)\n");

  /* HEY: to test gzip reading, we really want to do a system call to
     gzip compress the data, and write a new header to point to the
     compressed data, and make sure we can read in that just the same */

  airMopOkay(mop);
  return 0;
}