Example #1
0
/*
******** nrrdNew()
**
** creates and initializes a Nrrd
**
** this does NOT use biff
*/
Nrrd *
nrrdNew(void)
{
  int ii;
  Nrrd *nrrd;

  nrrd = (Nrrd*)(calloc(1, sizeof(Nrrd)));
  if (!nrrd)
  {
    return NULL;
  }

  /* explicitly set pointers to NULL, since calloc isn't officially
     guaranteed to do that.  */
  nrrd->data = NULL;
  for (ii=0; ii<NRRD_DIM_MAX; ii++)
  {
    _nrrdAxisInfoNewInit(nrrd->axis + ii);
  }
  for (ii=0; ii<NRRD_SPACE_DIM_MAX; ii++)
  {
    nrrd->spaceUnits[ii] = NULL;
  }
  nrrd->content = NULL;
  nrrd->sampleUnits = NULL;

  /* create comment airArray (even though it starts empty) */
  nrrd->cmt = NULL;
  void *pvoid = (void*)&(nrrd->cmt);
  nrrd->cmtArr = airArrayNew((void**)pvoid, NULL,
                             sizeof(char *), NRRD_COMMENT_INCR);
  if (!nrrd->cmtArr)
  {
    return NULL;
  }
  airArrayPointerCB(nrrd->cmtArr, airNull, airFree);

  /* create key/value airArray (even thought it starts empty) */
  nrrd->kvp = NULL;
  pvoid = &(nrrd->kvp);
  nrrd->kvpArr = airArrayNew((void**)pvoid, NULL,
                             2*sizeof(char *), NRRD_KEYVALUE_INCR);
  if (!nrrd->kvpArr)
  {
    return NULL;
  }
  /* key/value airArray uses no callbacks for now */

  /* finish initializations */
  nrrdInit(nrrd);

  return nrrd;
}
Example #2
0
biffMsg *
biffMsgNew(const char *key) {
  static const char me[]="biffMsgNew";
  biffMsg *msg;

  if (!key) {
    fprintf(stderr, "%s: PANIC got NULL key\n", me);
    return NULL; /* exit(1); */
  }
  msg = AIR_CALLOC(1, biffMsg);
  if (msg) {
    airPtrPtrUnion appu;

    msg->key = airStrdup(key);
    msg->err = NULL;
    msg->errNum = 0;
    appu.cp = &(msg->err);
    msg->errArr = airArrayNew(appu.v, &(msg->errNum),
                              sizeof(char*), _MSG_INCR);
    if (msg->errArr) {
      airArrayPointerCB(msg->errArr, NULL, airFree);
    }
  }
  if (!( msg && msg->key && msg->errArr )) {
    fprintf(stderr, "%s: PANIC couldn't calloc new msg\n", me);
    return NULL; /* exit(1); */
  }
  return msg;
}
Example #3
0
int
tkwbReadFileToString(char **strP, int *hitEOF, FILE *file, char *stop) {
    char **all, line[AIR_STRLEN_HUGE];
    airArray *allArr;
    unsigned int allLen;
    unsigned int lineLen, lineIdx, totalLen;
    _tkwbU uu;

    uu.pc = &all;
    allArr = airArrayNew(uu.v, &allLen, sizeof(char*), tkwbArrayIncr);
    airArrayPointerCB(allArr, airNull, airFree);
    lineLen = airOneLine(file, line, AIR_STRLEN_HUGE);
    totalLen = 0;
    while (lineLen && (!( airStrlen(stop) && !strcmp(line, stop) )) ) {
        lineIdx = airArrayLenIncr(allArr, 1); /* HEY error checking */
        all[lineIdx] = (char *)calloc(strlen(line) + strlen("\n") + 1,
                                      sizeof(char));
        sprintf(all[lineIdx], "%s\n", line);
        totalLen += strlen(line) + 1;
        lineLen = airOneLine(file, line, AIR_STRLEN_HUGE);
    }
    if (hitEOF) {
        *hitEOF = !lineLen;
    }

    *strP = (char*)calloc(totalLen+1, sizeof(char));
    strcpy(*strP, "");
    for (lineIdx=0; lineIdx<allLen; lineIdx++) {
        strcat(*strP, all[lineIdx]);
    }

    airArrayNuke(allArr);
    return 0;
}
Example #4
0
NrrdIoState *
nrrdIoStateNew(void)
{
  NrrdIoState *nio;

  nio = (NrrdIoState *)calloc(1, sizeof(NrrdIoState));
  if (nio)
  {
    nio->path = NULL;
    nio->base = NULL;
    nio->line = NULL;
    nio->dataFNFormat = NULL;
    nio->dataFN = NULL;
    nio->headerStringRead = NULL;
    nio->headerStringWrite = NULL;
    void* pvoid = (void*)&(nio->dataFN);
    nio->dataFNArr = airArrayNew((void**)pvoid, NULL,
                                 sizeof(char *), NRRD_FILENAME_INCR);
    airArrayPointerCB(nio->dataFNArr, airNull, airFree);
    nio->format = nrrdFormatUnknown;
    nio->encoding = nrrdEncodingUnknown;
    nrrdIoStateInit(nio);
  }
  return nio;
}
char *
_nrrdGetQuotedString(char **hP, int useBiff) {
  char me[]="_nrrdGetQuotedString", err[BIFF_STRLEN], *h, *buff, *ret;
  airArray *buffArr;
  int pos;
  _chpu uu;
  
  h = *hP;
  /* skip past space */
  /* printf("!%s: h |%s|\n", me, h);*/
  h += strspn(h, _nrrdFieldSep);
  /* printf("!%s: h |%s|\n", me, h);*/

  /* make sure we have something */
  if (!*h) {
    sprintf(err, "%s: hit end of string before seeing opening \"", me);
    biffMaybeAdd(NRRD, err, useBiff); return NULL;
  }
  /* make sure we have a starting quote */
  if ('"' != *h) {
    sprintf(err, "%s: didn't start with \"", me);
    biffMaybeAdd(NRRD, err, useBiff); return NULL;
  }
  h++;
    
  /* parse string until end quote */
  buff = NULL;
  uu.c = &buff;
  buffArr = airArrayNew(uu.v, NULL, sizeof(char), 2);
  if (!buffArr) {
    sprintf(err, "%s: couldn't create airArray", me);
      biffMaybeAdd(NRRD, err, useBiff); return NULL;
  }
  pos = airArrayLenIncr(buffArr, 1);  /* pos should get 0 */
  while (h[pos]) {
    /* printf("!%s: h+%d |%s|\n", me, pos, h+pos); */
    if ('\"' == h[pos]) {
      break;
    }
    if ('\\' == h[pos] && '\"' == h[pos+1]) {
      h += 1;
    }
    buff[pos] = h[pos];
    pos = airArrayLenIncr(buffArr, 1);
  }
  if ('\"' != h[pos]) {
    sprintf(err, "%s: didn't see ending \" soon enough", me);
    biffMaybeAdd(NRRD, err, useBiff); return NULL;
  }
  h += pos + 1;
  buff[pos] = 0;

  ret = airStrdup(buff);
  airArrayNuke(buffArr);
  *hP = h;
  
  return ret;
}
Example #6
0
/*
** because the pullContext keeps an array of bins (not pointers to them)
** we have Init and Done functions (not New and Nix)
*/
void
_pullBinInit(pullBin *bin, unsigned int incr) {

  bin->point = NULL;
  bin->pointNum = 0;
  bin->pointArr = airArrayNew((void**)&(bin->point), &(bin->pointNum),
                              sizeof(pullPoint *), incr);
  bin->neighBin = NULL;
  return;
}
Example #7
0
/*
** because the pushContext keeps an array of bins (not pointers to them)
** we have Init and Done functions (not New and Nix)
*/
void
pushBinInit(pushBin *bin, unsigned int incr) {
  pushPtrPtrUnion pppu;

  bin->pointNum = 0;
  bin->point = NULL;
  bin->pointArr = airArrayNew((pppu.point = &(bin->point), pppu.v),
                              &(bin->pointNum),
                              sizeof(pushPoint *), incr);
  bin->neighbor = NULL;
  return;
}
Example #8
0
/* Creates a new heap, returning NULL upon error.  If additional data
 * is to be stored with each node, dataUnit needs to be set to the
 * number of data bytes needed per element.  incr is used for dynamic
 * memory allocation (an additional number of incr elements are
 * allocated each time the heap grows past its current capacity).
 */
