/* * GVDR library for reading GVDR data files * Copyright (C) 1994 Michael J. Maurer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Michael Maurer * Durand Bldg - Room 232 * Stanford, CA 94305-4055 * (415) 723-1024 */ static char rcsid[]="$Id: gv_index.c,v 1.3 1993/11/02 21:14:21 maurer Exp $"; /****************************************************************************** gv_index.c Function: Interface to tile/cell index for GVDR. This file is part of the STARLab Magellan Altimeter Data Processing Software. Michael Maurer, July 1993. ******************************************************************************/ /* $Log: gv_index.c,v $ * Revision 1.3 1993/11/02 21:14:21 maurer * Changed gindex_write() and gindex_update() to not clobber index in memory. * * Revision 1.2 1993/09/10 19:37:42 maurer * Added gindex_free(). * * Revision 1.1 1993/08/25 21:18:23 maurer * Added multiplier to index interpretation. * Provided a few new functions. * * Revision 1.0 1993/08/02 01:02:51 maurer * Initial revision * */ #include #include #include #include #include "libmisc.h" #include "gvdr.h" #define GVDR_INDEX_C #include "gv_pack.p" #include "gv_cvt.p" #include "gv_index.p" /****************************************************************************** gindex_clear Clears fields of index. ******************************************************************************/ void gindex_clear(gvdr_index_t *I) { I->start=0; I->lo=0; I->hi=0; I->nalloc=0; I->nb=0; I->mult=0; I->index=NULL; } /****************************************************************************** gindex_free Frees memory associated with index I, and clears fields. ******************************************************************************/ void gindex_free(gvdr_index_t *I) { if (I->nalloc>0 && I->index) free(I->index); gindex_clear(I); } /****************************************************************************** gindex_alloc Allocates index. Index entries are integers of nb bytes. Values lo and hi give the lower and upper bounds of the index elements' addresses, so (hi-lo+1) index entries are allocated. The value of start will be subtracted from any values stored in the index by gindex_set(), and subsequently added to the values returned by gindex_get(). Returns nonzero on failure. ******************************************************************************/ int gindex_alloc(gvdr_index_t *I, long start, unsigned short mult, short lo, short hi, unsigned short nb) { int nelem = hi-lo+1; if (nelem<0) return 1; if (nelem*nb > I->nalloc) { if (I->index) free(I->index); I->nalloc=0; if ((I->index=malloc(nelem*nb))==NULL) return 2; I->nalloc=nelem*nb; } I->start=start; I->mult=mult; I->lo=lo; I->hi=hi; I->nb=nb; memset(I->index,0,I->nalloc); return 0; } /****************************************************************************** gindex_set Sets the value of a single element of the index. The element with address addr is set to value val. The actual value stored in the index is related to the value val by the following formula: I->index[addr - I->lo] = (val - I->start) / I->mult Returns nonzero on error. ******************************************************************************/ int gindex_set(gvdr_index_t *I, short addr, unsigned long val) { unsigned long *UL = (unsigned long *)I->index; unsigned short *US = (unsigned short *)I->index; unsigned char *UC = (unsigned char *)I->index; int i; i = addr - I->lo; if (addrlo || addr>I->hi || i>=I->nalloc/I->nb) { error(0,0,"[gindex_set] address %d out of range",addr); return 1; } if (valstart) { error(0,0,"[gindex_set] value %d before start",val); return 2; } if ((val-I->start)%I->mult != 0) { error(0,0,"[gindex_set] val-start (%d-%d) not divisible by mult (%d)", val,I->start,I->mult); return 3; } val-=I->start; val/=I->mult; switch (I->nb) { case 4: UL[i] = (unsigned long)val; break; case 2: if (val>USHRT_MAX) { error(0,0,"[gindex_set] value %d out of range",val); return 4; } US[i] = (unsigned short)val; break; case 1: if (val>UCHAR_MAX) { error(0,0,"[gindex_set] value %d out of range",val); return 5; } UC[i] = (unsigned char)val; break; default: error(0,0,"[gindex_set] illegal byte size"); return 6; } return 0; } /****************************************************************************** gindex_get Gets the value of a single element of the index. The return value is constructed from the index entry by the formula value = I->start + I->mult * I->index[addr - I->lo] Returns nonzero on error. ******************************************************************************/ int gindex_get(gvdr_index_t *I, short addr, unsigned long *val) { unsigned long *UL = (unsigned long *)I->index; unsigned short *US = (unsigned short *)I->index; unsigned char *UC = (unsigned char *)I->index; int i; i = addr - I->lo; if (addrlo || addr>I->hi || i>=I->nalloc/I->nb) return 1; /* address out of range */ switch (I->nb) { case 4: *val = UL[i]; break; case 2: *val = US[i]; break; case 1: *val = UC[i]; break; default: /* illegal byte size */ return 2; } *val*=I->mult; *val+=I->start; return 0; } /****************************************************************************** gindex_write Writes index to file fp. Contents of I->index are valid after call (a temporary copy of the index is created and converted to the current output format before writing). If iposp is non-NULL, the file position of the beginning of the index is stored in it. Returns nonzero on failure. ******************************************************************************/ int gindex_write(FILE *fp, gvdr_index_t *I, fpos_t *iposp) { gvdr_index_t I2; /* holds temp copy of index */ gvdr_index_rec Ir; /* disk version of index header */ int nelem; if (iposp && fgetpos(fp,iposp)) return 1; /* pack, convert and write index header */ gpack_indexh(I,&Ir); gcvt_indexh(&Ir); if (fwrite(&Ir,sizeof(gvdr_index_rec),1,fp)!=1) return 2; /* make copy of index itself, convert to output format, write, and free copy */ I2= *I; nelem = I->hi - I->lo + 1; if ((I2.index=malloc(I->nb*nelem))==NULL) return 3; memcpy(I2.index,I->index,I->nb*nelem); gcvt_index(&I2); if (fwrite(I2.index,I->nb,nelem,fp)!=nelem) return 4; free(I2.index); return 0; } /****************************************************************************** gindex_update Writes index I to file fp at file position specified in ipos. Contents of I->index are valid after call. Returns nonzero on failure. ******************************************************************************/ int gindex_update(FILE *fp, gvdr_index_t *I, fpos_t ipos) { fpos_t fpos; if (fgetpos(fp,&fpos)) return 1; if (fsetpos(fp,&ipos)) return 2; if (gindex_write(fp,I,NULL)) return 3; if (fsetpos(fp,&fpos)) return 4; return 0; } /****************************************************************************** gindex_read Reads index from file fp. The value of start will be added by gindex_get() to the values stored in the index. Returns nonzero on failure. ******************************************************************************/ int gindex_read(FILE *fp, gvdr_index_t *I, long start) { gvdr_index_rec Ir; int nelem; if (fread(&Ir,sizeof(gvdr_index_rec),1,fp)!=1) return 1; gcvt_indexh(&Ir); gunpack_indexh(&Ir,I); if (gindex_alloc(I,start,I->mult,I->lo,I->hi,I->nb)) return 2; nelem = I->hi - I->lo + 1; if (fread(I->index,I->nb,nelem,fp)!=nelem) return 3; gcvt_index(I); return 0; } /****************************************************************************** gindex_newstart Replaces the current value of 'I->start' with a new value. This is the number that is added by gindex_get() to the final result of any index lookup. ******************************************************************************/ void gindex_newstart(gvdr_index_t *I, long start) { I->start = start; } /****************************************************************************** gindex_len Returns length index will occupy on disk. ******************************************************************************/ int gindex_len(gvdr_index_t *I) { return sizeof(gvdr_index_rec) + I->nb*(I->hi - I->lo + 1); }