/****************************************************************************** * * NSSDC/CDF CDF library miscellaneous functions, part 3. * * Version 1.0e, 29-Oct-97, Hughes STX. * * Modification history: * * V1.0 5-Sep-96, J Love Original version. * V1.0a 21-Feb-97, J Love Removed RICE. * V1.0b 4-Mar-97, J Love Windows NT for MS Visual C/C++ on an IBM PC. * V1.0c 11-Sep-97, J Love Magic number are now uInt32. * V1.0d 20-Oct-97, J Love Properly cast the uInt32 magic numbers. More * Windows NT. * V3.2 25-Apr-07, D Berger Changed COPYblockBYTES from 512. * ******************************************************************************/ #include "cdflib.h" /****************************************************************************** * Macros/function prototypes. ******************************************************************************/ #define COPYblockSIZE nCACHE_BUFFER_BYTEs static CDFstatus SearchForRecord_r PROTOARGs(( vFILE *fp, Int32 vxrOffset, Int32 recNum, Int32 *firstRec, Int32 *lastRec, Int32 *offset, Logical *found )); static CDFstatus IndexingStatistics_r PROTOARGs(( vFILE *fp, Int32 vxrOffset, Int32 maxRec, int level, Int32 *nLevels, Int32 *nVXRs, Int32 *nEntries, Int32 *nAlloc, Int32 *nRecords )); static CDFstatus PrevRecord_r PROTOARGs(( vFILE *fp, Int32 vxrOffset, Int32 baseRec, Int32 *prevRec, Logical *found )); static CDFstatus NextRecord_r PROTOARGs(( vFILE *fp, Int32 vxrOffset, Int32 baseRec, Int32 *nextRec, Logical *found )); static CDFstatus CalcCompressionPct_r PROTOARGs(( vFILE *fp, Int32 vxrOffset, Int32 nPhyRecBytes, long *uTotal, long *cTotal )); static CDFstatus ModIndexOffset_r PROTOARGs(( vFILE *fp, Int32 vxrOffset, Int32 firstRec, Int32 lastRec, Int32 newOffset )); static CDFstatus ReadSparseFull PROTOARGs(( struct CDFstruct *CDF, struct VarStruct *Var, Int32 firstRec, Int32 lastRec, void *buffer )); static CDFstatus ReadSparsePartial PROTOARGs(( struct CDFstruct *CDF, struct VarStruct *Var, Int32 recNum, Int32 offset, Int32 nValues, void *buffer )); static CDFstatus ReadCompressedFull PROTOARGs(( struct CDFstruct *CDF, struct VarStruct *Var, Int32 firstRec, Int32 lastRec, void *buffer )); static CDFstatus ReadCompressedPartial PROTOARGs(( struct CDFstruct *CDF, struct VarStruct *Var, Int32 recNum, Int32 offset, Int32 nValues, void *buffer )); static CDFstatus BringToStage PROTOARGs(( struct CDFstruct *CDF, struct VarStruct *Var, Int32 recNum, Logical *found )); static CDFstatus WriteCompressedRecords PROTOARGs(( struct CDFstruct *CDF, struct VarStruct *Var, Int32 firstRec, Int32 lastRec, void *buffer, Int32 nValues, Int32 offset, Logical fullRecord )); /****************************************************************************** * DecompressCDF. ******************************************************************************/ STATICforIDL CDFstatus DecompressCDF (dotFp, uDotFp) vFILE *dotFp; /* In: File pointer to dotCDF file. */ vFILE *uDotFp; /* In: Uncompressed CDF file pointer. */ { CDFstatus pStatus = CDF_OK; struct CCRstruct CCR; struct CPRstruct CPR; uInt32 magicNumber1 = V2magicNUMBER_1, magicNumber2u = V2magicNUMBER_2u; Int32 cSize, cOffset; /**************************************************************************** * Read/validate CCR. ****************************************************************************/ if (!sX(ReadCCR(dotFp,V2_CCR_OFFSET, CCR_RECORD,&CCR, CCR_NULL),&pStatus)) return pStatus; if (CCR.uSize == 0) return EMPTY_COMPRESSED_CDF; /**************************************************************************** * Read CPR. ****************************************************************************/ if (!sX(ReadCPR(dotFp,CCR.CPRoffset, CPR_RECORD,&CPR, CPR_NULL),&pStatus)) return pStatus; /**************************************************************************** * Write magic numbers. ****************************************************************************/ if (!SEEKv(uDotFp,V2_MAGIC_OFFSET_1,vSEEK_SET)) return CDF_WRITE_ERROR; if (!Write32(uDotFp,(Int32 *)&magicNumber1)) return CDF_WRITE_ERROR; if (!Write32(uDotFp,(Int32 *)&magicNumber2u)) return CDF_WRITE_ERROR; /**************************************************************************** * Copy/decompress. ****************************************************************************/ cOffset = V2_CCR_OFFSET + CCR_BASE_SIZE; cSize = CCR.RecordSize - CCR_BASE_SIZE; if (!sX(Decompress(dotFp,cOffset, cSize,CDF_READ_ERROR, CPR.cType,CPR.cParms, uDotFp,FIRST_IR_OFFSET, CDF_WRITE_ERROR),&pStatus)) return pStatus; return pStatus; } /****************************************************************************** * WriteCompressedCDF. ******************************************************************************/ STATICforIDL CDFstatus WriteCompressedCDF (CDF, CPR, empty) struct CDFstruct *CDF; struct CPRstruct *CPR; Logical empty; /* In: If TRUE, write an empty CCR. */ { uInt32 magicNumber1 = V2magicNUMBER_1; uInt32 magicNumber2c = V2magicNUMBER_2c; struct CCRstruct CCR; CDFstatus pStatus = CDF_OK; /**************************************************************************** * Write magic numbers. ****************************************************************************/ if (!SEEKv(CDF->dotFp,V2_MAGIC_OFFSET_1,vSEEK_SET)) return CDF_WRITE_ERROR; if (!Write32(CDF->dotFp,(Int32 *)&magicNumber1)) return CDF_WRITE_ERROR; if (!Write32(CDF->dotFp,(Int32 *)&magicNumber2c)) return CDF_WRITE_ERROR; /**************************************************************************** * Write CCR. ****************************************************************************/ if (empty) { CCR.RecordSize = CCR_BASE_SIZE; CCR.RecordType = CCR_; CCR.CPRoffset = V2_CCR_OFFSET + CCR.RecordSize; CCR.uSize = 0; CCR.rfuA = 0; if (!sX(WriteCCR(CDF->dotFp,V2_CCR_OFFSET, CCR_RECORD,&CCR, CCR_NULL),&pStatus)) return CDF_WRITE_ERROR; } else { Int32 uSize, eof, cSize, cOffset, GDRoffset; if (!sX(ReadCDR(CDF->uDotFp,V2_CDR_OFFSET, CDR_GDROFFSET,&GDRoffset, CDR_NULL),&pStatus)) return pStatus; if (!sX(ReadGDR(CDF->uDotFp,GDRoffset, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; uSize = eof - FIRST_IR_OFFSET; cOffset = V2_CCR_OFFSET + CCR_BASE_SIZE; if (!sX(Compress(CDF->uDotFp,FIRST_IR_OFFSET, uSize,CDF_READ_ERROR,CPR->cType, CPR->cParms,CDF->dotFp,cOffset, &cSize,CDF_WRITE_ERROR),&pStatus)) return pStatus; CCR.RecordSize = CCR_BASE_SIZE + cSize; CCR.RecordType = CCR_; CCR.CPRoffset = V2_CCR_OFFSET + CCR.RecordSize; CCR.uSize = uSize; CCR.rfuA = 0; if (!sX(WriteCCR(CDF->dotFp,V2_CCR_OFFSET, CCR_RECORD,&CCR, CCR_NULL),&pStatus)) return CDF_WRITE_ERROR; } /**************************************************************************** * Write CPR. ****************************************************************************/ if (!sX(WriteCPR(CDF->dotFp,CCR.CPRoffset, CPR_RECORD,CPR, CPR_NULL),&pStatus)) return CDF_WRITE_ERROR; return pStatus; } /****************************************************************************** * CopyCDF. ******************************************************************************/ STATICforIDL CDFstatus CopyCDF (srcFp, destFp) vFILE *srcFp; vFILE *destFp; { Int32 nBytes, offset; Byte buffer[nCACHE_BUFFER_BYTEs]; CDFstatus pStatus = CDF_OK; if (!SEEKv(srcFp,0L,vSEEK_END)) return CDF_READ_ERROR; nBytes = V_tell (srcFp); if (nBytes == EOF) return CDF_READ_ERROR; if (!SEEKv(srcFp,0L,vSEEK_SET)) return CDF_READ_ERROR; if (!SEEKv(destFp,0L,vSEEK_SET)) return CDF_WRITE_ERROR; for (offset = 0; offset < nBytes; offset += nCACHE_BUFFER_BYTEs) { Int32 nBytesRemaining = nBytes - offset; size_t count = (size_t) MINIMUM (nBytesRemaining, nCACHE_BUFFER_BYTEs); if (!READv(buffer,count,1,srcFp)) return CDF_READ_ERROR; if (!WRITEv(buffer,count,1,destFp)) return CDF_WRITE_ERROR; } return pStatus; } /****************************************************************************** * WriteVarValues. * NOTE: If more than one record is being written, full records are assumed * and the `offset' must be zero. ******************************************************************************/ STATICforIDL CDFstatus WriteVarValues (CDF, Var, startRec, offset, nValues, buffer) struct CDFstruct *CDF; struct VarStruct *Var; Int32 startRec; /* Physical record number at which to write. */ Int32 offset; /* Byte offset within (first) record at which to begin writing. */ Int32 nValues; /* Number of values to write. */ void *buffer; { Int32 tOffset; Logical fullRecord; Byte *tBuffer = buffer; Int32 numElems, firstRec, lastRec, lastRecInVVR, nBytes, padTo, recNum; Int32 writeTo, recCount; CDFstatus pStatus = CDF_OK; /**************************************************************************** * Determine first/last record(s) being written and if full physical * record(s). ****************************************************************************/ firstRec = startRec; if (nValues < Var->NphyRecValues) { fullRecord = FALSE; lastRec = startRec; } else { fullRecord = TRUE; lastRec = startRec + ((nValues - 1) / Var->NphyRecValues); } /**************************************************************************** * Based on variable type... ****************************************************************************/ switch (Var->vType) { /************************************************************************** * Standard variable in single-file CDF... **************************************************************************/ case STANDARD_: { /************************************************************************ * Allocate/pad records. ************************************************************************/ if (lastRec > Var->maxAllocated) { struct AllocStruct alloc; Int32 nNeeded = lastRec - Var->maxAllocated; Int32 nRecords = MAXIMUM(nNeeded,Var->blockingFactor); LoadAllocVVR (alloc, Var->maxAllocated + 1, Var->maxAllocated + nRecords, FALSE) if (!sX(AllocateRecords(CDF,Var,alloc),&pStatus)) return pStatus; Var->maxAllocated = alloc.last; } padTo = BOO(fullRecord,firstRec - 1,firstRec); if (padTo > Var->maxWritten) { Int32 padFrom = Var->maxWritten + 1; if (!sX(PadUnRecords(CDF,Var,padFrom,padTo),&pStatus)) return pStatus; Var->maxWritten = padTo; } /************************************************************************ * Write value(s). ************************************************************************/ if (fullRecord) { recNum = firstRec; while (recNum <= lastRec) { if (!sX(SearchForRecord(CDF,Var->VDRoffset, Var->zVar,recNum, NULL,&lastRecInVVR, NULL,NULL),&pStatus)) return pStatus; writeTo = MINIMUM(lastRec,lastRecInVVR); recCount = writeTo - recNum + 1; if (!sX(RecordByteOffset(CDF,Var, recNum, &tOffset),&pStatus)) return pStatus; numElems = recCount * Var->NphyRecElems; if (!sX(WriteVarElems(Var,CDF->fp,tOffset, numElems,tBuffer),&pStatus)) return pStatus; recNum += recCount; tBuffer += (size_t) (recCount * Var->NphyRecBytes); } } else { if (!sX(RecordByteOffset(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; tOffset += (Int32) offset; numElems = nValues * Var->NvalueElems; if (!sX(WriteVarElems(Var,CDF->fp,tOffset, numElems,buffer),&pStatus)) return pStatus; } /************************************************************************ * Update the maximum record written. ************************************************************************/ Var->maxWritten = MAXIMUM(Var->maxWritten,lastRec); break; } /************************************************************************** * Sparse records... **************************************************************************/ case SPARSE_RECORDS_: { Int32 maxRecInStage, recordOffsetInStage, nextRec; int how; void *padBuffer; Logical found; /************************************************************************ * Pad records. ************************************************************************/ padTo = BOO(fullRecord,firstRec - 1,firstRec); if (padTo > Var->maxWritten) { Int32 padFrom = Var->maxWritten + 1; if (!sX(PadUnRecords(CDF,Var,padFrom,padTo),&pStatus)) return pStatus; Var->maxWritten = padTo; } /************************************************************************ * Write value(s). ************************************************************************/ recNum = firstRec; while (recNum <= lastRec) { /********************************************************************** * Check if this record already exists (is allocated). **********************************************************************/ if (!sX(SearchForRecord(CDF,Var->VDRoffset, Var->zVar,recNum, NULL,&lastRecInVVR, NULL,&found),&pStatus)) return pStatus; if (found) { writeTo = MINIMUM(lastRec,lastRecInVVR); recCount = writeTo - recNum + 1; if (!sX(RecordByteOffset(CDF,Var, recNum,&tOffset),&pStatus)) return pStatus; if (fullRecord) numElems = recCount * Var->NphyRecElems; else { tOffset += offset; numElems = nValues * Var->NvalueElems; } if (!sX(WriteVarElems(Var,CDF->fp,tOffset, numElems,tBuffer),&pStatus)) return pStatus; Var->maxWritten = MAXIMUM(Var->maxWritten,writeTo); recNum += recCount; tBuffer += (size_t) (numElems * Var->NelemBytes); continue; } /********************************************************************** * This record doesn't exist - initialize the staging area. **********************************************************************/ if (Var->stage.areaOffset == NO_OFFSET) { nBytes = Var->blockingFactor * Var->NphyRecBytes; if (!sX(InitVarStage(CDF,Var,nBytes),&pStatus)) return pStatus; } /********************************************************************** * Check if this record is in the staging area. **********************************************************************/ if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) { maxRecInStage = Var->stage.firstRec + Var->blockingFactor - 1; writeTo = MINIMUM(lastRec,maxRecInStage); if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar, recNum,&nextRec,&found),&pStatus)) return pStatus; if (found) { Int32 prevRecN = nextRec - 1; writeTo = MINIMUM(writeTo,prevRecN); } recCount = writeTo - recNum + 1; recordOffsetInStage = recNum - Var->stage.firstRec; tOffset = Var->stage.areaOffset; tOffset += (recordOffsetInStage * Var->NphyRecBytes); if (fullRecord) numElems = recCount * Var->NphyRecElems; else { tOffset += offset; numElems = nValues * Var->NvalueElems; } if (!sX(WriteVarElems(Var,CDF->stage.fp,tOffset, numElems,tBuffer),&pStatus)) return pStatus; Var->stage.lastRec = MAXIMUM(Var->stage.lastRec,writeTo); Var->stage.modified = TRUE; recNum += recCount; tBuffer += (size_t) (numElems * Var->NelemBytes); continue; } /********************************************************************** * This record is not in the staging area. Check if it can be added. **********************************************************************/ if (Var->stage.firstRec != NO_RECORD) { if (recNum == Var->stage.lastRec + 1) { maxRecInStage = Var->stage.firstRec + Var->blockingFactor - 1; if (recNum <= maxRecInStage) { writeTo = MINIMUM(lastRec,maxRecInStage); if (!sX(NextRecord(CDF,Var->VDRoffset, Var->zVar,recNum, &nextRec,&found),&pStatus)) return pStatus; if (found) { Int32 prevRecN = nextRec - 1; writeTo = MINIMUM(writeTo,prevRecN); } recCount = writeTo - recNum + 1; recordOffsetInStage = recNum - Var->stage.firstRec; tOffset = Var->stage.areaOffset; tOffset += (recordOffsetInStage * Var->NphyRecBytes); if (fullRecord) numElems = recCount * Var->NphyRecElems; else { if (!sX(BuildPadBuffer(CDF,Var,recCount, &how,&padBuffer, TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues(Var,CDF->stage.fp,tOffset, recCount,how,padBuffer),&pStatus)) { cdf_FreeMemory (padBuffer, NULL); return pStatus; } cdf_FreeMemory (padBuffer, NULL); tOffset += offset; numElems = nValues * Var->NvalueElems; } if (!sX(WriteVarElems(Var,CDF->stage.fp, tOffset,numElems, tBuffer),&pStatus)) return pStatus; Var->stage.lastRec = MAXIMUM(Var->stage.lastRec,writeTo); Var->stage.modified = TRUE; recNum += recCount; tBuffer += (size_t) (numElems * Var->NelemBytes); continue; } } } /********************************************************************** * This record cannot be added to the staging area. First flush the * staging area (if necessary)... **********************************************************************/ if (!sX(FlushStage(CDF,Var),&pStatus)) return pStatus; /********************************************************************** * ...and then start a new staging area with this record. **********************************************************************/ maxRecInStage = recNum + Var->blockingFactor - 1; writeTo = MINIMUM(lastRec,maxRecInStage); if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar, recNum,&nextRec,&found),&pStatus)) return pStatus; if (found) { Int32 prevRecN = nextRec - 1; writeTo = MINIMUM(writeTo,prevRecN); } recCount = writeTo - recNum + 1; tOffset = Var->stage.areaOffset; if (fullRecord) numElems = recCount * Var->NphyRecElems; else { if (!sX(BuildPadBuffer(CDF,Var,recCount, &how,&padBuffer, TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues(Var,CDF->stage.fp,tOffset, recCount,how,padBuffer),&pStatus)) { cdf_FreeMemory (padBuffer, NULL); return pStatus; } cdf_FreeMemory (padBuffer, NULL); tOffset += offset; numElems = nValues * Var->NvalueElems; } if (!sX(WriteVarElems(Var,CDF->stage.fp,tOffset, numElems,tBuffer),&pStatus)) return pStatus; Var->stage.firstRec = recNum; Var->stage.lastRec = writeTo; Var->stage.modified = TRUE; recNum += recCount; tBuffer += (size_t) (numElems * Var->NelemBytes); } break; } /************************************************************************** * Compressed records... * Sparse/compressed records... **************************************************************************/ case COMPRESSED_: case SPARSE_COMPRESSED_RECORDS_: { Logical sparseRecords = (Var->vType == SPARSE_COMPRESSED_RECORDS_); /************************************************************************ * Initialize staging area. ************************************************************************/ if (Var->stage.areaOffset == NO_OFFSET) { if (Var->blockingFactor == 0) { if (Var->recVary) { Int32 bf = ((MIN_BLOCKING_BYTES_compressed-1)/Var->NphyRecBytes)+1; Var->blockingFactor = MAXIMUM(bf,MIN_BLOCKING_RECS_compressed); } else Var->blockingFactor = 1; if (!sX(WriteVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar, VDR_BLOCKING,&(Var->blockingFactor), VDR_NULL),&pStatus)) return pStatus; } nBytes = Var->blockingFactor * Var->NphyRecBytes; if (!sX(InitVarStage(CDF,Var,nBytes),&pStatus)) return pStatus; } /************************************************************************ * Pad records (if necessary). ************************************************************************/ if (!sparseRecords) { padTo = firstRec - 1; if (Var->maxRec < padTo) { Int32 nRecords = padTo + 1, recN, valueN; void *padBuffer; int how; if (!sX(BuildPadBuffer(CDF,Var, nRecords,&how, &padBuffer,FALSE),&pStatus)) return pStatus; switch (how) { case ALLrecordsATonce: if (!sX(WriteCompressedRecords(CDF,Var,Var->maxRec+1, padTo,padBuffer, nRecords*Var->NphyRecValues, ZERO_OFFSET, TRUE),&pStatus)) return pStatus; break; case ONErecordATaTIME: for (recN = Var->maxRec + 1; recN <= padTo; recN++) { if (!sX(WriteCompressedRecords(CDF,Var,recN,recN, padBuffer,Var->NphyRecValues, ZERO_OFFSET,TRUE),&pStatus)) { cdf_FreeMemory (padBuffer, NULL); return pStatus; } } break; case ONEvalueATaTIME: for (recN = 0; recN < nRecords; recN++) { for (valueN = 0; valueN < Var->NphyRecValues; valueN++) { tOffset = valueN * Var->NvalueBytes; if (!sX(WriteCompressedRecords(CDF,Var,recN,recN, padBuffer,INT32_ONE, tOffset,FALSE),&pStatus)) { cdf_FreeMemory (padBuffer, NULL); return pStatus; } } } break; } cdf_FreeMemory (padBuffer, NULL); } } /************************************************************************ * Write the record(s). ************************************************************************/ if (!sX(WriteCompressedRecords(CDF,Var,firstRec,lastRec, buffer,nValues,offset, fullRecord),&pStatus)) return pStatus; break; } /************************************************************************** * Can't do sparse arrays yet... **************************************************************************/ case SPARSE_ARRAYS_: case SPARSE_RECORDS_AND_ARRAYS_: return UNKNOWN_SPARSENESS; /************************************************************************** * Variable in multi-file CDF... **************************************************************************/ case IN_MULTI_: { padTo = BOO(fullRecord,firstRec - 1,firstRec); /************************************************************************ * Extend variable (if necessary). ************************************************************************/ if (padTo > Var->maxRec) { Int32 padFrom = Var->maxRec + 1; if (!sX(PadUnRecords(CDF,Var,padFrom,padTo),&pStatus)) return pStatus; } /************************************************************************ * Write value(s). ************************************************************************/ if (!sX(RecordByteOffset(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; tOffset += (Int32) offset; numElems = nValues * Var->NvalueElems; if (!sX(WriteVarElems(Var,Var->fp,tOffset, numElems,buffer),&pStatus)) return pStatus; break; } /************************************************************************** * Unknown variable type - this should never happen. **************************************************************************/ default: return CDF_INTERNAL_ERROR; } /**************************************************************************** * Update maximum record numbers. ****************************************************************************/ if (!sX(UpdateMaxRec(CDF,Var,lastRec),&pStatus)) return pStatus; return pStatus; } /****************************************************************************** * WriteVarElems. * NOTE: On IBM PCs, it is assumed that the number of bytes being written * will not exceed 65535. ******************************************************************************/ STATICforIDL CDFstatus WriteVarElems (Var, fp, offset, numElems, buffer) struct VarStruct *Var; vFILE *fp; Int32 offset; Int32 numElems; void *buffer; { CDFstatus pStatus = CDF_OK; Int32 elemCount; /**************************************************************************** * Seek to the desired offset. ****************************************************************************/ if (!SEEKv(fp,(long)offset,vSEEK_SET)) return VAR_WRITE_ERROR; /**************************************************************************** * If no encoding is necessary, simply write the buffer and return. ****************************************************************************/ if (Var->EncodeFunction == NULL) { Int32 nBytes = numElems * Var->NelemBytes; if (!WRITEv(buffer,1,(size_t)nBytes,fp)) return VAR_WRITE_ERROR; return pStatus; } /**************************************************************************** * Use as large a temporary buffer as possible for the encoding conversion. * Start at the full number of elements and then halve that number until an * allocation succeeds. ****************************************************************************/ elemCount = numElems; for (;;) { size_t nBytes = (size_t) (elemCount * Var->NelemBytes); void *tBuffer = cdf_AllocateMemory (nBytes, NULL); if (tBuffer != NULL) { Int32 elemN = 0; Byte *bOffset = buffer; while (elemN < numElems) { Int32 thisElemCount = MinInt32 (elemCount, numElems - elemN); size_t thisByteCount = (size_t) (thisElemCount * Var->NelemBytes); memmove (tBuffer, bOffset, thisByteCount); if (!sX(Var->EncodeFunction(tBuffer,thisElemCount),&pStatus)) { cdf_FreeMemory (tBuffer, NULL); return pStatus; } if (!WRITEv(tBuffer,1,thisByteCount,fp)) { cdf_FreeMemory (tBuffer, NULL); return VAR_WRITE_ERROR; } elemN += thisElemCount; bOffset += thisByteCount; } cdf_FreeMemory (tBuffer, NULL); return pStatus; } if (elemCount == 1) break; elemCount = (elemCount + 1) / 2; } return BAD_MALLOC; } /****************************************************************************** * PrevRecord. * Determine the last record allocated AT or BEFORE `baseRec'. This routine * should only be used for single-file CDFs. ******************************************************************************/ STATICforIDL CDFstatus PrevRecord (CDF, VDRoffset, zVar, baseRec, prevRec, found) struct CDFstruct *CDF; Int32 VDRoffset; Logical zVar; Int32 baseRec; Int32 *prevRec; Logical *found; /* If NULL, return NO_SUCH_RECORD if the previous record doesn't exist. Otherwise, set according to whether or not the previous record exists and return the pending status. */ { CDFstatus pStatus = CDF_OK; Int32 VXRoffset; /**************************************************************************** * If multi-file... ****************************************************************************/ if (!CDF->singleFile) return CDF_INTERNAL_ERROR; /**************************************************************************** * Single-file...read the offset of the first VXR. ****************************************************************************/ if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar, VDR_VXRHEAD,&VXRoffset, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start there (unless there are no VXRs). ****************************************************************************/ if (VXRoffset != ZERO_OFFSET) { if (!sX(PrevRecord_r(CDF->fp,VXRoffset, baseRec,prevRec,found),&pStatus)) return pStatus; } else { ASSIGNnotNULL (found, FALSE) if (found == NULL) pStatus = NO_SUCH_RECORD; } return pStatus; } static CDFstatus PrevRecord_r (fp, vxrOffset, baseRec, prevRec, found) vFILE *fp; Int32 vxrOffset; Int32 baseRec; Int32 *prevRec; Logical *found; { CDFstatus pStatus = CDF_OK; int entryN = 0; struct VXRstruct VXR, nextVXR; Int32 irType; /**************************************************************************** * Read the first VXR. ****************************************************************************/ if (!sX(ReadVXR(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; /**************************************************************************** * Check if there isn't a previous allocated record. This could only be the * case at the top level of VXRs (ie. not when this routine is recursively * called). ****************************************************************************/ if (baseRec < VXR.First[0]) { ASSIGNnotNULL (found, FALSE) return BOO(found == NULL,NO_SUCH_RECORD,pStatus); } /**************************************************************************** * Until it's time to return... ****************************************************************************/ for (;;) { /************************************************************************* * If the record is in the current entry... *************************************************************************/ if (INCLUSIVE(VXR.First[entryN],baseRec,VXR.Last[entryN])) { if (!sX(ReadIrType(fp,VXR.Offset[entryN],&irType),&pStatus)) { return pStatus; } switch (irType) { case VXR_: return PrevRecord_r(fp,VXR.Offset[entryN],baseRec,prevRec,found); case VVR_: case CVVR_: *prevRec = baseRec; ASSIGNnotNULL (found, TRUE) return pStatus; default: return CORRUPTED_V2_CDF; } } /************************************************************************* * If this is the last entry in the current VXR... *************************************************************************/ if (entryN == VXR.NusedEntries - 1) { if (VXR.VXRnext == ZERO_OFFSET) { *prevRec = VXR.Last[entryN]; ASSIGNnotNULL (found, TRUE) return pStatus; } if (!sX(ReadVXR(fp,VXR.VXRnext, VXR_RECORD,&nextVXR, VXR_NULL),&pStatus)) return pStatus; if (baseRec < nextVXR.First[0]) { *prevRec = VXR.Last[entryN]; ASSIGNnotNULL (found, TRUE) return pStatus; } VXR = nextVXR; entryN = 0; } else { if (baseRec < VXR.First[entryN+1]) { *prevRec = VXR.Last[entryN]; ASSIGNnotNULL (found, TRUE) return pStatus; } entryN++; } } } /****************************************************************************** * NextRecord. * Determine the next allocated record AT or AFTER `baseRec'. I.e., if * `baseRec' is allocated, it is returned as `nextRec'. ******************************************************************************/ STATICforIDL CDFstatus NextRecord (CDF, VDRoffset, zVar, baseRec, nextRec, found) struct CDFstruct *CDF; Int32 VDRoffset; Logical zVar; Int32 baseRec; Int32 *nextRec; Logical *found; /* If NULL, return NO_SUCH_RECORD if the next record doesn't exist. Otherwise, set according to whether or not the next record exists and return the pending status. */ { CDFstatus pStatus = CDF_OK; Int32 VXRoffset, maxRec; /**************************************************************************** * If multi-file... ****************************************************************************/ if (!CDF->singleFile) { if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar, VDR_MAXREC,&maxRec, VDR_NULL),&pStatus)) return pStatus; if (baseRec <= maxRec) { *nextRec = baseRec; ASSIGNnotNULL (found, TRUE) } else { ASSIGNnotNULL (found, FALSE) if (found == NULL) pStatus = NO_SUCH_RECORD; } return pStatus; } /**************************************************************************** * ...single-file, read the offset of the first VXR. ****************************************************************************/ if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar, VDR_VXRHEAD,&VXRoffset, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start there. ****************************************************************************/ if (!sX(NextRecord_r(CDF->fp,VXRoffset, baseRec,nextRec,found),&pStatus)) return pStatus; return pStatus; } static CDFstatus NextRecord_r (fp, vxrOffset, baseRec, nextRec, found) vFILE *fp; Int32 vxrOffset; Int32 baseRec; Int32 *nextRec; Logical *found; { CDFstatus pStatus = CDF_OK; int entryN; struct VXRstruct VXR; Int32 irType; /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != ZERO_OFFSET) { /************************************************************************** * Read the VXR. **************************************************************************/ if (!sX(ReadVXR(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; /************************************************************************** * Search entries... **************************************************************************/ if (baseRec <= VXR.Last[(int)(VXR.NusedEntries-1)]) { for (entryN = 0; entryN < VXR.NusedEntries; entryN++) { if (baseRec <= VXR.Last[entryN]) { if (!sX(ReadIrType(fp, VXR.Offset[entryN], &irType),&pStatus)) return pStatus; switch (irType) { case VXR_: return NextRecord_r(fp,VXR.Offset[entryN], baseRec,nextRec,found); case VVR_: case CVVR_: *nextRec = BOO(VXR.First[entryN] <= baseRec, baseRec,VXR.First[entryN]); ASSIGNnotNULL (found, TRUE) return pStatus; default: return CORRUPTED_V2_CDF; } } } } vxrOffset = VXR.VXRnext; } /**************************************************************************** * No (more) VXRs. The record number was never found. ****************************************************************************/ ASSIGNnotNULL (found, FALSE) return BOO(found == NULL,NO_SUCH_RECORD,pStatus); } /****************************************************************************** * SearchForRecord. ******************************************************************************/ STATICforIDL CDFstatus SearchForRecord (CDF, VDRoffset, zVar, recNum, firstRec, lastRec, offset, found) struct CDFstruct *CDF; Int32 VDRoffset; Logical zVar; Int32 recNum; Int32 *firstRec; Int32 *lastRec; Int32 *offset; Logical *found; /* If NULL, return NO_SUCH_RECORD if the record is not found. Otherwise, set according to whether or not the record is found and return the pending status. */ { CDFstatus pStatus = CDF_OK; Int32 vxrOffset, maxRec; /**************************************************************************** * If multi-file... ****************************************************************************/ if (!CDF->singleFile) { if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar, VDR_MAXREC,&maxRec, VDR_NULL),&pStatus)) return pStatus; if (recNum <= maxRec) { ASSIGNnotNULL (firstRec, 0) ASSIGNnotNULL (lastRec, maxRec) ASSIGNnotNULL (offset, ZERO_OFFSET) ASSIGNnotNULL (found, TRUE) } else { ASSIGNnotNULL (found, FALSE) if (found == NULL) pStatus = NO_SUCH_RECORD; } return pStatus; } /**************************************************************************** * ...single-file, read the offset of the first VXR. ****************************************************************************/ if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar, VDR_VXRHEAD,&vxrOffset, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start searching there. ****************************************************************************/ if (!sX(SearchForRecord_r(CDF->fp,vxrOffset,recNum, firstRec,lastRec, offset,found),&pStatus)) return pStatus; return pStatus; } static CDFstatus SearchForRecord_r (fp, vxrOffset, recNum, firstRec, lastRec, offset, found) vFILE *fp; Int32 vxrOffset; Int32 recNum; Int32 *firstRec; Int32 *lastRec; Int32 *offset; Logical *found; { CDFstatus pStatus = CDF_OK; int entryN; struct VXRstruct VXR; Int32 irType; /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != ZERO_OFFSET) { /************************************************************************** * Read the VXR. **************************************************************************/ if (!sX(ReadVXR(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; /************************************************************************** * Search entries... **************************************************************************/ if (recNum <= VXR.Last[(int)(VXR.NusedEntries-1)]) { for (entryN = 0; entryN < VXR.NusedEntries; entryN++) { if (recNum <= VXR.Last[entryN]) { if (VXR.First[entryN] <= recNum) { if (!sX(ReadIrType(fp, VXR.Offset[entryN], &irType),&pStatus)) return pStatus; switch (irType) { case VXR_: return SearchForRecord_r(fp,VXR.Offset[entryN],recNum, firstRec,lastRec,offset,found); case VVR_: case CVVR_: ASSIGNnotNULL (firstRec, VXR.First[entryN]) ASSIGNnotNULL (lastRec, VXR.Last[entryN]) ASSIGNnotNULL (offset, VXR.Offset[entryN]) ASSIGNnotNULL (found, TRUE) return pStatus; default: return CORRUPTED_V2_CDF; } } else { ASSIGNnotNULL (found, FALSE) return BOO(found == NULL,NO_SUCH_RECORD,pStatus); } } } } vxrOffset = VXR.VXRnext; } /**************************************************************************** * No (more) VXRs. The record number was never found. ****************************************************************************/ ASSIGNnotNULL (found, FALSE) return BOO(found == NULL,NO_SUCH_RECORD,pStatus); } /****************************************************************************** * IndexingStatistics. ******************************************************************************/ STATICforIDL CDFstatus IndexingStatistics (CDF, VDRoffset, zVar, nVXRsP, nEntriesP, nAllocP, nRecordsP, nLevelsP) struct CDFstruct *CDF; Int32 VDRoffset; Logical zVar; Int32 *nVXRsP; Int32 *nEntriesP; Int32 *nAllocP; Int32 *nRecordsP; Int32 *nLevelsP; { CDFstatus pStatus = CDF_OK; Int32 vxrOffset, maxRec; int level = 1; Int32 nVXRs = 0, nEntries = 0, nAlloc = 0, nRecords = 0, nLevels = 0; /**************************************************************************** * Read the maximum record and the offset of the first VXR... ****************************************************************************/ if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar, VDR_VXRHEAD,&vxrOffset, VDR_MAXREC,&maxRec, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start there. ****************************************************************************/ if (vxrOffset != ZERO_OFFSET) { if (!sX(IndexingStatistics_r(CDF->fp,vxrOffset, maxRec,level,&nLevels, &nVXRs,&nEntries, &nAlloc,&nRecords),&pStatus)) return pStatus; } /**************************************************************************** * Pass back requested statistics. ****************************************************************************/ ASSIGNnotNULL (nVXRsP, nVXRs) ASSIGNnotNULL (nEntriesP, nEntries) ASSIGNnotNULL (nAllocP, nAlloc) ASSIGNnotNULL (nRecordsP, nRecords) ASSIGNnotNULL (nLevelsP, nLevels) return pStatus; } static CDFstatus IndexingStatistics_r (fp, vxrOffset, maxRec, level, nLevels, nVXRs, nEntries, nAlloc, nRecords) vFILE *fp; Int32 vxrOffset; Int32 maxRec; int level; Int32 *nLevels; Int32 *nVXRs; Int32 *nEntries; Int32 *nAlloc; Int32 *nRecords; { CDFstatus pStatus = CDF_OK; int e; Int32 irType; struct VXRstruct VXR; /**************************************************************************** * Check if a new level has been reached. ****************************************************************************/ *nLevels = MAXIMUM(*nLevels,level); /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != ZERO_OFFSET) { /************************************************************************** * Read/tally the VXR. **************************************************************************/ if (!sX(ReadVXR(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; (*nVXRs)++; /************************************************************************** * Scan/count entries... **************************************************************************/ for (e = 0; e < VXR.NusedEntries; e++) { (*nEntries)++; if (!sX(ReadIrType(fp, VXR.Offset[e], &irType),&pStatus)) return pStatus; switch (irType) { case VXR_: if (!sX(IndexingStatistics_r(fp,VXR.Offset[e], maxRec,level+1, nLevels,nVXRs, nEntries,nAlloc, nRecords),&pStatus)) return pStatus; break; case VVR_: case CVVR_: *nAlloc += (VXR.Last[e] - VXR.First[e] + 1); if (VXR.First[e] <= maxRec) { *nRecords += MINIMUM(maxRec,VXR.Last[e]) - VXR.First[e] + 1; } break; default: return CORRUPTED_V2_CDF; } } vxrOffset = VXR.VXRnext; } return pStatus; } /****************************************************************************** * BuildPadBuffer. ******************************************************************************/ STATICforIDL CDFstatus BuildPadBuffer (CDF, Var, nRecords, how, buffer, encode) struct CDFstruct *CDF; struct VarStruct *Var; Int32 nRecords; int *how; void **buffer; Logical encode; /* If TRUE, return values in CDF's encoding. If FALSE, return values in host computer's encoding. */ { Byte *ptr; Int32 nBytes, nValues, valueN; void *padValue; Int32 VDRflags, dataType, numElems; CDFstatus pStatus = CDF_OK; /**************************************************************************** * Determine pad value. ****************************************************************************/ if (!sX(ReadVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar, VDR_DATATYPE,&dataType, VDR_NUMELEMS,&numElems, VDR_FLAGS,&VDRflags, VDR_NULL),&pStatus)) return pStatus; padValue = (void *) cdf_AllocateMemory ((size_t) Var->NvalueBytes, NULL); if (padValue == NULL) return BAD_MALLOC; if (PADvalueBITset(VDRflags)) { if (!sX(ReadVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar, VDR_PADVALUE,padValue, VDR_NULL),&pStatus)) { cdf_FreeMemory (padValue, NULL); return pStatus; } if (!encode) { if (!sX(ConvertBuffer(CDF->encoding,HostDecoding(), CDF->negToPosFp0,dataType, numElems,padValue,padValue),&pStatus)) { cdf_FreeMemory (padValue, NULL); return pStatus; } } } else { DefaultPadValue (dataType, numElems, padValue); if (encode) { if (!sX(ConvertBuffer(HostEncoding(),CDF->encoding, CDF->negToPosFp0,dataType, numElems,padValue,padValue),&pStatus)) { cdf_FreeMemory (padValue, NULL); return pStatus; } } } /**************************************************************************** * Try to allocate all of the records at once... ****************************************************************************/ nValues = nRecords * Var->NphyRecValues; nBytes = nValues * Var->NvalueBytes; #if LIMITof64K if (nBytes < 65536L) { #endif *buffer = (void *) cdf_AllocateMemory ((size_t) nBytes, NULL); if (*buffer != NULL) { for (valueN = 0, ptr = (Byte *) *buffer; valueN < nValues; valueN++, ptr += (size_t) Var->NvalueBytes) { memmove (ptr, padValue, (size_t) Var->NvalueBytes); } cdf_FreeMemory (padValue, NULL); *how = ALLrecordsATonce; return pStatus; } #if LIMITof64K } #endif /**************************************************************************** * Not enough memory for that, try allocating one record... ****************************************************************************/ #if LIMITof64K if (Var->NphyRecBytes < 65536L) { #endif *buffer = (void *) cdf_AllocateMemory ((size_t) Var->NphyRecBytes, NULL); if (*buffer != NULL) { for (valueN = 0, ptr = (Byte *) *buffer; valueN < Var->NphyRecValues; valueN++, ptr += (size_t) Var->NvalueBytes) { memmove (ptr, padValue, (size_t) Var->NvalueBytes); } cdf_FreeMemory (padValue, NULL); *how = ONErecordATaTIME; return pStatus; } #if LIMITof64K } #endif /**************************************************************************** * Not enough memory for that either, use the one allocated value... ****************************************************************************/ *buffer = padValue; *how = ONEvalueATaTIME; return pStatus; } /****************************************************************************** * ReadVarValues. * NOTE: If more than one record is being read, full records are assumed * and the `offset' must be zero. ******************************************************************************/ STATICforIDL CDFstatus ReadVarValues (CDF, Var, startRec, offset, nValues, buffer) struct CDFstruct *CDF; struct VarStruct *Var; Int32 startRec; /* Physical record number at which to start reading. */ Int32 offset; /* Byte offset within (first) record at which to begin reading. */ Int32 nValues; /* Number of values to read. */ void *buffer; { CDFstatus pStatus = CDF_OK; Int32 tOffset; Logical fullRecord; Int32 numElems, firstRec, lastRec, lastRecInVVR, nPadValues; Int32 readTo, recCount, nBytes; /**************************************************************************** * Determine first/last record(s) being read and if full physical record(s). ****************************************************************************/ firstRec = startRec; if (nValues < Var->NphyRecValues) { fullRecord = FALSE; lastRec = startRec; } else { fullRecord = TRUE; lastRec = startRec + ((nValues - 1) / Var->NphyRecValues); } /**************************************************************************** * Read value(s). ****************************************************************************/ switch (Var->vType) { /************************************************************************** * Standard variable in a single-file CDF... **************************************************************************/ case STANDARD_: if (fullRecord) { /********************************************************************** * Full record(s) - read from contiguous groups... **********************************************************************/ Byte *tBuffer = buffer; Int32 recNum = firstRec; while (recNum <= lastRec) { if (recNum <= Var->maxRec) { if (!sX(SearchForRecord(CDF,Var->VDRoffset, Var->zVar,recNum, NULL,&lastRecInVVR, NULL,NULL),&pStatus)) return pStatus; readTo = MINIMUMof3(Var->maxRec,lastRec,lastRecInVVR); recCount = readTo - recNum + 1; if (!sX(RecordByteOffset(CDF,Var, recNum, &tOffset),&pStatus)) return pStatus; numElems = recCount * Var->NphyRecElems; if (!sX(ReadVarElems(Var,CDF->fp,tOffset, numElems,tBuffer),&pStatus)) return pStatus; } else { recCount = lastRec - recNum + 1; nPadValues = recCount * Var->NphyRecValues; if (!sX(PadBuffer(CDF,Var, nPadValues, tBuffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); } recNum += recCount; tBuffer += (size_t) (recCount * Var->NphyRecBytes); } } else { /********************************************************************** * Partial record... **********************************************************************/ if (firstRec <= Var->maxRec) { if (!sX(RecordByteOffset(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; tOffset += (Int32) offset; numElems = nValues * Var->NvalueElems; if (!sX(ReadVarElems(Var,CDF->fp,tOffset, numElems,buffer),&pStatus)) return pStatus; } else { if (!sX(PadBuffer(CDF,Var,nValues,buffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); } } break; /************************************************************************** * Sparse records... **************************************************************************/ case SPARSE_RECORDS_: { if (fullRecord) { if (!sX(ReadSparseFull(CDF,Var,firstRec, lastRec,buffer),&pStatus)) return pStatus; } else { if (!sX(ReadSparsePartial(CDF,Var, startRec,offset, nValues,buffer),&pStatus)) return pStatus; } break; } /************************************************************************** * Compressed variable... **************************************************************************/ case COMPRESSED_: case SPARSE_COMPRESSED_RECORDS_: { /************************************************************************ * Initialize staging area. Note that the staging area is only * initialized if records have been written. This prevents the * CORRUPTED_V2_CDF error code from being returned if an explicit * blocking factor has not been specified for the variable. ************************************************************************/ if (Var->stage.areaOffset == NO_OFFSET && Var->maxRec > NO_RECORD) { if (Var->blockingFactor == 0) return CORRUPTED_V2_CDF; nBytes = Var->blockingFactor * Var->NphyRecBytes; if (!sX(InitVarStage(CDF,Var,nBytes),&pStatus)) return pStatus; } /************************************************************************ * If full record(s) or partial record... ************************************************************************/ if (fullRecord) { if (!sX(ReadCompressedFull(CDF,Var,firstRec, lastRec,buffer),&pStatus)) return pStatus; } else { if (!sX(ReadCompressedPartial(CDF,Var,startRec, offset,nValues, buffer),&pStatus)) return pStatus; } break; } /************************************************************************** * Can't do sparse arrays yet... **************************************************************************/ case SPARSE_ARRAYS_: case SPARSE_RECORDS_AND_ARRAYS_: return UNKNOWN_SPARSENESS; case IN_MULTI_: if (fullRecord) { /******************************************************************** * Full record(s). ********************************************************************/ Byte *tBuffer = buffer; if (firstRec <= Var->maxRec) { if (!sX(RecordByteOffset(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; recCount = MINIMUM(lastRec,Var->maxRec) - firstRec + 1; numElems = recCount * Var->NphyRecElems; if (!sX(ReadVarElems(Var,Var->fp,tOffset, numElems,tBuffer),&pStatus)) return pStatus; tBuffer += (size_t) (recCount * Var->NphyRecBytes); } if (lastRec > Var->maxRec) { recCount = BOO(Var->maxRec < firstRec, lastRec - firstRec + 1, lastRec - Var->maxRec); nPadValues = recCount * Var->NphyRecValues; if (!sX(PadBuffer(CDF,Var, nPadValues, tBuffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); } } else { /******************************************************************** * Partial record. ********************************************************************/ if (firstRec <= Var->maxRec) { if (!sX(RecordByteOffset(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; tOffset += (Int32) offset; numElems = nValues * Var->NvalueElems; if (!sX(ReadVarElems(Var,Var->fp,tOffset, numElems,buffer),&pStatus)) return pStatus; } else { if (!sX(PadBuffer(CDF,Var,nValues,buffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); } } break; } return pStatus; } /****************************************************************************** * ReadVarElems. * NOTE: On IBM PCs, it is assumed that the number of bytes being read * will not exceed 65535. ******************************************************************************/ STATICforIDL CDFstatus ReadVarElems (Var, fp, offset, numElems, buffer) struct VarStruct *Var; vFILE *fp; Int32 offset; Int32 numElems; void *buffer; { CDFstatus pStatus = CDF_OK; size_t nBytes; /**************************************************************************** * Seek to the desired offset. ****************************************************************************/ if (!SEEKv(fp,(long)offset,vSEEK_SET)) return VAR_READ_ERROR; /**************************************************************************** * Read the value(s). ****************************************************************************/ nBytes = (size_t) (numElems * Var->NelemBytes); if (!READv(buffer,nBytes,1,fp)) return VAR_READ_ERROR; /**************************************************************************** * Decode value(s). ****************************************************************************/ if (!sX(DECODE(Var->DecodeFunction,buffer,numElems),&pStatus)) { return pStatus; } return pStatus; } /****************************************************************************** * ROWtoCOL. ******************************************************************************/ VISIBLE_PREFIX void ROWtoCOL (iBuffer, oBuffer, numDims, dimSizes, nValueBytes) void *iBuffer; void *oBuffer; long numDims; long dimSizes[]; long nValueBytes; { switch (numDims) { case 0: case 1: { long nValues; int dimN; for (dimN = 0, nValues = 1; dimN < numDims; dimN++) { nValues *= dimSizes[dimN]; } memmove (oBuffer, iBuffer, (size_t) (nValues * nValueBytes)); break; } default: { long products[CDF_MAX_DIMS]; /* Products, what each dimension is `worth'. */ long iBoffset; /* Input buffer, byte offset. */ long oBoffset; /* Output buffer, byte offset. */ long oVoffset; /* Output buffer, value offset. */ int dimN; /* Dimension number. */ for (dimN = 1, products[0] = 1; dimN < numDims; dimN++) { products[dimN] = products[dimN-1] * dimSizes[dimN-1]; } switch (numDims) { case 2: { long d0, d1; /* Indices... */ for (d0 = 0, iBoffset = 0; d0 < dimSizes[0]; d0++) { for (d1 = 0; d1 < dimSizes[1]; d1++) { oVoffset = (d0 * products[0]) + (d1 * products[1]); oBoffset = oVoffset * nValueBytes; memmove ((Byte *) oBuffer + (size_t) oBoffset, (Byte *) iBuffer + (size_t) iBoffset, (size_t) nValueBytes); iBoffset += nValueBytes; } } break; } case 3: { long d0, d1, d2; /* Indices... */ for (d0 = 0, iBoffset = 0; d0 < dimSizes[0]; d0++) { for (d1 = 0; d1 < dimSizes[1]; d1++) { for (d2 = 0; d2 < dimSizes[2]; d2++) { oVoffset = (d0 * products[0]) + (d1 * products[1]) + (d2 * products[2]); oBoffset = oVoffset * nValueBytes; memmove ((Byte *) oBuffer + (size_t) oBoffset, (Byte *) iBuffer + (size_t) iBoffset, (size_t) nValueBytes); iBoffset += nValueBytes; } } } break; } default: { long indices[CDF_MAX_DIMS]; long nValues; long i; for (dimN = 0; dimN < numDims; dimN++) indices[dimN] = 0; for (dimN = 0, nValues = 1; dimN < numDims; dimN++) { nValues *= dimSizes[dimN]; } for (i = 0, iBoffset = 0; i < nValues; i++) { for (oVoffset = 0, dimN = 0; dimN < numDims; dimN++) { oVoffset += indices[dimN] * products[dimN]; } oBoffset = oVoffset * nValueBytes; memmove ((Byte *) oBuffer + (size_t) oBoffset, (Byte *) iBuffer + (size_t) iBoffset, (size_t) nValueBytes); iBoffset += nValueBytes; INCRindicesROW (numDims, dimSizes, indices); } break; } } break; } } return; } /****************************************************************************** * COLtoROW. ******************************************************************************/ VISIBLE_PREFIX void COLtoROW (iBuffer, oBuffer, numDims, dimSizes, nValueBytes) void *iBuffer; void *oBuffer; long numDims; long dimSizes[]; long nValueBytes; { switch (numDims) { case 0: case 1: { long nValues; int dimN; for (dimN = 0, nValues = 1; dimN < numDims; dimN++) { nValues *= dimSizes[dimN]; } memmove (oBuffer, iBuffer, (size_t) (nValues * nValueBytes)); break; } default: { long products[CDF_MAX_DIMS]; /* Products, what each dimension is `worth'. */ long iBoffset; /* Input buffer, byte offset. */ long oBoffset; /* Output buffer, byte offset. */ long oVoffset; /* Output buffer, value offset. */ int dimN; /* Dimension number. */ products[(int)(numDims-1)] = 1; for (dimN = (int) (numDims - 2); dimN >= 0; dimN--) { products[dimN] = products[dimN+1] * dimSizes[dimN+1]; } switch (numDims) { case 2: { long d0, d1; /* Indices... */ for (d1 = 0, iBoffset = 0; d1 < dimSizes[1]; d1++) { for (d0 = 0; d0 < dimSizes[0]; d0++) { oVoffset = (d0 * products[0]) + (d1 * products[1]); oBoffset = oVoffset * nValueBytes; memmove ((Byte *) oBuffer + (size_t) oBoffset, (Byte *) iBuffer + (size_t) iBoffset, (size_t) nValueBytes); iBoffset += nValueBytes; } } break; } case 3: { long d0, d1, d2; /* Indices... */ for (d2 = 0, iBoffset = 0; d2 < dimSizes[2]; d2++) { for (d1 = 0; d1 < dimSizes[1]; d1++) { for (d0 = 0; d0 < dimSizes[0]; d0++) { oVoffset = (d0 * products[0]) + (d1 * products[1]) + (d2 * products[2]); oBoffset = oVoffset * nValueBytes; memmove ((Byte *) oBuffer + (size_t) oBoffset, (Byte *) iBuffer + (size_t) iBoffset, (size_t) nValueBytes); iBoffset += nValueBytes; } } } break; } default: { long indices[CDF_MAX_DIMS]; long nValues; long i; for (dimN = 0; dimN < numDims; dimN++) indices[dimN] = 0; for (dimN = 0, nValues = 1; dimN < numDims; dimN++) { nValues *= dimSizes[dimN]; } for (i = 0, iBoffset = 0; i < nValues; i++) { for (oVoffset = 0, dimN = 0; dimN < numDims; dimN++) { oVoffset += indices[dimN] * products[dimN]; } oBoffset = oVoffset * nValueBytes; memmove ((Byte *) oBuffer + (size_t) oBoffset, (Byte *) iBuffer + (size_t) iBoffset, (size_t) nValueBytes); iBoffset += nValueBytes; INCRindicesCOL (numDims, dimSizes, indices); } break; } } break; } } return; } /****************************************************************************** * INCRindicesROW. * Increment to next set of indices, row majority. When at the last set of * indices, roll over to 0,0,0,... ******************************************************************************/ VISIBLE_PREFIX void INCRindicesROW (numDims, dimSizes, indices) long numDims; long dimSizes[]; long indices[]; { int dimN; for (dimN = (int) (numDims - 1); dimN >= 0; dimN--) if (indices[dimN] == dimSizes[dimN] - 1) indices[dimN] = 0; else { indices[dimN]++; break; } return; } /****************************************************************************** * INCRindicesCOL. * Increment to next set of indices, column majority. When at the last set * of indices, roll over to 0,0,0,... ******************************************************************************/ VISIBLE_PREFIX void INCRindicesCOL (numDims, dimSizes, indices) long numDims; long dimSizes[]; long indices[]; { int dimN; for (dimN = 0; dimN < numDims; dimN++) if (indices[dimN] == dimSizes[dimN] - 1) indices[dimN] = 0; else { indices[dimN]++; break; } return; } /****************************************************************************** * InitVarStage. ******************************************************************************/ STATICforIDL CDFstatus InitVarStage (CDF, Var, nBytes) struct CDFstruct *CDF; struct VarStruct *Var; Int32 nBytes; { if (CDF->stage.fp == NULL) { CDF->stage.fp = V_scratch (ScratchDirectory(CDF), "stg"); if (CDF->stage.fp == NULL) return SCRATCH_CREATE_ERROR; if (!CACHEv(CDF->stage.fp,CDF->stage.cacheSize)) { V_delete (CDF->stage.fp, NULL); CDF->stage.fp = NULL; return BAD_CACHE_SIZE; } CDF->stage.mark = ZERO_OFFSET; } Var->stage.areaOffset = CDF->stage.mark; Var->stage.firstRec = NO_RECORD; Var->stage.lastRec = NO_RECORD; Var->stage.dotOffset = NO_OFFSET; Var->stage.modified = FALSE; CDF->stage.mark += nBytes; return CDF_OK; } /****************************************************************************** * InitScratch. ******************************************************************************/ STATICforIDL CDFstatus InitScratch (scratchDir, scratchFpH, cacheSize) char *scratchDir; /* Scratch directory to be used. */ vFILE **scratchFpH; /* Scratch file handle (pointer to pointer). */ int cacheSize; /* Number of cache buffers to request. */ { if (*scratchFpH == NULL) { *scratchFpH = V_scratch (scratchDir, NULL); if (*scratchFpH == NULL) return SCRATCH_CREATE_ERROR; if (!CACHEv(*scratchFpH,cacheSize)) { V_delete (*scratchFpH, NULL); *scratchFpH = NULL; return BAD_CACHE_SIZE; } } else { if (V_clear(*scratchFpH) != 0) return SCRATCH_READ_ERROR; if (!SEEKv(*scratchFpH,0L,vSEEK_SET)) return SCRATCH_READ_ERROR; } return CDF_OK; } /****************************************************************************** * ScratchDirectory. ******************************************************************************/ STATICforIDL char *ScratchDirectory (CDF) struct CDFstruct *CDF; /* Pointer to CDF structure. This might be NULL if a scratch directory is needed but a CDF has not yet been opened/created. */ { char *envTmp = NULL; if (CDF != NULL) { if (CDF->scratchDir != NULL) return CDF->scratchDir; } #if defined(vms) envTmp = getenv ("CDF$TMP"); #endif #if defined(unix) || defined(dos) || defined(posixSHELL) || defined(win32) envTmp = getenv ("CDF_TMP"); #endif if (envTmp != NULL) return envTmp; return NULL; } /****************************************************************************** * FlushStage. ******************************************************************************/ STATICforIDL CDFstatus FlushStage (CDF, Var) struct CDFstruct *CDF; struct VarStruct *Var; { CDFstatus pStatus = CDF_OK; /**************************************************************************** * Based on the variable type... ****************************************************************************/ switch (Var->vType) { case SPARSE_RECORDS_: { Int32 nRecords, nBytes, tOffset; struct AllocStruct alloc; /************************************************************************ * First check if there are records to be flushed in the staging area. ************************************************************************/ if (!Var->stage.modified) return pStatus; /************************************************************************ * Allocate a new VVR. ************************************************************************/ LoadAllocVVR (alloc, Var->stage.firstRec, Var->stage.lastRec, FALSE) if (!sX(AllocateRecords(CDF,Var,alloc),&pStatus)) return pStatus; Var->maxAllocated = MAXIMUM(Var->maxAllocated,Var->stage.lastRec); /************************************************************************ * Copy the records to the new VVR. ************************************************************************/ if (!sX(RecordByteOffset(CDF,Var, Var->stage.firstRec, &tOffset),&pStatus)) return pStatus; nRecords = Var->stage.lastRec - Var->stage.firstRec + 1; nBytes = nRecords * Var->NphyRecBytes; if (!sX(CopyBytes(CDF->stage.fp,Var->stage.areaOffset, SCRATCH_READ_ERROR,nBytes,CDF->fp, tOffset,CDF_WRITE_ERROR),&pStatus)) return pStatus; Var->maxWritten = MAXIMUM(Var->maxWritten,Var->stage.lastRec); /************************************************************************ * Clear the staging area control. ************************************************************************/ Var->stage.firstRec = NO_RECORD; Var->stage.lastRec = NO_RECORD; Var->stage.dotOffset = NO_OFFSET; Var->stage.modified = FALSE; break; } case COMPRESSED_: case SPARSE_COMPRESSED_RECORDS_: { Int32 cSize, xSize, irSize, newOffset, nRecords, uSize; struct CVVRstruct CVVR; struct VVRstruct VVR; struct AllocStruct alloc; /************************************************************************ * First check if there are records to be flushed in the staging area. ************************************************************************/ if (!Var->stage.modified) return pStatus; /************************************************************************ * Check if the scratch file is created/initialized. ************************************************************************/ if (!sX(InitScratch(ScratchDirectory(CDF), &(CDF->compressFp), CDF->compressCacheSize),&pStatus)) return pStatus; /************************************************************************ * Compress the records in the stage. ************************************************************************/ nRecords = Var->stage.lastRec - Var->stage.firstRec + 1; uSize = nRecords * Var->NphyRecBytes; if (!sX(Compress(CDF->stage.fp,Var->stage.areaOffset, uSize,SCRATCH_READ_ERROR,Var->cType, Var->cParms,CDF->compressFp,ZERO_OFFSET, &cSize,SCRATCH_WRITE_ERROR),&pStatus)) return pStatus; /************************************************************************ * Does a VVR/CVVR for this block of records already exist? ************************************************************************/ if (Var->stage.dotOffset != NO_OFFSET) { /********************************************************************** * Read the size of the existing VVR/CVVR. **********************************************************************/ if (!sX(ReadIrSize(CDF->fp, Var->stage.dotOffset, &irSize),&pStatus)) return pStatus; /********************************************************************** * Will a CVVR fit? Note that reserve space is only added to new CVVRs. **********************************************************************/ if (CVVR_BASE_SIZE + cSize <= irSize) { LoadCVVRx (CVVR, irSize, cSize) if (!sX(WriteCVVR(CDF->fp,Var->stage.dotOffset, CVVR_RECORDx,&CVVR, CVVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes(CDF->compressFp,ZERO_OFFSET, SCRATCH_READ_ERROR,cSize,CDF->fp, Var->stage.dotOffset + CVVR_BASE_SIZE, CDF_WRITE_ERROR),&pStatus)) return pStatus; Var->stage.modified = FALSE; return pStatus; } /********************************************************************** * Will a VVR fit? **********************************************************************/ if (VVR_BASE_SIZE + uSize <= irSize) { LoadVVRx (VVR, irSize) if (!sX(WriteVVR(CDF->fp,Var->stage.dotOffset, VVR_RECORDx,&VVR, VVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes(CDF->stage.fp,Var->stage.areaOffset, SCRATCH_READ_ERROR,uSize,CDF->fp, Var->stage.dotOffset + VVR_BASE_SIZE, CDF_WRITE_ERROR),&pStatus)) return pStatus; Var->stage.modified = FALSE; sX (DID_NOT_COMPRESS, &pStatus); return pStatus; } /********************************************************************** * The existing VVR/CVVR will have to be resized. Will a CVVR be * smaller than a VVR? Note that reserve space is not added to the * size of the CVVR because a new one isn't being created. **********************************************************************/ if (CVVR_BASE_SIZE + cSize < VVR_BASE_SIZE + uSize) { if (!sX(ResizeIR(CDF,Var->stage.dotOffset, CVVR_BASE_SIZE + cSize, &newOffset,TRUE,NULL),&pStatus)) return pStatus; LoadCVVRx (CVVR, CVVR_BASE_SIZE + cSize, cSize) if (!sX(WriteCVVR(CDF->fp,newOffset, CVVR_RECORDx,&CVVR, CVVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes(CDF->compressFp,ZERO_OFFSET, SCRATCH_READ_ERROR,cSize, CDF->fp,newOffset + CVVR_BASE_SIZE, CDF_WRITE_ERROR),&pStatus)) return pStatus; } else { if (!sX(ResizeIR(CDF,Var->stage.dotOffset, VVR_BASE_SIZE + uSize, &newOffset,TRUE,NULL),&pStatus)) return pStatus; LoadVVRx (VVR, VVR_BASE_SIZE + uSize) if (!sX(WriteVVR(CDF->fp,newOffset, VVR_RECORDx,&VVR, VVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes(CDF->stage.fp,Var->stage.areaOffset, SCRATCH_READ_ERROR,uSize, CDF->fp,newOffset + VVR_BASE_SIZE, CDF_WRITE_ERROR),&pStatus)) return pStatus; sX (DID_NOT_COMPRESS, &pStatus); } if (!sX(ModIndexOffset(CDF,Var, Var->stage.firstRec, Var->stage.lastRec, newOffset),&pStatus)) return pStatus; Var->stage.dotOffset = newOffset; Var->stage.modified = FALSE; return pStatus; } /************************************************************************ * A new VVR/CVVR will have to be created. First calculate the reserve * size. ************************************************************************/ if (Var->reservePct <= 0) xSize = 0; else { if (Var->reservePct <= 100) { Int32 tSize = (Int32) ((uSize * (Var->reservePct/100.0)) + 0.5); xSize = MAXIMUM(cSize,tSize) - cSize; } else { Int32 tSize = (Int32) ((cSize * (Var->reservePct/100.0)) + 0.5); xSize = tSize - cSize; } } /************************************************************************ * Will a CVVR be smaller than a VVR? ************************************************************************/ if (CVVR_BASE_SIZE + cSize + xSize < VVR_BASE_SIZE + uSize) { LoadAllocCVVR (alloc, Var->stage.firstRec, Var->stage.lastRec, cSize, xSize) if (!sX(AllocateRecords(CDF,Var,alloc),&pStatus)) return pStatus; if (!sX(SearchForRecord(CDF,Var->VDRoffset,Var->zVar, Var->stage.firstRec,NULL,NULL, &newOffset,NULL),&pStatus)) return pStatus; LoadCVVRx (CVVR, CVVR_BASE_SIZE + cSize + xSize, cSize) if (!sX(WriteCVVR(CDF->fp,newOffset, CVVR_RECORDx,&CVVR, CVVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes(CDF->compressFp,ZERO_OFFSET, SCRATCH_READ_ERROR,cSize, CDF->fp,newOffset + CVVR_BASE_SIZE, CDF_WRITE_ERROR),&pStatus)) return pStatus; Var->stage.dotOffset = newOffset; Var->stage.modified = FALSE; return pStatus; } /************************************************************************ * The CVVR will be too big - create a VVR. ************************************************************************/ LoadAllocVVR (alloc, Var->stage.firstRec, Var->stage.lastRec, TRUE) if (!sX(AllocateRecords(CDF,Var,alloc),&pStatus)) return pStatus; if (!sX(SearchForRecord(CDF,Var->VDRoffset,Var->zVar, Var->stage.firstRec,NULL,NULL, &newOffset,NULL),&pStatus)) return pStatus; LoadVVRx (VVR, VVR_BASE_SIZE + uSize) if (!sX(WriteVVR(CDF->fp,newOffset, VVR_RECORDx,&VVR, VVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes(CDF->stage.fp,Var->stage.areaOffset, SCRATCH_READ_ERROR,uSize, CDF->fp,newOffset + VVR_BASE_SIZE, CDF_WRITE_ERROR),&pStatus)) return pStatus; Var->stage.dotOffset = newOffset; Var->stage.modified = FALSE; sX (DID_NOT_COMPRESS, &pStatus); return pStatus; } default: return CDF_INTERNAL_ERROR; } return pStatus; } /****************************************************************************** * BringToStage. ******************************************************************************/ static CDFstatus BringToStage (CDF, Var, recNum, found) struct CDFstruct *CDF; struct VarStruct *Var; Int32 recNum; Logical *found; { CDFstatus pStatus = CDF_OK; /**************************************************************************** * First check if record is already in the stage. ****************************************************************************/ if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) { ASSIGNnotNULL (found, TRUE) return pStatus; } /**************************************************************************** * Then, based on variable type... ****************************************************************************/ switch (Var->vType) { case COMPRESSED_: case SPARSE_COMPRESSED_RECORDS_: { Int32 firstRec, lastRec, offset, nRecords, uSize; Logical foundX; /************************************************************************ * Determine if the record exists. ************************************************************************/ if (!sX(SearchForRecord(CDF,Var->VDRoffset,Var->zVar, recNum,&firstRec,&lastRec, &offset,&foundX),&pStatus)) return pStatus; ASSIGNnotNULL (found, foundX) if (!foundX) return BOO(found == NULL,NO_SUCH_RECORD,pStatus); /************************************************************************ * Flush the stage before... ************************************************************************/ if (!sX(FlushStage(CDF,Var),&pStatus)) return pStatus; /************************************************************************ * ...decompressing the CVVR (or VVR if the records did not compress) to * the staging area. ************************************************************************/ nRecords = lastRec - firstRec + 1; uSize = nRecords * Var->NphyRecBytes; if (!sX(DecompressToStage(CDF,Var, offset,uSize),&pStatus)) return pStatus; /************************************************************************ * Update staging control. ************************************************************************/ Var->stage.firstRec = firstRec; Var->stage.lastRec = lastRec; Var->stage.dotOffset = offset; Var->stage.modified = FALSE; break; } default: return CDF_INTERNAL_ERROR; } return pStatus; } /****************************************************************************** * CopyBytes. ******************************************************************************/ STATICforIDL CDFstatus CopyBytes (iFp, iStart, iError, nBytes, oFp, oStart, oError) vFILE *iFp; Int32 iStart; CDFstatus iError; Int32 nBytes; vFILE *oFp; Int32 oStart; CDFstatus oError; { Int32 nBlocks = nBytes / COPYblockSIZE; /* Number of full blocks that can be copied. */ Int32 lastCount = nBytes % COPYblockSIZE; /* Number of bytes remaining to be copied after the full blocks have been copied. */ Int32 i; Byte buffer[COPYblockSIZE]; /**************************************************************************** * If the copy is within the same file... ****************************************************************************/ if (iFp == oFp) { /************************************************************************** * If the input group (of bytes) is before the output group start at the * end in case they overlap. **************************************************************************/ if (iStart < oStart) { if (nBlocks > 0) { Int32 iOffset = iStart + nBytes - COPYblockSIZE; Int32 oOffset = oStart + nBytes - COPYblockSIZE; for (i = 0; i < nBlocks; i++) { if (!SEEKv(iFp,(long)iOffset,vSEEK_SET)) return iError; if (!READv(buffer,(size_t)COPYblockSIZE,(size_t)1,iFp)) return iError; if (!SEEKv(oFp,(long)oOffset,vSEEK_SET)) return oError; if (!WRITEv(buffer,(size_t)COPYblockSIZE,(size_t)1,oFp)) return oError; iOffset -= COPYblockSIZE; oOffset -= COPYblockSIZE; } } if (lastCount > 0) { if (!SEEKv(iFp,(long)iStart,vSEEK_SET)) return iError; if (!READv(buffer,(size_t)lastCount,(size_t)1,iFp)) return iError; if (!SEEKv(oFp,(long)oStart,vSEEK_SET)) return oError; if (!WRITEv(buffer,(size_t)lastCount,(size_t)1,oFp)) return oError; } } /************************************************************************** * If the input group (of bytes) is after the output group start at the * beginning in case they overlap. **************************************************************************/ if (iStart > oStart) { Int32 iOffset = iStart; Int32 oOffset = oStart; if (nBlocks > 0) { for (i = 0; i < nBlocks; i++) { if (!SEEKv(iFp,(long)iOffset,vSEEK_SET)) return iError; if (!READv(buffer,(size_t)COPYblockSIZE,(size_t)1,iFp)) return iError; if (!SEEKv(oFp,(long)oOffset,vSEEK_SET)) return oError; if (!WRITEv(buffer,(size_t)COPYblockSIZE,(size_t)1,oFp)) return oError; iOffset += COPYblockSIZE; oOffset += COPYblockSIZE; } } if (lastCount > 0) { if (!SEEKv(iFp,(long)iOffset,vSEEK_SET)) return iError; if (!READv(buffer,(size_t)lastCount,(size_t)1,iFp)) return iError; if (!SEEKv(oFp,(long)oOffset,vSEEK_SET)) return oError; if (!WRITEv(buffer,(size_t)lastCount,(size_t)1,oFp)) return oError; } } /************************************************************************** * Offsets are the same - do nothing. **************************************************************************/ } else { /************************************************************************** * Different files... **************************************************************************/ if (!SEEKv(iFp,(long)iStart,vSEEK_SET)) return iError; if (!SEEKv(oFp,(long)oStart,vSEEK_SET)) return oError; for (i = 0; i < nBlocks; i++) { if (!READv(buffer,(size_t)COPYblockSIZE,(size_t)1,iFp)) return iError; if (!WRITEv(buffer,(size_t)COPYblockSIZE,(size_t)1,oFp)) return oError; } if (lastCount > 0) { if (!READv(buffer,(size_t)lastCount,(size_t)1,iFp)) return iError; if (!WRITEv(buffer,(size_t)lastCount,(size_t)1,oFp)) return oError; } } return CDF_OK; } /****************************************************************************** * ModIndexOffset. ******************************************************************************/ STATICforIDL CDFstatus ModIndexOffset (CDF, Var, firstRec, lastRec, newOffset) struct CDFstruct *CDF; /* Pointer to CDF. */ struct VarStruct *Var; /* Pointer to variable. */ Int32 firstRec; /* First record of entry. */ Int32 lastRec; /* Last record of entry. */ Int32 newOffset; /* New VVR/CVVR/SVVR offset. */ { CDFstatus pStatus = CDF_OK; Int32 vxrOffset; /**************************************************************************** * Read offset of first VXR... ****************************************************************************/ if (!sX(ReadVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar, VDR_VXRHEAD,&vxrOffset, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start there. ****************************************************************************/ if (!sX(ModIndexOffset_r(CDF->fp,vxrOffset, firstRec,lastRec, newOffset),&pStatus)) return pStatus; return pStatus; } static CDFstatus ModIndexOffset_r (fp, vxrOffset, firstRec, lastRec, newOffset) vFILE *fp; /* File pointer to dotCDF file. */ Int32 vxrOffset; /* VXR at which to start. */ Int32 firstRec; /* First record of entry. */ Int32 lastRec; /* Last record of entry. */ Int32 newOffset; /* New VVR/CVVR/SVVR offset. */ { CDFstatus pStatus = CDF_OK; struct VXRstruct VXR; int entryN; Int32 irType; /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != ZERO_OFFSET) { /************************************************************************** * Read the VXR. **************************************************************************/ if (!sX(ReadVXR(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; /************************************************************************** * Search through index entries... **************************************************************************/ for (entryN = 0; entryN < VXR.NusedEntries; entryN++) { if (VXR.First[entryN] <= firstRec && lastRec <= VXR.Last[entryN]) { if (!sX(ReadIrType(fp, VXR.Offset[entryN], &irType),&pStatus)) return pStatus; if (irType == VXR_) return ModIndexOffset_r(fp,VXR.Offset[entryN], firstRec,lastRec, newOffset); if (VXR.First[entryN] == firstRec && lastRec == VXR.Last[entryN]) { VXR.Offset[entryN] = newOffset; if (!sX(WriteVXR(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; return pStatus; } return CDF_INTERNAL_ERROR; /* or CORRUPTED_V2_CDF? */ } } /************************************************************************** * Go to next VXR. **************************************************************************/ vxrOffset = VXR.VXRnext; } /**************************************************************************** * No more VXRs. ****************************************************************************/ return CDF_INTERNAL_ERROR; } /****************************************************************************** * WriteCompressedRecords. ******************************************************************************/ static CDFstatus WriteCompressedRecords (CDF, Var, firstRec, lastRec, buffer, nValues, offset, fullRecord) struct CDFstruct *CDF; /* Pointer to CDF. */ struct VarStruct *Var; /* Pointer to variable. */ Int32 firstRec; /* First record being written. */ Int32 lastRec; /* Last record being written. */ void *buffer; /* Buffer of values. */ Int32 nValues; /* Number of values being written. */ Int32 offset; /* If not full record(s), byte offset in record at which to write. */ Logical fullRecord; /* Full record(s) being written? */ { CDFstatus pStatus = CDF_OK; Logical found; Int32 recCount, tOffset, recordOffsetInStage, maxRecThisBlock; Int32 nextRec, writeTo, numElems; void *padBuffer; int how; Int32 recNum = firstRec; Byte *tBuffer = (Byte *) buffer; /**************************************************************************** * From first to last record... ****************************************************************************/ while (recNum <= lastRec) { /************************************************************************* * Check if this record is in the staging area. *************************************************************************/ if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) { recordOffsetInStage = recNum - Var->stage.firstRec; tOffset = Var->stage.areaOffset; tOffset += (recordOffsetInStage * Var->NphyRecBytes); if (fullRecord) { if (Var->stage.dotOffset == NO_OFFSET) { maxRecThisBlock = Var->stage.firstRec + Var->blockingFactor - 1; if (!sX(NextRecord(CDF,Var->VDRoffset, Var->zVar,recNum, &nextRec,&found),&pStatus)) return pStatus; if (!found) writeTo = MINIMUM(maxRecThisBlock,lastRec); else { Int32 prevRecN = nextRec - 1; writeTo = MINIMUMof3(maxRecThisBlock,prevRecN,lastRec); } } else writeTo = MINIMUM(Var->stage.lastRec,lastRec); recCount = writeTo - recNum + 1; numElems = recCount * Var->NphyRecElems; } else { writeTo = recNum; recCount = 1; numElems = nValues * Var->NvalueElems; tOffset += offset; } if (!sX(WriteVarElems(Var,CDF->stage.fp, tOffset,numElems, tBuffer),&pStatus)) return pStatus; Var->stage.lastRec = MAXIMUM(Var->stage.lastRec,writeTo); Var->stage.modified = TRUE; tBuffer += (size_t) (numElems * Var->NelemBytes); recNum += recCount; continue; } /************************************************************************* * Not in the staging area...check if this record is in an existing CVVR. *************************************************************************/ if (!sX(BringToStage(CDF,Var,recNum,&found),&pStatus)) return pStatus; if (found) { recordOffsetInStage = recNum - Var->stage.firstRec; tOffset = Var->stage.areaOffset; tOffset += (recordOffsetInStage * Var->NphyRecBytes); if (fullRecord) { writeTo = MINIMUM(Var->stage.lastRec,lastRec); recCount = writeTo - recNum + 1; numElems = recCount * Var->NphyRecElems; } else { writeTo = recNum; recCount = 1; numElems = nValues * Var->NvalueElems; tOffset += offset; } if (!sX(WriteVarElems(Var,CDF->stage.fp, tOffset,numElems, tBuffer),&pStatus)) return pStatus; Var->stage.modified = TRUE; tBuffer += (size_t) (numElems * Var->NelemBytes); recNum += recCount; continue; } /************************************************************************* * Not in an existing CVVR...this record does not exist. First check * if the record(s) can be added to the records in the stage. *************************************************************************/ if (Var->stage.firstRec != NO_RECORD) { if (Var->stage.dotOffset == NO_OFFSET) { if (recNum == Var->stage.lastRec + 1) { maxRecThisBlock = Var->stage.firstRec + Var->blockingFactor - 1; if (recNum <= maxRecThisBlock) { recordOffsetInStage = recNum - Var->stage.firstRec; tOffset = Var->stage.areaOffset; tOffset += (recordOffsetInStage * Var->NphyRecBytes); if (fullRecord) { if (!sX(NextRecord(CDF,Var->VDRoffset, Var->zVar,recNum, &nextRec,&found),&pStatus)) return pStatus; if (!found) writeTo = MINIMUM(maxRecThisBlock,lastRec); else { Int32 prevRecN = nextRec - 1; writeTo = MINIMUMof3(maxRecThisBlock,prevRecN,lastRec); } recCount = writeTo - recNum + 1; numElems = recCount * Var->NphyRecElems; } else { if (!sX(BuildPadBuffer(CDF,Var,INT32_ONE, &how,&padBuffer, TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues(Var,CDF->stage.fp, tOffset,INT32_ONE,how, padBuffer),&pStatus)) return pStatus; cdf_FreeMemory (padBuffer, NULL); writeTo = recNum; recCount = 1; numElems = nValues * Var->NvalueElems; tOffset += offset; } if (!sX(WriteVarElems(Var,CDF->stage.fp, tOffset,numElems, tBuffer),&pStatus)) return pStatus; Var->stage.lastRec = MAXIMUM(Var->stage.lastRec,writeTo); Var->stage.modified = TRUE; tBuffer += (size_t) (numElems * Var->NelemBytes); recNum += recCount; continue; } } } } /************************************************************************* * This record cannot be added to the block of records currently in * the staging area. Start a new block of records. *************************************************************************/ if (!sX(FlushStage(CDF,Var),&pStatus)) return pStatus; tOffset = Var->stage.areaOffset; if (fullRecord) { maxRecThisBlock = recNum + Var->blockingFactor - 1; if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar, recNum,&nextRec,&found),&pStatus)) return pStatus; if (!found) writeTo = MINIMUM(maxRecThisBlock,lastRec); else { Int32 prevRecN = nextRec - 1; writeTo = MINIMUMof3(maxRecThisBlock,prevRecN,lastRec); } recCount = writeTo - recNum + 1; numElems = recCount * Var->NphyRecElems; } else { if (!sX(BuildPadBuffer(CDF,Var,INT32_ONE, &how,&padBuffer, TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues(Var,CDF->stage.fp, tOffset,INT32_ONE,how, padBuffer),&pStatus)) return pStatus; cdf_FreeMemory (padBuffer, NULL); writeTo = recNum; recCount = 1; numElems = nValues * Var->NvalueElems; tOffset += offset; } if (!sX(WriteVarElems(Var,CDF->stage.fp, tOffset,numElems, tBuffer),&pStatus)) return pStatus; Var->stage.firstRec = recNum; Var->stage.lastRec = writeTo; Var->stage.dotOffset = NO_OFFSET; Var->stage.modified = TRUE; tBuffer += (size_t) (numElems * Var->NelemBytes); recNum += recCount; } return pStatus; } /****************************************************************************** * CalcCompressionPct. ******************************************************************************/ STATICforIDL CDFstatus CalcCompressionPct (CDF, vdrOffset, zVar, cPct) struct CDFstruct *CDF; Int32 vdrOffset; Logical zVar; long *cPct; { CDFstatus pStatus = CDF_OK; Int32 vxrOffset; long uTotal = 0, cTotal = 0; Int32 nPhyRecBytes; /**************************************************************************** * Calculate the number of bytes per physical record. ****************************************************************************/ if (!sX(CalcPhyRecBytes(CDF,vdrOffset, zVar,&nPhyRecBytes),&pStatus)) return pStatus; /**************************************************************************** * Read the offset of the first VXR (return 0% if no VXRs)... ****************************************************************************/ if (!sX(ReadVDR(CDF,CDF->fp,vdrOffset,zVar, VDR_VXRHEAD,&vxrOffset, VDR_NULL),&pStatus)) return pStatus; if (vxrOffset == ZERO_OFFSET) { *cPct = 0; return pStatus; } /**************************************************************************** * ...and start there. ****************************************************************************/ if (!sX(CalcCompressionPct_r(CDF->fp,vxrOffset, nPhyRecBytes, &uTotal,&cTotal),&pStatus)) return pStatus; /**************************************************************************** * Calculate percentage. ****************************************************************************/ *cPct = (long) (((100.0*cTotal) / uTotal) + 0.5); return pStatus; } static CDFstatus CalcCompressionPct_r (fp, vxrOffset, nPhyRecBytes, uTotal, cTotal) vFILE *fp; Int32 vxrOffset; Int32 nPhyRecBytes; long *uTotal; long *cTotal; { CDFstatus pStatus = CDF_OK; struct VXRstruct VXR; int entryN; Int32 nRecords, uSize, irType, irSize; /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != ZERO_OFFSET) { /************************************************************************** * Read the VXR. **************************************************************************/ if (!sX(ReadVXR(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; /************************************************************************** * Scan entries... **************************************************************************/ for (entryN = 0; entryN < VXR.NusedEntries; entryN++) { if (!sX(ReadIrType(fp,VXR.Offset[entryN],&irType),&pStatus)) return pStatus; switch (irType) { case VXR_: if (!sX(CalcCompressionPct_r(fp,VXR.Offset[entryN], nPhyRecBytes,uTotal, cTotal),&pStatus)) return pStatus; break; case VVR_: case CVVR_: /******************************************************************* * Accumulate uncompressed size. *******************************************************************/ nRecords = VXR.Last[entryN] - VXR.First[entryN] + 1; uSize = nRecords * nPhyRecBytes; *uTotal += uSize; /******************************************************************* * Accumulate compressed size. *******************************************************************/ if (!sX(ReadIrSize(fp,VXR.Offset[entryN],&irSize),&pStatus)) return pStatus; *cTotal += irSize - BOO(irType == CVVR_, CVVR_BASE_SIZE, VVR_BASE_SIZE); break; default: return CORRUPTED_V2_CDF; } } vxrOffset = VXR.VXRnext; } return pStatus; } /****************************************************************************** * CalcPhyRecBytes. ******************************************************************************/ STATICforIDL CDFstatus CalcPhyRecBytes (CDF, vdrOffset, zVar, nPhyRecBytes) struct CDFstruct *CDF; Int32 vdrOffset; Logical zVar; Int32 *nPhyRecBytes; { CDFstatus pStatus = CDF_OK; int dimN; Int32 dataType, numElems; Int32 numDims, dimSizes[CDF_MAX_DIMS], dimVarys[CDF_MAX_DIMS]; if (!sX(CalcDimParms(CDF,vdrOffset,zVar, &numDims,dimSizes,dimVarys),&pStatus)) return pStatus; if (!sX(ReadVDR(CDF,CDF->fp,vdrOffset,zVar, VDR_DATATYPE,&dataType, VDR_NUMELEMS,&numElems, VDR_NULL),&pStatus)) return pStatus; *nPhyRecBytes = CDFelemSize((long)dataType) * numElems; for (dimN = 0; dimN < numDims; dimN++) { if (dimVarys[dimN]) *nPhyRecBytes *= dimSizes[dimN]; } return pStatus; } /****************************************************************************** * ReadSparseFull. ******************************************************************************/ static CDFstatus ReadSparseFull (CDF, Var, firstRec, lastRec, buffer) struct CDFstruct *CDF; struct VarStruct *Var; Int32 firstRec; Int32 lastRec; void *buffer; { CDFstatus pStatus = CDF_OK; Logical found; Int32 readTo, recCount, numElems, recX, prevRecN; Int32 nextRec, padTo, tOffset, nPadValues; Int32 recNum = firstRec; Byte *tBuffer = (Byte *) buffer; /**************************************************************************** * While there are more records to be read/generated... ****************************************************************************/ while (recNum <= lastRec) { /************************************************************************** * Is the record in the staging area? **************************************************************************/ if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) { readTo = MINIMUM(Var->stage.lastRec,lastRec); recCount = readTo - recNum + 1; numElems = recCount * Var->NphyRecElems; recX = recNum - Var->stage.firstRec; tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes); if (!sX(ReadVarElems(Var,CDF->stage.fp, tOffset,numElems,tBuffer),&pStatus)) return pStatus; tBuffer += (size_t) (recCount * Var->NphyRecBytes); recNum += recCount; continue; } /************************************************************************** * Does the record exist and has been written to (not just allocated)? **************************************************************************/ if (recNum <= Var->maxRec) { Int32 firstRecInVVR, lastRecInVVR; if (!sX(SearchForRecord(CDF,Var->VDRoffset, Var->zVar,recNum, &firstRecInVVR, &lastRecInVVR, &tOffset,&found),&pStatus)) return pStatus; if (found) { readTo = MINIMUMof3(Var->maxRec,lastRec,lastRecInVVR); recCount = readTo - recNum + 1; numElems = recCount * Var->NphyRecElems; recX = recNum - firstRecInVVR; tOffset += VVR_BASE_SIZE + (recX * Var->NphyRecBytes); if (!sX(ReadVarElems(Var,CDF->fp,tOffset, numElems,tBuffer),&pStatus)) return pStatus; tBuffer += (size_t) (recCount * Var->NphyRecBytes); recNum += recCount; continue; } } /************************************************************************** * Determine which records need to be padded. **************************************************************************/ if (recNum <= Var->maxRec) { if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar, recNum,&nextRec,&found),&pStatus)) return pStatus; if (found) { if (EXCLUSIVE(recNum, Var->stage.firstRec, nextRec)) nextRec = Var->stage.firstRec; prevRecN = nextRec - 1; padTo = MINIMUM(prevRecN,lastRec); } else { prevRecN = Var->stage.firstRec - 1; padTo = MINIMUM(prevRecN,lastRec); } } else padTo = lastRec; recCount = padTo - recNum + 1; /************************************************************************** * If sRecords.PREV... **************************************************************************/ if (Var->prevIfMissing) { Int32 prevRec; Byte *destBuffer; if (!sX(PrevRecord(CDF,Var->VDRoffset,Var->zVar, MINIMUM(recNum,Var->maxRec), &prevRec,&found),&pStatus)) return pStatus; if (found) { if (EXCLUSIVE(prevRec,Var->stage.lastRec,recNum)) { recX = Var->stage.lastRec - Var->stage.firstRec; tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes); if (!sX(ReadVarElems(Var,CDF->stage.fp, tOffset,Var->NphyRecElems, tBuffer),&pStatus)) return pStatus; } else { if (!sX(RecordByteOffset(CDF,Var, prevRec, &tOffset),&pStatus)) return pStatus; if (!sX(ReadVarElems(Var,CDF->fp,tOffset, Var->NphyRecElems, tBuffer),&pStatus)) return pStatus; } destBuffer = tBuffer + ((size_t) Var->NphyRecBytes); for (recX = 1; recX < recCount; recX++) { memmove (destBuffer, tBuffer, (size_t) Var->NphyRecBytes); destBuffer += (size_t) Var->NphyRecBytes; } sX (VIRTUAL_RECORD_DATA, &pStatus); tBuffer += (size_t) (recCount * Var->NphyRecBytes); recNum += recCount; continue; } if (EXCLUSIVE(NO_RECORD,Var->stage.lastRec,recNum)) { recX = Var->stage.lastRec - Var->stage.firstRec; tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes); if (!sX(ReadVarElems(Var,CDF->stage.fp, tOffset,Var->NphyRecElems, tBuffer),&pStatus)) return pStatus; destBuffer = tBuffer + ((size_t) Var->NphyRecBytes); for (recX = 1; recX < recCount; recX++) { memmove (destBuffer, tBuffer, (size_t) Var->NphyRecBytes); destBuffer += (size_t) Var->NphyRecBytes; } sX (VIRTUAL_RECORD_DATA, &pStatus); tBuffer += (size_t) (recCount * Var->NphyRecBytes); recNum += recCount; continue; } } /************************************************************************** * Pad with the variable's pad value. This occurs if the variable is * sRecords.NO, sRecords.PAD, or if sRecords.PREV but a previous record * does not exist (in a VVR or the staging area). **************************************************************************/ nPadValues = recCount * Var->NphyRecValues; if (!sX(PadBuffer(CDF,Var,nPadValues,tBuffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); tBuffer += (size_t) (recCount * Var->NphyRecBytes); recNum += recCount; } return pStatus; } /****************************************************************************** * ReadSparsePartial. ******************************************************************************/ static CDFstatus ReadSparsePartial (CDF, Var, recNum, offset, nValues, buffer) struct CDFstruct *CDF; struct VarStruct *Var; Int32 recNum; Int32 offset; Int32 nValues; void *buffer; { CDFstatus pStatus = CDF_OK; Logical found; Int32 tOffset, firstRec, prevRec; Int32 numElems = nValues * Var->NvalueElems; /**************************************************************************** * If the record is in the staging area... ****************************************************************************/ if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) { tOffset = Var->stage.areaOffset; tOffset += Var->NphyRecBytes * (recNum - Var->stage.firstRec); tOffset += offset; if (!sX(ReadVarElems(Var,CDF->stage.fp, tOffset,numElems,buffer),&pStatus)) return pStatus; return pStatus; } /**************************************************************************** * If the record exists and has been written (ie. not just allocated)... ****************************************************************************/ if (recNum <= Var->maxRec) { if (!sX(SearchForRecord(CDF,Var->VDRoffset, Var->zVar,recNum,&firstRec, NULL,&tOffset,&found),&pStatus)) return pStatus; if (found) { tOffset += VVR_BASE_SIZE; tOffset += Var->NphyRecBytes * (recNum - firstRec); tOffset += offset; if (!sX(ReadVarElems(Var,CDF->fp, tOffset,numElems,buffer),&pStatus)) return pStatus; return pStatus; } } /**************************************************************************** * If missing records are to be read from the previous record... ****************************************************************************/ if (Var->prevIfMissing) { /************************************************************************** * Check if a previous record exists in a VVR. **************************************************************************/ if (!sX(PrevRecord(CDF,Var->VDRoffset,Var->zVar, MINIMUM(recNum,Var->maxRec), &prevRec,&found),&pStatus)) return pStatus; /************************************************************************** * If so, also make sure that the last record in the staging area isn't * really the previous record to use. **************************************************************************/ if (found) { if (EXCLUSIVE(prevRec,Var->stage.lastRec,recNum)) { Int32 recNumInStage = Var->stage.lastRec - Var->stage.firstRec; tOffset = Var->stage.areaOffset; tOffset += Var->NphyRecBytes * recNumInStage; tOffset += offset; if (!sX(ReadVarElems(Var,CDF->stage.fp,tOffset, numElems,buffer),&pStatus)) return pStatus; } else { if (!sX(RecordByteOffset(CDF,Var, prevRec, &tOffset),&pStatus)) return pStatus; tOffset += offset; if (!sX(ReadVarElems(Var,CDF->fp,tOffset, numElems,buffer),&pStatus)) return pStatus; } sX (VIRTUAL_RECORD_DATA, &pStatus); return pStatus; } /************************************************************************** * A previous record does not exist in a VVR...check if the last record in * the staging area is the previous record. **************************************************************************/ if (EXCLUSIVE(NO_RECORD,Var->stage.lastRec,recNum)) { Int32 recNumInStage = Var->stage.lastRec - Var->stage.firstRec; tOffset = Var->stage.areaOffset; tOffset += Var->NphyRecBytes * recNumInStage; tOffset += offset; if (!sX(ReadVarElems(Var,CDF->stage.fp, tOffset,numElems,buffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); return pStatus; } } /**************************************************************************** * Pad the buffer with the variable's pad value. Note that this is also done * if the variable is sRecords.PREV but a previous record does not exist. ****************************************************************************/ if (!sX(PadBuffer(CDF,Var,nValues,buffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); return pStatus; } /****************************************************************************** * ReadCompressedFull. ******************************************************************************/ static CDFstatus ReadCompressedFull (CDF, Var, firstRec, lastRec, buffer) struct CDFstruct *CDF; struct VarStruct *Var; Int32 firstRec; Int32 lastRec; void *buffer; { CDFstatus pStatus = CDF_OK; Logical found; Int32 readTo, recCount, numElems, recX, tOffset, nextRec; Int32 recNum = firstRec, nPadValues, prevRec, padTo; Byte *tBuffer = (Byte *) buffer, *destBuffer; /**************************************************************************** * While there are more records to be read/generated... ****************************************************************************/ while (recNum <= lastRec) { /************************************************************************** * Try to bring the record to the staging area. **************************************************************************/ if (!sX(BringToStage(CDF,Var,recNum,&found),&pStatus)) return pStatus; if (found) { readTo = MINIMUM(Var->stage.lastRec,lastRec); recCount = readTo - recNum + 1; numElems = recCount * Var->NphyRecElems; recX = recNum - Var->stage.firstRec; tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes); if (!sX(ReadVarElems(Var,CDF->stage.fp, tOffset,numElems,tBuffer),&pStatus)) return pStatus; tBuffer += (size_t) (recCount * Var->NphyRecBytes); recNum += recCount; continue; } /************************************************************************** * Determine which records need to be padded. **************************************************************************/ if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar, recNum,&nextRec,&found),&pStatus)) return pStatus; if (found) { if (EXCLUSIVE(recNum, Var->stage.firstRec, nextRec)) nextRec = Var->stage.firstRec; prevRec = nextRec - 1; padTo = MINIMUM(prevRec,lastRec); } else padTo = BOO(Var->stage.firstRec > recNum, Var->stage.firstRec - 1,lastRec); recCount = padTo - recNum + 1; /************************************************************************** * If sRecords.PREV... **************************************************************************/ if (Var->prevIfMissing) { if (!sX(PrevRecord(CDF,Var->VDRoffset,Var->zVar, recNum,&prevRec,&found),&pStatus)) return pStatus; if (!found) prevRec = NO_RECORD; if (EXCLUSIVE(prevRec, Var->stage.lastRec, recNum)) prevRec = Var->stage.lastRec; if (prevRec > NO_RECORD) { if (!sX(BringToStage(CDF,Var,prevRec,NULL),&pStatus)) return pStatus; recX = prevRec - Var->stage.firstRec; tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes); if (!sX(ReadVarElems(Var,CDF->stage.fp, tOffset,Var->NphyRecElems, tBuffer),&pStatus)) return pStatus; destBuffer = tBuffer + ((size_t) Var->NphyRecBytes); for (recX = 1; recX < recCount; recX++) { memmove (destBuffer, tBuffer, (size_t) Var->NphyRecBytes); destBuffer += (size_t) Var->NphyRecBytes; } sX (VIRTUAL_RECORD_DATA, &pStatus); tBuffer += (size_t) (recCount * Var->NphyRecBytes); recNum += recCount; continue; } } /************************************************************************** * Pad with the variable's pad value. This occurs if the variable is * sRecords.NO, sRecords.PAD, or if sRecords.PREV but a previous record * does not exist (in a CVVR/VVR or the staging area). **************************************************************************/ nPadValues = recCount * Var->NphyRecValues; if (!sX(PadBuffer(CDF,Var,nPadValues,tBuffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); tBuffer += (size_t) (recCount * Var->NphyRecBytes); recNum += recCount; } return pStatus; } /****************************************************************************** * ReadCompressedPartial. ******************************************************************************/ static CDFstatus ReadCompressedPartial (CDF, Var, recNum, offset, nValues, buffer) struct CDFstruct *CDF; struct VarStruct *Var; Int32 recNum; Int32 offset; Int32 nValues; void *buffer; { CDFstatus pStatus = CDF_OK; Int32 numElems = nValues * Var->NvalueElems; Int32 tOffset, prevRec, recX; Logical found; /**************************************************************************** * Try to bring the record to the staging area. ****************************************************************************/ if (!sX(BringToStage(CDF,Var,recNum,&found),&pStatus)) return pStatus; if (found) { tOffset = Var->stage.areaOffset; tOffset += Var->NphyRecBytes * (recNum - Var->stage.firstRec); tOffset += offset; if (!sX(ReadVarElems(Var,CDF->stage.fp, tOffset,numElems,buffer),&pStatus)) return pStatus; return pStatus; } /**************************************************************************** * If sRecords.PREV... ****************************************************************************/ if (Var->prevIfMissing) { if (!sX(PrevRecord(CDF,Var->VDRoffset, Var->zVar,recNum, &prevRec,&found),&pStatus)) return pStatus; if (!found) prevRec = NO_RECORD; if (EXCLUSIVE(prevRec, Var->stage.lastRec, recNum)) prevRec = Var->stage.lastRec; if (prevRec > NO_RECORD) { if (!sX(BringToStage(CDF,Var,prevRec,NULL),&pStatus)) return pStatus; recX = Var->stage.lastRec - Var->stage.firstRec; tOffset = Var->stage.areaOffset + (Var->NphyRecBytes * recX) + offset; if (!sX(ReadVarElems(Var,CDF->stage.fp, tOffset,numElems,buffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); return pStatus; } } /**************************************************************************** * Pad the buffer with the variable's pad value. Note that this is also done * if the variable is sRecords.PREV but a previous record does not exist. ****************************************************************************/ if (!sX(PadBuffer(CDF,Var,nValues,buffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); return pStatus; } #if defined(MSVC67) /****************************************************************************** * Replace _ftol2 with _ftol on Windows as VC 6.0 doesn't have a such function. ******************************************************************************/ VISIBLE_PREFIX long _ftol2(dblSource) double dblSource; { return (long) _ftol( dblSource ); } #endif