airHeap *airHeapNew(size_t dataUnit, unsigned int incr) {
  airHeap *h;
  h = AIR_CALLOC(1, airHeap);
  if (h==NULL) {
    return NULL;
  }

  h->key_a = airArrayNew((void**)&h->key, NULL, sizeof(double), incr);
  if (dataUnit>0) { /* data is optional */
    h->data_a = airArrayNew((void**)&h->data, NULL, dataUnit, incr);
  }
  h->idx_a = airArrayNew((void**)&h->idx, NULL, sizeof(unsigned int), incr);
  h->invidx_a = airArrayNew((void**)&h->invidx, NULL, sizeof(unsigned int),
			    incr);

  if (h->key_a==NULL || (dataUnit>0 && h->data_a==NULL) || h->idx_a==NULL ||
      h->invidx_a==NULL) { /* allocation failed (partly) */
    airHeapNuke(h);
    return NULL;
  }
  return h;
}
Example #9
0
echoScene *
echoSceneNew(void) {
  echoScene *ret;
  
  ret = (echoScene *)calloc(1, sizeof(echoScene));
  if (ret) {
    ret->cat = NULL;
    ret->catArr = airArrayNew((void**)&(ret->cat), NULL,
                              sizeof(echoObject *),
                              ECHO_LIST_OBJECT_INCR);
    airArrayPointerCB(ret->catArr,
                      airNull,
                      (void *(*)(void *))echoObjectNix);
    ret->rend = NULL;
    ret->rendArr = airArrayNew((void**)&(ret->rend), NULL,
                               sizeof(echoObject *),
                               ECHO_LIST_OBJECT_INCR);
    /* no callbacks set, renderable objecs are nixed from catArr */
    ret->light = NULL;
    ret->lightArr = airArrayNew((void**)&(ret->light), NULL,
                                sizeof(echoObject *),
                                ECHO_LIST_OBJECT_INCR);
    /* no callbacks set; light objects are nixed from catArr */
    ret->nrrd = NULL;
    ret->nrrdArr = airArrayNew((void**)&(ret->nrrd), NULL,
                               sizeof(Nrrd *),
                               ECHO_LIST_OBJECT_INCR);
    airArrayPointerCB(ret->nrrdArr,
                      airNull,
                      (void *(*)(void *))nrrdNuke);
    ret->envmap = NULL;
    ELL_3V_SET(ret->ambi, 1.0, 1.0, 1.0);
    ELL_3V_SET(ret->bkgr, 0.0, 0.0, 0.0);
  }
  return ret;
}
/*
** _biffInit()
**
** allocates data structers needed by biff.  Panics and exit(1)s if 
** anything goes wrong.  Can be harmlessly called multiple times.
*/
void
_biffInit(void) {
  char me[]="_biffInit";
  _beu uu;

  uu.b = &_biffErr;
  if (!_biffAA) {
    _biffAA = airArrayNew(uu.v, &_biffNum, sizeof(_biffEntry*), _BIFF_INCR);
    if (!_biffAA) {
      fprintf(stderr, "%s: PANIC: couldn't allocate internal data\n", me);
      exit(1);
    }
  }
  return;
}
Example #11
0
int
miteRayBegin(miteThread *mtt, miteRender *mrr, miteUser *muu,
             int uIndex, int vIndex,
             double rayLen,
             double rayStartWorld[3], double rayStartIndex[3],
             double rayDirWorld[3], double rayDirIndex[3]) {
  airPtrPtrUnion appu;
  AIR_UNUSED(mrr);
  AIR_UNUSED(rayStartWorld);
  AIR_UNUSED(rayStartIndex);
  AIR_UNUSED(rayDirIndex);

  mtt->ui = uIndex;
  mtt->vi = vIndex;
  mtt->rayStep = (muu->rayStep*rayLen /
                  (muu->hctx->cam->vspFaar - muu->hctx->cam->vspNeer));
  if (!uIndex) {
    fprintf(stderr, "%d/%d ", vIndex, muu->hctx->imgSize[1]);
    fflush(stderr);
  }
  mtt->verbose = (uIndex == muu->verbUi && vIndex == muu->verbVi);
  mtt->skip = (muu->verbUi >= 0 && muu->verbVi >= 0
               && !mtt->verbose);
  if (mtt->verbose) {
    /* create muu->ndebug */
    muu->ndebug = nrrdNew();
    /* we want to store the value and index for each txf domain variable,
       plus the RGBAZ computed for that sample */
    muu->ndebug->axis[0].size = 2*mtt->stageNum + 5;
    /* we really do want to associate ndebug with the miteUser's mop,
       because the information stored in it has to persist for as long as
       the user wants: mite itself doesn't call miteUserNix */
    airMopAdd(muu->umop, muu->ndebug, (airMopper)nrrdNuke, airMopAlways);
    /* but the scope of the debug array allocation is within this ray */
    muu->debugArr = airArrayNew((appu.d = &(muu->debug), appu.v),
                                NULL, sizeof(double), 128);
  }
  mtt->raySample = 0;
  mtt->RR = mtt->GG = mtt->BB = 0.0;
  mtt->TT = 1.0;
  mtt->ZZ = AIR_NAN;
  ELL_3V_SCALE(mtt->V, -1, rayDirWorld);

  return 0;
}
Example #12
0
/*
** _bmsgStart()
**
** allocates data structers needed by biff.  Panics if
** anything goes wrong.
**
** NOTE: Can be harmlessly called multiple times.
*/
static void
_bmsgStart(void) {
  static const char me[]="[biff] _bmsgStart";
  _beu uu;

  if (_bmsgArr) {
    /* its non-NULL, must have been called already */
    return;
  }
  uu.b = &_bmsg;
  _bmsgArr = airArrayNew(uu.v, &_bmsgNum, sizeof(biffMsg*), __INCR);
  if (!_bmsgArr) {
    fprintf(stderr, "%s: PANIC: couldn't allocate internal data\n", me);
    /* exit(1); */
  }
  /* airArrayPointerCB(_bmsgArr, NULL, (airMopper)biffMsgNix);*/
  return;
}
/*
** _biffNewEntry()
**
** creates and initializes one new _biffEntry, returning a pointer to it
** panics and exit(1)s if there is a problem.
*/
_biffEntry *
_biffNewEntry(const char *key) {
  char me[]="_biffInitEntry";
  _biffEntry *ent;

  ent = (_biffEntry *)calloc(1, sizeof(_biffEntry));
  if (!ent) {
    fprintf(stderr, "%s: couldn't make entry for new key \"%s\"\n", me, key);
    exit(1);
  }
  strcpy(ent->key, key);
  ent->AA = airArrayNew((void**)&(ent->err),
                        &(ent->num), sizeof(char*), _BIFF_INCR);
  if (!ent->AA) {
    fprintf(stderr, "%s: couldn't make array for new key \"%s\"\n", me, key);
    exit(1);
  }
  airArrayPointerCB(ent->AA, NULL, airFree);
  return ent;
}
Example #14
0
/*
** the reason to take the pushContext *pctx argument is to allow
** doling out the ttaagg ID
*/
pushPoint *
pushPointNew(pushContext *pctx) {
  pushPoint *pnt;

  if (pctx) {
    pnt = AIR_CAST(pushPoint *, calloc(1, sizeof(pushPoint)));
    if (pnt) {
      pnt->ttaagg = pctx->ttaagg++;
      ELL_3V_SET(pnt->pos, AIR_NAN, AIR_NAN, AIR_NAN);
      ELL_3V_SET(pnt->frc, AIR_NAN, AIR_NAN, AIR_NAN);
      TEN_T_SET(pnt->ten, AIR_NAN, AIR_NAN, AIR_NAN,
                AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN);
      TEN_T_SET(pnt->inv, AIR_NAN, AIR_NAN, AIR_NAN,
                AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN);
      ELL_3V_SET(pnt->cnt, AIR_NAN, AIR_NAN, AIR_NAN);
      pnt->grav = AIR_NAN;
      ELL_3V_SET(pnt->gravGrad, AIR_NAN, AIR_NAN, AIR_NAN);
      pnt->seedThresh = AIR_NAN;
      pnt->enr = DBL_MAX;  /* any finite quantity will be less than this */

      pnt->neighArr = airArrayNew((void**)&(pnt->neigh), &(pnt->neighNum),
                                  sizeof(pushPoint *), 10);
    }
  } else {
Example #15
0
int
tkwbReadSlides(tkwbSlide ***slideP, char *filename, airArray *pmop) {
    char me[]="tkwbReadSlides", err[BIFF_STRLEN];
    FILE *file;
    airArray *mop, *slideArr;
    tkwbSlide **slide = NULL;
    char *title, *image, *text, stop[AIR_STRLEN_HUGE], line[AIR_STRLEN_HUGE];
    int slideIdx=0, hitEOF, notReally;
    unsigned int len;
    _tkwbU uu;

    mop = airMopNew();
    if (!( file = airFopen(filename, stdin, "rb") )) {
        sprintf(err, "%s: couldn't open %s: %s", me, filename, strerror(errno));
        biffAdd(TKWB, err);
        airMopError(mop);
        return 1;
    }
    airMopAdd(mop, file, (airMopper)airFclose, airMopAlways);

    len = airOneLine(file, stop, AIR_STRLEN_HUGE);
    if (!( len > 1 )) {
        sprintf(err, "%s: didn't get a stop delimiter from %s", me, filename);
        biffAdd(TKWB, err);
        airMopError(mop);
        return 1;
    }

    uu.ps = &slide;
    slideArr = airArrayNew(uu.v, NULL,
                           sizeof(tkwbSlide*), tkwbArrayIncr);
    airMopAdd(mop, slideArr, (airMopper)airArrayNix, airMopAlways);
    hitEOF = notReally = AIR_FALSE;
    while (!hitEOF) {
        slideIdx = airArrayLenIncr(slideArr, 1); /* HEY error checking */
        len = airOneLine(file, line, AIR_STRLEN_HUGE);
        if (!len) {
            /* got EOF after a division marker, that's okay */
            notReally = AIR_TRUE;
            break;
        }
        title = airStrdup(line);
        len = airOneLine(file, line, AIR_STRLEN_HUGE);
        if (!len) {
            break;
        }
        image = airStrdup(line);
        if (tkwbReadFileToString(&text, &hitEOF, file, stop)) {
            sprintf(err, "%s: couldn't read in slide %d", me, slideIdx);
            biffAdd(TKWB, err);
            airMopError(mop);
            return 1;
        }
        slide[slideIdx] = tkwbSlideNew(title, image, text);
        airMopAdd(pmop, slide[slideIdx], (airMopper)tkwbSlideNix, airMopAlways);
    }
    if (!hitEOF && !notReally) {
        sprintf(err, "%s: got incomplete slide info for slide %d\n", me, slideIdx);
        biffAdd(TKWB, err);
        airMopError(mop);
        return 1;
    }
    if (!notReally) {
        slideIdx = airArrayLenIncr(slideArr, 1); /* HEY error checking */
    }
    slide[slideIdx] = NULL;

    *slideP = slide;
    airMopOkay(mop);
    return 0;
}
Example #16
0
airArray *
airMopNew()
{

    return airArrayNew(NULL, NULL, sizeof(airMop), AIR_MOP_INCR);
}
/*
******** tenFiberTraceSet
**
** slightly more flexible API for fiber tracking than tenFiberTrace
**
** EITHER: pass a non-NULL nfiber, and NULL, 0, NULL, NULL for 
** the following arguments, and things are the same as with tenFiberTrace:
** data inside the nfiber is allocated, and the tract vertices are copied
** into it, having been stored in dynamically allocated airArrays
**
** OR: pass a NULL nfiber, and a buff allocated for 3*(2*halfBuffLen + 1)
** (note the "+ 1" !!!) doubles.  The fiber tracking on each half will stop
** at halfBuffLen points. The given seedpoint will be stored in
** buff[0,1,2 + 3*halfBuffLen].  The indices for the end of the first
** tract half, and the end of the second tract half, will be set in
** *startIdxP and *endIdxP respectively.
*/
int
tenFiberTraceSet(tenFiberContext *tfx, Nrrd *nfiber,
                 double *buff, unsigned int halfBuffLen,
                 unsigned int *startIdxP, unsigned int *endIdxP,
                 double seed[3]) {
  char me[]="tenFiberTraceSet", err[BIFF_STRLEN];
  airArray *fptsArr[2];      /* airArrays of backward (0) and forward (1)
                                fiber points */
  double *fpts[2];           /* arrays storing forward and backward
                                fiber points */
  double
    tmp[3],
    iPos[3],
    currPoint[3], 
    forwDir[3],
    *fiber;                  /* array of both forward and backward points, 
                                when finished */
  int ret, whyStop, buffIdx, fptsIdx, outIdx, oldStop;
  unsigned int i;
  airArray *mop;

  if (!(tfx)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(TEN, err); return 1;
  }
  /* HEY: a hack to preserve the state inside tenFiberContext so that
     we have fewer side effects (tfx->maxNumSteps may still be set) */
  oldStop = tfx->stop;
  if (!nfiber) {
    if (!( buff && halfBuffLen > 0 && startIdxP && startIdxP )) {
      sprintf(err, "%s: need either non-NULL nfiber or fpts buffer info", me);
      biffAdd(TEN, err); return 1;
    }
    if (tenFiberStopSet(tfx, tenFiberStopNumSteps, halfBuffLen)) {
      sprintf(err, "%s: error setting new fiber stop", me);
      biffAdd(TEN, err); return 1;
    }
  }

  /* initialize the quantities which describe the fiber halves */
  tfx->halfLen[0] = tfx->halfLen[1] = 0.0;
  tfx->numSteps[0] = tfx->numSteps[1] = 0;
  tfx->whyStop[0] = tfx->whyStop[1] = tenFiberStopUnknown;

  /* try probing once */
  if (tfx->useIndexSpace) {
    ret = gageProbe(tfx->gtx,
                    AIR_CAST(gage_t, seed[0]),
                    AIR_CAST(gage_t, seed[1]),
                    AIR_CAST(gage_t, seed[2]));
  } else {
    gageShapeWtoI(tfx->gtx->shape, tmp, seed);
    ret = gageProbe(tfx->gtx,
                    AIR_CAST(gage_t, tmp[0]),
                    AIR_CAST(gage_t, tmp[1]),
                    AIR_CAST(gage_t, tmp[2]));
  }
  if (ret) {
    sprintf(err, "%s: first gageProbe failed: %s (%d)", 
            me, tfx->gtx->errStr, tfx->gtx->errNum);
    biffAdd(TEN, err); return 1;
  }

  /* see if we're doomed */
  if ((whyStop = _tenFiberStopCheck(tfx))) {
    /* stopped immediately at seed point, but that's not an error */
    tfx->whyNowhere = whyStop;
    if (nfiber) {
      nrrdEmpty(nfiber);
    } else {
      *startIdxP = *endIdxP = 0;
    }
    return 0;
  } else {
    /* did not immediately halt */
    tfx->whyNowhere = tenFiberStopUnknown;
  }

  /* record the principal eigenvector at the seed point, which
     is needed to align the 4 intermediate steps of RK4 for the
     FIRST step of each half of the tract */
  ELL_3V_COPY(tfx->firstEvec, tfx->evec + 3*0);

  /* airMop{Error,Okay}() can safely be called on NULL */
  mop = nfiber ? airMopNew() : NULL;

  for (tfx->dir=0; tfx->dir<=1; tfx->dir++) {
    if (nfiber) {
      fptsArr[tfx->dir] = airArrayNew((void**)&(fpts[tfx->dir]), NULL, 
                                      3*sizeof(double), TEN_FIBER_INCR);
      airMopAdd(mop, fptsArr[tfx->dir], (airMopper)airArrayNuke, airMopAlways);
      buffIdx = -1;
    } else {
      fptsArr[tfx->dir] = NULL;
      fpts[tfx->dir] = NULL;
      buffIdx = halfBuffLen;
      fptsIdx = -1;
    }
    tfx->halfLen[tfx->dir] = 0;
    if (tfx->useIndexSpace) {
      ELL_3V_COPY(iPos, seed);
      gageShapeItoW(tfx->gtx->shape, tfx->wPos, iPos);
    } else {
      gageShapeWtoI(tfx->gtx->shape, iPos, seed);
      ELL_3V_COPY(tfx->wPos, seed);
    }
    ELL_3V_SET(tfx->lastDir, 0, 0, 0);
    tfx->lastDirSet = AIR_FALSE;
    for (tfx->numSteps[tfx->dir] = 0; AIR_TRUE; tfx->numSteps[tfx->dir]++) {
      if (_tenFiberProbe(tfx, tfx->wPos)) {
        /* even if gageProbe had an error OTHER than going out of bounds,
           we're not going to report it any differently here, alas */
        tfx->whyStop[tfx->dir] = tenFiberStopBounds;
        break;
      }
      if ((whyStop = _tenFiberStopCheck(tfx))) {
        if (tenFiberStopNumSteps == whyStop) {
          /* we stopped along this direction because tfx->numSteps[tfx->dir]
             exceeded tfx->maxNumSteps.  Okay.  But tfx->numSteps[tfx->dir]
             is supposed to be a record of how steps were (successfully)
             taken.  So we need to decrementing before moving on ... */
          tfx->numSteps[tfx->dir]--;
        }
        tfx->whyStop[tfx->dir] = whyStop;
        break;
      }
      if (tfx->useIndexSpace) {
        gageShapeWtoI(tfx->gtx->shape, iPos, tfx->wPos);
        ELL_3V_COPY(currPoint, iPos);
      } else {
        ELL_3V_COPY(currPoint, tfx->wPos);
      }
      if (nfiber) {
        fptsIdx = airArrayLenIncr(fptsArr[tfx->dir], 1);
        ELL_3V_COPY(fpts[tfx->dir] + 3*fptsIdx, currPoint);
      } else {
        ELL_3V_COPY(buff + 3*buffIdx, currPoint);
        /*
        fprintf(stderr, "!%s: (dir %d) saving to %d pnt %g %g %g\n", me,
                tfx->dir, buffIdx,
                currPoint[0], currPoint[1], currPoint[2]);
        */
        buffIdx += !tfx->dir ? -1 : 1;
      }
      /* forwDir is set by this to point to the next fiber point */
      if (_tenFiberIntegrate[tfx->intg](tfx, forwDir)) {
        tfx->whyStop[tfx->dir] = tenFiberStopBounds;
        break;
      }
      ELL_3V_COPY(tfx->lastDir, forwDir);
      tfx->lastDirSet = AIR_TRUE;
      ELL_3V_ADD2(tfx->wPos, tfx->wPos, forwDir);
      tfx->halfLen[tfx->dir] += ELL_3V_LEN(forwDir);
    }
  }

  if (nfiber) {
    if (nrrdMaybeAlloc_va(nfiber, nrrdTypeDouble, 2,
                          AIR_CAST(size_t, 3),
                          AIR_CAST(size_t, (fptsArr[0]->len 
                                            + fptsArr[1]->len - 1)))) {
      sprintf(err, "%s: couldn't allocate fiber nrrd", me);
      biffMove(TEN, err, NRRD); airMopError(mop); return 1;
    }
    fiber = (double*)(nfiber->data);
    outIdx = 0;
    for (i=fptsArr[0]->len-1; i>=1; i--) {
      ELL_3V_COPY(fiber + 3*outIdx, fpts[0] + 3*i);
      outIdx++;
    }
    for (i=0; i<=fptsArr[1]->len-1; i++) {
      ELL_3V_COPY(fiber + 3*outIdx, fpts[1] + 3*i);
      outIdx++;
    }
  } else {
    *startIdxP = halfBuffLen - tfx->numSteps[0];
    *endIdxP = halfBuffLen + tfx->numSteps[1];
  }

  tfx->stop = oldStop;
  airMopOkay(mop);
  return 0;
}
Example #18
0
/*
** nio->byteSkip < 0 functionality contributed by Katharina Quintus
*/
static int
_nrrdEncodingGzip_read(FILE *file, void *_data, size_t elNum,
                       Nrrd *nrrd, NrrdIoState *nio) {
  static const char me[]="_nrrdEncodingGzip_read";
#if TEEM_ZLIB
  size_t sizeData, sizeRed;
  int error;
  long int bi;
  unsigned int didread, sizeChunk, maxChunk;
  char *data;
  gzFile gzfin;
  airPtrPtrUnion appu;

  sizeData = nrrdElementSize(nrrd)*elNum;
  /* Create the gzFile for reading in the gzipped data. */
  if ((gzfin = _nrrdGzOpen(file, "rb")) == Z_NULL) {
    /* there was a problem */
    biffAddf(NRRD, "%s: error opening gzFile", me);
    return 1;
  }

  /* keeps track of how many bytes have been successfully read in */
  sizeRed = 0;

  /* zlib can only handle data sizes up to UINT_MAX ==> if there's more than
     UINT_MAX bytes to read in, we read in in chunks. However, we wrap a value
     _nrrdZlibMaxChunk around UINT_MAX for testing purposes.  Given how
     sizeChunk is used below, we also cap chunk size at _nrrdZlibMaxChunk/2 to
     prevent overflow. */
  maxChunk = _nrrdZlibMaxChunk/2;
  sizeChunk = AIR_CAST(unsigned int, AIR_MIN(sizeData, maxChunk));

  if (nio->byteSkip < 0) {
    /* We don't know the size of the size to skip before the data, so
       decompress the data first into a temporary memory buffer.  Then
       the byteskipping is then just memcpy-ing the appropriate region
       of memory from "buff" into the given "_data" pointer */
    char *buff;
    airArray *buffArr;
    long backwards;

    /* setting the airArray increment to twice the chunk size means that for
       headers that are small compared to the data, the airArray never
       actually has to reallocate.  The unit is 1 because we are managing
       the reading in terms of bytes (sizeof(char)==1 by definition) */
    buff = NULL;
    appu.c = &buff;
    buffArr = airArrayNew(appu.v, NULL, 1, 2*sizeChunk);
    airArrayLenSet(buffArr, sizeChunk);
    if (!( buffArr && buffArr->data )) {
      biffAddf(NRRD, "%s: couldn't initialize airArray\n", me);
      return 1;
    }

    /* we keep reading in chunks as long as there hasn't been an error,
       and we haven't hit EOF (EOF signified by read == 0).  Unlike the
       code below (for positive byteskip), we are obligated to read until
       the bitter end, and can't update sizeChunk to encompass only the
       required data. */
    while (!(error = _nrrdGzRead(gzfin, buff + sizeRed,
                                 sizeChunk, &didread))
           && didread > 0) {
      sizeRed += didread;
      if (didread >= sizeChunk) {
        /* we were able to read as much data as we requested, maybe there is
           more, so we need to make our temp buffer bigger */
        unsigned int newlen = buffArr->len + sizeChunk;
        if (newlen < buffArr->len) {
          biffAddf(NRRD, "%s: array size will exceed uint capacity", me);
          return 1;
        }
        airArrayLenSet(buffArr, newlen);
        if (!buffArr->data) {
          biffAddf(NRRD, "%s: couldn't re-allocate data buffer", me);
          return 1;
        }
      }
    }
    if (error) {
      biffAddf(NRRD, "%s: error reading from gzFile", me);
      return 1;
    }
    /* backwards is (positive) number of bytes AFTER data that we ignore */
    backwards = -nio->byteSkip - 1;
    if (sizeRed < sizeData + AIR_CAST(size_t, backwards)) {
      char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL];
      biffAddf(NRRD, "%s: expected %s bytes but received only %s", me,
               airSprintSize_t(stmp1, sizeData + AIR_CAST(size_t, backwards)),
               airSprintSize_t(stmp2, sizeRed));
      return 1;
    }
    /* also handles nio->byteSkip == -N-1 signifying extra N bytes at end */
    memcpy(_data, buff + sizeRed - sizeData - backwards, sizeData);
    airArrayNuke(buffArr);
  } else {
    /* no negative byteskip: after byteskipping, we can read directly
       into given data buffer */
    if (nio->byteSkip > 0) {
      for (bi=0; bi<nio->byteSkip; bi++) {
        unsigned char b;
        /* Check to see if a single byte was able to be read. */
        if (_nrrdGzRead(gzfin, &b, 1, &didread) != 0 || didread != 1) {
          biffAddf(NRRD, "%s: hit an error skipping byte %ld of %ld",
                   me, bi, nio->byteSkip);
          return 1;
        }
      }
    }
    /* Pointer to chunks as we read them. */
    data = AIR_CAST(char *, _data);
    while (!(error = _nrrdGzRead(gzfin, data, sizeChunk, &didread))
           && didread > 0) {
      /* Increment the data pointer to the next available chunk. */
      data += didread;
      sizeRed += didread;
      /* We only want to read as much data as we need, so we need to check
         to make sure that we don't request data that might be there but that
         we don't want.  This will reduce sizeChunk when we get to the last
         block (which may be smaller than the original sizeChunk). */
      if (sizeData >= sizeRed
          && sizeData - sizeRed < sizeChunk) {
        sizeChunk = AIR_CAST(unsigned int, sizeData - sizeRed);
      }
    }
    if (error) {
      biffAddf(NRRD, "%s: error reading from gzFile", me);
      return 1;
    }
    /* Check to see if we got out as much as we thought we should. */
    if (sizeRed != sizeData) {
      char stmp1[AIR_STRLEN_SMALL], stmp2[AIR_STRLEN_SMALL];
      biffAddf(NRRD, "%s: expected %s bytes but received %s", me,
               airSprintSize_t(stmp1, sizeData),
               airSprintSize_t(stmp2, sizeRed));
      return 1;
    }
  }
int
_limnReadCamanim(int imgSize[2], limnCamera **keycamP, double **timeP,
                 unsigned int *numKeysP, FILE *fin) {
  char me[]="_limnReadCamanim", err[AIR_STRLEN_MED];
  char line[AIR_STRLEN_HUGE];
  unsigned int ki;
  double *tmp, *dwell, di, dn, df, fr[3], at[3], up[3], va;
  airArray *mop, *camA, *dwellA;
  
  if (!( 0 < airOneLine(fin, line, AIR_STRLEN_HUGE)
         && !strcmp(_LIMNMAGIC, line) )) {
    sprintf(err, "%s: couldn't read first line or it wasn't \"%s\"",
            me, _LIMNMAGIC);
    biffAdd(LIMN, err); return 1;
  }
  if (!( 0 < airOneLine(fin, line, AIR_STRLEN_HUGE)
         && 2 == (airStrtrans(airStrtrans(line, '{', ' '), '}', ' '),
                  sscanf(line, "imgSize %d %d", imgSize+0, imgSize+1)) )) {
    sprintf(err, "%s: couldn't read second line or it wasn't "
            "\"imgSize <sizeX> <sizeY>\"", me);
    biffAdd(LIMN, err); return 1;
  }
  
  mop = airMopNew();
  camA = airArrayNew((void **)keycamP, numKeysP, sizeof(limnCamera), 1);
  dwellA = airArrayNew((void **)&dwell, NULL, sizeof(double), 1);
  airMopAdd(mop, camA, (airMopper)airArrayNix, airMopAlways);
  airMopAdd(mop, dwellA, (airMopper)airArrayNuke, airMopAlways);

  while ( 0 < airOneLine(fin, line, AIR_STRLEN_HUGE) ) {
    airStrtrans(airStrtrans(line, '{', ' '), '}', ' ');
    ki = airArrayLenIncr(camA, 1);
    airArrayLenIncr(dwellA, 1);
    if (14 != sscanf(line, "cam.di %lg cam.at %lg %lg %lg "
                     "cam.up %lg %lg %lg cam.dn %lg cam.df %lg cam.va %lg "
                     "relDwell %lg cam.fr %lg %lg %lg",
                     &di, at+0, at+1, at+2,
                     up+0, up+1, up+2, &dn, &df, &va,
                     dwell+ki, fr+0, fr+1, fr+2)) {
      sprintf(err, "%s: trouble parsing line %d: \"%s\"", me, ki, line);
      biffAdd(LIMN, err); airMopError(mop); return 1;
    }
    (*keycamP)[ki].neer = dn;
    (*keycamP)[ki].faar = df;
    (*keycamP)[ki].dist = di;
    ELL_3V_COPY((*keycamP)[ki].from, fr);
    ELL_3V_COPY((*keycamP)[ki].at, at);
    ELL_3V_COPY((*keycamP)[ki].up, up);
    (*keycamP)[ki].fov = va;
    (*keycamP)[ki].aspect = (double)imgSize[0]/imgSize[1];
    (*keycamP)[ki].atRelative = AIR_FALSE;
    (*keycamP)[ki].orthographic = AIR_FALSE;
    (*keycamP)[ki].rightHanded = AIR_TRUE;
  }

  tmp = (double*)calloc(*numKeysP, sizeof(double));
  airMopAdd(mop, tmp, airFree, airMopAlways);
  *timeP = (double*)calloc(*numKeysP, sizeof(double));
  for (ki=0; ki<*numKeysP; ki++) {
    dwell[ki] = AIR_CLAMP(0, dwell[ki], 2);
    tmp[ki] = tan(AIR_AFFINE(-0.01, dwell[ki], 2.01, 0.0, AIR_PI/2));
  }
  (*timeP)[0] = 0;
  for (ki=1; ki<*numKeysP; ki++) {
    (*timeP)[ki] = (*timeP)[ki-1] + (tmp[ki-1] + tmp[ki])/2;
  } 
  for (ki=0; ki<*numKeysP; ki++) {
    (*timeP)[ki] /= (*timeP)[*numKeysP-1];
  }

  airMopOkay(mop);
  return 0;
}
Example #20
0
int
main(int argc, char *argv[]) {
  char *me, *fname, *incrS;
  airArray *mop, *dataArr;
  FILE *file;
  unsigned int incr, numRed;
  unsigned char *data;
  int datum; /* must be int, so it can store EOF */
  airPtrPtrUnion appu;

  me = argv[0];
  if (3 != argc) {
    /*                      0      1         2    (3) */
    fprintf(stderr, "usage: %s <filename> <incr>\n", me);
    return 1;
  }
  fname = argv[1];
  incrS = argv[2];

  /* the "mop" is for management of dynamically allocated resources
     cleanly in combination with error handling, its not important
     for understanding how airArrays work (although as you can tell
     from the declaration, the "mop" is built on an airArray) */

  mop = airMopNew();
  if (!(file = fopen(fname, "rb"))) {
    fprintf(stderr, "%s: couldn't open %s for reading\n", me, fname);
    airMopError(mop); return 1;
  }
  airMopAdd(mop, file, (airMopper)airFclose, airMopAlways);
  if (1 != sscanf(incrS, "%ud", &incr)) {
    fprintf(stderr, "%s: couln't parse incr \"%s\" as unsigned int\n",
            me, incrS);
    airMopError(mop); return 1;
  }

  /* now "file" is the open file that we read from, and "incr is the
     size increment (the granularity) for re-allocating the data */

  /* the arguments here are as follows:
     1) &data: the address of the array (itself a pointer) into which
     we'll copy the data.  Whenever the airArray re-allocates the array,
     it will update the value of the array variable to the new location.
     So, while it seems a little weird at first, the value of the "data"
     variable can change as a side-effect of calling the airArray functions.
     2) NULL: we could pass the address of a variable to record the current
     allocated length of the array, and this might be useful, but isn't
     necessary
     3) sizeof(unsigned char): this is the size of the individual elements
     that we are saving in the array.  Because memory is allocated and
     addressed at the level of individual bytes (and files can be read
     one byte at-a-time), we manage the buffer as an array of unsigned chars.
     4) incr: when the array length is a multiple of incr, the memory
     segment is re-allocated, so this determines how often the re-allocation
     happens (we want it to happen fairly infrequently) */
  /* dataArr = airArrayNew(&data, NULL, sizeof(unsigned char), incr); */
  /* but wait: to play well with type checking, we have to use a stupid
     union to pass in the address of the array.  So, appu.v == &data,
     but the types are right.  We don't do a cast because recent versions
     of gcc will complain about breaking "strict-aliasing rules". */
  appu.uc = &data;
  dataArr = airArrayNew(appu.v, NULL, sizeof(unsigned char), incr);
  if (!dataArr) {
    fprintf(stderr, "%s: couldn't allocate airArray\n", me);
    airMopError(mop); return 1;
  }

  /* numRed will keep track of the number of bytes that have been
     successfully read from the file AND stored in data[] */
  numRed = 0;
  /* try to get the first byte of data */
  datum = fgetc(file);
  if (EOF == datum) {
    fprintf(stderr, "%s: hit EOF trying to get first byte\n", me);
    airMopError(mop); return 1;
  }
  while (EOF != datum) {
    airArrayLenSet(dataArr, numRed+1);
    if (!data) {
      fprintf(stderr, "%s: couldn't re-allocated data buffer\n", me);
      airMopError(mop); return 1;
    }
    /* now "data" is the address of a sufficiently large array */
    data[numRed++] = datum;
    datum = fgetc(file);
  }
  /* loop finishes when there's nothing more to read from file */

  printf("%s: read %u bytes into memory\n", me, numRed);

  /* destroy the airArray, but keep the data allocated */
  airArrayNix(dataArr);

  printf("%s: first value was %u\n", me, data[0]);

  /* free up the data array itself */
  free(data);

  airMopOkay(mop);
  return 0;
}
Example #21
0
void
undosConvert(char *me, char *name, int reverse, int mac,
             int quiet, int noAction) {
  airArray *mop;
  FILE *fin, *fout;
  char *data=NULL;
  airArray *dataArr;
  unsigned int ci;
  int car, numBad, willConvert;
  _undosU uu;

  mop = airMopNew();
  if (!airStrlen(name)) {
    fprintf(stderr, "%s: empty filename\n", me);
    airMopError(mop); return;
  }

  /* -------------------------------------------------------- */
  /* open input file  */
  fin = airFopen(name, stdin, "rb");
  if (!fin) {
    if (!quiet) {
      fprintf(stderr, "%s: couldn't open \"%s\" for reading: \"%s\"\n", 
              me, name, strerror(errno));
    }
    airMopError(mop); return;
  }
  airMopAdd(mop, fin, (airMopper)airFclose, airMopOnError);

  /* -------------------------------------------------------- */
  /* create buffer */
  uu.c = &data;
  dataArr = airArrayNew(uu.v, NULL, sizeof(char), AIR_STRLEN_HUGE);
  if (!dataArr) {
    if (!quiet) {
      fprintf(stderr, "%s: internal allocation error #1\n", me);
    }
    airMopError(mop); return;
  }
  airMopAdd(mop, dataArr, (airMopper)airArrayNuke, airMopAlways);

  /* -------------------------------------------------------- */
  /* read input file, testing for binary-ness along the way */
  numBad = 0;
  car = getc(fin);
  if (EOF == car) {
    if (!quiet) {
      fprintf(stderr, "%s: \"%s\" is empty, skipping ...\n", me, name);
    }
    airMopError(mop); return;
  }
  do {
    ci = airArrayLenIncr(dataArr, 1);
    if (!dataArr->data) {
      if (!quiet) {
        fprintf(stderr, "%s: internal allocation error #2\n", me);
      }
      airMopError(mop); return;
    }
    data[ci] = car;
    numBad += !(isprint(data[ci]) || isspace(data[ci]));
    car = getc(fin);
  } while (EOF != car && BAD_PERC > 100.0*numBad/dataArr->len);
  if (EOF != car) {
    if (!quiet) {
      fprintf(stderr, "%s: more than %g%% of \"%s\" is non-printing, "
              "skipping ...\n", me, BAD_PERC, name);
    }
    airMopError(mop); return;    
  }
  fin = airFclose(fin);

  /* -------------------------------------------------------- */
  /* see if we really need to do anything */
  willConvert = AIR_FALSE;
  if (!strcmp("-", name)) {
    willConvert = AIR_TRUE;
  } else if (reverse) {
    for (ci=0; ci<dataArr->len; ci++) {
      if (mac) {
        if (CR == data[ci]) {
          willConvert = AIR_TRUE;
          break;
        }
      } else {
        if (CR == data[ci] && (ci && LF != data[ci-1])) {
          willConvert = AIR_TRUE;
          break;
        }
      }
    }
  } else {
    for (ci=0; ci<dataArr->len; ci++) {
      if (mac) {
        if (LF == data[ci]) {
          willConvert = AIR_TRUE;
          break;
        }
      } else {
        if (LF == data[ci] && (ci+1<dataArr->len && CR == data[ci+1])) {
          willConvert = AIR_TRUE;
          break;
        }
      }
    }
  }
  if (!willConvert) {
    /* no, we don't need to do anything; quietly quit */
    airMopOkay(mop);
    return;
  } else {
    if (!quiet) {
      fprintf(stderr, "%s: %s \"%s\" %s %s ... \n", me, 
              noAction ? "would convert" : "converting",
              name,
              reverse ? "to" : "from",
              mac ? "MAC" : "DOS");
    }
  }
  if (noAction) {
    /* just joking, we won't actually write anything.
       (yes, even if input was stdin) */
    airMopOkay(mop);
    return;
  }

  /* -------------------------------------------------------- */
  /* open output file */
  fout = airFopen(name, stdout, "wb");
  if (!fout) {
    if (!quiet) {
      fprintf(stderr, "%s: couldn't open \"%s\" for writing: \"%s\"\n", 
              me, name, strerror(errno));
    }
    airMopError(mop); return;
  }
  airMopAdd(mop, fout, (airMopper)airFclose, airMopOnError);

  /* -------------------------------------------------------- */
  /* write output file */
  car = 'a';
  if (reverse) {
    for (ci=0; ci<dataArr->len; ci++) {
      if ((mac && CR == data[ci])
          || (CR == data[ci] && (ci && LF != data[ci-1]))) {
        car = putc(LF, fout);
        if (!mac && EOF != car) {
          car = putc(CR, fout);
        }
      } else {
        car = putc(data[ci], fout);
      }
    }
  } else {
    for (ci=0; EOF != car && ci<dataArr->len; ci++) {
      if ((mac && LF == data[ci])
          || (LF == data[ci] && (ci+1<dataArr->len && CR == data[ci+1]))) {
        car = putc(CR, fout);
        ci += !mac;
      } else {
        car = putc(data[ci], fout);
      }
    }
  }
  if (EOF == car) {
    if (!quiet) {
      fprintf(stderr, "%s: ERROR writing \"%s\" possible data loss !!! "
              "(sorry)\n", me, name);
    }
  }
  fout = airFclose(fout);

  airMopOkay(mop);
  return;
}
Example #22
0
/*
** nio->byteSkip < 0 functionality contributed by Katharina Quintus
*/
int
_nrrdEncodingGzip_read(FILE *file, void *_data, size_t elNum,
                       Nrrd *nrrd, NrrdIoState *nio) {
  char me[]="_nrrdEncodingGzip_read", err[BIFF_STRLEN];
#if TEEM_ZLIB
  size_t sizeData, sizeRed, sizeChunk;
  int error;
  long int bi;
  unsigned int read;
  char *data;
  gzFile gzfin;
  ptrHack hack;

  sizeData = nrrdElementSize(nrrd)*elNum;
  /* Create the gzFile for reading in the gzipped data. */
  if ((gzfin = _nrrdGzOpen(file, "rb")) == Z_NULL) {
    /* there was a problem */
    sprintf(err, "%s: error opening gzFile", me);
    biffAdd(NRRD, err);
    return 1;
  }

  /* keeps track of how many bytes have been successfully read in */
  sizeRed = 0;
  
  /* zlib can only handle data sizes up to UINT_MAX ==> if there's more
     than UINT_MAX bytes to read in, we read in in chunks */
  sizeChunk = AIR_MIN(sizeData, UINT_MAX);
  
  if (nio->byteSkip < 0) { 
    /* We don't know the size of the size to skip before the data, so
       decompress the data first into a temporary memory buffer.  Then
       the byteskipping is then just memcpy-ing the appropriate region
       of memory from "buff" into the given "_data" pointer */
    char *buff;
    airArray *buffArr;
      
    /* setting the airArray increment to twice the chunk size means that for
       headers that are small compared to the data, the airArray never
       actually has to reallocate.  The unit is 1 because we are managing
       the reading in terms of bytes (sizeof(char)==1 by definition) */
    buff = NULL;
    hack.c = &buff;
    buffArr = airArrayNew(hack.v, NULL, 1, 2*sizeChunk);
    airArrayLenSet(buffArr, sizeChunk);
    if (!( buffArr && buffArr->data )) {
      sprintf(err, "%s: couldn't initialize airArray\n", me);
      biffAdd(NRRD, err);
      return 1;
    }
    
    /* we keep reading in chunks as long as there hasn't been an error,
       and we haven't hit EOF (EOF signified by read == 0).  Unlike the
       code below (for positive byteskip), we are obligated to read until
       the bitter end, and can't update sizeChunk to encompass only the 
       required data.  Cast on third arg ok because of AIR_MIN use above */
    while (!(error = _nrrdGzRead(gzfin, buff + sizeRed,
                                 AIR_CAST(unsigned int, sizeChunk),
                                 &read))
           && read > 0) {
      sizeRed += read;
      if (read >= sizeChunk) {
        /* we were able to read as much data as we requested, maybe there is
           more, so we need to make our temp buffer bigger */
        airArrayLenIncr(buffArr, sizeChunk);
        if (!buffArr->data) {
          sprintf(err, "%s: couldn't re-allocate data buffer", me);
          biffAdd(NRRD, err);
          return 1;
        }
      }
    }
    if (error) {
      sprintf(err, "%s: error reading from gzFile", me);
      biffAdd(NRRD, err);
      return 1;
    }
    if (sizeRed < sizeData + (-nio->byteSkip - 1)) {
      sprintf(err, "%s: expected " _AIR_SIZE_T_CNV " bytes and received only "
              _AIR_SIZE_T_CNV " bytes", me,
              AIR_CAST(size_t, sizeData + (-nio->byteSkip - 1)), sizeRed);
      biffAdd(NRRD, err);
      return 1;
    }
    /* also handles nio->byteSkip == -N-1 signifying extra N bytes at end */
    memcpy(_data, buff + sizeRed - sizeData - (-nio->byteSkip - 1), sizeData);
    airArrayNuke(buffArr);
  } else {