/*--------------------------------------------------------------------------*/ int mem_iraf_open(char *filename, int rwmode, int *hdl) /* This routine creates an empty memory buffer, then calls iraf2mem to open the IRAF disk file and convert it to a FITS file in memeory. */ { int status; size_t filesize = 0; /* create a memory file with size = 0 for the FITS converted IRAF file */ status = mem_createmem(filesize, hdl); if (status) { ffpmsg("failed to create empty memory file (mem_iraf_open)"); return(status); } /* convert the iraf file into a FITS file in memory */ status = iraf2mem(filename, memTable[*hdl].memaddrptr, memTable[*hdl].memsizeptr, &filesize, &status); if (status) { mem_close_free(*hdl); /* free up the memory */ ffpmsg("failed to convert IRAF file into memory (mem_iraf_open)"); return(status); } memTable[*hdl].currentpos = 0; /* save starting position */ memTable[*hdl].fitsfilesize=filesize; /* and initial file size */ return(0); }
/*--------------------------------------------------------------------------*/ int mem_write(int hdl, void *buffer, long nbytes) /* write bytes at the current position in the file */ { size_t newsize; char *ptr; if ((size_t) (memTable[hdl].currentpos + nbytes) > *(memTable[hdl].memsizeptr) ) { if (!(memTable[hdl].mem_realloc)) { ffpmsg("realloc function not defined (mem_write)"); return(WRITE_ERROR); } /* Attempt to reallocate additional memory: the memory buffer size is incremented by the larger of: 1 FITS block (2880 bytes) or the defined 'deltasize' parameter */ newsize = maxvalue( (size_t) (((memTable[hdl].currentpos + nbytes - 1) / 2880) + 1) * 2880, *(memTable[hdl].memsizeptr) + memTable[hdl].deltasize); /* call the realloc function */ ptr = (memTable[hdl].mem_realloc)( *(memTable[hdl].memaddrptr), newsize); if (!ptr) { ffpmsg("Failed to reallocate memory (mem_write)"); return(MEMORY_ALLOCATION); } *(memTable[hdl].memaddrptr) = ptr; *(memTable[hdl].memsizeptr) = newsize; } /* now copy the bytes from the buffer into memory */ memcpy( *(memTable[hdl].memaddrptr) + memTable[hdl].currentpos, buffer, nbytes); memTable[hdl].currentpos += nbytes; memTable[hdl].fitsfilesize = maxvalue(memTable[hdl].fitsfilesize, memTable[hdl].currentpos); return(0); }
/*--------------------------------------------------------------------------*/ int ffxypx(double xpos, double ypos, double xref, double yref, double xrefpix, double yrefpix, double xinc, double yinc, double rot, char *type, double *xpix, double *ypix, int *status) { if (*status > 0) return(*status); ffpmsg("This non-GNU version of CFITSIO does not support"); ffpmsg(" celestial coordinate transformations."); return(*status = 503); }
/*--------------------------------------------------------------------------*/ int mem_compress_stdin_open(char *filename, int rwmode, int *hdl) /* This routine reads the compressed input stream and creates an empty memory buffer, then calls mem_uncompress2mem. */ { int status; char *ptr; if (rwmode != READONLY) { ffpmsg( "cannot open compressed input stream with WRITE access (mem_compress_stdin_open)"); return(READONLY_FILE); } /* create a memory file for the uncompressed file */ status = mem_createmem(28800, hdl); if (status) { ffpmsg("failed to create empty memory file (compress_stdin_open)"); return(status); } /* uncompress file into memory */ status = mem_uncompress2mem(filename, stdin, *hdl); if (status) { mem_close_free(*hdl); /* free up the memory */ ffpmsg("failed to uncompress stdin into memory (compress_stdin_open)"); return(status); } /* if we allocated too much memory initially, then free it */ if (*(memTable[*hdl].memsizeptr) > (( (size_t) memTable[*hdl].fitsfilesize) + 256L) ) { ptr = realloc(*(memTable[*hdl].memaddrptr), memTable[*hdl].fitsfilesize); if (!ptr) { ffpmsg("Failed to reduce size of allocated memory (compress_stdin_open)"); return(MEMORY_ALLOCATION); } *(memTable[*hdl].memaddrptr) = ptr; *(memTable[*hdl].memsizeptr) = memTable[*hdl].fitsfilesize; } return(0); }
int gsiftp_open(char *filename, int rwmode, int *handle) { FILE *gsiftpfile; int num_streams; if (getenv("GSIFTP_STREAMS")) { num_streams = (int)getenv("GSIFTP_STREAMS"); } else { num_streams = 1; } if (rwmode) { gsiftpopen = 2; } else { gsiftpopen = 1; } if (gsiftpurl) free(gsiftpurl); gsiftpurl = strdup(filename); if (setjmp(env) != 0) { ffpmsg("Timeout (gsiftp_open)"); goto error; } signal(SIGALRM, signal_handler); alarm(NETTIMEOUT); if (gsiftp_get(filename,&gsiftpfile,num_streams)) { alarm(0); ffpmsg("Unable to open gsiftp file (gsiftp_open)"); ffpmsg(filename); goto error; } fclose(gsiftpfile); signal(SIGALRM, SIG_DFL); alarm(0); return file_open(gsiftp_tmpfile, rwmode, handle); error: alarm(0); signal(SIGALRM, SIG_DFL); return (FILE_NOT_OPENED); }
/*--------------------------------------------------------------------------*/ int ffpprn( fitsfile *fptr, /* I - FITS file pointer */ LONGLONG firstelem, /* I - first vector element to write(1 = 1st) */ LONGLONG nelem, /* I - number of values to write */ int *status) /* IO - error status */ /* Write null values to the primary array. (Doesn't support groups). */ { long row = 1; /* the primary array is represented as a binary table: each group of the primary array is a row in the table, where the first column contains the group parameters and the second column contains the image itself. */ if (fits_is_compressed_image(fptr, status)) { /* this is a compressed image in a binary table */ ffpmsg("writing to compressed image is not supported"); return(*status = DATA_COMPRESSION_ERR); } ffpclu(fptr, 2, row, firstelem, nelem, status); return(*status); }
/*--------------------------------------------------------------------------*/ int mem_truncate(int handle, LONGLONG filesize) /* truncate the file to a new size */ { char *ptr; /* call the memory reallocation function, if defined */ if ( memTable[handle].mem_realloc ) { /* explicit LONGLONG->size_t cast */ ptr = (memTable[handle].mem_realloc)( *(memTable[handle].memaddrptr), (size_t) filesize); if (!ptr) { ffpmsg("Failed to reallocate memory (mem_truncate)"); return(MEMORY_ALLOCATION); } /* if allocated more memory, initialize it to zero */ if ( filesize > *(memTable[handle].memsizeptr) ) { memset(ptr + *(memTable[handle].memsizeptr), 0, ((size_t) filesize) - *(memTable[handle].memsizeptr) ); } *(memTable[handle].memaddrptr) = ptr; *(memTable[handle].memsizeptr) = (size_t) (filesize); } memTable[handle].currentpos = filesize; memTable[handle].fitsfilesize = filesize; return(0); }
/*--------------------------------------------------------------------------*/ int mem_truncate(int handle, OFF_T filesize) /* truncate the file to a new size */ { char *ptr; /* call the memory reallocation function, if defined */ if ( memTable[handle].mem_realloc ) { ptr = (memTable[handle].mem_realloc)( *(memTable[handle].memaddrptr), filesize); if (!ptr) { ffpmsg("Failed to reallocate memory (mem_truncate)"); return(MEMORY_ALLOCATION); } /* if allocated more memory, initialize it to zero */ if ( (size_t) filesize > *(memTable[handle].memsizeptr) ) { memset(ptr + *(memTable[handle].memsizeptr), 0, filesize - *(memTable[handle].memsizeptr) ); } *(memTable[handle].memaddrptr) = ptr; *(memTable[handle].memsizeptr) = filesize; } memTable[handle].fitsfilesize = filesize; return(0); }
/*--------------------------------------------------------------------------*/ int ffiimg(fitsfile *fptr, /* I - FITS file pointer */ int bitpix, /* I - bits per pixel */ int naxis, /* I - number of axes in the array */ long *naxes, /* I - size of each axis */ int *status) /* IO - error status */ /* insert an IMAGE extension following the current HDU */ { LONGLONG tnaxes[99]; int ii; if (*status > 0) return(*status); if (naxis > 99) { ffpmsg("NAXIS value is too large (>99) (ffiimg)"); return(*status = 212); } for (ii = 0; (ii < naxis); ii++) tnaxes[ii] = naxes[ii]; ffiimgll(fptr, bitpix, naxis, tnaxes, status); return(*status); }
/*--------------------------------------------------------------------------*/ int mem_close_comp(int handle) /* compress the memory file, writing it out to the fileptr (which might be stdout) */ { int status = 0; size_t compsize; /* compress file in memory to a .gz disk file */ if(compress2file_from_mem(memTable[handle].memaddr, memTable[handle].fitsfilesize, memTable[handle].fileptr, &compsize, &status ) ) { ffpmsg("failed to copy memory file to file (mem_close_comp)"); status = WRITE_ERROR; } free( memTable[handle].memaddr ); /* free the memory */ memTable[handle].memaddrptr = 0; memTable[handle].memaddr = 0; /* close the compressed disk file (except if it is 'stdout' */ if (memTable[handle].fileptr != stdout) fclose(memTable[handle].fileptr); return(status); }
/*--------------------------------------------------------------------------*/ int ffpprd( fitsfile *fptr, /* I - FITS file pointer */ long group, /* I - group to write(1 = 1st group) */ long firstelem, /* I - first vector element to write(1 = 1st) */ long nelem, /* I - number of values to write */ double *array, /* I - array of values that are written */ int *status) /* IO - error status */ /* Write an array of values to the primary array. Data conversion and scaling will be performed if necessary (e.g, if the datatype of the FITS array is not the same as the array being written). */ { long row; /* the primary array is represented as a binary table: each group of the primary array is a row in the table, where the first column contains the group parameters and the second column contains the image itself. */ if (fits_is_compressed_image(fptr, status)) { /* this is a compressed image in a binary table */ ffpmsg("writing to compressed image is not supported"); return(*status = DATA_COMPRESSION_ERR); } row=maxvalue(1,group); ffpcld(fptr, 2, row, firstelem, nelem, array, status); return(*status); }
int gsiftp_flush(int handle) { FILE *gsiftpfile; int num_streams; if (getenv("GSIFTP_STREAMS")) { num_streams = (int)getenv("GSIFTP_STREAMS"); } else { num_streams = 1; } int rc = file_flush(handle); if (gsiftpopen != 1) { if (setjmp(env) != 0) { ffpmsg("Timeout (gsiftp_write)"); goto error; } signal(SIGALRM, signal_handler); alarm(NETTIMEOUT); if (gsiftp_put(gsiftpurl,&gsiftpfile,num_streams)) { alarm(0); ffpmsg("Unable to open gsiftp file (gsiftp_flush)"); ffpmsg(gsiftpurl); goto error; } fclose(gsiftpfile); signal(SIGALRM, SIG_DFL); alarm(0); } return rc; error: alarm(0); signal(SIGALRM, SIG_DFL); return (FILE_NOT_OPENED); }
/*--------------------------------------------------------------------------*/ int stdin2file(int handle) /* handle number */ /* Copy the stdin stream to a file. . */ { size_t nread = 0; char simple[] = "SIMPLE"; int c, ii, jj, status = 0; char recbuf[RECBUFLEN]; ii = 0; for(jj = 0; (c = fgetc(stdin)) != EOF && jj < 2000; jj++) { /* Skip over any garbage at the beginning of the stdin stream by */ /* reading 1 char at a time, looking for 'S', 'I', 'M', 'P', 'L', 'E' */ /* Give up if not found in the first 2000 characters */ if (c == simple[ii]) { ii++; if (ii == 6) /* found the complete string? */ { memcpy(recbuf, simple, 6); /* copy "SIMPLE" to buffer */ break; } } else ii = 0; /* reset search to beginning of the string */ } if (ii != 6) { ffpmsg("Couldn't find the string 'SIMPLE' in the stdin stream"); return(FILE_NOT_OPENED); } /* fill up the remainder of the buffer */ nread = fread(recbuf + 6, 1, RECBUFLEN - 6, stdin); nread += 6; /* add in the 6 characters in 'SIMPLE' */ status = file_write(handle, recbuf, nread); if (status) return(status); /* copy the rest of stdin stream */ while(0 != (nread = fread(recbuf,1,RECBUFLEN, stdin))) { status = file_write(handle, recbuf, nread); if (status) return(status); } return(status); }
/*--------------------------------------------------------------------------*/ int ffdkey(fitsfile *fptr, /* I - FITS file pointer */ char *keyname, /* I - keyword name */ int *status) /* IO - error status */ /* delete a specified header keyword */ { int keypos, len; char valstring[FLEN_VALUE], comm[FLEN_COMMENT], value[FLEN_VALUE]; char message[FLEN_ERRMSG]; if (*status > 0) /* inherit input status value if > 0 */ return(*status); if (ffgkey(fptr, keyname, valstring, comm, status) > 0) /* read keyword */ { sprintf(message, "Could not find the %s keyword to delete (ffdkey)", keyname); ffpmsg(message); return(*status); } /* calc position of keyword in header */ keypos = ((fptr->nextkey) - (fptr->headstart[fptr->curhdu])) / 80; ffdrec(fptr, keypos, status); /* delete the keyword */ /* check for string value which may be continued over multiple keywords */ ffc2s(valstring, value, status); /* remove quotes and trailing spaces */ len = strlen(value); while (value[len - 1] == '&') /* ampersand used as continuation char */ { ffgcnt(fptr, value, status); if (value) { ffdrec(fptr, keypos, status); /* delete the keyword */ len = strlen(value); } else /* a null valstring indicates no continuation */ len = 1; } return(*status); }
/*--------------------------------------------------------------------------*/ int mem_create(char *filename, int *handle) /* Create a new empty memory file for subsequent writes. The file name is ignored in this case. */ { int status; /* initially allocate 1 FITS block = 2880 bytes */ status = mem_createmem(2880L, handle); if (status) { ffpmsg("failed to create empty memory file (mem_create)"); return(status); } return(0); }
/*--------------------------------------------------------------------------*/ int mem_createmem(size_t msize, int *handle) /* lowest level routine to allocate a memory file. */ { int ii; *handle = -1; for (ii = 0; ii < NMAXFILES; ii++) /* find empty slot in handle table */ { if (memTable[ii].memaddrptr == 0) { *handle = ii; break; } } if (*handle == -1) return(TOO_MANY_FILES); /* too many files opened */ /* use the internally allocated memaddr and memsize variables */ memTable[ii].memaddrptr = &memTable[ii].memaddr; memTable[ii].memsizeptr = &memTable[ii].memsize; /* allocate initial block of memory for the file */ if (msize > 0) { memTable[ii].memaddr = malloc(msize); if ( !(memTable[ii].memaddr) ) { ffpmsg("malloc of initial memory failed (mem_createmem)"); return(FILE_NOT_OPENED); } } /* set initial state of the file */ memTable[ii].memsize = msize; memTable[ii].deltasize = 2880; memTable[ii].fitsfilesize = 0; memTable[ii].currentpos = 0; memTable[ii].mem_realloc = realloc; return(0); }
int gsiftp_init(void) { if (getenv("GSIFTP_TMPFILE")) { gsiftp_tmpfile = getenv("GSIFTP_TMPFILE"); } else { strncpy(gsiftp_tmpdir, "/tmp/gsiftp_XXXXXX", sizeof gsiftp_tmpdir); if (mkdtemp(gsiftp_tmpdir) == NULL) { ffpmsg("Cannot create temporary directory!"); return (FILE_NOT_OPENED); } gsiftp_tmpfile = malloc(strlen(gsiftp_tmpdir) + strlen("/gsiftp_buffer.tmp")+1); gsiftp_tmpfile[0]=0; free_gsiftp_tmp=1; strcat(gsiftp_tmpfile, gsiftp_tmpdir); strcat(gsiftp_tmpfile, "/gsiftp_buffer.tmp"); } return file_init(); }
/*--------------------------------------------------------------------------*/ int stdout_close(int handle) /* copy the memory file to stdout, then free the memory */ { int status = 0; /* copy from memory to standard out */ if(fwrite(memTable[handle].memaddr, 1, memTable[handle].fitsfilesize, stdout) != (size_t) memTable[handle].fitsfilesize ) { ffpmsg("failed to copy memory file to stdout (stdout_close)"); status = WRITE_ERROR; } free( memTable[handle].memaddr ); /* free the memory */ memTable[handle].memaddrptr = 0; memTable[handle].memaddr = 0; return(status); }
static int htrans(int a[],int nx,int ny) { int nmax, log2n, h0, hx, hy, hc, nxtop, nytop, i, j, k; int oddx, oddy; int shift, mask, mask2, prnd, prnd2, nrnd2; int s10, s00; int *tmp; /* * log2n is log2 of max(nx,ny) rounded up to next power of 2 */ nmax = (nx>ny) ? nx : ny; log2n = (int) (log((float) nmax)/log(2.0)+0.5); if ( nmax > (1<<log2n) ) { log2n += 1; } /* * get temporary storage for shuffling elements */ tmp = (int *) malloc(((nmax+1)/2)*sizeof(int)); if(tmp == (int *) NULL) { ffpmsg("htrans: insufficient memory"); return(DATA_COMPRESSION_ERR); } /* * set up rounding and shifting masks */ shift = 0; mask = -2; mask2 = mask << 1; prnd = 1; prnd2 = prnd << 1; nrnd2 = prnd2 - 1; /* * do log2n reductions * * We're indexing a as a 2-D array with dimensions (nx,ny). */ nxtop = nx; nytop = ny; for (k = 0; k<log2n; k++) { oddx = nxtop % 2; oddy = nytop % 2; for (i = 0; i<nxtop-oddx; i += 2) { s00 = i*ny; /* s00 is index of a[i,j] */ s10 = s00+ny; /* s10 is index of a[i+1,j] */ for (j = 0; j<nytop-oddy; j += 2) { /* * Divide h0,hx,hy,hc by 2 (1 the first time through). */ h0 = (a[s10+1] + a[s10] + a[s00+1] + a[s00]) >> shift; hx = (a[s10+1] + a[s10] - a[s00+1] - a[s00]) >> shift; hy = (a[s10+1] - a[s10] + a[s00+1] - a[s00]) >> shift; hc = (a[s10+1] - a[s10] - a[s00+1] + a[s00]) >> shift; /* * Throw away the 2 bottom bits of h0, bottom bit of hx,hy. * To get rounding to be same for positive and negative * numbers, nrnd2 = prnd2 - 1. */ a[s10+1] = hc; a[s10 ] = ( (hx>=0) ? (hx+prnd) : hx ) & mask ; a[s00+1] = ( (hy>=0) ? (hy+prnd) : hy ) & mask ; a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2; s00 += 2; s10 += 2; } if (oddy) { /* * do last element in row if row length is odd * s00+1, s10+1 are off edge */ h0 = (a[s10] + a[s00]) << (1-shift); hx = (a[s10] - a[s00]) << (1-shift); a[s10 ] = ( (hx>=0) ? (hx+prnd) : hx ) & mask ; a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2; s00 += 1; s10 += 1; } } if (oddx) { /* * do last row if column length is odd * s10, s10+1 are off edge */ s00 = i*ny; for (j = 0; j<nytop-oddy; j += 2) { h0 = (a[s00+1] + a[s00]) << (1-shift); hy = (a[s00+1] - a[s00]) << (1-shift); a[s00+1] = ( (hy>=0) ? (hy+prnd) : hy ) & mask ; a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2; s00 += 2; } if (oddy) { /* * do corner element if both row and column lengths are odd * s00+1, s10, s10+1 are off edge */ h0 = a[s00] << (2-shift); a[s00 ] = ( (h0>=0) ? (h0+prnd2) : (h0+nrnd2) ) & mask2; } } /* * now shuffle in each dimension to group coefficients by order */ for (i = 0; i<nxtop; i++) { shuffle(&a[ny*i],nytop,1,tmp); } for (j = 0; j<nytop; j++) { shuffle(&a[j],nxtop,ny,tmp); } /* * image size reduced by 2 (round up if odd) */ nxtop = (nxtop+1)>>1; nytop = (nytop+1)>>1; /* * divisor doubles after first reduction */ shift = 1; /* * masks, rounding values double after each iteration */ mask = mask2; prnd = prnd2; mask2 = mask2 << 1; prnd2 = prnd2 << 1; nrnd2 = prnd2 - 1; } free(tmp); return(0); }
static int qtree_encode(char *outfile, int a[], int n, int nqx, int nqy, int nbitplanes) { /* int a[]; int n; physical dimension of row in a int nqx; length of row int nqy; length of column (<=n) int nbitplanes; number of bit planes to output */ int log2n, i, k, bit, b, bmax, nqmax, nqx2, nqy2, nx, ny; unsigned char *scratch, *buffer; /* * log2n is log2 of max(nqx,nqy) rounded up to next power of 2 */ nqmax = (nqx>nqy) ? nqx : nqy; log2n = (int) (log((float) nqmax)/log(2.0)+0.5); if (nqmax > (1<<log2n)) { log2n += 1; } /* * initialize buffer point, max buffer size */ nqx2 = (nqx+1)/2; nqy2 = (nqy+1)/2; bmax = (nqx2*nqy2+1)/2; /* * We're indexing A as a 2-D array with dimensions (nqx,nqy). * Scratch is 2-D with dimensions (nqx/2,nqy/2) rounded up. * Buffer is used to store string of codes for output. */ scratch = (unsigned char *) malloc(2*bmax); buffer = (unsigned char *) malloc(bmax); if ((scratch == (unsigned char *) NULL) || (buffer == (unsigned char *) NULL)) { ffpmsg("qtree_encode: insufficient memory"); return(DATA_COMPRESSION_ERR); } /* * now encode each bit plane, starting with the top */ for (bit=nbitplanes-1; bit >= 0; bit--) { /* * initial bit buffer */ b = 0; bitbuffer = 0; bits_to_go3 = 0; /* * on first pass copy A to scratch array */ qtree_onebit(a,n,nqx,nqy,scratch,bit); nx = (nqx+1)>>1; ny = (nqy+1)>>1; /* * copy non-zero values to output buffer, which will be written * in reverse order */ if (bufcopy(scratch,nx*ny,buffer,&b,bmax)) { /* * quadtree is expanding data, * change warning code and just fill buffer with bit-map */ write_bdirect(outfile,a,n,nqx,nqy,scratch,bit); goto bitplane_done; } /* * do log2n reductions */ for (k = 1; k<log2n; k++) { qtree_reduce(scratch,ny,nx,ny,scratch); nx = (nx+1)>>1; ny = (ny+1)>>1; if (bufcopy(scratch,nx*ny,buffer,&b,bmax)) { write_bdirect(outfile,a,n,nqx,nqy,scratch,bit); goto bitplane_done; } } /* * OK, we've got the code in buffer * Write quadtree warning code, then write buffer in reverse order */ output_nybble(outfile,0xF); if (b==0) { if (bits_to_go3>0) { /* * put out the last few bits */ output_nbits(outfile, bitbuffer & ((1<<bits_to_go3)-1), bits_to_go3); } else { /* * have to write a zero nybble if there are no 1's in array */ output_huffman(outfile,0); } } else { if (bits_to_go3>0) { /* * put out the last few bits */ output_nbits(outfile, bitbuffer & ((1<<bits_to_go3)-1), bits_to_go3); } for (i=b-1; i>=0; i--) { output_nbits(outfile,buffer[i],8); } } bitplane_done: ; } free(buffer); free(scratch); return(0); }
static int encode(char *outfile, long *nlength, int a[], int nx, int ny, int scale) { /* FILE *outfile; - change outfile to a char array */ /* long * nlength returned length (in bytes) of the encoded array) int a[]; input H-transform array (nx,ny) int nx,ny; size of H-transform array int scale; scale factor for digitization */ int nel, nx2, ny2, i, j, k, q, vmax[3], nsign, bits_to_go; unsigned char nbitplanes[3]; unsigned char *signbits; int stat; noutchar = 0; /* initialize the number of compressed bytes that have been written */ nel = nx*ny; /* * write magic value */ qwrite(outfile, code_magic, sizeof(code_magic)); writeint(outfile, nx); /* size of image */ writeint(outfile, ny); writeint(outfile, scale); /* scale factor for digitization */ /* * write first value of A (sum of all pixels -- the only value * which does not compress well) */ writelonglong(outfile, (LONGLONG) a[0]); a[0] = 0; /* * allocate array for sign bits and save values, 8 per byte */ signbits = (unsigned char *) malloc((nel+7)/8); if (signbits == (unsigned char *) NULL) { ffpmsg("encode: insufficient memory"); return(DATA_COMPRESSION_ERR); } nsign = 0; bits_to_go = 8; signbits[0] = 0; for (i=0; i<nel; i++) { if (a[i] > 0) { /* * positive element, put zero at end of buffer */ signbits[nsign] <<= 1; bits_to_go -= 1; } else if (a[i] < 0) { /* * negative element, shift in a one */ signbits[nsign] <<= 1; signbits[nsign] |= 1; bits_to_go -= 1; /* * replace a by absolute value */ a[i] = -a[i]; } if (bits_to_go == 0) { /* * filled up this byte, go to the next one */ bits_to_go = 8; nsign += 1; signbits[nsign] = 0; } } if (bits_to_go != 8) { /* * some bits in last element * move bits in last byte to bottom and increment nsign */ signbits[nsign] <<= bits_to_go; nsign += 1; } /* * calculate number of bit planes for 3 quadrants * * quadrant 0=bottom left, 1=bottom right or top left, 2=top right, */ for (q=0; q<3; q++) { vmax[q] = 0; } /* * get maximum absolute value in each quadrant */ nx2 = (nx+1)/2; ny2 = (ny+1)/2; j=0; /* column counter */ k=0; /* row counter */ for (i=0; i<nel; i++) { q = (j>=ny2) + (k>=nx2); if (vmax[q] < a[i]) vmax[q] = a[i]; if (++j >= ny) { j = 0; k += 1; } } /* * now calculate number of bits for each quadrant */ /* this is a more efficient way to do this, */ for (q = 0; q < 3; q++) { for (nbitplanes[q] = 0; vmax[q]>0; vmax[q] = vmax[q]>>1, nbitplanes[q]++) ; } /* for (q = 0; q < 3; q++) { nbitplanes[q] = (int) (log((float) (vmax[q]+1))/log(2.0)+0.5); if ( (vmax[q]+1) > (1<<nbitplanes[q]) ) { nbitplanes[q] += 1; } } */ /* * write nbitplanes */ if (0 == qwrite(outfile, (char *) nbitplanes, sizeof(nbitplanes))) { *nlength = noutchar; ffpmsg("encode: output buffer too small"); return(DATA_COMPRESSION_ERR); } /* * write coded array */ stat = doencode(outfile, a, nx, ny, nbitplanes); /* * write sign bits */ if (nsign > 0) { if ( 0 == qwrite(outfile, (char *) signbits, nsign)) { free(signbits); *nlength = noutchar; ffpmsg("encode: output buffer too small"); return(DATA_COMPRESSION_ERR); } } free(signbits); *nlength = noutchar; if (noutchar >= noutmax) { ffpmsg("encode: output buffer too small"); return(DATA_COMPRESSION_ERR); } return(stat); }
/*--------------------------------------------------------------------------*/ int ffpcll( fitsfile *fptr, /* I - FITS file pointer */ int colnum, /* I - number of column to write (1 = 1st col) */ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */ LONGLONG nelem, /* I - number of values to write */ char *array, /* I - array of values to write */ int *status) /* IO - error status */ /* Write an array of logical values to a column in the current FITS HDU. */ { int tcode, maxelem, hdutype; long twidth, incre; LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull; double scale, zero; char tform[20], ctrue = 'T', cfalse = 'F'; char message[FLEN_ERRMSG]; char snull[20]; /* the FITS null value */ if (*status > 0) /* inherit input status value if > 0 */ return(*status); /*---------------------------------------------------*/ /* Check input and get parameters about the column: */ /*---------------------------------------------------*/ if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero, tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre, &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0) return(*status); if (tcode != TLOGICAL) return(*status = NOT_LOGICAL_COL); /*---------------------------------------------------------------------*/ /* Now write the logical values one at a time to the FITS column. */ /*---------------------------------------------------------------------*/ remain = nelem; /* remaining number of values to write */ next = 0; /* next element in array to be written */ rownum = 0; /* row number, relative to firstrow */ while (remain) { wrtptr = startpos + (rowlen * rownum) + (elemnum * incre); ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */ if (array[next]) ffpbyt(fptr, 1, &ctrue, status); else ffpbyt(fptr, 1, &cfalse, status); if (*status > 0) /* test for error during previous write operation */ { sprintf(message, "Error writing element %.0f of input array of logicals (ffpcll).", (double) (next+1)); ffpmsg(message); return(*status); } /*--------------------------------------------*/ /* increment the counters for the next loop */ /*--------------------------------------------*/ remain--; if (remain) { next++; elemnum++; if (elemnum == repeat) /* completed a row; start on next row */ { elemnum = 0; rownum++; } } } /* End of main while Loop */ return(*status); }
/*--------------------------------------------------------------------------*/ int ffpcld( fitsfile *fptr, /* I - FITS file pointer */ int colnum, /* I - number of column to write (1 = 1st col) */ LONGLONG firstrow, /* I - first row to write (1 = 1st row) */ LONGLONG firstelem, /* I - first vector element to write (1 = 1st) */ LONGLONG nelem, /* I - number of values to write */ double *array, /* I - array of values to write */ int *status) /* IO - error status */ /* Write an array of values to a column in the current FITS HDU. The column number may refer to a real column in an ASCII or binary table, or it may refer to a virtual column in a 1 or more grouped FITS primary array. FITSIO treats a primary array as a binary table with 2 vector columns: the first column contains the group parameters (often with length = 0) and the second column contains the array of image pixels. Each row of the table represents a group in the case of multigroup FITS images. The input array of values will be converted to the datatype of the column and will be inverse-scaled by the FITS TSCALn and TZEROn values if necessary. */ { int tcode, maxelem, hdutype, writeraw; long twidth, incre; long ntodo; LONGLONG repeat, startpos, elemnum, wrtptr, rowlen, rownum, remain, next, tnull; double scale, zero; char tform[20], cform[20]; char message[FLEN_ERRMSG]; char snull[20]; /* the FITS null value */ double cbuff[DBUFFSIZE / sizeof(double)]; /* align cbuff on word boundary */ void *buffer; if (*status > 0) /* inherit input status value if > 0 */ return(*status); buffer = cbuff; /*---------------------------------------------------*/ /* Check input and get parameters about the column: */ /*---------------------------------------------------*/ if (ffgcprll( fptr, colnum, firstrow, firstelem, nelem, 1, &scale, &zero, tform, &twidth, &tcode, &maxelem, &startpos, &elemnum, &incre, &repeat, &rowlen, &hdutype, &tnull, snull, status) > 0) return(*status); if (tcode == TSTRING) ffcfmt(tform, cform); /* derive C format for writing strings */ /* if there is no scaling and the native machine format is not byteswapped, then we can simply write the raw data bytes into the FITS file if the datatype of the FITS column is the same as the input values. Otherwise, we must convert the raw values into the scaled and/or machine dependent format in a temporary buffer that has been allocated for this purpose. */ if (scale == 1. && zero == 0. && MACHINE == NATIVE && tcode == TDOUBLE) { writeraw = 1; maxelem = (int) nelem; /* we can write the entire array at one time */ } else writeraw = 0; /*---------------------------------------------------------------------*/ /* Now write the pixels to the FITS column. */ /* First call the ffXXfYY routine to (1) convert the datatype */ /* if necessary, and (2) scale the values by the FITS TSCALn and */ /* TZEROn linear scaling parameters into a temporary buffer. */ /*---------------------------------------------------------------------*/ remain = nelem; /* remaining number of values to write */ next = 0; /* next element in array to be written */ rownum = 0; /* row number, relative to firstrow */ while (remain) { /* limit the number of pixels to process a one time to the number that will fit in the buffer space or to the number of pixels that remain in the current vector, which ever is smaller. */ ntodo = (long) minvalue(remain, maxelem); ntodo = (long) minvalue(ntodo, (repeat - elemnum)); wrtptr = startpos + ((LONGLONG)rownum * rowlen) + (elemnum * incre); ffmbyt(fptr, wrtptr, IGNORE_EOF, status); /* move to write position */ switch (tcode) { case (TDOUBLE): if (writeraw) { /* write raw input bytes without conversion */ ffpr8b(fptr, ntodo, incre, &array[next], status); } else { /* convert the raw data before writing to FITS file */ ffr8fr8(&array[next], ntodo, scale, zero, (double *) buffer, status); ffpr8b(fptr, ntodo, incre, (double *) buffer, status); } break; case (TLONGLONG): ffr8fi8(&array[next], ntodo, scale, zero, (LONGLONG *) buffer, status); ffpi8b(fptr, ntodo, incre, (long *) buffer, status); break; case (TBYTE): ffr8fi1(&array[next], ntodo, scale, zero, (unsigned char *) buffer, status); ffpi1b(fptr, ntodo, incre, (unsigned char *) buffer, status); break; case (TSHORT): ffr8fi2(&array[next], ntodo, scale, zero, (short *) buffer, status); ffpi2b(fptr, ntodo, incre, (short *) buffer, status); break; case (TLONG): ffr8fi4(&array[next], ntodo, scale, zero, (INT32BIT *) buffer, status); ffpi4b(fptr, ntodo, incre, (INT32BIT *) buffer, status); break; case (TFLOAT): ffr8fr4(&array[next], ntodo, scale, zero, (float *) buffer, status); ffpr4b(fptr, ntodo, incre, (float *) buffer, status); break; case (TSTRING): /* numerical column in an ASCII table */ if (cform[1] != 's') /* "%s" format is a string */ { ffr8fstr(&array[next], ntodo, scale, zero, cform, twidth, (char *) buffer, status); if (incre == twidth) /* contiguous bytes */ ffpbyt(fptr, ntodo * twidth, buffer, status); else ffpbytoff(fptr, twidth, ntodo, incre - twidth, buffer, status); break; } /* can't write to string column, so fall thru to default: */ default: /* error trap */ sprintf(message, "Cannot write numbers to column %d which has format %s", colnum,tform); ffpmsg(message); if (hdutype == ASCII_TBL) return(*status = BAD_ATABLE_FORMAT); else return(*status = BAD_BTABLE_FORMAT); } /* End of switch block */ /*-------------------------*/ /* Check for fatal error */ /*-------------------------*/ if (*status > 0) /* test for error during previous write operation */ { sprintf(message, "Error writing elements %.0f thru %.0f of input data array (ffpcld).", (double) (next+1), (double) (next+ntodo)); ffpmsg(message); return(*status); } /*--------------------------------------------*/ /* increment the counters for the next loop */ /*--------------------------------------------*/ remain -= ntodo; if (remain) { next += ntodo; elemnum += ntodo; if (elemnum == repeat) /* completed a row; start on next row */ { elemnum = 0; rownum++; } } } /* End of main while Loop */ /*--------------------------------*/ /* check for numerical overflow */ /*--------------------------------*/ if (*status == OVERFLOW_ERR) { ffpmsg( "Numerical overflow during type conversion while writing FITS data."); *status = NUM_OVERFLOW; } return(*status); }
/*--------------------------------------------------------------------------*/ int ffpssd(fitsfile *fptr, /* I - FITS file pointer */ long group, /* I - group to write(1 = 1st group) */ long naxis, /* I - number of data axes in array */ long *naxes, /* I - size of each FITS axis */ long *fpixel, /* I - 1st pixel in each axis to write (1=1st) */ long *lpixel, /* I - last pixel in each axis to write */ double *array, /* I - array to be written */ int *status) /* IO - error status */ /* Write a subsection of pixels to the primary array or image. A subsection is defined to be any contiguous rectangular array of pixels within the n-dimensional FITS data file. Data conversion and scaling will be performed if necessary (e.g, if the datatype of the FITS array is not the same as the array being written). */ { long tablerow; long fpix[7], irange[7], dimen[7], astart, pstart; long off2, off3, off4, off5, off6, off7; long st10, st20, st30, st40, st50, st60, st70; long st1, st2, st3, st4, st5, st6, st7; long ii, i1, i2, i3, i4, i5, i6, i7; if (*status > 0) return(*status); if (fits_is_compressed_image(fptr, status)) { /* this is a compressed image in a binary table */ ffpmsg("writing to compressed image is not supported"); return(*status = DATA_COMPRESSION_ERR); } if (naxis < 1 || naxis > 7) return(*status = BAD_DIMEN); tablerow=maxvalue(1,group); /* calculate the size and number of loops to perform in each dimension */ for (ii = 0; ii < 7; ii++) { fpix[ii]=1; irange[ii]=1; dimen[ii]=1; } for (ii = 0; ii < naxis; ii++) { fpix[ii]=fpixel[ii]; irange[ii]=lpixel[ii]-fpixel[ii]+1; dimen[ii]=naxes[ii]; } i1=irange[0]; /* compute the pixel offset between each dimension */ off2 = dimen[0]; off3 = off2 * dimen[1]; off4 = off3 * dimen[2]; off5 = off4 * dimen[3]; off6 = off5 * dimen[4]; off7 = off6 * dimen[5]; st10 = fpix[0]; st20 = (fpix[1] - 1) * off2; st30 = (fpix[2] - 1) * off3; st40 = (fpix[3] - 1) * off4; st50 = (fpix[4] - 1) * off5; st60 = (fpix[5] - 1) * off6; st70 = (fpix[6] - 1) * off7; /* store the initial offset in each dimension */ st1 = st10; st2 = st20; st3 = st30; st4 = st40; st5 = st50; st6 = st60; st7 = st70; astart = 0; for (i7 = 0; i7 < irange[6]; i7++) { for (i6 = 0; i6 < irange[5]; i6++) { for (i5 = 0; i5 < irange[4]; i5++) { for (i4 = 0; i4 < irange[3]; i4++) { for (i3 = 0; i3 < irange[2]; i3++) { pstart = st1 + st2 + st3 + st4 + st5 + st6 + st7; for (i2 = 0; i2 < irange[1]; i2++) { if (ffpcld(fptr, 2, tablerow, pstart, i1, &array[astart], status) > 0) return(*status); astart += i1; pstart += off2; } st2 = st20; st3 = st3+off3; } st3 = st30; st4 = st4+off4; } st4 = st40; st5 = st5+off5; } st5 = st50; st6 = st6+off6; } st6 = st60; st7 = st7+off7; } return(*status); }
/*--------------------------------------------------------------------------*/ int ffp3dd(fitsfile *fptr, /* I - FITS file pointer */ long group, /* I - group to write(1 = 1st group) */ long ncols, /* I - number of pixels in each row of array */ long nrows, /* I - number of rows in each plane of array */ long naxis1, /* I - FITS image NAXIS1 value */ long naxis2, /* I - FITS image NAXIS2 value */ long naxis3, /* I - FITS image NAXIS3 value */ double *array, /* I - array to be written */ int *status) /* IO - error status */ /* Write an entire 3-D cube of values to the primary array. Data conversion and scaling will be performed if necessary (e.g, if the datatype of the FITS array is not the same as the array being written). */ { long tablerow, nfits, narray, ii, jj; /* the primary array is represented as a binary table: each group of the primary array is a row in the table, where the first column contains the group parameters and the second column contains the image itself. */ if (fits_is_compressed_image(fptr, status)) { /* this is a compressed image in a binary table */ ffpmsg("writing to compressed image is not supported"); return(*status = DATA_COMPRESSION_ERR); } tablerow=maxvalue(1,group); if (ncols == naxis1 && nrows == naxis2) /* arrays have same size? */ { /* all the image pixels are contiguous, so write all at once */ ffpcld(fptr, 2, tablerow, 1L, naxis1 * naxis2 * naxis3, array, status); return(*status); } if (ncols < naxis1 || nrows < naxis2) return(*status = BAD_DIMEN); nfits = 1; /* next pixel in FITS image to write to */ narray = 0; /* next pixel in input array to be written */ /* loop over naxis3 planes in the data cube */ for (jj = 0; jj < naxis3; jj++) { /* loop over the naxis2 rows in the FITS image, */ /* writing naxis1 pixels to each row */ for (ii = 0; ii < naxis2; ii++) { if (ffpcld(fptr, 2, tablerow, nfits, naxis1,&array[narray],status) > 0) return(*status); nfits += naxis1; narray += ncols; } narray += (nrows - naxis2) * ncols; } return(*status); }
/*--------------------------------------------------------------------------*/ int ffiter(int n_cols, iteratorCol *cols, long offset, long n_per_loop, int (*work_fn)(long total_n, long offset, long first_n, long n_values, int n_cols, iteratorCol *cols, void *userPointer), void *userPointer, int *status) /* The iterator function. This function will pass the specified columns from a FITS table or pixels from a FITS image to the user-supplied function. Depending on the size of the table or image, only a subset of the rows or pixels may be passed to the function on each call, in which case the function will be called multiple times until all the rows or pixels have been processed. */ { typedef struct /* structure to store the column null value */ { int nullsize; /* length of the null value, in bytes */ union { /* default null value for the column */ char *stringnull; unsigned char charnull; int intnull; short shortnull; long longnull; unsigned int uintnull; unsigned short ushortnull; unsigned long ulongnull; float floatnull; double doublenull; } null; } colNulls; void *dataptr, *defaultnull; colNulls *col; int ii, jj, tstatus; int typecode, hdutype, jtype, type, anynul, nfiles, nbytes; long totaln, nleft, frow, felement, n_optimum, i_optimum, ntodo; long rept, width, tnull; double zeros = 0.; char message[FLEN_ERRMSG], keyname[FLEN_KEYWORD], nullstr[FLEN_VALUE]; char **stringptr, *nullptr, *cptr; if (*status > 0) return(*status); if (n_cols < 0 || n_cols > 999 ) { ffpmsg("Illegal number of columms (ffiter)"); return(*status = BAD_COL_NUM); /* negative number of columns */ } col = calloc(n_cols, sizeof(colNulls) ); /* memory for the null values */ /*------------------------------------------------------------*/ /* Make sure column numbers and datatypes are in legal range */ /* and column numbers and datatypes are legal. */ /* Also fill in other parameters in the column structure. */ /*------------------------------------------------------------*/ ffghdt(cols[0].fptr, &hdutype, status); /* type of first HDU */ for (jj = 0; jj < n_cols; jj++) { /* check that output datatype code value is legal */ type = cols[jj].datatype; if (type != 0 && type != TBYTE && type != TLOGICAL && type != TSTRING && type != TSHORT && type != TINT && type != TLONG && type != TFLOAT && type != TDOUBLE && type != TCOMPLEX && type != TULONG && type != TUSHORT && type != TDBLCOMPLEX) { sprintf(message, "Illegal datatype for column number %d: %d (ffiter)", jj + 1, cols[jj].datatype); ffpmsg(message); return(*status = BAD_DATATYPE); } /* initialize TLMINn, TLMAXn, column name, and display format */ cols[jj].tlmin = 0; cols[jj].tlmax = 0; cols[jj].tunit[0] = '\0'; cols[jj].tdisp[0] = '\0'; ffghdt(cols[jj].fptr, &jtype, status); /* get HDU type */ if (hdutype == IMAGE_HDU) { if (jtype != IMAGE_HDU) { sprintf(message, "File %d not positioned to an image extension (ffiter)", jj + 1); return(*status = NOT_IMAGE); } /* images are stored in column 2; ignore the input value */ cols[jj].colnum = 2; strcpy(cols[jj].colname, "IMAGE"); /* dummy name for images */ tstatus = 0; ffgkys(cols[jj].fptr, "BUNIT", cols[jj].tunit, 0, &tstatus); } else { if (jtype == IMAGE_HDU) { sprintf(message, "File %d not positioned to a table extension (ffiter)", jj + 1); return(*status = NOT_TABLE); } if (cols[jj].colnum < 1) { /* find the column number for the named column */ if (ffgcno(cols[jj].fptr, CASEINSEN, cols[jj].colname, &cols[jj].colnum, status) ) { sprintf(message, "Column '%s' not found for column number %d (ffiter)", cols[jj].colname, jj + 1); ffpmsg(message); return(*status); } } if (cols[jj].colnum < 1 || cols[jj].colnum > ((cols[jj].fptr)->Fptr)->tfield) { sprintf(message, "Column %d has illegal table position number: %d (ffiter)", jj + 1, cols[jj].colnum); ffpmsg(message); return(*status = BAD_COL_NUM); } /* look for column description keywords and update structure */ tstatus = 0; ffkeyn("TLMIN", cols[jj].colnum, keyname, &tstatus); ffgkyj(cols[jj].fptr, keyname, &cols[jj].tlmin, 0, &tstatus); tstatus = 0; ffkeyn("TLMAX", cols[jj].colnum, keyname, &tstatus); ffgkyj(cols[jj].fptr, keyname, &cols[jj].tlmax, 0, &tstatus); tstatus = 0; ffkeyn("TTYPE", cols[jj].colnum, keyname, &tstatus); ffgkys(cols[jj].fptr, keyname, cols[jj].colname, 0, &tstatus); if (tstatus) cols[jj].colname[0] = '\0'; tstatus = 0; ffkeyn("TUNIT", cols[jj].colnum, keyname, &tstatus); ffgkys(cols[jj].fptr, keyname, cols[jj].tunit, 0, &tstatus); tstatus = 0; ffkeyn("TDISP", cols[jj].colnum, keyname, &tstatus); ffgkys(cols[jj].fptr, keyname, cols[jj].tdisp, 0, &tstatus); } } /*-----------------------------------------------------------------*/ /* use the first file to set the total number of values to process */ /*-----------------------------------------------------------------*/ offset = maxvalue(offset, 0L); /* make sure offset is legal */ if (hdutype == IMAGE_HDU) /* get total number of pixels in the image */ { ffgtcl(cols[0].fptr, cols[0].colnum, NULL, &totaln, &width, status); frow = 1; felement = 1 + offset; } else /* get total number or rows in the table */ { ffgkyj(cols[0].fptr, "NAXIS2", &totaln, 0, status); frow = 1 + offset; felement = 1; } /* adjust total by the input starting offset value */ totaln -= offset; totaln = maxvalue(totaln, 0L); /* don't allow negative number */ /*------------------------------------------------------------------*/ /* Determine number of values to pass to work function on each loop */ /*------------------------------------------------------------------*/ if (n_per_loop == 0) { /* Determine optimum number of values for each iteration. */ /* Look at all the fitsfile pointers to determine the number */ /* of unique files. */ nfiles = 1; ffgrsz(cols[0].fptr, &n_optimum, status); for (jj = 1; jj < n_cols; jj++) { for (ii = 0; ii < jj; ii++) { if (cols[ii].fptr == cols[jj].fptr) break; } if (ii == jj) /* this is a new file */ { nfiles++; ffgrsz(cols[jj].fptr, &i_optimum, status); n_optimum = minvalue(n_optimum, i_optimum); } } n_optimum = n_optimum / nfiles; } else if (n_per_loop < 0) /* must pass all the values at one time */ { n_optimum = totaln; } else /* calling routine specified how many values to pass at a time */ { n_optimum = minvalue(n_per_loop, totaln); } /*--------------------------------------*/ /* allocate work arrays for each column */ /* and determine the null pixel value */ /*--------------------------------------*/ for (jj = 0; jj < n_cols; jj++) { /* get column datatype and vector length */ if (ffgtcl(cols[jj].fptr, cols[jj].colnum, &typecode, &rept, &width, status) > 0) goto cleanup; /* special case where sizeof(long) = 8: use TINT instead of TLONG */ if (typecode == TLONG && sizeof(long) == 8 && sizeof(int) == 4) typecode = TINT; /* Special case: interprete 'X' column as 'B' */ if (abs(typecode) == TBIT) { typecode = typecode / TBIT * TBYTE; rept = (rept + 7) / 8; } if (cols[jj].datatype == 0) /* output datatype not specified? */ { /* special case if sizeof(long) = 8: use TINT instead of TLONG */ if (typecode == TLONG && sizeof(long) == 8 && sizeof(int) == 4) cols[jj].datatype = TINT; else cols[jj].datatype = typecode; } /* calc total number of elements to do on each iteration */ if (hdutype == IMAGE_HDU || cols[jj].datatype == TSTRING) { ntodo = n_optimum; cols[jj].repeat = 1; /* get the BLANK keyword value, if it exists */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { tstatus = 0; ffgkyj(cols[jj].fptr, "BLANK", &tnull, 0, &tstatus); if (tstatus) { tnull = 0L; /* no null values */ } } } else { ntodo = n_optimum * rept; /* vector columns */ cols[jj].repeat = rept; /* get the TNULL keyword value, if it exists */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { tstatus = 0; if (hdutype == ASCII_TBL) /* TNULLn value is a string */ { ffkeyn("TNULL", cols[jj].colnum, keyname, &tstatus); ffgkys(cols[jj].fptr, keyname, nullstr, 0, &tstatus); if (tstatus) { tnull = 0L; /* keyword doesn't exist; no null values */ } else { cptr = nullstr; while (*cptr == ' ') /* skip over leading blanks */ cptr++; if (*cptr == '\0') /* TNULLn is all blanks? */ tnull = LONG_MIN; else { /* attempt to read TNULLn string as an integer */ ffc2ii(nullstr, &tnull, &tstatus); if (tstatus) tnull = LONG_MIN; /* choose smallest value */ } /* to represent nulls */ } } else /* Binary table; TNULLn value is an integer */ { ffkeyn("TNULL", cols[jj].colnum, keyname, &tstatus); ffgkyj(cols[jj].fptr, keyname, &tnull, 0, &tstatus); if (tstatus) { tnull = 0L; /* keyword doesn't exist; no null values */ } else if (tnull == 0) { /* worst possible case: a value of 0 is used to */ /* represent nulls in the FITS file. We have to */ /* use a non-zero null value here (zero is used to */ /* mean there are no null values in the array) so we */ /* will use the smallest possible integer instead. */ tnull = LONG_MIN; /* choose smallest possible value */ } } } } /* Note that the data array starts with 2nd element; */ /* 1st element of the array gives the null data value */ switch (cols[jj].datatype) { case TBYTE: cols[jj].array = calloc(ntodo + 1, sizeof(char)); col[jj].nullsize = sizeof(char); /* number of bytes per value */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { tnull = minvalue(tnull, 255); tnull = maxvalue(tnull, 0); col[jj].null.charnull = (unsigned char) tnull; } else { col[jj].null.charnull = (unsigned char) 255; /* use 255 as null */ } break; case TSHORT: cols[jj].array = calloc(ntodo + 1, sizeof(short)); col[jj].nullsize = sizeof(short); /* number of bytes per value */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { tnull = minvalue(tnull, SHRT_MAX); tnull = maxvalue(tnull, SHRT_MIN); col[jj].null.shortnull = (short) tnull; } else { col[jj].null.shortnull = SHRT_MIN; /* use minimum as null */ } break; case TUSHORT: cols[jj].array = calloc(ntodo + 1, sizeof(unsigned short)); col[jj].nullsize = sizeof(unsigned short); /* bytes per value */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { tnull = minvalue(tnull, USHRT_MAX); tnull = maxvalue(tnull, 0); /* don't allow negative value */ col[jj].null.ushortnull = (unsigned short) tnull; } else { col[jj].null.ushortnull = USHRT_MAX; /* use maximum null */ } break; case TINT: cols[jj].array = calloc(ntodo + 1, sizeof(int)); col[jj].nullsize = sizeof(int); /* number of bytes per value */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { tnull = minvalue(tnull, INT_MAX); tnull = maxvalue(tnull, INT_MIN); col[jj].null.intnull = (int) tnull; } else { col[jj].null.intnull = INT_MIN; /* use minimum as null */ } break; case TUINT: cols[jj].array = calloc(ntodo + 1, sizeof(unsigned int)); col[jj].nullsize = sizeof(unsigned int); /* bytes per value */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { tnull = minvalue(tnull, INT32_MAX); tnull = maxvalue(tnull, 0); col[jj].null.uintnull = (unsigned int) tnull; } else { col[jj].null.intnull = UINT_MAX; /* use maximum as null */ } break; case TLONG: cols[jj].array = calloc(ntodo + 1, sizeof(long)); col[jj].nullsize = sizeof(long); /* number of bytes per value */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { col[jj].null.longnull = tnull; } else { col[jj].null.longnull = LONG_MIN; /* use minimum as null */ } break; case TULONG: cols[jj].array = calloc(ntodo + 1, sizeof(unsigned long)); col[jj].nullsize = sizeof(unsigned long); /* bytes per value */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { if (tnull < 0) /* can't use a negative null value */ col[jj].null.ulongnull = LONG_MAX; else col[jj].null.ulongnull = (unsigned long) tnull; } else { col[jj].null.ulongnull = LONG_MAX; /* use maximum as null */ } break; case TFLOAT: cols[jj].array = calloc(ntodo + 1, sizeof(float)); col[jj].nullsize = sizeof(float); /* number of bytes per value */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { col[jj].null.floatnull = (float) tnull; } else { col[jj].null.floatnull = FLOATNULLVALUE; /* special value */ } break; case TCOMPLEX: cols[jj].array = calloc((ntodo * 2) + 1, sizeof(float)); col[jj].nullsize = sizeof(float); /* number of bytes per value */ col[jj].null.floatnull = FLOATNULLVALUE; /* special value */ break; case TDOUBLE: cols[jj].array = calloc(ntodo + 1, sizeof(double)); col[jj].nullsize = sizeof(double); /* number of bytes per value */ if (typecode == TBYTE || typecode == TSHORT || typecode == TLONG) { col[jj].null.doublenull = (double) tnull; } else { col[jj].null.doublenull = DOUBLENULLVALUE; /* special value */ } break; case TDBLCOMPLEX: cols[jj].array = calloc((ntodo * 2) + 1, sizeof(double)); col[jj].nullsize = sizeof(double); /* number of bytes per value */ col[jj].null.doublenull = DOUBLENULLVALUE; /* special value */ break; case TSTRING: /* allocate array of pointers to all the strings */ if( hdutype==ASCII_TBL ) rept = width; stringptr = calloc((ntodo + 1) , sizeof(stringptr)); cols[jj].array = stringptr; col[jj].nullsize = rept + 1; /* number of bytes per value */ if (stringptr) { /* allocate string to store the null string value */ col[jj].null.stringnull = calloc(rept + 1, sizeof(char) ); col[jj].null.stringnull[1] = 1; /* to make sure string != 0 */ /* allocate big block for the array of table column strings */ stringptr[0] = calloc((ntodo + 1) * (rept + 1), sizeof(char) ); if (stringptr[0]) { for (ii = 1; ii <= ntodo; ii++) { /* pointer to each string */ stringptr[ii] = stringptr[ii - 1] + (rept + 1); } /* get the TNULL keyword value, if it exists */ tstatus = 0; ffkeyn("TNULL", cols[jj].colnum, keyname, &tstatus); ffgkys(cols[jj].fptr, keyname, nullstr, 0, &tstatus); if (!tstatus) strncat(col[jj].null.stringnull, nullstr, rept); } else { ffpmsg("ffiter failed to allocate memory arrays"); *status = MEMORY_ALLOCATION; /* memory allocation failed */ goto cleanup; } } break; case TLOGICAL: cols[jj].array = calloc(ntodo + 1, sizeof(char)); col[jj].nullsize = sizeof(char); /* number of bytes per value */ /* use value = 2 to flag null values in logical columns */ col[jj].null.charnull = 2; break; default: sprintf(message, "Column %d datatype currently not supported: %d: (ffiter)", jj + 1, cols[jj].datatype); ffpmsg(message); *status = BAD_DATATYPE; goto cleanup; } /* end of switch block */ /* check that all the arrays were allocated successfully */ if (!cols[jj].array) { ffpmsg("ffiter failed to allocate memory arrays"); *status = MEMORY_ALLOCATION; /* memory allocation failed */ goto cleanup; } } /*--------------------------------------------------*/ /* main loop while there are values left to process */ /*--------------------------------------------------*/ nleft = totaln; while (nleft) { ntodo = minvalue(nleft, n_optimum); /* no. of values for this loop */ /* read input columns from FITS file(s) */ for (jj = 0; jj < n_cols; jj++) { if (cols[jj].iotype != OutputCol) { if (cols[jj].datatype == TSTRING) { stringptr = cols[jj].array; dataptr = stringptr + 1; defaultnull = col[jj].null.stringnull; /* ptr to the null value */ } else { dataptr = (char *) cols[jj].array + col[jj].nullsize; defaultnull = &col[jj].null.charnull; /* ptr to the null value */ } if (ffgcv(cols[jj].fptr, cols[jj].datatype, cols[jj].colnum, frow, felement, cols[jj].repeat * ntodo, defaultnull, dataptr, &anynul, status) > 0) { break; } /* copy the appropriate null value into first array element */ if (anynul) /* are there any nulls in the data? */ { if (cols[jj].datatype == TSTRING) { stringptr = cols[jj].array; memcpy(*stringptr, col[jj].null.stringnull, col[jj].nullsize); } else { memcpy(cols[jj].array, defaultnull, col[jj].nullsize); } } else /* no null values so copy zero into first element */ { if (cols[jj].datatype == TSTRING) { stringptr = cols[jj].array; memset(*stringptr, 0, col[jj].nullsize); } else { memset(cols[jj].array, 0, col[jj].nullsize); } } } } if (*status > 0) break; /* looks like an error occurred; quit immediately */ /* call work function */ if (hdutype == IMAGE_HDU) *status = work_fn(totaln, offset, felement, ntodo, n_cols, cols, userPointer); else *status = work_fn(totaln, offset, frow, ntodo, n_cols, cols, userPointer); if (*status > 0 || *status < -1 ) break; /* looks like an error occurred; quit immediately */ /* write output columns before quiting if status = -1 */ tstatus = 0; for (jj = 0; jj < n_cols; jj++) { if (cols[jj].iotype != InputCol) { if (cols[jj].datatype == TSTRING) { stringptr = cols[jj].array; dataptr = stringptr + 1; nullptr = *stringptr; nbytes = 2; } else { dataptr = (char *) cols[jj].array + col[jj].nullsize; nullptr = (char *) cols[jj].array; nbytes = col[jj].nullsize; } if (memcmp(nullptr, &zeros, nbytes) ) { /* null value flag not zero; must check for and write nulls */ if (ffpcn(cols[jj].fptr, cols[jj].datatype, cols[jj].colnum, frow, felement, cols[jj].repeat * ntodo, dataptr, nullptr, &tstatus) > 0) break; } else { /* no null values; just write the array */ if (ffpcl(cols[jj].fptr, cols[jj].datatype, cols[jj].colnum, frow, felement, cols[jj].repeat * ntodo, dataptr, &tstatus) > 0) break; } } } if (*status == 0) *status = tstatus; /* propagate any error status from the writes */ if (*status) break; /* exit on any error */ nleft -= ntodo; if (hdutype == IMAGE_HDU) felement += ntodo; else frow += ntodo; } cleanup: /*----------------------------------*/ /* free work arrays for the columns */ /*----------------------------------*/ for (jj = 0; jj < n_cols; jj++) { if (cols[jj].datatype == TSTRING) { if (cols[jj].array) { stringptr = cols[jj].array; free(*stringptr); /* free the block of strings */ free(col[jj].null.stringnull); /* free the null string */ } } free(cols[jj].array); /* memory for the array of values from the col */ } free(col); /* the structure containing the null values */ return(*status); }
// ffhist3: same as ffhist2, but does not close the original file, // and/or replace the original file pointer fitsfile *ffhist3(fitsfile *fptr, /* I - ptr to table with X and Y cols*/ char *outfile, /* I - name for the output histogram file */ int imagetype, /* I - datatype for image: TINT, TSHORT, etc */ int naxis, /* I - number of axes in the histogram image */ char colname[4][FLEN_VALUE], /* I - column names */ double *minin, /* I - minimum histogram value, for each axis */ double *maxin, /* I - maximum histogram value, for each axis */ double *binsizein, /* I - bin size along each axis */ char minname[4][FLEN_VALUE], /* I - optional keywords for min */ char maxname[4][FLEN_VALUE], /* I - optional keywords for max */ char binname[4][FLEN_VALUE], /* I - optional keywords for binsize */ double weightin, /* I - binning weighting factor */ char wtcol[FLEN_VALUE], /* I - optional keyword or col for weight*/ int recip, /* I - use reciprocal of the weight? */ char *selectrow, /* I - optional array (length = no. of */ /* rows in the table). If the element is true */ /* then the corresponding row of the table will*/ /* be included in the histogram, otherwise the */ /* row will be skipped. Ingnored if *selectrow*/ /* is equal to NULL. */ int *status) { fitsfile *histptr; int bitpix, colnum[4], wtcolnum; long haxes[4]; float amin[4], amax[4], binsize[4], weight; if (*status > 0) return(NULL); if (naxis > 4) { ffpmsg("histogram has more than 4 dimensions"); *status = BAD_DIMEN; return(NULL); } /* reset position to the correct HDU if necessary */ if ((fptr)->HDUposition != ((fptr)->Fptr)->curhdu) ffmahd(fptr, ((fptr)->HDUposition) + 1, NULL, status); if (imagetype == TBYTE) bitpix = BYTE_IMG; else if (imagetype == TSHORT) bitpix = SHORT_IMG; else if (imagetype == TINT) bitpix = LONG_IMG; else if (imagetype == TFLOAT) bitpix = FLOAT_IMG; else if (imagetype == TDOUBLE) bitpix = DOUBLE_IMG; else{ *status = BAD_DATATYPE; return(NULL); } /* Calculate the binning parameters: */ /* columm numbers, axes length, min values, max values, and binsizes. */ if (fits_calc_binning( fptr, naxis, colname, minin, maxin, binsizein, minname, maxname, binname, colnum, haxes, amin, amax, binsize, status) > 0) { ffpmsg("failed to determine binning parameters"); return(NULL); } /* get the histogramming weighting factor, if any */ if (*wtcol) { /* first, look for a keyword with the weight value */ if (fits_read_key(fptr, TFLOAT, wtcol, &weight, NULL, status) ) { /* not a keyword, so look for column with this name */ *status = 0; /* get the column number in the table */ if (ffgcno(fptr, CASEINSEN, wtcol, &wtcolnum, status) > 0) { ffpmsg( "keyword or column for histogram weights doesn't exist: "); ffpmsg(wtcol); return(NULL); } weight = FLOATNULLVALUE; } } else weight = (float) weightin; if (weight <= 0. && weight != FLOATNULLVALUE) { ffpmsg("Illegal histogramming weighting factor <= 0."); *status = URL_PARSE_ERROR; return(NULL); } if (recip && weight != FLOATNULLVALUE) /* take reciprocal of weight */ weight = (float) (1.0 / weight); /* size of histogram is now known, so create temp output file */ if (fits_create_file(&histptr, outfile, status) > 0) { ffpmsg("failed to create temp output file for histogram"); return(NULL); } /* create output FITS image HDU */ if (ffcrim(histptr, bitpix, naxis, haxes, status) > 0) { ffpmsg("failed to create output histogram FITS image"); return(NULL); } /* copy header keywords, converting pixel list WCS keywords to image WCS form */ if (fits_copy_pixlist2image(fptr, histptr, 9, naxis, colnum, status) > 0) { ffpmsg("failed to copy pixel list keywords to new histogram header"); return(NULL); } /* if the table columns have no WCS keywords, then write default keywords */ fits_write_keys_histo(fptr, histptr, naxis, colnum, status); /* update the WCS keywords for the ref. pixel location, and pixel size */ fits_rebin_wcs(histptr, naxis, amin, binsize, status); /* now compute the output image by binning the column values */ if (fits_make_hist(fptr, histptr, bitpix, naxis, haxes, colnum, amin, amax, binsize, weight, wtcolnum, recip, selectrow, status) > 0) { ffpmsg("failed to calculate new histogram values"); return(NULL); } return(histptr); }
/*--------------------------------------------------------------------------*/ int file_open(char *filename, int rwmode, int *handle) { FILE *diskfile; int copyhandle, ii, status; char recbuf[2880]; size_t nread; /* if an output filename has been specified as part of the input file, as in "inputfile.fits(outputfile.fit)" then we have to create the output file, copy the input to it, then reopen the the new copy. */ if (*file_outfile) { /* open the original file, with readonly access */ status = file_openfile(filename, READONLY, &diskfile); if (status) { file_outfile[0] = '\0'; return(status); } /* create the output file */ status = file_create(file_outfile,handle); if (status) { ffpmsg("Unable to create output file for copy of input file:"); ffpmsg(file_outfile); file_outfile[0] = '\0'; return(status); } /* copy the file from input to output */ while(0 != (nread = fread(recbuf,1,2880, diskfile))) { status = file_write(*handle, recbuf, nread); if (status) { file_outfile[0] = '\0'; return(status); } } /* close both files */ fclose(diskfile); copyhandle = *handle; file_close(*handle); *handle = copyhandle; /* reuse the old file handle */ /* reopen the new copy, with correct rwmode */ status = file_openfile(file_outfile, rwmode, &diskfile); file_outfile[0] = '\0'; } else { *handle = -1; for (ii = 0; ii < NMAXFILES; ii++) /* find empty slot in table */ { if (handleTable[ii].fileptr == 0) { *handle = ii; break; } } if (*handle == -1) return(TOO_MANY_FILES); /* too many files opened */ /*open the file */ status = file_openfile(filename, rwmode, &diskfile); } handleTable[*handle].fileptr = diskfile; handleTable[*handle].currentpos = 0; handleTable[*handle].last_io_op = IO_SEEK; return(status); }
/*--------------------------------------------------------------------------*/ int file_compress_open(char *filename, int rwmode, int *hdl) /* This routine opens the compressed diskfile by creating a new uncompressed file then opening it. The input file name (the name of the compressed file) gets replaced with the name of the uncompressed file, which is initially stored in the global file_outfile string. file_outfile then gets set to a null string. */ { FILE *indiskfile, *outdiskfile; int status; char *cptr; /* open the compressed disk file */ status = file_openfile(filename, READONLY, &indiskfile); if (status) { ffpmsg("failed to open compressed disk file (file_compress_open)"); ffpmsg(filename); return(status); } /* name of the output uncompressed file is stored in the */ /* global variable called 'file_outfile'. */ cptr = file_outfile; if (*cptr == '!') { /* clobber any existing file with the same name */ cptr++; remove(cptr); } else { outdiskfile = fopen(file_outfile, "r"); /* does file already exist? */ if (outdiskfile) { ffpmsg("uncompressed file already exists: (file_compress_open)"); ffpmsg(file_outfile); fclose(outdiskfile); /* close file and exit with error */ file_outfile[0] = '\0'; return(FILE_NOT_CREATED); } } outdiskfile = fopen(cptr, "w+b"); /* create new file */ if (!outdiskfile) { ffpmsg("could not create uncompressed file: (file_compress_open)"); ffpmsg(file_outfile); file_outfile[0] = '\0'; return(FILE_NOT_CREATED); } /* uncompress file into another file */ uncompress2file(filename, indiskfile, outdiskfile, &status); fclose(indiskfile); fclose(outdiskfile); if (status) { ffpmsg("error in file_compress_open: failed to uncompressed file:"); ffpmsg(filename); ffpmsg(" into new output file:"); ffpmsg(file_outfile); file_outfile[0] = '\0'; return(status); } strcpy(filename, cptr); /* switch the names */ file_outfile[0] = '\0'; status = file_open(filename, rwmode, hdl); return(status); }
static float xMedian (float x[], int n) { /* arguments: float x[] io: the array (will be scrambled and possibly modified) int n i: number of elements in x (modified locally) */ int i, j; int next_n; int npix; int done; float median = 0.; if (n < 1) { ffpmsg("xMedian: no data"); return (0.); } if (n == 1) return (x[0]); if (n == 2) return ((x[0] + x[1]) / 2.); done = 0; while (!done) { if (n < SORT_CUTOFF) { qsort (x, n, sizeof (float), FqCompare); if (n / 2 * 2 == n) median = (x[n/2-1] + x[n/2]) / 2.; else median = x[n/2]; return (median); } /* ignore trailing groups of less than three elements */ next_n = (n + NELEM-3) / NELEM; for (j = 0; j < next_n; j++) { i = j * NELEM; npix = minvalue (NELEM, n - j*NELEM); InsertionSort (&x[i], npix); switch (npix) { case 1: median = x[i]; break; case 2: median = (x[i] + x[i+1]) / 2.; break; case 3: median = x[i+1]; break; case 4: median = (x[i+1] + x[i+2]) / 2.; break; case 5: /* NELEM = 5 */ median = x[i+2]; break; default: ffpmsg("npix should be 1..5"); } x[j] = median; } if (next_n <= 1) done = 1; else n = next_n; } return (x[0]); }