/****************************************************************************** * * 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. * V2.0 29-Jun-04, M Liu Added LFS (Large File Support > 2G). * V3.2 25-Apr-07, D Berger Changed COPYblockSIZE from 512. * ******************************************************************************/ #include "cdflib.h" #include "cdflib64.h" /****************************************************************************** * Macros/function prototypes. ******************************************************************************/ #define COPYblockSIZE nCACHE_BUFFER_BYTEs static CDFstatus SearchForRecord_r_64 PROTOARGs(( vFILE *fp, OFF_T vxrOffset, Int32 recNum, Int32 *firstRec, Int32 *lastRec, OFF_T *offset, Logical *found )); static CDFstatus IndexingStatistics_r_64 PROTOARGs(( vFILE *fp, OFF_T vxrOffset, Int32 maxRec, int level, Int32 *nLevels, Int32 *nVXRs, Int32 *nEntries, Int32 *nAlloc, Int32 *nRecords )); static CDFstatus PrevRecord_r_64 PROTOARGs(( vFILE *fp, OFF_T vxrOffset, Int32 baseRec, Int32 *prevRec, Logical *found )); static CDFstatus NextRecord_r_64 PROTOARGs(( vFILE *fp, OFF_T vxrOffset, Int32 baseRec, Int32 *nextRec, Logical *found )); static CDFstatus CalcCompressionPct_r_64 PROTOARGs(( vFILE *fp, OFF_T vxrOffset, Int32 nPhyRecBytes, OFF_T *uTotal, OFF_T *cTotal )); static CDFstatus ModIndexOffset_r_64 PROTOARGs(( vFILE *fp, OFF_T vxrOffset, Int32 firstRec, Int32 lastRec, OFF_T 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, OFF_T 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, OFF_T 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, OFF_T offset, Logical fullRecord )); /****************************************************************************** * DecompressCDF64. ******************************************************************************/ STATICforIDL CDFstatus DecompressCDF64 (dotFp, uDotFp) vFILE *dotFp; /* In: File pointer to dotCDF file. */ vFILE *uDotFp; /* In: Uncompressed CDF file pointer. */ { CDFstatus pStatus = CDF_OK; struct CCRstruct64 CCR; struct CPRstruct64 CPR; uInt32 magicNumber1 = V3magicNUMBER_1, magicNumber2u = V2magicNUMBER_2u; OFF_T cSize, cOffset; /**************************************************************************** * Read/validate CCR. ****************************************************************************/ if (!sX(ReadCCR64(dotFp,V3_CCR_OFFSET64, CCR_RECORD,&CCR, CCR_NULL),&pStatus)) return pStatus; if (CCR.uSize == 0) return EMPTY_COMPRESSED_CDF; /**************************************************************************** * Read CPR. ****************************************************************************/ if (!sX(ReadCPR64(dotFp,CCR.CPRoffset, CPR_RECORD,&CPR, CPR_NULL),&pStatus)) return pStatus; /**************************************************************************** * Write magic numbers. ****************************************************************************/ if (!SEEKv64(uDotFp,(OFF_T) V3_MAGIC_OFFSET_1,vSEEK_SET)) return CDF_WRITE_ERROR; if (!Write32_64(uDotFp,(Int32 *)&magicNumber1)) return CDF_WRITE_ERROR; if (!Write32_64(uDotFp,(Int32 *)&magicNumber2u)) return CDF_WRITE_ERROR; /**************************************************************************** * Copy/decompress. ****************************************************************************/ cOffset = (OFF_T) (V3_CCR_OFFSET64 + CCR_BASE_SIZE64); cSize = CCR.RecordSize - CCR_BASE_SIZE64; if (!sX(Decompress64(dotFp,cOffset, cSize,CDF_READ_ERROR, CPR.cType,CPR.cParms, uDotFp,FIRST_IR_OFFSET, CDF_WRITE_ERROR),&pStatus)) return pStatus; return pStatus; } /****************************************************************************** * WriteCompressedCDF64. ******************************************************************************/ STATICforIDL CDFstatus WriteCompressedCDF64 (CDF, CPR, empty) struct CDFstruct *CDF; struct CPRstruct64 *CPR; Logical empty; /* In: If TRUE, write an empty CCR. */ { uInt32 magicNumber1 = V3magicNUMBER_1; uInt32 magicNumber2c = V2magicNUMBER_2c; struct CCRstruct64 CCR; CDFstatus pStatus = CDF_OK; /**************************************************************************** * Write magic numbers. ****************************************************************************/ if (!SEEKv64(CDF->dotFp,(OFF_T) V3_MAGIC_OFFSET_1,vSEEK_SET)) return CDF_WRITE_ERROR; if (!Write32_64(CDF->dotFp,(Int32 *)&magicNumber1)) return CDF_WRITE_ERROR; if (!Write32_64(CDF->dotFp,(Int32 *)&magicNumber2c)) return CDF_WRITE_ERROR; /**************************************************************************** * Write CCR. ****************************************************************************/ if (empty) { CCR.RecordSize = CCR_BASE_SIZE64; CCR.RecordType = CCR_; CCR.CPRoffset = (OFF_T) V3_CCR_OFFSET64 + CCR.RecordSize; CCR.uSize = 0; CCR.rfuA = 0; if (!sX(WriteCCR64(CDF->dotFp,V3_CCR_OFFSET64, CCR_RECORD,&CCR, CCR_NULL),&pStatus)) return CDF_WRITE_ERROR; } else { OFF_T uSize, eof, cSize, cOffset, GDRoffset; if (!sX(ReadCDR64(CDF->uDotFp,V3_CDR_OFFSET64, CDR_GDROFFSET,&GDRoffset, CDR_NULL),&pStatus)) return pStatus; if (!sX(ReadGDR64(CDF->uDotFp,GDRoffset, GDR_EOF,&eof, GDR_NULL),&pStatus)) return pStatus; uSize = eof - FIRST_IR_OFFSET; cOffset = (OFF_T) (V3_CCR_OFFSET64 + CCR_BASE_SIZE64); if (!sX(Compress64(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 = (OFF_T) (CCR_BASE_SIZE64 + cSize); CCR.RecordType = CCR_; CCR.CPRoffset = (OFF_T) (V3_CCR_OFFSET64 + CCR.RecordSize); CCR.uSize = uSize; CCR.rfuA = 0; if (!sX(WriteCCR64(CDF->dotFp,V3_CCR_OFFSET64, CCR_RECORD,&CCR, CCR_NULL),&pStatus)) return CDF_WRITE_ERROR; } /**************************************************************************** * Write CPR. ****************************************************************************/ if (!sX(WriteCPR64(CDF->dotFp,CCR.CPRoffset, CPR_RECORD,CPR, CPR_NULL),&pStatus)) return CDF_WRITE_ERROR; return pStatus; } /****************************************************************************** * CopyCDF64. ******************************************************************************/ STATICforIDL CDFstatus CopyCDF64 (srcFp, destFp) vFILE *srcFp; vFILE *destFp; { OFF_T nBytes, offset; Byte buffer[nCACHE_BUFFER_BYTEs]; CDFstatus pStatus = CDF_OK; if (!SEEKv64(srcFp,(OFF_T)0,vSEEK_END)) return CDF_READ_ERROR; nBytes = V_tell64 (srcFp); if (nBytes == EOF) return CDF_READ_ERROR; if (!SEEKv64(srcFp,(OFF_T)0,vSEEK_SET)) return CDF_READ_ERROR; if (!SEEKv64(destFp,(OFF_T)0,vSEEK_SET)) return CDF_WRITE_ERROR; for (offset = 0; offset < nBytes; offset += nCACHE_BUFFER_BYTEs) { OFF_T nBytesRemaining = nBytes - offset; size_t count = (size_t) MINIMUM (nBytesRemaining, nCACHE_BUFFER_BYTEs); if (!READv64(buffer,count,1,srcFp)) return CDF_READ_ERROR; if (!WRITEv64(buffer,count,1,destFp)) return CDF_WRITE_ERROR; } return pStatus; } /****************************************************************************** * WriteVarValues64. * NOTE: If more than one record is being written, full records are assumed * and the `offset' must be zero. ******************************************************************************/ STATICforIDL CDFstatus WriteVarValues64 (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; { OFF_T 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); LoadAllocVVR64 (alloc, Var->maxAllocated + 1, Var->maxAllocated + nRecords, FALSE) if (!sX(AllocateRecords64(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(PadUnRecords64(CDF,Var,padFrom,padTo),&pStatus)) return pStatus; Var->maxWritten = padTo; } /************************************************************************ * Write value(s). ************************************************************************/ if (fullRecord) { recNum = firstRec; while (recNum <= lastRec) { if (!sX(SearchForRecord64(CDF,Var->VDRoffset64, Var->zVar,recNum, NULL,&lastRecInVVR, NULL,NULL),&pStatus)) return pStatus; writeTo = MINIMUM(lastRec,lastRecInVVR); recCount = writeTo - recNum + 1; if (!sX(RecordByteOffset64(CDF,Var, recNum, &tOffset),&pStatus)) return pStatus; numElems = recCount * Var->NphyRecElems; if (!sX(WriteVarElems64(Var,CDF->fp,tOffset, numElems,tBuffer),&pStatus)) return pStatus; recNum += recCount; tBuffer += (size_t) (recCount * Var->NphyRecBytes); } } else { if (!sX(RecordByteOffset64(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; tOffset += (OFF_T) offset; numElems = nValues * Var->NvalueElems; if (!sX(WriteVarElems64(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(PadUnRecords64(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(SearchForRecord64(CDF,Var->VDRoffset64, Var->zVar,recNum, NULL,&lastRecInVVR, NULL,&found),&pStatus)) return pStatus; if (found) { writeTo = MINIMUM(lastRec,lastRecInVVR); recCount = writeTo - recNum + 1; if (!sX(RecordByteOffset64(CDF,Var, recNum,&tOffset),&pStatus)) return pStatus; if (fullRecord) numElems = recCount * Var->NphyRecElems; else { tOffset += offset; numElems = nValues * Var->NvalueElems; } if (!sX(WriteVarElems64(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.areaOffset64 == (OFF_T) NO_OFFSET64) { nBytes = Var->blockingFactor * Var->NphyRecBytes; if (!sX(InitVarStage64(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(NextRecord64(CDF,Var->VDRoffset64,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.areaOffset64; tOffset += (recordOffsetInStage * Var->NphyRecBytes); if (fullRecord) numElems = recCount * Var->NphyRecElems; else { tOffset += offset; numElems = nValues * Var->NvalueElems; } if (!sX(WriteVarElems64(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(NextRecord64(CDF,Var->VDRoffset64, 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.areaOffset64; tOffset += (recordOffsetInStage * Var->NphyRecBytes); if (fullRecord) numElems = recCount * Var->NphyRecElems; else { if (!sX(BuildPadBuffer64(CDF,Var,recCount, &how,&padBuffer, TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues64(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(WriteVarElems64(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(FlushStage64(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(NextRecord64(CDF,Var->VDRoffset64,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.areaOffset64; if (fullRecord) numElems = recCount * Var->NphyRecElems; else { if (!sX(BuildPadBuffer64(CDF,Var,recCount, &how,&padBuffer, TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues64(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(WriteVarElems64(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.areaOffset64 == (OFF_T) NO_OFFSET64) { 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(WriteVDR64(CDF,CDF->fp,Var->VDRoffset64,Var->zVar, VDR_BLOCKING,&(Var->blockingFactor), VDR_NULL),&pStatus)) return pStatus; } nBytes = Var->blockingFactor * Var->NphyRecBytes; if (!sX(InitVarStage64(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(BuildPadBuffer64(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, (OFF_T) ZERO_OFFSET64, 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, (OFF_T) ZERO_OFFSET64,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(PadUnRecords64(CDF,Var,padFrom,padTo),&pStatus)) return pStatus; } /************************************************************************ * Write value(s). ************************************************************************/ if (!sX(RecordByteOffset64(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; tOffset += (OFF_T) offset; numElems = nValues * Var->NvalueElems; if (!sX(WriteVarElems64(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(UpdateMaxRec64(CDF,Var,lastRec),&pStatus)) return pStatus; return pStatus; } /****************************************************************************** * WriteVarElems64. * NOTE: On IBM PCs, it is assumed that the number of bytes being written * will not exceed 65535. ******************************************************************************/ STATICforIDL CDFstatus WriteVarElems64 (Var, fp, offset, numElems, buffer) struct VarStruct *Var; vFILE *fp; OFF_T offset; Int32 numElems; void *buffer; { CDFstatus pStatus = CDF_OK; Int32 elemCount; /**************************************************************************** * Seek to the desired offset. ****************************************************************************/ if (!SEEKv64(fp,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 (!WRITEv64(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 (;;) { OFF_T xBytes = (OFF_T) elemCount * Var->NelemBytes; #if defined(win32) if (xBytes < (OFF_T) ((1i64 << 31) - 1)) { #else if (xBytes < (OFF_T) ((1LL << 31) - 1)) { #endif 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 (!WRITEv64(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; } /****************************************************************************** * PrevRecord64. * Determine the last record allocated AT or BEFORE `baseRec'. This routine * should only be used for single-file CDFs. ******************************************************************************/ STATICforIDL CDFstatus PrevRecord64 (CDF, VDRoffset, zVar, baseRec, prevRec, found) struct CDFstruct *CDF; OFF_T 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; OFF_T VXRoffset; /**************************************************************************** * If multi-file... ****************************************************************************/ if (!CDF->singleFile) return CDF_INTERNAL_ERROR; /**************************************************************************** * Single-file...read the offset of the first VXR. ****************************************************************************/ if (!sX(ReadVDR64(CDF,CDF->fp,VDRoffset,zVar, VDR_VXRHEAD,&VXRoffset, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start there (unless there are no VXRs). ****************************************************************************/ if (VXRoffset != (OFF_T) ZERO_OFFSET64) { if (!sX(PrevRecord_r_64(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_64 (fp, vxrOffset, baseRec, prevRec, found) vFILE *fp; OFF_T vxrOffset; Int32 baseRec; Int32 *prevRec; Logical *found; { CDFstatus pStatus = CDF_OK; int entryN = 0; struct VXRstruct64 VXR, nextVXR; Int32 irType; /**************************************************************************** * Read the first VXR. ****************************************************************************/ if (!sX(ReadVXR64(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(ReadIrType64(fp,VXR.Offset[entryN],&irType),&pStatus)) { return pStatus; } switch (irType) { case VXR_: return PrevRecord_r_64(fp,VXR.Offset[entryN],baseRec,prevRec,found); case VVR_: case CVVR_: *prevRec = baseRec; ASSIGNnotNULL (found, TRUE) return pStatus; default: return CORRUPTED_V3_CDF; } } /************************************************************************* * If this is the last entry in the current VXR... *************************************************************************/ if (entryN == VXR.NusedEntries - 1) { if (VXR.VXRnext == (OFF_T) ZERO_OFFSET64) { *prevRec = VXR.Last[entryN]; ASSIGNnotNULL (found, TRUE) return pStatus; } if (!sX(ReadVXR64(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++; } } } /****************************************************************************** * NextRecord64. * Determine the next allocated record AT or AFTER `baseRec'. I.e., if * `baseRec' is allocated, it is returned as `nextRec'. ******************************************************************************/ STATICforIDL CDFstatus NextRecord64 (CDF, VDRoffset, zVar, baseRec, nextRec, found) struct CDFstruct *CDF; OFF_T 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 maxRec; OFF_T VXRoffset; /**************************************************************************** * If multi-file... ****************************************************************************/ if (!CDF->singleFile) { if (!sX(ReadVDR64(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(ReadVDR64(CDF,CDF->fp,VDRoffset,zVar, VDR_VXRHEAD,&VXRoffset, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start there. ****************************************************************************/ if (!sX(NextRecord_r_64(CDF->fp,VXRoffset, baseRec,nextRec,found),&pStatus)) return pStatus; return pStatus; } static CDFstatus NextRecord_r_64 (fp, vxrOffset, baseRec, nextRec, found) vFILE *fp; OFF_T vxrOffset; Int32 baseRec; Int32 *nextRec; Logical *found; { CDFstatus pStatus = CDF_OK; int entryN; struct VXRstruct64 VXR; Int32 irType; /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != (OFF_T) ZERO_OFFSET64) { /************************************************************************** * Read the VXR. **************************************************************************/ if (!sX(ReadVXR64(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(ReadIrType64(fp, VXR.Offset[entryN], &irType),&pStatus)) return pStatus; switch (irType) { case VXR_: return NextRecord_r_64(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_V3_CDF; } } } } vxrOffset = VXR.VXRnext; } /**************************************************************************** * No (more) VXRs. The record number was never found. ****************************************************************************/ ASSIGNnotNULL (found, FALSE) return BOO(found == NULL,NO_SUCH_RECORD,pStatus); } /****************************************************************************** * SearchForRecord64. ******************************************************************************/ STATICforIDL CDFstatus SearchForRecord64 (CDF, VDRoffset, zVar, recNum, firstRec, lastRec, offset, found) struct CDFstruct *CDF; OFF_T VDRoffset; Logical zVar; Int32 recNum; Int32 *firstRec; Int32 *lastRec; OFF_T *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 maxRec; OFF_T vxrOffset; /**************************************************************************** * If multi-file... ****************************************************************************/ if (!CDF->singleFile) { if (!sX(ReadVDR64(CDF,CDF->fp,VDRoffset,zVar, VDR_MAXREC,&maxRec, VDR_NULL),&pStatus)) return pStatus; if (recNum <= maxRec) { ASSIGNnotNULL (firstRec, 0) ASSIGNnotNULL (lastRec, maxRec) ASSIGNnotNULL (offset, (OFF_T) ZERO_OFFSET64) 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(ReadVDR64(CDF,CDF->fp,VDRoffset,zVar, VDR_VXRHEAD,&vxrOffset, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start searching there. ****************************************************************************/ if (!sX(SearchForRecord_r_64(CDF->fp,vxrOffset,recNum, firstRec,lastRec, offset,found),&pStatus)) return pStatus; return pStatus; } static CDFstatus SearchForRecord_r_64 (fp, vxrOffset, recNum, firstRec, lastRec, offset, found) vFILE *fp; OFF_T vxrOffset; Int32 recNum; Int32 *firstRec; Int32 *lastRec; OFF_T *offset; Logical *found; { CDFstatus pStatus = CDF_OK; int entryN; struct VXRstruct64 VXR; Int32 irType; /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != (OFF_T) ZERO_OFFSET64) { /************************************************************************** * Read the VXR. **************************************************************************/ if (!sX(ReadVXR64(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(ReadIrType64(fp, VXR.Offset[entryN], &irType),&pStatus)) return pStatus; switch (irType) { case VXR_: return SearchForRecord_r_64(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_V3_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); } /****************************************************************************** * IndexingStatistics64. ******************************************************************************/ STATICforIDL CDFstatus IndexingStatistics64 (CDF, VDRoffset, zVar, nVXRsP, nEntriesP, nAllocP, nRecordsP, nLevelsP) struct CDFstruct *CDF; OFF_T VDRoffset; Logical zVar; Int32 *nVXRsP; Int32 *nEntriesP; Int32 *nAllocP; Int32 *nRecordsP; Int32 *nLevelsP; { CDFstatus pStatus = CDF_OK; Int32 maxRec; int level = 1; Int32 nVXRs = 0, nEntries = 0, nAlloc = 0, nRecords = 0, nLevels = 0; OFF_T vxrOffset; /**************************************************************************** * Read the maximum record and the offset of the first VXR... ****************************************************************************/ if (!sX(ReadVDR64(CDF,CDF->fp,VDRoffset,zVar, VDR_VXRHEAD,&vxrOffset, VDR_MAXREC,&maxRec, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start there. ****************************************************************************/ if (vxrOffset != (OFF_T) ZERO_OFFSET64) { if (!sX(IndexingStatistics_r_64(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_64 (fp, vxrOffset, maxRec, level, nLevels, nVXRs, nEntries, nAlloc, nRecords) vFILE *fp; OFF_T vxrOffset; Int32 maxRec; int level; Int32 *nLevels; Int32 *nVXRs; Int32 *nEntries; Int32 *nAlloc; Int32 *nRecords; { CDFstatus pStatus = CDF_OK; int e; Int32 irType; struct VXRstruct64 VXR; /**************************************************************************** * Check if a new level has been reached. ****************************************************************************/ *nLevels = MAXIMUM(*nLevels,level); /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != (OFF_T) ZERO_OFFSET64) { /************************************************************************** * Read/tally the VXR. **************************************************************************/ if (!sX(ReadVXR64(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; (*nVXRs)++; /************************************************************************** * Scan/count entries... **************************************************************************/ for (e = 0; e < VXR.NusedEntries; e++) { (*nEntries)++; if (!sX(ReadIrType64(fp, VXR.Offset[e], &irType),&pStatus)) return pStatus; switch (irType) { case VXR_: if (!sX(IndexingStatistics_r_64(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_V3_CDF; } } vxrOffset = VXR.VXRnext; } return pStatus; } /****************************************************************************** * BuildPadBuffer64. ******************************************************************************/ STATICforIDL CDFstatus BuildPadBuffer64 (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; OFF_T xBytes; /**************************************************************************** * Determine pad value. ****************************************************************************/ if (!sX(ReadVDR64(CDF,CDF->fp,Var->VDRoffset64,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(ReadVDR64(CDF,CDF->fp,Var->VDRoffset64,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; xBytes = (OFF_T) nValues * Var->NvalueBytes; #if defined(win32) if (xBytes < (OFF_T) ((1i64 << 31) - 1)) { #else if (xBytes < (OFF_T) ((1LL << 31) - 1)) { #endif 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; } /****************************************************************************** * ReadVarValues64. * NOTE: If more than one record is being read, full records are assumed * and the `offset' must be zero. ******************************************************************************/ STATICforIDL CDFstatus ReadVarValues64 (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; OFF_T 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(SearchForRecord64(CDF,Var->VDRoffset64, Var->zVar,recNum, NULL,&lastRecInVVR, NULL,NULL),&pStatus)) return pStatus; readTo = MINIMUMof3(Var->maxRec,lastRec,lastRecInVVR); recCount = readTo - recNum + 1; if (!sX(RecordByteOffset64(CDF,Var, recNum, &tOffset),&pStatus)) return pStatus; numElems = recCount * Var->NphyRecElems; if (!sX(ReadVarElems64(Var,CDF->fp,tOffset, numElems,tBuffer),&pStatus)) return pStatus; } else { recCount = lastRec - recNum + 1; nPadValues = recCount * Var->NphyRecValues; if (!sX(PadBuffer64(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(RecordByteOffset64(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; tOffset += (OFF_T) offset; numElems = nValues * Var->NvalueElems; if (!sX(ReadVarElems64(Var,CDF->fp,tOffset, numElems,buffer),&pStatus)) return pStatus; } else { if (!sX(PadBuffer64(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_V3_CDF error code from being returned if an explicit * blocking factor has not been specified for the variable. ************************************************************************/ if (Var->stage.areaOffset64 == (OFF_T) NO_OFFSET64 && Var->maxRec > NO_RECORD) { if (Var->blockingFactor == 0) return CORRUPTED_V3_CDF; nBytes = Var->blockingFactor * Var->NphyRecBytes; if (!sX(InitVarStage64(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(RecordByteOffset64(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; recCount = MINIMUM(lastRec,Var->maxRec) - firstRec + 1; numElems = recCount * Var->NphyRecElems; if (!sX(ReadVarElems64(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(PadBuffer64(CDF,Var, nPadValues, tBuffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); } } else { /******************************************************************** * Partial record. ********************************************************************/ if (firstRec <= Var->maxRec) { if (!sX(RecordByteOffset64(CDF,Var, firstRec, &tOffset),&pStatus)) return pStatus; tOffset += (OFF_T) offset; numElems = nValues * Var->NvalueElems; if (!sX(ReadVarElems64(Var,Var->fp,tOffset, numElems,buffer),&pStatus)) return pStatus; } else { if (!sX(PadBuffer64(CDF,Var,nValues,buffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); } } break; } return pStatus; } /****************************************************************************** * ReadVarElems64. * NOTE: On IBM PCs, it is assumed that the number of bytes being read * will not exceed 65535. ******************************************************************************/ STATICforIDL CDFstatus ReadVarElems64 (Var, fp, offset, numElems, buffer) struct VarStruct *Var; vFILE *fp; OFF_T offset; Int32 numElems; void *buffer; { CDFstatus pStatus = CDF_OK; size_t nBytes; /**************************************************************************** * Seek to the desired offset. ****************************************************************************/ if (!SEEKv64(fp,offset,vSEEK_SET)) return VAR_READ_ERROR; /**************************************************************************** * Read the value(s). ****************************************************************************/ nBytes = (size_t) (numElems * Var->NelemBytes); if (!READv64(buffer,nBytes,1,fp)) return VAR_READ_ERROR; /**************************************************************************** * Decode value(s). ****************************************************************************/ if (!sX(DECODE(Var->DecodeFunction,buffer,numElems),&pStatus)) { return pStatus; } return pStatus; } /****************************************************************************** * InitVarStage64. ******************************************************************************/ STATICforIDL CDFstatus InitVarStage64 (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 (!CACHEv64(CDF->stage.fp,CDF->stage.cacheSize)) { V_delete64 (CDF->stage.fp, NULL); CDF->stage.fp = NULL; return BAD_CACHE_SIZE; } CDF->stage.mark64 = (OFF_T) ZERO_OFFSET64; } Var->stage.areaOffset64 = CDF->stage.mark64; Var->stage.firstRec = NO_RECORD; Var->stage.lastRec = NO_RECORD; Var->stage.dotOffset64 = (OFF_T) NO_OFFSET64; Var->stage.modified = FALSE; CDF->stage.mark64 += nBytes; return CDF_OK; } /****************************************************************************** * InitScratch64. ******************************************************************************/ STATICforIDL CDFstatus InitScratch64 (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 (!CACHEv64(*scratchFpH,cacheSize)) { V_delete64 (*scratchFpH, NULL); *scratchFpH = NULL; return BAD_CACHE_SIZE; } } else { if (V_clear(*scratchFpH) != 0) return SCRATCH_READ_ERROR; if (!SEEKv64(*scratchFpH,(OFF_T)0,vSEEK_SET)) return SCRATCH_READ_ERROR; } return CDF_OK; } /****************************************************************************** * FlushStage64. ******************************************************************************/ STATICforIDL CDFstatus FlushStage64 (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; struct AllocStruct alloc; OFF_T tOffset; /************************************************************************ * First check if there are records to be flushed in the staging area. ************************************************************************/ if (!Var->stage.modified) return pStatus; /************************************************************************ * Allocate a new VVR. ************************************************************************/ LoadAllocVVR64 (alloc, Var->stage.firstRec, Var->stage.lastRec, FALSE) if (!sX(AllocateRecords64(CDF,Var,alloc),&pStatus)) return pStatus; Var->maxAllocated = MAXIMUM(Var->maxAllocated,Var->stage.lastRec); /************************************************************************ * Copy the records to the new VVR. ************************************************************************/ if (!sX(RecordByteOffset64(CDF,Var, Var->stage.firstRec, &tOffset),&pStatus)) return pStatus; nRecords = Var->stage.lastRec - Var->stage.firstRec + 1; nBytes = nRecords * Var->NphyRecBytes; if (!sX(CopyBytes64(CDF->stage.fp,Var->stage.areaOffset64, 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.dotOffset64 = (OFF_T) NO_OFFSET64; Var->stage.modified = FALSE; break; } case COMPRESSED_: case SPARSE_COMPRESSED_RECORDS_: { Int32 nRecords; OFF_T cSize, xSize, irSize, uSize, newOffset; struct CVVRstruct64 CVVR; struct VVRstruct64 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(InitScratch64(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(Compress64(CDF->stage.fp,Var->stage.areaOffset64, uSize,SCRATCH_READ_ERROR,Var->cType, Var->cParms,CDF->compressFp,(OFF_T) ZERO_OFFSET64, &cSize,SCRATCH_WRITE_ERROR),&pStatus)) return pStatus; /************************************************************************ * Does a VVR/CVVR for this block of records already exist? ************************************************************************/ if (Var->stage.dotOffset64 != (OFF_T) NO_OFFSET64) { /********************************************************************** * Read the size of the existing VVR/CVVR. **********************************************************************/ if (!sX(ReadIrSize64(CDF->fp, Var->stage.dotOffset64, &irSize),&pStatus)) return pStatus; /********************************************************************** * Will a CVVR fit? Note that reserve space is only added to new CVVRs. **********************************************************************/ if (CVVR_BASE_SIZE64 + cSize <= irSize) { LoadCVVRx64 (CVVR, irSize, cSize) if (!sX(WriteCVVR64(CDF->fp,Var->stage.dotOffset64, CVVR_RECORDx,&CVVR, CVVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes64(CDF->compressFp,(OFF_T) ZERO_OFFSET64, SCRATCH_READ_ERROR,cSize,CDF->fp, Var->stage.dotOffset64 + CVVR_BASE_SIZE64, CDF_WRITE_ERROR),&pStatus)) return pStatus; Var->stage.modified = FALSE; return pStatus; } /********************************************************************** * Will a VVR fit? **********************************************************************/ if (VVR_BASE_SIZE64 + uSize <= irSize) { LoadVVRx64 (VVR, irSize) if (!sX(WriteVVR64(CDF->fp,Var->stage.dotOffset64, VVR_RECORDx,&VVR, VVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes64(CDF->stage.fp,Var->stage.areaOffset64, SCRATCH_READ_ERROR,uSize,CDF->fp, Var->stage.dotOffset64 + VVR_BASE_SIZE64, 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_SIZE64 + cSize < VVR_BASE_SIZE64 + uSize) { if (!sX(ResizeIR64(CDF,Var->stage.dotOffset64, CVVR_BASE_SIZE64 + cSize, &newOffset,TRUE,NULL),&pStatus)) return pStatus; LoadCVVRx64 (CVVR, CVVR_BASE_SIZE64 + cSize, cSize) if (!sX(WriteCVVR64(CDF->fp,newOffset, CVVR_RECORDx,&CVVR, CVVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes64(CDF->compressFp,(OFF_T) ZERO_OFFSET64, SCRATCH_READ_ERROR,cSize, CDF->fp,newOffset + CVVR_BASE_SIZE64, CDF_WRITE_ERROR),&pStatus)) return pStatus; } else { if (!sX(ResizeIR64(CDF,Var->stage.dotOffset64, VVR_BASE_SIZE64 + uSize, &newOffset,TRUE,NULL),&pStatus)) return pStatus; LoadVVRx64 (VVR, VVR_BASE_SIZE64 + uSize) if (!sX(WriteVVR64(CDF->fp,newOffset, VVR_RECORDx,&VVR, VVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes64(CDF->stage.fp,Var->stage.areaOffset64, SCRATCH_READ_ERROR,uSize, CDF->fp,newOffset + VVR_BASE_SIZE64, CDF_WRITE_ERROR),&pStatus)) return pStatus; sX (DID_NOT_COMPRESS, &pStatus); } if (!sX(ModIndexOffset64(CDF,Var, Var->stage.firstRec, Var->stage.lastRec, newOffset),&pStatus)) return pStatus; Var->stage.dotOffset64 = 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_SIZE64 + cSize + xSize < VVR_BASE_SIZE64 + uSize) { LoadAllocCVVR64 (alloc, Var->stage.firstRec, Var->stage.lastRec, cSize, xSize) if (!sX(AllocateRecords64(CDF,Var,alloc),&pStatus)) return pStatus; if (!sX(SearchForRecord64(CDF,Var->VDRoffset64,Var->zVar, Var->stage.firstRec,NULL,NULL, &newOffset,NULL),&pStatus)) return pStatus; LoadCVVRx64 (CVVR, CVVR_BASE_SIZE64 + cSize + xSize, cSize) if (!sX(WriteCVVR64(CDF->fp,newOffset, CVVR_RECORDx,&CVVR, CVVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes64(CDF->compressFp,(OFF_T) ZERO_OFFSET64, SCRATCH_READ_ERROR,cSize, CDF->fp,newOffset + CVVR_BASE_SIZE64, CDF_WRITE_ERROR),&pStatus)) return pStatus; Var->stage.dotOffset64 = newOffset; Var->stage.modified = FALSE; return pStatus; } /************************************************************************ * The CVVR will be too big - create a VVR. ************************************************************************/ LoadAllocVVR64 (alloc, Var->stage.firstRec, Var->stage.lastRec, TRUE) if (!sX(AllocateRecords64(CDF,Var,alloc),&pStatus)) return pStatus; if (!sX(SearchForRecord64(CDF,Var->VDRoffset64,Var->zVar, Var->stage.firstRec,NULL,NULL, &newOffset,NULL),&pStatus)) return pStatus; LoadVVRx64 (VVR, VVR_BASE_SIZE64 + uSize) if (!sX(WriteVVR64(CDF->fp,newOffset, VVR_RECORDx,&VVR, VVR_NULL),&pStatus)) return pStatus; if (!sX(CopyBytes64(CDF->stage.fp,Var->stage.areaOffset64, SCRATCH_READ_ERROR,uSize, CDF->fp,newOffset + VVR_BASE_SIZE64, CDF_WRITE_ERROR),&pStatus)) return pStatus; Var->stage.dotOffset64 = 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, nRecords; OFF_T uSize; Logical foundX; OFF_T offset; /************************************************************************ * Determine if the record exists. ************************************************************************/ if (!sX(SearchForRecord64(CDF,Var->VDRoffset64,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(FlushStage64(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(DecompressToStage64(CDF,Var, offset,uSize),&pStatus)) return pStatus; /************************************************************************ * Update staging control. ************************************************************************/ Var->stage.firstRec = firstRec; Var->stage.lastRec = lastRec; Var->stage.dotOffset64 = offset; Var->stage.modified = FALSE; break; } default: return CDF_INTERNAL_ERROR; } return pStatus; } /****************************************************************************** * CopyBytes64. ******************************************************************************/ STATICforIDL CDFstatus CopyBytes64 (iFp, iStart, iError, nBytes, oFp, oStart, oError) vFILE *iFp; OFF_T iStart; CDFstatus iError; OFF_T nBytes; vFILE *oFp; OFF_T oStart; CDFstatus oError; { Int32 nBlocks = (Int32) (nBytes / COPYblockSIZE); /* Number of full blocks that can be copied. */ Int32 lastCount = (Int32) (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) { OFF_T iOffset = iStart + (OFF_T) (nBytes - COPYblockSIZE); OFF_T oOffset = oStart + (OFF_T) (nBytes - COPYblockSIZE); for (i = 0; i < nBlocks; i++) { if (!SEEKv64(iFp,iOffset,vSEEK_SET)) return iError; if (!READv64(buffer,(size_t)COPYblockSIZE,(size_t)1,iFp)) return iError; if (!SEEKv64(oFp,oOffset,vSEEK_SET)) return oError; if (!WRITEv64(buffer,(size_t)COPYblockSIZE,(size_t)1,oFp)) return oError; iOffset -= (OFF_T) COPYblockSIZE; oOffset -= (OFF_T) COPYblockSIZE; } } if (lastCount > 0) { if (!SEEKv64(iFp,iStart,vSEEK_SET)) return iError; if (!READv64(buffer,(size_t)lastCount,(size_t)1,iFp)) return iError; if (!SEEKv64(oFp,oStart,vSEEK_SET)) return oError; if (!WRITEv64(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) { OFF_T iOffset = iStart; OFF_T oOffset = oStart; if (nBlocks > 0) { for (i = 0; i < nBlocks; i++) { if (!SEEKv64(iFp,iOffset,vSEEK_SET)) return iError; if (!READv64(buffer,(size_t)COPYblockSIZE,(size_t)1,iFp)) return iError; if (!SEEKv64(oFp,oOffset,vSEEK_SET)) return oError; if (!WRITEv64(buffer,(size_t)COPYblockSIZE,(size_t)1,oFp)) return oError; iOffset += (OFF_T) COPYblockSIZE; oOffset += (OFF_T) COPYblockSIZE; } } if (lastCount > 0) { if (!SEEKv64(iFp,iOffset,vSEEK_SET)) return iError; if (!READv64(buffer,(size_t)lastCount,(size_t)1,iFp)) return iError; if (!SEEKv64(oFp,oOffset,vSEEK_SET)) return oError; if (!WRITEv64(buffer,(size_t)lastCount,(size_t)1,oFp)) return oError; } } /************************************************************************** * Offsets are the same - do nothing. **************************************************************************/ } else { /************************************************************************** * Different files... **************************************************************************/ if (!SEEKv64(iFp,iStart,vSEEK_SET)) return iError; if (!SEEKv64(oFp,oStart,vSEEK_SET)) return oError; for (i = 0; i < nBlocks; i++) { if (!READv64(buffer,(size_t)COPYblockSIZE,(size_t)1,iFp)) return iError; if (!WRITEv64(buffer,(size_t)COPYblockSIZE,(size_t)1,oFp)) return oError; } if (lastCount > 0) { if (!READv64(buffer,(size_t)lastCount,(size_t)1,iFp)) return iError; if (!WRITEv64(buffer,(size_t)lastCount,(size_t)1,oFp)) return oError; } } return CDF_OK; } /****************************************************************************** * ModIndexOffset64. ******************************************************************************/ STATICforIDL CDFstatus ModIndexOffset64 (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. */ OFF_T newOffset; /* New VVR/CVVR/SVVR offset. */ { CDFstatus pStatus = CDF_OK; OFF_T vxrOffset; /**************************************************************************** * Read offset of first VXR... ****************************************************************************/ if (!sX(ReadVDR64(CDF,CDF->fp,Var->VDRoffset64,Var->zVar, VDR_VXRHEAD,&vxrOffset, VDR_NULL),&pStatus)) return pStatus; /**************************************************************************** * ...and start there. ****************************************************************************/ if (!sX(ModIndexOffset_r_64(CDF->fp,vxrOffset, firstRec,lastRec, newOffset),&pStatus)) return pStatus; return pStatus; } static CDFstatus ModIndexOffset_r_64 (fp, vxrOffset, firstRec, lastRec, newOffset) vFILE *fp; /* File pointer to dotCDF file. */ OFF_T vxrOffset; /* VXR at which to start. */ Int32 firstRec; /* First record of entry. */ Int32 lastRec; /* Last record of entry. */ OFF_T newOffset; /* New VVR/CVVR/SVVR offset. */ { CDFstatus pStatus = CDF_OK; struct VXRstruct64 VXR; int entryN; Int32 irType; /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != (OFF_T) ZERO_OFFSET64) { /************************************************************************** * Read the VXR. **************************************************************************/ if (!sX(ReadVXR64(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(ReadIrType64(fp, VXR.Offset[entryN], &irType),&pStatus)) return pStatus; if (irType == VXR_) return ModIndexOffset_r_64(fp,VXR.Offset[entryN], firstRec,lastRec, newOffset); if (VXR.First[entryN] == firstRec && lastRec == VXR.Last[entryN]) { VXR.Offset[entryN] = newOffset; if (!sX(WriteVXR64(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; return pStatus; } return CDF_INTERNAL_ERROR; /* or CORRUPTED_V3_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. */ OFF_T 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, recordOffsetInStage, maxRecThisBlock; Int32 nextRec, writeTo, numElems; void *padBuffer; int how; Int32 recNum = firstRec; Byte *tBuffer = (Byte *) buffer; OFF_T tOffset; /**************************************************************************** * 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.areaOffset64; tOffset += (recordOffsetInStage * Var->NphyRecBytes); if (fullRecord) { if (Var->stage.dotOffset64 == (OFF_T) NO_OFFSET64) { maxRecThisBlock = Var->stage.firstRec + Var->blockingFactor - 1; if (!sX(NextRecord64(CDF,Var->VDRoffset64, 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(WriteVarElems64(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.areaOffset64; 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(WriteVarElems64(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.dotOffset64 == (OFF_T) NO_OFFSET64) { if (recNum == Var->stage.lastRec + 1) { maxRecThisBlock = Var->stage.firstRec + Var->blockingFactor - 1; if (recNum <= maxRecThisBlock) { recordOffsetInStage = recNum - Var->stage.firstRec; tOffset = Var->stage.areaOffset64; tOffset += (recordOffsetInStage * Var->NphyRecBytes); if (fullRecord) { if (!sX(NextRecord64(CDF,Var->VDRoffset64, 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(BuildPadBuffer64(CDF,Var,INT32_ONE, &how,&padBuffer, TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues64(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(WriteVarElems64(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(FlushStage64(CDF,Var),&pStatus)) return pStatus; tOffset = Var->stage.areaOffset64; if (fullRecord) { maxRecThisBlock = recNum + Var->blockingFactor - 1; if (!sX(NextRecord64(CDF,Var->VDRoffset64,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(BuildPadBuffer64(CDF,Var,INT32_ONE, &how,&padBuffer, TRUE),&pStatus)) return pStatus; if (!sX(WritePadValues64(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(WriteVarElems64(Var,CDF->stage.fp, tOffset,numElems, tBuffer),&pStatus)) return pStatus; Var->stage.firstRec = recNum; Var->stage.lastRec = writeTo; Var->stage.dotOffset64 = (OFF_T) NO_OFFSET64; Var->stage.modified = TRUE; tBuffer += (size_t) (numElems * Var->NelemBytes); recNum += recCount; } return pStatus; } /****************************************************************************** * CalcCompressionPct64. ******************************************************************************/ STATICforIDL CDFstatus CalcCompressionPct64 (CDF, vdrOffset, zVar, cPct) struct CDFstruct *CDF; OFF_T vdrOffset; Logical zVar; long *cPct; { CDFstatus pStatus = CDF_OK; OFF_T vxrOffset; OFF_T uTotal = 0, cTotal = 0; Int32 nPhyRecBytes; /**************************************************************************** * Calculate the number of bytes per physical record. ****************************************************************************/ if (!sX(CalcPhyRecBytes64(CDF,vdrOffset, zVar,&nPhyRecBytes),&pStatus)) return pStatus; /**************************************************************************** * Read the offset of the first VXR (return 0% if no VXRs)... ****************************************************************************/ if (!sX(ReadVDR64(CDF,CDF->fp,vdrOffset,zVar, VDR_VXRHEAD,&vxrOffset, VDR_NULL),&pStatus)) return pStatus; if (vxrOffset == (OFF_T) ZERO_OFFSET64) { *cPct = 0; return pStatus; } /**************************************************************************** * ...and start there. ****************************************************************************/ if (!sX(CalcCompressionPct_r_64(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_64 (fp, vxrOffset, nPhyRecBytes, uTotal, cTotal) vFILE *fp; OFF_T vxrOffset; Int32 nPhyRecBytes; OFF_T *uTotal; OFF_T *cTotal; { CDFstatus pStatus = CDF_OK; struct VXRstruct64 VXR; int entryN; Int32 nRecords, irType; OFF_T uSize, irSize; /**************************************************************************** * While more VXRs... ****************************************************************************/ while (vxrOffset != (OFF_T) ZERO_OFFSET64) { /************************************************************************** * Read the VXR. **************************************************************************/ if (!sX(ReadVXR64(fp,vxrOffset, VXR_RECORD,&VXR, VXR_NULL),&pStatus)) return pStatus; /************************************************************************** * Scan entries... **************************************************************************/ for (entryN = 0; entryN < VXR.NusedEntries; entryN++) { if (!sX(ReadIrType64(fp,VXR.Offset[entryN],&irType),&pStatus)) return pStatus; switch (irType) { case VXR_: if (!sX(CalcCompressionPct_r_64(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(ReadIrSize64(fp,VXR.Offset[entryN],&irSize),&pStatus)) return pStatus; *cTotal += irSize - BOO(irType == CVVR_, CVVR_BASE_SIZE64, VVR_BASE_SIZE64); break; default: return CORRUPTED_V3_CDF; } } vxrOffset = VXR.VXRnext; } return pStatus; } /****************************************************************************** * CalcPhyRecBytes64. ******************************************************************************/ STATICforIDL CDFstatus CalcPhyRecBytes64 (CDF, vdrOffset, zVar, nPhyRecBytes) struct CDFstruct *CDF; OFF_T 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(CalcDimParms64(CDF,vdrOffset,zVar, &numDims,dimSizes,dimVarys),&pStatus)) return pStatus; if (!sX(ReadVDR64(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, nPadValues; OFF_T tOffset; 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.areaOffset64 + (OFF_T) (recX * Var->NphyRecBytes); if (!sX(ReadVarElems64(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(SearchForRecord64(CDF,Var->VDRoffset64, 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_SIZE64 + (OFF_T) (recX * Var->NphyRecBytes); if (!sX(ReadVarElems64(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(NextRecord64(CDF,Var->VDRoffset64,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(PrevRecord64(CDF,Var->VDRoffset64,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.areaOffset64 + (OFF_T) (recX * Var->NphyRecBytes); if (!sX(ReadVarElems64(Var,CDF->stage.fp, tOffset,Var->NphyRecElems, tBuffer),&pStatus)) return pStatus; } else { if (!sX(RecordByteOffset64(CDF,Var, prevRec, &tOffset),&pStatus)) return pStatus; if (!sX(ReadVarElems64(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.areaOffset64 + (OFF_T) (recX * Var->NphyRecBytes); if (!sX(ReadVarElems64(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(PadBuffer64(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; OFF_T offset; Int32 nValues; void *buffer; { CDFstatus pStatus = CDF_OK; Logical found; Int32 firstRec, prevRec; OFF_T tOffset; 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.areaOffset64; tOffset += (OFF_T) (Var->NphyRecBytes * (recNum - Var->stage.firstRec)); tOffset += offset; if (!sX(ReadVarElems64(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(SearchForRecord64(CDF,Var->VDRoffset64, Var->zVar,recNum,&firstRec, NULL,&tOffset,&found),&pStatus)) return pStatus; if (found) { tOffset += (OFF_T) VVR_BASE_SIZE64; tOffset += (OFF_T) Var->NphyRecBytes * (recNum - firstRec); tOffset += offset; if (!sX(ReadVarElems64(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(PrevRecord64(CDF,Var->VDRoffset64,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.areaOffset64; tOffset += (OFF_T) Var->NphyRecBytes * recNumInStage; tOffset += offset; if (!sX(ReadVarElems64(Var,CDF->stage.fp,tOffset, numElems,buffer),&pStatus)) return pStatus; } else { if (!sX(RecordByteOffset64(CDF,Var, prevRec, &tOffset),&pStatus)) return pStatus; tOffset += offset; if (!sX(ReadVarElems64(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.areaOffset64; tOffset += (OFF_T) Var->NphyRecBytes * recNumInStage; tOffset += offset; if (!sX(ReadVarElems64(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(PadBuffer64(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, nextRec; Int32 recNum = firstRec, nPadValues, prevRec, padTo; Byte *tBuffer = (Byte *) buffer, *destBuffer; OFF_T tOffset; /**************************************************************************** * 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.areaOffset64 + (OFF_T) (recX * Var->NphyRecBytes); if (!sX(ReadVarElems64(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(NextRecord64(CDF,Var->VDRoffset64,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(PrevRecord64(CDF,Var->VDRoffset64,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.areaOffset64 + (OFF_T) (recX * Var->NphyRecBytes); if (!sX(ReadVarElems64(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(PadBuffer64(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; OFF_T offset; Int32 nValues; void *buffer; { CDFstatus pStatus = CDF_OK; Int32 numElems = nValues * Var->NvalueElems; Int32 prevRec, recX; Logical found; OFF_T tOffset; /**************************************************************************** * Try to bring the record to the staging area. ****************************************************************************/ if (!sX(BringToStage(CDF,Var,recNum,&found),&pStatus)) return pStatus; if (found) { tOffset = Var->stage.areaOffset64; tOffset += (OFF_T) Var->NphyRecBytes * (recNum - Var->stage.firstRec); tOffset += offset; if (!sX(ReadVarElems64(Var,CDF->stage.fp, tOffset,numElems,buffer),&pStatus)) return pStatus; return pStatus; } /**************************************************************************** * If sRecords.PREV... ****************************************************************************/ if (Var->prevIfMissing) { if (!sX(PrevRecord64(CDF,Var->VDRoffset64, 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.areaOffset64 + (OFF_T) (Var->NphyRecBytes * recX) + offset; if (!sX(ReadVarElems64(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(PadBuffer64(CDF,Var,nValues,buffer),&pStatus)) return pStatus; sX (VIRTUAL_RECORD_DATA, &pStatus); return pStatus; } /****************************************************************************** * CheckLFS. ******************************************************************************/ VISIBLE_PREFIX CDFstatus CheckLFS (CDFname, isLFS, CDFfullName) char *CDFname; Logical *isLFS; char *CDFfullName; { CDFstatus pStatus = CDF_OK; #if defined(win32) && (_FILE_OFFSET_BITS == 64) int fp; #else FILE *fp; #endif Int32 temp, magicNumber1; OFF_T length64 = (OFF_T) 0; Logical upper_case_ext, version_numbers, no_append; char CDFpathX[DU_MAX_PATH_LEN+1], CDFpathT[DU_MAX_PATH_LEN+1]; if (CDFfullName != NULL) strcpyX (CDFfullName, CDFname, DU_MAX_PATH_LEN); /************************************************************************** * Open CDF file. **************************************************************************/ if (strlen(CDFname) > (size_t) CDF_PATHNAME_LEN) { if (!sX(CDF_NAME_TRUNC,&pStatus)) return pStatus; } strcpyX (CDFpathT, CDFname, CDF_PATHNAME_LEN); #if STRIP_TRAILING_BLANKS_FROM_CDFPATH StripTrailingBlanks (CDFpathT); #endif #if defined(vms) || defined(dos) MakeUpperString (CDFpathT); #endif if (!ValidCDFname(CDFpathT)) return BAD_CDF_NAME; if (!sX(FindCDF(CDFpathT,&no_append, &upper_case_ext, &version_numbers),&pStatus)) return pStatus; BuildFilePath (CDFt, CDFpathT, no_append, upper_case_ext, version_numbers, INT32_ZERO, CDFpathX); #if defined(win32) && (_FILE_OFFSET_BITS == 64) fp = FOPEN64 (CDFpathX, _O_RDONLY); if (fp == EOF) return CDF_OPEN_ERROR; #else fp = (FILE *) FOPEN64 (CDFpathX, READ_ONLY_a_mode); if (fp == NULL) return CDF_OPEN_ERROR; #endif if (FSEEK64(fp,(OFF_T)0,vSEEK_END) == EOF) { FCLOSE64 (fp); return CDF_OPEN_ERROR; } length64 = FTELL64 (fp); if (length64 == 0) /* A new one... Must be a LFS. */ *isLFS = TRUE; else { /* Existing one... Check its magic number at the 1st 4-byte. */ if (FSEEK64(fp,0,vSEEK_SET) == EOF) return CDF_OPEN_ERROR; #if defined(win32) && (_FILE_OFFSET_BITS == 64) if (FREAD64(fp,&magicNumber1,(unsigned int)4) != 4) #else if (FREAD64(&magicNumber1,(size_t)4,(size_t)1,fp) != 1) #endif return CDF_READ_ERROR; #ifndef NETWORKbyteORDERcpu temp = magicNumber1; REVERSE4bIO (&temp, &magicNumber1) #endif if (magicNumber1 == V3magicNUMBER_1) *isLFS = TRUE; else *isLFS = FALSE; } FCLOSE64 (fp); if (CDFfullName != NULL) strcpyX (CDFfullName, CDFpathX, DU_MAX_PATH_LEN); return pStatus; } /****************************************************************************** * StrStrIgCaseX. ******************************************************************************/ VISIBLE_PREFIX Logical StrStrIgCaseX (string, chkstring) char *string; char *chkstring; { int stringL = strlen(string); int chkstringL = strlen(chkstring); int i; if (stringL == 0 || chkstringL == 0) return FALSE; if (stringL != chkstringL) return FALSE; for (i = 0; i < stringL; i++) { if (MakeLower(chkstring[i]) != MakeLower(string[i])) return FALSE; } return TRUE; } /****************************************************************************** * Check if a given string ends with the provided substring, case sensitive. * TRUE if s1 ends with s2. Otherwise, FALSE is returned. ******************************************************************************/ int EndsWith (s1, s2) char *s1; char *s2; { int i; char *ps1, *ps2; if (strlen(s2) > strlen(s1)) return FALSE; ps1 = s1 + strlen(s1) - strlen(s2); ps2 = s2; for (i=0; i < (int) strlen(s2); i++) if (*(ps1++) != *(ps2++)) return FALSE; return TRUE; } /****************************************************************************** * Check if a given string ends with the provided substring, ignoring case. * TRUE if s1 ends with s2. Otherwise, FALSE is returned. ******************************************************************************/ int EndsWithIgCase (s1, s2) char *s1; char *s2; { int i; char *ps1, *ps2; if (strlen(s2) > strlen(s1)) return FALSE; ps1 = s1 + strlen(s1) - strlen(s2); ps2 = s2; for (i=0; i < (int) strlen(s2); i++) { if (MakeLower(*ps1) != MakeLower(*ps2)) return FALSE; ps1++; ps2++; } return TRUE; } /****************************************************************************** * Find the last occurence of a substring within a given string, case * sensitive. If the substring is found, it returns the offset where the * substring is at in the original string. If the substring is not found, it * returns -1. ******************************************************************************/ int StrLaststr (s1, s2) char *s1; char *s2; { char *sc2, *psc1, *ps1; if (*s2 == '\0') return -1; ps1 = s1 + strlen(s1); while(ps1 != s1) { --ps1; for (psc1 = ps1, sc2 = s2; ; ) if (*(psc1++) != *(sc2++)) break; else if (*sc2 == '\0') return (int) (ps1 - s1); } return -1; } /****************************************************************************** * Find the last occurence of a substring within a given string, ignoring case. * If the substring is found, it returns the offset where the substring is at * in the original string. If the substring is not found, it returns -1. ******************************************************************************/ int StrLaststrIgCase (s1, s2) char *s1; char *s2; { char *sc2, *psc1, *ps1; if (*s2 == '\0') return -1; ps1 = s1 + strlen(s1); while (ps1 != s1) { --ps1; for (psc1 = ps1, sc2 = s2; ; ) { if (MakeLower(*psc1) != MakeLower(*sc2)) break; else if (*sc2 == '\0') return (int) (ps1 - s1); psc1++; sc2++; } } return -1; } /****************************************************************************** * Remove the ".cdf" file extension from the given file name if it's there. * It ignores the case. * Example: * mydata.cdf => mydata ******************************************************************************/ void RemoveCDFFileExtension (fileName, dstPath) char *fileName; /* CDF file name. */ char *dstPath; /* The string holding file name without extension. */ { int ptr = -1; strcpyX (dstPath, fileName, CDF_PATHNAME_LEN); if (EndsWithIgCase (dstPath, ".cdf")) { ptr = StrLaststrIgCase(dstPath, ".cdf"); if (ptr != -1) ((char *) dstPath)[ptr] = (char) '\0'; } return; } /****************************************************************************** * CDFgetFileBackwardEnvVar. ******************************************************************************/ VISIBLE_PREFIX int CDFgetFileBackwardEnvVar () { char *bk = NULL; #if defined(vms) bk = getenv("CDF$FILEBACKWARD"); #else bk = getenv("CDF_FILEBACKWARD"); #endif if (bk != NULL) { if (strlen(bk) == 0) return 0; if (StrStrIgCaseX(bk, "TRUE")) return 1; } return 0; } /****************************************************************************** * CDFgetChecksumEnvVar. ******************************************************************************/ VISIBLE_PREFIX int CDFgetChecksumEnvVar () { char *bk = NULL; #if defined(vms) bk = getenv("CDF$CHECKSUM"); #else bk = getenv("CDF_CHECKSUM"); #endif if (bk != NULL) { if (strlen(bk) == 0) return 0; if (StrStrIgCaseX(bk, "none") || StrStrIgCaseX(bk, "no")) return 0; if (StrStrIgCaseX(bk, "md5")) return 1; } return 0; } /****************************************************************************** * ChecksumMethod. ******************************************************************************/ VISIBLE_PREFIX long ChecksumMethod (flags) Int32 flags; { int md5 = 0; int other = 0; if (!BITSET(flags,CDR_CHECKSUM_BIT)) return NONE_CHECKSUM; md5 = (int) BITSET(flags,CDR_CHECKSUM_MD5_BIT); other = (int) BITSET(flags,CDR_CHECKSUM_OTHER_BIT); if (md5 == 1) return MD5_CHECKSUM; else if (other == 1) return OTHER_CHECKSUM; return NONE_CHECKSUM; }