1 /******************************************************************************
2 *
3 *  NSSDC/CDF                     CDF library miscellaneous functions, part 3.
4 *
5 *  Version 1.0e, 29-Oct-97, Hughes STX.
6 *
7 *  Modification history:
8 *
9 *   V1.0   5-Sep-96, J Love     Original version.
10 *   V1.0a 21-Feb-97, J Love	Removed RICE.
11 *   V1.0b  4-Mar-97, J Love	Windows NT for MS Visual C/C++ on an IBM PC.
12 *   V1.0c 11-Sep-97, J Love	Magic number are now uInt32.
13 *   V1.0d 20-Oct-97, J Love	Properly cast the uInt32 magic numbers.  More
14 *				Windows NT.
15 *   V3.2  25-Apr-07, D Berger   Changed COPYblockBYTES from 512.
16 *
17 ******************************************************************************/
18 
19 #include "cdflib.h"
20 
21 /******************************************************************************
22 * Macros/function prototypes.
23 ******************************************************************************/
24 
25 #define COPYblockSIZE nCACHE_BUFFER_BYTEs
26 
27 static CDFstatus SearchForRecord_r PROTOARGs((
28   vFILE *fp, Int32 vxrOffset, Int32 recNum, Int32 *firstRec, Int32 *lastRec,
29   Int32 *offset, Logical *found
30 ));
31 static CDFstatus IndexingStatistics_r PROTOARGs((
32   vFILE *fp, Int32 vxrOffset, Int32 maxRec, int level, Int32 *nLevels,
33   Int32 *nVXRs, Int32 *nEntries, Int32 *nAlloc, Int32 *nRecords
34 ));
35 static CDFstatus PrevRecord_r PROTOARGs((
36   vFILE *fp, Int32 vxrOffset, Int32 baseRec, Int32 *prevRec, Logical *found
37 ));
38 static CDFstatus NextRecord_r PROTOARGs((
39   vFILE *fp, Int32 vxrOffset, Int32 baseRec, Int32 *nextRec, Logical *found
40 ));
41 static CDFstatus CalcCompressionPct_r PROTOARGs((
42   vFILE *fp, Int32 vxrOffset, Int32 nPhyRecBytes, long *uTotal, long *cTotal
43 ));
44 static CDFstatus ModIndexOffset_r PROTOARGs((
45   vFILE *fp, Int32 vxrOffset, Int32 firstRec, Int32 lastRec, Int32 newOffset
46 ));
47 static CDFstatus ReadSparseFull PROTOARGs((
48   struct CDFstruct *CDF, struct VarStruct *Var, Int32 firstRec, Int32 lastRec,
49   void *buffer
50 ));
51 static CDFstatus ReadSparsePartial PROTOARGs((
52   struct CDFstruct *CDF, struct VarStruct *Var, Int32 recNum, Int32 offset,
53   Int32 nValues, void *buffer
54 ));
55 static CDFstatus ReadCompressedFull PROTOARGs((
56   struct CDFstruct *CDF, struct VarStruct *Var, Int32 firstRec, Int32 lastRec,
57   void *buffer
58 ));
59 static CDFstatus ReadCompressedPartial PROTOARGs((
60   struct CDFstruct *CDF, struct VarStruct *Var, Int32 recNum, Int32 offset,
61   Int32 nValues, void *buffer
62 ));
63 static CDFstatus BringToStage PROTOARGs((
64   struct CDFstruct *CDF, struct VarStruct *Var, Int32 recNum, Logical *found
65 ));
66 static CDFstatus WriteCompressedRecords PROTOARGs((
67   struct CDFstruct *CDF, struct VarStruct *Var, Int32 firstRec, Int32 lastRec,
68   void *buffer, Int32 nValues, Int32 offset, Logical fullRecord
69 ));
70 
71 /******************************************************************************
72 * DecompressCDF.
73 ******************************************************************************/
74 
DecompressCDF(dotFp,uDotFp)75 STATICforIDL CDFstatus DecompressCDF (dotFp, uDotFp)
76 vFILE *dotFp;           /* In: File pointer to dotCDF file. */
77 vFILE *uDotFp;          /* In: Uncompressed CDF file pointer. */
78 {
79   CDFstatus pStatus = CDF_OK; struct CCRstruct CCR; struct CPRstruct CPR;
80   uInt32 magicNumber1 = V2magicNUMBER_1, magicNumber2u = V2magicNUMBER_2u;
81   Int32 cSize, cOffset;
82   /****************************************************************************
83   * Read/validate CCR.
84   ****************************************************************************/
85   if (!sX(ReadCCR(dotFp,V2_CCR_OFFSET,
86 		  CCR_RECORD,&CCR,
87 		  CCR_NULL),&pStatus)) return pStatus;
88   if (CCR.uSize == 0) return EMPTY_COMPRESSED_CDF;
89   /****************************************************************************
90   * Read CPR.
91   ****************************************************************************/
92   if (!sX(ReadCPR(dotFp,CCR.CPRoffset,
93 		  CPR_RECORD,&CPR,
94 		  CPR_NULL),&pStatus)) return pStatus;
95   /****************************************************************************
96   * Write magic numbers.
97   ****************************************************************************/
98   if (!SEEKv(uDotFp,V2_MAGIC_OFFSET_1,vSEEK_SET)) return CDF_WRITE_ERROR;
99   if (!Write32(uDotFp,(Int32 *)&magicNumber1)) return CDF_WRITE_ERROR;
100   if (!Write32(uDotFp,(Int32 *)&magicNumber2u)) return CDF_WRITE_ERROR;
101   /****************************************************************************
102   * Copy/decompress.
103   ****************************************************************************/
104   cOffset = V2_CCR_OFFSET + CCR_BASE_SIZE;
105   cSize = CCR.RecordSize - CCR_BASE_SIZE;
106   if (!sX(Decompress(dotFp,cOffset,
107 		     cSize,CDF_READ_ERROR,
108 		     CPR.cType,CPR.cParms,
109 		     uDotFp,FIRST_IR_OFFSET,
110 		     CDF_WRITE_ERROR),&pStatus)) return pStatus;
111   return pStatus;
112 }
113 
114 /******************************************************************************
115 * WriteCompressedCDF.
116 ******************************************************************************/
117 
WriteCompressedCDF(CDF,CPR,empty)118 STATICforIDL CDFstatus WriteCompressedCDF (CDF, CPR, empty)
119 struct CDFstruct *CDF;
120 struct CPRstruct *CPR;
121 Logical empty;          /* In: If TRUE, write an empty CCR. */
122 {
123   uInt32 magicNumber1 = V2magicNUMBER_1;
124   uInt32 magicNumber2c = V2magicNUMBER_2c;
125   struct CCRstruct CCR; CDFstatus pStatus = CDF_OK;
126   /****************************************************************************
127   * Write magic numbers.
128   ****************************************************************************/
129   if (!SEEKv(CDF->dotFp,V2_MAGIC_OFFSET_1,vSEEK_SET)) return CDF_WRITE_ERROR;
130   if (!Write32(CDF->dotFp,(Int32 *)&magicNumber1)) return CDF_WRITE_ERROR;
131   if (!Write32(CDF->dotFp,(Int32 *)&magicNumber2c)) return CDF_WRITE_ERROR;
132   /****************************************************************************
133   * Write CCR.
134   ****************************************************************************/
135   if (empty) {
136     CCR.RecordSize = CCR_BASE_SIZE;
137     CCR.RecordType = CCR_;
138     CCR.CPRoffset = V2_CCR_OFFSET + CCR.RecordSize;
139     CCR.uSize = 0;
140     CCR.rfuA = 0;
141     if (!sX(WriteCCR(CDF->dotFp,V2_CCR_OFFSET,
142 		     CCR_RECORD,&CCR,
143 		     CCR_NULL),&pStatus)) return CDF_WRITE_ERROR;
144   }
145   else {
146     Int32 uSize, eof, cSize, cOffset, GDRoffset;
147     if (!sX(ReadCDR(CDF->uDotFp,V2_CDR_OFFSET,
148 		    CDR_GDROFFSET,&GDRoffset,
149 		    CDR_NULL),&pStatus)) return pStatus;
150     if (!sX(ReadGDR(CDF->uDotFp,GDRoffset,
151 		    GDR_EOF,&eof,
152 		    GDR_NULL),&pStatus)) return pStatus;
153     uSize = eof - FIRST_IR_OFFSET;
154     cOffset = V2_CCR_OFFSET + CCR_BASE_SIZE;
155     if (!sX(Compress(CDF->uDotFp,FIRST_IR_OFFSET,
156 		     uSize,CDF_READ_ERROR,CPR->cType,
157 		     CPR->cParms,CDF->dotFp,cOffset,
158 		     &cSize,CDF_WRITE_ERROR),&pStatus)) return pStatus;
159     CCR.RecordSize = CCR_BASE_SIZE + cSize;
160     CCR.RecordType = CCR_;
161     CCR.CPRoffset = V2_CCR_OFFSET + CCR.RecordSize;
162     CCR.uSize = uSize;
163     CCR.rfuA = 0;
164     if (!sX(WriteCCR(CDF->dotFp,V2_CCR_OFFSET,
165 		     CCR_RECORD,&CCR,
166 		     CCR_NULL),&pStatus)) return CDF_WRITE_ERROR;
167   }
168   /****************************************************************************
169   * Write CPR.
170   ****************************************************************************/
171   if (!sX(WriteCPR(CDF->dotFp,CCR.CPRoffset,
172 		   CPR_RECORD,CPR,
173 		   CPR_NULL),&pStatus)) return CDF_WRITE_ERROR;
174   return pStatus;
175 }
176 
177 /******************************************************************************
178 * CopyCDF.
179 ******************************************************************************/
180 
CopyCDF(srcFp,destFp)181 STATICforIDL CDFstatus CopyCDF (srcFp, destFp)
182 vFILE *srcFp;
183 vFILE *destFp;
184 {
185   Int32 nBytes, offset; Byte buffer[nCACHE_BUFFER_BYTEs];
186   CDFstatus pStatus = CDF_OK;
187   if (!SEEKv(srcFp,0L,vSEEK_END)) return CDF_READ_ERROR;
188   nBytes = V_tell (srcFp);
189   if (nBytes == EOF) return CDF_READ_ERROR;
190   if (!SEEKv(srcFp,0L,vSEEK_SET)) return CDF_READ_ERROR;
191   if (!SEEKv(destFp,0L,vSEEK_SET)) return CDF_WRITE_ERROR;
192   for (offset = 0; offset < nBytes; offset += nCACHE_BUFFER_BYTEs) {
193      Int32 nBytesRemaining = nBytes - offset;
194      size_t count = (size_t) MINIMUM (nBytesRemaining, nCACHE_BUFFER_BYTEs);
195      if (!READv(buffer,count,1,srcFp)) return CDF_READ_ERROR;
196      if (!WRITEv(buffer,count,1,destFp)) return CDF_WRITE_ERROR;
197   }
198   return pStatus;
199 }
200 
201 /******************************************************************************
202 * WriteVarValues.
203 *    NOTE: If more than one record is being written, full records are assumed
204 * and the `offset' must be zero.
205 ******************************************************************************/
206 
WriteVarValues(CDF,Var,startRec,offset,nValues,buffer)207 STATICforIDL CDFstatus WriteVarValues (CDF, Var, startRec, offset, nValues,
208 				       buffer)
209 struct CDFstruct *CDF;
210 struct VarStruct *Var;
211 Int32 startRec;          /* Physical record number at which to write. */
212 Int32 offset;            /* Byte offset within (first) record at which to
213 			    begin writing. */
214 Int32 nValues;           /* Number of values to write. */
215 void *buffer;
216 {
217   Int32 tOffset; Logical fullRecord; Byte *tBuffer = buffer;
218   Int32 numElems, firstRec, lastRec, lastRecInVVR, nBytes, padTo, recNum;
219   Int32 writeTo, recCount; CDFstatus pStatus = CDF_OK;
220   /****************************************************************************
221   * Determine first/last record(s) being written and if full physical
222   * record(s).
223   ****************************************************************************/
224   firstRec = startRec;
225   if (nValues < Var->NphyRecValues) {
226     fullRecord = FALSE;
227     lastRec = startRec;
228   }
229   else {
230     fullRecord = TRUE;
231     lastRec = startRec + ((nValues - 1) / Var->NphyRecValues);
232   }
233   /****************************************************************************
234   * Based on variable type...
235   ****************************************************************************/
236   switch (Var->vType) {
237     /**************************************************************************
238     * Standard variable in single-file CDF...
239     **************************************************************************/
240     case STANDARD_: {
241       /************************************************************************
242       * Allocate/pad records.
243       ************************************************************************/
244       if (lastRec > Var->maxAllocated) {
245 	struct AllocStruct alloc;
246 	Int32 nNeeded = lastRec - Var->maxAllocated;
247 	Int32 nRecords = MAXIMUM(nNeeded,Var->blockingFactor);
248 	LoadAllocVVR (alloc, Var->maxAllocated + 1,
249 		      Var->maxAllocated + nRecords, FALSE)
250 	if (!sX(AllocateRecords(CDF,Var,alloc),&pStatus)) return pStatus;
251 	Var->maxAllocated = alloc.last;
252       }
253       padTo = BOO(fullRecord,firstRec - 1,firstRec);
254       if (padTo > Var->maxWritten) {
255 	Int32 padFrom = Var->maxWritten + 1;
256 	if (!sX(PadUnRecords(CDF,Var,padFrom,padTo),&pStatus)) return pStatus;
257 	Var->maxWritten = padTo;
258       }
259       /************************************************************************
260       * Write value(s).
261       ************************************************************************/
262       if (fullRecord) {
263 	recNum = firstRec;
264 	while (recNum <= lastRec) {
265 	  if (!sX(SearchForRecord(CDF,Var->VDRoffset,
266 				  Var->zVar,recNum,
267 				  NULL,&lastRecInVVR,
268 				  NULL,NULL),&pStatus)) return pStatus;
269 	  writeTo = MINIMUM(lastRec,lastRecInVVR);
270 	  recCount = writeTo - recNum + 1;
271 	  if (!sX(RecordByteOffset(CDF,Var,
272 				   recNum,
273 				   &tOffset),&pStatus)) return pStatus;
274 	  numElems = recCount * Var->NphyRecElems;
275 	  if (!sX(WriteVarElems(Var,CDF->fp,tOffset,
276 				numElems,tBuffer),&pStatus)) return pStatus;
277 	  recNum += recCount;
278 	  tBuffer += (size_t) (recCount * Var->NphyRecBytes);
279 	}
280       }
281       else {
282 	if (!sX(RecordByteOffset(CDF,Var,
283 				 firstRec,
284 				 &tOffset),&pStatus)) return pStatus;
285 	tOffset += (Int32) offset;
286 	numElems = nValues * Var->NvalueElems;
287 	if (!sX(WriteVarElems(Var,CDF->fp,tOffset,
288 			      numElems,buffer),&pStatus)) return pStatus;
289       }
290       /************************************************************************
291       * Update the maximum record written.
292       ************************************************************************/
293       Var->maxWritten = MAXIMUM(Var->maxWritten,lastRec);
294       break;
295     }
296     /**************************************************************************
297     * Sparse records...
298     **************************************************************************/
299     case SPARSE_RECORDS_: {
300       Int32 maxRecInStage, recordOffsetInStage, nextRec;
301       int how; void *padBuffer; Logical found;
302       /************************************************************************
303       * Pad records.
304       ************************************************************************/
305       padTo = BOO(fullRecord,firstRec - 1,firstRec);
306       if (padTo > Var->maxWritten) {
307 	Int32 padFrom = Var->maxWritten + 1;
308 	if (!sX(PadUnRecords(CDF,Var,padFrom,padTo),&pStatus)) return pStatus;
309 	Var->maxWritten = padTo;
310       }
311       /************************************************************************
312       * Write value(s).
313       ************************************************************************/
314       recNum = firstRec;
315       while (recNum <= lastRec) {
316 	/**********************************************************************
317 	* Check if this record already exists (is allocated).
318 	**********************************************************************/
319 	if (!sX(SearchForRecord(CDF,Var->VDRoffset,
320 				Var->zVar,recNum,
321 				NULL,&lastRecInVVR,
322 				NULL,&found),&pStatus)) return pStatus;
323 	if (found) {
324 	  writeTo = MINIMUM(lastRec,lastRecInVVR);
325 	  recCount = writeTo - recNum + 1;
326 	  if (!sX(RecordByteOffset(CDF,Var,
327 				   recNum,&tOffset),&pStatus)) return pStatus;
328 	  if (fullRecord)
329 	    numElems = recCount * Var->NphyRecElems;
330 	  else {
331 	    tOffset += offset;
332 	    numElems = nValues * Var->NvalueElems;
333 	  }
334 	  if (!sX(WriteVarElems(Var,CDF->fp,tOffset,
335 				numElems,tBuffer),&pStatus)) return pStatus;
336 	  Var->maxWritten = MAXIMUM(Var->maxWritten,writeTo);
337 	  recNum += recCount;
338 	  tBuffer += (size_t) (numElems * Var->NelemBytes);
339 	  continue;
340 	}
341 	/**********************************************************************
342 	* This record doesn't exist - initialize the staging area.
343 	**********************************************************************/
344 	if (Var->stage.areaOffset == NO_OFFSET) {
345 	  nBytes = Var->blockingFactor * Var->NphyRecBytes;
346 	  if (!sX(InitVarStage(CDF,Var,nBytes),&pStatus)) return pStatus;
347 	}
348 	/**********************************************************************
349 	* Check if this record is in the staging area.
350 	**********************************************************************/
351 	if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) {
352 	  maxRecInStage = Var->stage.firstRec + Var->blockingFactor - 1;
353 	  writeTo = MINIMUM(lastRec,maxRecInStage);
354 	  if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar,
355 			     recNum,&nextRec,&found),&pStatus)) return pStatus;
356 	  if (found) {
357 	    Int32 prevRecN = nextRec - 1;
358 	    writeTo = MINIMUM(writeTo,prevRecN);
359 	  }
360 	  recCount = writeTo - recNum + 1;
361 	  recordOffsetInStage = recNum - Var->stage.firstRec;
362 	  tOffset = Var->stage.areaOffset;
363 	  tOffset += (recordOffsetInStage * Var->NphyRecBytes);
364 	  if (fullRecord)
365 	    numElems = recCount * Var->NphyRecElems;
366 	  else {
367 	    tOffset += offset;
368 	    numElems = nValues * Var->NvalueElems;
369 	  }
370 	  if (!sX(WriteVarElems(Var,CDF->stage.fp,tOffset,
371 				numElems,tBuffer),&pStatus)) return pStatus;
372 	  Var->stage.lastRec = MAXIMUM(Var->stage.lastRec,writeTo);
373 	  Var->stage.modified = TRUE;
374 	  recNum += recCount;
375 	  tBuffer += (size_t) (numElems * Var->NelemBytes);
376 	  continue;
377 	}
378 	/**********************************************************************
379 	* This record is not in the staging area.  Check if it can be added.
380 	**********************************************************************/
381 	if (Var->stage.firstRec != NO_RECORD) {
382 	  if (recNum == Var->stage.lastRec + 1) {
383 	    maxRecInStage = Var->stage.firstRec + Var->blockingFactor - 1;
384 	    if (recNum <= maxRecInStage) {
385 	      writeTo = MINIMUM(lastRec,maxRecInStage);
386 	      if (!sX(NextRecord(CDF,Var->VDRoffset,
387 				 Var->zVar,recNum,
388 				 &nextRec,&found),&pStatus)) return pStatus;
389 	      if (found) {
390 		Int32 prevRecN = nextRec - 1;
391 		writeTo = MINIMUM(writeTo,prevRecN);
392 	      }
393 	      recCount = writeTo - recNum + 1;
394 	      recordOffsetInStage = recNum - Var->stage.firstRec;
395 	      tOffset = Var->stage.areaOffset;
396 	      tOffset += (recordOffsetInStage * Var->NphyRecBytes);
397 	      if (fullRecord)
398 		numElems = recCount * Var->NphyRecElems;
399 	      else {
400 		if (!sX(BuildPadBuffer(CDF,Var,recCount,
401 				       &how,&padBuffer,
402 				       TRUE),&pStatus)) return pStatus;
403 		if (!sX(WritePadValues(Var,CDF->stage.fp,tOffset,
404 				       recCount,how,padBuffer),&pStatus)) {
405 		  cdf_FreeMemory (padBuffer, NULL);
406 		  return pStatus;
407 		}
408 		cdf_FreeMemory (padBuffer, NULL);
409 		tOffset += offset;
410 		numElems = nValues * Var->NvalueElems;
411 	      }
412 	      if (!sX(WriteVarElems(Var,CDF->stage.fp,
413 				    tOffset,numElems,
414 				    tBuffer),&pStatus)) return pStatus;
415 	      Var->stage.lastRec = MAXIMUM(Var->stage.lastRec,writeTo);
416 	      Var->stage.modified = TRUE;
417 	      recNum += recCount;
418 	      tBuffer += (size_t) (numElems * Var->NelemBytes);
419 	      continue;
420 	    }
421 	  }
422 	}
423 	/**********************************************************************
424 	* This record cannot be added to the staging area.  First flush the
425 	* staging area (if necessary)...
426 	**********************************************************************/
427 	if (!sX(FlushStage(CDF,Var),&pStatus)) return pStatus;
428 	/**********************************************************************
429 	* ...and then start a new staging area with this record.
430 	**********************************************************************/
431 	maxRecInStage = recNum + Var->blockingFactor - 1;
432 	writeTo = MINIMUM(lastRec,maxRecInStage);
433 	if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar,
434 			   recNum,&nextRec,&found),&pStatus)) return pStatus;
435 	if (found) {
436 	  Int32 prevRecN = nextRec - 1;
437 	  writeTo = MINIMUM(writeTo,prevRecN);
438 	}
439 	recCount = writeTo - recNum + 1;
440 	tOffset = Var->stage.areaOffset;
441 	if (fullRecord)
442 	  numElems = recCount * Var->NphyRecElems;
443 	else {
444 	  if (!sX(BuildPadBuffer(CDF,Var,recCount,
445 				 &how,&padBuffer,
446 				 TRUE),&pStatus)) return pStatus;
447 	  if (!sX(WritePadValues(Var,CDF->stage.fp,tOffset,
448 				 recCount,how,padBuffer),&pStatus)) {
449 	  cdf_FreeMemory (padBuffer, NULL);
450 	  return pStatus;
451 	  }
452 	  cdf_FreeMemory (padBuffer, NULL);
453 	  tOffset += offset;
454 	  numElems = nValues * Var->NvalueElems;
455 	}
456 	if (!sX(WriteVarElems(Var,CDF->stage.fp,tOffset,
457 			      numElems,tBuffer),&pStatus)) return pStatus;
458 	Var->stage.firstRec = recNum;
459 	Var->stage.lastRec = writeTo;
460 	Var->stage.modified = TRUE;
461 	recNum += recCount;
462 	tBuffer += (size_t) (numElems * Var->NelemBytes);
463       }
464       break;
465     }
466     /**************************************************************************
467     * Compressed records...
468     * Sparse/compressed records...
469     **************************************************************************/
470     case COMPRESSED_:
471     case SPARSE_COMPRESSED_RECORDS_: {
472       Logical sparseRecords = (Var->vType == SPARSE_COMPRESSED_RECORDS_);
473       /************************************************************************
474       * Initialize staging area.
475       ************************************************************************/
476       if (Var->stage.areaOffset == NO_OFFSET) {
477 	if (Var->blockingFactor == 0) {
478 	  if (Var->recVary) {
479 	    Int32 bf = ((MIN_BLOCKING_BYTES_compressed-1)/Var->NphyRecBytes)+1;
480 	    Var->blockingFactor = MAXIMUM(bf,MIN_BLOCKING_RECS_compressed);
481 	  }
482 	  else
483 	    Var->blockingFactor = 1;
484 	  if (!sX(WriteVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar,
485 			   VDR_BLOCKING,&(Var->blockingFactor),
486 			   VDR_NULL),&pStatus)) return pStatus;
487 	}
488 	nBytes = Var->blockingFactor * Var->NphyRecBytes;
489 	if (!sX(InitVarStage(CDF,Var,nBytes),&pStatus)) return pStatus;
490       }
491       /************************************************************************
492       * Pad records (if necessary).
493       ************************************************************************/
494       if (!sparseRecords) {
495 	padTo = firstRec - 1;
496 	if (Var->maxRec < padTo) {
497 	  Int32 nRecords = padTo + 1, recN, valueN; void *padBuffer; int how;
498 	  if (!sX(BuildPadBuffer(CDF,Var,
499 				 nRecords,&how,
500 				 &padBuffer,FALSE),&pStatus)) return pStatus;
501 	  switch (how) {
502 	    case ALLrecordsATonce:
503 	      if (!sX(WriteCompressedRecords(CDF,Var,Var->maxRec+1,
504 					     padTo,padBuffer,
505 					     nRecords*Var->NphyRecValues,
506 					     ZERO_OFFSET,
507 					     TRUE),&pStatus)) return pStatus;
508 	      break;
509 	    case ONErecordATaTIME:
510 	      for (recN = Var->maxRec + 1; recN <= padTo; recN++) {
511 		 if (!sX(WriteCompressedRecords(CDF,Var,recN,recN,
512 						padBuffer,Var->NphyRecValues,
513 						ZERO_OFFSET,TRUE),&pStatus)) {
514 		   cdf_FreeMemory (padBuffer, NULL);
515 		   return pStatus;
516 		 }
517 	      }
518 	      break;
519 	    case ONEvalueATaTIME:
520 	      for (recN = 0; recN < nRecords; recN++) {
521 		 for (valueN = 0; valueN < Var->NphyRecValues; valueN++) {
522 		    tOffset = valueN * Var->NvalueBytes;
523 		    if (!sX(WriteCompressedRecords(CDF,Var,recN,recN,
524 						   padBuffer,INT32_ONE,
525 						   tOffset,FALSE),&pStatus)) {
526 		      cdf_FreeMemory (padBuffer, NULL);
527 		      return pStatus;
528 		    }
529 		 }
530 	      }
531 	      break;
532 	  }
533 	  cdf_FreeMemory (padBuffer, NULL);
534 	}
535       }
536       /************************************************************************
537       * Write the record(s).
538       ************************************************************************/
539       if (!sX(WriteCompressedRecords(CDF,Var,firstRec,lastRec,
540 				     buffer,nValues,offset,
541 				     fullRecord),&pStatus)) return pStatus;
542       break;
543     }
544     /**************************************************************************
545     * Can't do sparse arrays yet...
546     **************************************************************************/
547     case SPARSE_ARRAYS_:
548     case SPARSE_RECORDS_AND_ARRAYS_:
549       return UNKNOWN_SPARSENESS;
550     /**************************************************************************
551     * Variable in multi-file CDF...
552     **************************************************************************/
553     case IN_MULTI_: {
554       padTo = BOO(fullRecord,firstRec - 1,firstRec);
555       /************************************************************************
556       * Extend variable (if necessary).
557       ************************************************************************/
558       if (padTo > Var->maxRec) {
559 	Int32 padFrom = Var->maxRec + 1;
560 	if (!sX(PadUnRecords(CDF,Var,padFrom,padTo),&pStatus)) return pStatus;
561       }
562       /************************************************************************
563       * Write value(s).
564       ************************************************************************/
565       if (!sX(RecordByteOffset(CDF,Var,
566 			       firstRec,
567 			       &tOffset),&pStatus)) return pStatus;
568       tOffset += (Int32) offset;
569       numElems = nValues * Var->NvalueElems;
570       if (!sX(WriteVarElems(Var,Var->fp,tOffset,
571 			    numElems,buffer),&pStatus)) return pStatus;
572       break;
573     }
574     /**************************************************************************
575     * Unknown variable type - this should never happen.
576     **************************************************************************/
577     default:
578       return CDF_INTERNAL_ERROR;
579   }
580   /****************************************************************************
581   * Update maximum record numbers.
582   ****************************************************************************/
583   if (!sX(UpdateMaxRec(CDF,Var,lastRec),&pStatus)) return pStatus;
584   return pStatus;
585 }
586 
587 /******************************************************************************
588 * WriteVarElems.
589 *   NOTE: On IBM PCs, it is assumed that the number of bytes being written
590 * will not exceed 65535.
591 ******************************************************************************/
592 
WriteVarElems(Var,fp,offset,numElems,buffer)593 STATICforIDL CDFstatus WriteVarElems (Var, fp, offset, numElems, buffer)
594 struct VarStruct *Var;
595 vFILE *fp;
596 Int32 offset;
597 Int32 numElems;
598 void *buffer;
599 {
600   CDFstatus pStatus = CDF_OK; Int32 elemCount;
601   /****************************************************************************
602   * Seek to the desired offset.
603   ****************************************************************************/
604   if (!SEEKv(fp,(long)offset,vSEEK_SET)) return VAR_WRITE_ERROR;
605   /****************************************************************************
606   * If no encoding is necessary, simply write the buffer and return.
607   ****************************************************************************/
608   if (Var->EncodeFunction == NULL) {
609     Int32 nBytes = numElems * Var->NelemBytes;
610     if (!WRITEv(buffer,1,(size_t)nBytes,fp)) return VAR_WRITE_ERROR;
611     return pStatus;
612   }
613   /****************************************************************************
614   * Use as large a temporary buffer as possible for the encoding conversion.
615   * Start at the full number of elements and then halve that number until an
616   * allocation succeeds.
617   ****************************************************************************/
618   elemCount = numElems;
619   for (;;) {
620      size_t nBytes = (size_t) (elemCount * Var->NelemBytes);
621      void *tBuffer;
622      if ((int) nBytes <= 0) return VAR_READ_ERROR;
623      tBuffer = cdf_AllocateMemory (nBytes, NULL);
624      if (tBuffer != NULL) {
625        Int32 elemN = 0; Byte *bOffset = buffer;
626        while (elemN < numElems) {
627 	 Int32 thisElemCount = MinInt32 (elemCount, numElems - elemN);
628 	 size_t thisByteCount = (size_t) (thisElemCount * Var->NelemBytes);
629 	 memmove (tBuffer, bOffset, thisByteCount);
630 	 if (!sX(Var->EncodeFunction(tBuffer,thisElemCount),&pStatus)) {
631 	   cdf_FreeMemory (tBuffer, NULL);
632 	   return pStatus;
633 	 }
634 	 if (!WRITEv(tBuffer,1,thisByteCount,fp)) {
635 	   cdf_FreeMemory (tBuffer, NULL);
636 	   return VAR_WRITE_ERROR;
637 	 }
638 	 elemN += thisElemCount;
639 	 bOffset += thisByteCount;
640        }
641        cdf_FreeMemory (tBuffer, NULL);
642        return pStatus;
643      }
644      if (elemCount == 1) break;
645      elemCount = (elemCount + 1) / 2;
646   }
647   return BAD_MALLOC;
648 }
649 
650 /******************************************************************************
651 * PrevRecord.
652 *   Determine the last record allocated AT or BEFORE `baseRec'.  This routine
653 * should only be used for single-file CDFs.
654 ******************************************************************************/
655 
PrevRecord(CDF,VDRoffset,zVar,baseRec,prevRec,found)656 STATICforIDL CDFstatus PrevRecord (CDF, VDRoffset, zVar, baseRec, prevRec,
657 				   found)
658 struct CDFstruct *CDF;
659 Int32 VDRoffset;
660 Logical zVar;
661 Int32 baseRec;
662 Int32 *prevRec;
663 Logical *found;         /* If NULL, return NO_SUCH_RECORD if the previous
664 			   record doesn't exist.  Otherwise, set according to
665 			   whether or not the previous record exists and
666 			   return the pending status. */
667 {
668   CDFstatus pStatus = CDF_OK; Int32 VXRoffset;
669   /****************************************************************************
670   * If multi-file...
671   ****************************************************************************/
672   if (!CDF->singleFile) return CDF_INTERNAL_ERROR;
673   /****************************************************************************
674   * Single-file...read the offset of the first VXR.
675   ****************************************************************************/
676   if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar,
677 		  VDR_VXRHEAD,&VXRoffset,
678 		  VDR_NULL),&pStatus)) return pStatus;
679   /****************************************************************************
680   * ...and start there (unless there are no VXRs).
681   ****************************************************************************/
682   if (VXRoffset != ZERO_OFFSET) {
683     if (!sX(PrevRecord_r(CDF->fp,VXRoffset,
684 			 baseRec,prevRec,found),&pStatus)) return pStatus;
685   }
686   else {
687     ASSIGNnotNULL (found, FALSE)
688     if (found == NULL) pStatus = NO_SUCH_RECORD;
689   }
690   return pStatus;
691 }
692 
PrevRecord_r(fp,vxrOffset,baseRec,prevRec,found)693 static CDFstatus PrevRecord_r (fp, vxrOffset, baseRec, prevRec, found)
694 vFILE *fp;
695 Int32 vxrOffset;
696 Int32 baseRec;
697 Int32 *prevRec;
698 Logical *found;
699 {
700   CDFstatus pStatus = CDF_OK; int entryN = 0;
701   struct VXRstruct VXR, nextVXR; Int32 irType;
702   /****************************************************************************
703   * Read the first VXR.
704   ****************************************************************************/
705   if (!sX(ReadVXR(fp,vxrOffset,
706 		  VXR_RECORD,&VXR,
707 		  VXR_NULL),&pStatus)) return pStatus;
708   /****************************************************************************
709   * Check if there isn't a previous allocated record.  This could only be the
710   * case at the top level of VXRs (ie. not when this routine is recursively
711   * called).
712   ****************************************************************************/
713   if (baseRec < VXR.First[0]) {
714     ASSIGNnotNULL (found, FALSE)
715     return BOO(found == NULL,NO_SUCH_RECORD,pStatus);
716   }
717   /****************************************************************************
718   * Until it's time to return...
719   ****************************************************************************/
720   for (;;) {
721      /*************************************************************************
722      * If the record is in the current entry...
723      *************************************************************************/
724      if (INCLUSIVE(VXR.First[entryN],baseRec,VXR.Last[entryN])) {
725        if (!sX(ReadIrType(fp,VXR.Offset[entryN],&irType),&pStatus)) {
726 	 return pStatus;
727        }
728        switch (irType) {
729 	 case VXR_:
730 	   return PrevRecord_r(fp,VXR.Offset[entryN],baseRec,prevRec,found);
731 	 case VVR_:
732 	 case CVVR_:
733 	   *prevRec = baseRec;
734 	   ASSIGNnotNULL (found, TRUE)
735 	   return pStatus;
736 	 default:
737 	   return CORRUPTED_V2_CDF;
738        }
739      }
740      /*************************************************************************
741      * If this is the last entry in the current VXR...
742      *************************************************************************/
743      if (entryN == VXR.NusedEntries - 1) {
744        if (VXR.VXRnext == ZERO_OFFSET) {
745 	 *prevRec = VXR.Last[entryN];
746 	 ASSIGNnotNULL (found, TRUE)
747 	 return pStatus;
748        }
749        if (!sX(ReadVXR(fp,VXR.VXRnext,
750 		       VXR_RECORD,&nextVXR,
751 		       VXR_NULL),&pStatus)) return pStatus;
752        if (baseRec < nextVXR.First[0]) {
753 	 *prevRec = VXR.Last[entryN];
754 	 ASSIGNnotNULL (found, TRUE)
755 	 return pStatus;
756        }
757        VXR = nextVXR;
758        entryN = 0;
759      }
760      else {
761        if (baseRec < VXR.First[entryN+1]) {
762 	 *prevRec = VXR.Last[entryN];
763 	 ASSIGNnotNULL (found, TRUE)
764 	 return pStatus;
765        }
766        entryN++;
767      }
768   }
769 }
770 
771 /******************************************************************************
772 * NextRecord.
773 *   Determine the next allocated record AT or AFTER `baseRec'.  I.e., if
774 * `baseRec' is allocated, it is returned as `nextRec'.
775 ******************************************************************************/
776 
NextRecord(CDF,VDRoffset,zVar,baseRec,nextRec,found)777 STATICforIDL CDFstatus NextRecord (CDF, VDRoffset, zVar, baseRec, nextRec,
778 				   found)
779 struct CDFstruct *CDF;
780 Int32 VDRoffset;
781 Logical zVar;
782 Int32 baseRec;
783 Int32 *nextRec;
784 Logical *found;         /* If NULL, return NO_SUCH_RECORD if the next record
785 			   doesn't exist.  Otherwise, set according to whether
786 			   or not the next record exists and return the pending
787 			   status. */
788 {
789   CDFstatus pStatus = CDF_OK; Int32 VXRoffset, maxRec;
790   /****************************************************************************
791   * If multi-file...
792   ****************************************************************************/
793   if (!CDF->singleFile) {
794     if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar,
795 		    VDR_MAXREC,&maxRec,
796 		    VDR_NULL),&pStatus)) return pStatus;
797     if (baseRec <= maxRec) {
798       *nextRec = baseRec;
799       ASSIGNnotNULL (found, TRUE)
800     }
801     else {
802       ASSIGNnotNULL (found, FALSE)
803       if (found == NULL) pStatus = NO_SUCH_RECORD;
804     }
805     return pStatus;
806   }
807   /****************************************************************************
808   * ...single-file, read the offset of the first VXR.
809   ****************************************************************************/
810   if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar,
811 		  VDR_VXRHEAD,&VXRoffset,
812 		  VDR_NULL),&pStatus)) return pStatus;
813   /****************************************************************************
814   * ...and start there.
815   ****************************************************************************/
816   if (!sX(NextRecord_r(CDF->fp,VXRoffset,
817 		       baseRec,nextRec,found),&pStatus)) return pStatus;
818   return pStatus;
819 }
820 
NextRecord_r(fp,vxrOffset,baseRec,nextRec,found)821 static CDFstatus NextRecord_r (fp, vxrOffset, baseRec, nextRec, found)
822 vFILE *fp;
823 Int32 vxrOffset;
824 Int32 baseRec;
825 Int32 *nextRec;
826 Logical *found;
827 {
828   CDFstatus pStatus = CDF_OK;
829   int entryN; struct VXRstruct VXR; Int32 irType;
830   /****************************************************************************
831   * While more VXRs...
832   ****************************************************************************/
833   while (vxrOffset != ZERO_OFFSET) {
834     /**************************************************************************
835     * Read the VXR.
836     **************************************************************************/
837     if (!sX(ReadVXR(fp,vxrOffset,
838 		    VXR_RECORD,&VXR,
839 		    VXR_NULL),&pStatus)) return pStatus;
840     /**************************************************************************
841     * Search entries...
842     **************************************************************************/
843     if (baseRec <= VXR.Last[(int)(VXR.NusedEntries-1)]) {
844       for (entryN = 0; entryN < VXR.NusedEntries; entryN++) {
845 	 if (baseRec <= VXR.Last[entryN]) {
846 	   if (!sX(ReadIrType(fp,
847 			      VXR.Offset[entryN],
848 			      &irType),&pStatus)) return pStatus;
849 	   switch (irType) {
850 	     case VXR_:
851 	       return NextRecord_r(fp,VXR.Offset[entryN],
852 				   baseRec,nextRec,found);
853 	     case VVR_:
854 	     case CVVR_:
855 	       *nextRec = BOO(VXR.First[entryN] <= baseRec,
856 			      baseRec,VXR.First[entryN]);
857 	       ASSIGNnotNULL (found, TRUE)
858 	       return pStatus;
859 	     default:
860 	       return CORRUPTED_V2_CDF;
861 	   }
862 	 }
863       }
864     }
865     vxrOffset = VXR.VXRnext;
866   }
867   /****************************************************************************
868   * No (more) VXRs.  The record number was never found.
869   ****************************************************************************/
870   ASSIGNnotNULL (found, FALSE)
871   return BOO(found == NULL,NO_SUCH_RECORD,pStatus);
872 }
873 
874 /******************************************************************************
875 * SearchForRecord.
876 ******************************************************************************/
877 
SearchForRecord(CDF,VDRoffset,zVar,recNum,firstRec,lastRec,offset,found)878 STATICforIDL CDFstatus SearchForRecord (CDF, VDRoffset, zVar, recNum,
879 					firstRec, lastRec, offset, found)
880 struct CDFstruct *CDF;
881 Int32 VDRoffset;
882 Logical zVar;
883 Int32 recNum;
884 Int32 *firstRec;
885 Int32 *lastRec;
886 Int32 *offset;
887 Logical *found;         /* If NULL, return NO_SUCH_RECORD if the record is
888 			   not found.  Otherwise, set according to whether
889 			   or not the record is found and return the pending
890 			   status. */
891 {
892   CDFstatus pStatus = CDF_OK; Int32 vxrOffset, maxRec;
893   /****************************************************************************
894   * If multi-file...
895   ****************************************************************************/
896   if (!CDF->singleFile) {
897     if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar,
898 		    VDR_MAXREC,&maxRec,
899 		    VDR_NULL),&pStatus)) return pStatus;
900     if (recNum <= maxRec) {
901       ASSIGNnotNULL (firstRec, 0)
902       ASSIGNnotNULL (lastRec, maxRec)
903       ASSIGNnotNULL (offset, ZERO_OFFSET)
904       ASSIGNnotNULL (found, TRUE)
905     }
906     else {
907       ASSIGNnotNULL (found, FALSE)
908       if (found == NULL) pStatus = NO_SUCH_RECORD;
909     }
910     return pStatus;
911   }
912   /****************************************************************************
913   * ...single-file, read the offset of the first VXR.
914   ****************************************************************************/
915   if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar,
916 		  VDR_VXRHEAD,&vxrOffset,
917 		  VDR_NULL),&pStatus)) return pStatus;
918   /****************************************************************************
919   * ...and start searching there.
920   ****************************************************************************/
921   if (!sX(SearchForRecord_r(CDF->fp,vxrOffset,recNum,
922 			    firstRec,lastRec,
923 			    offset,found),&pStatus)) return pStatus;
924   return pStatus;
925 }
926 
SearchForRecord_r(fp,vxrOffset,recNum,firstRec,lastRec,offset,found)927 static CDFstatus SearchForRecord_r (fp, vxrOffset, recNum, firstRec, lastRec,
928 				    offset, found)
929 vFILE *fp;
930 Int32 vxrOffset;
931 Int32 recNum;
932 Int32 *firstRec;
933 Int32 *lastRec;
934 Int32 *offset;
935 Logical *found;
936 {
937   CDFstatus pStatus = CDF_OK;
938   int entryN; struct VXRstruct VXR; Int32 irType;
939   /****************************************************************************
940   * While more VXRs...
941   ****************************************************************************/
942   while (vxrOffset != ZERO_OFFSET) {
943     /**************************************************************************
944     * Read the VXR.
945     **************************************************************************/
946     if (!sX(ReadVXR(fp,vxrOffset,
947 		    VXR_RECORD,&VXR,
948 		    VXR_NULL),&pStatus)) return pStatus;
949     /**************************************************************************
950     * Search entries...
951     **************************************************************************/
952     if (recNum <= VXR.Last[(int)(VXR.NusedEntries-1)]) {
953       for (entryN = 0; entryN < VXR.NusedEntries; entryN++) {
954 	 if (recNum <= VXR.Last[entryN]) {
955 	   if (VXR.First[entryN] <= recNum) {
956 	     if (!sX(ReadIrType(fp,
957 				VXR.Offset[entryN],
958 				&irType),&pStatus)) return pStatus;
959 	     switch (irType) {
960 	       case VXR_:
961 		 return SearchForRecord_r(fp,VXR.Offset[entryN],recNum,
962 					  firstRec,lastRec,offset,found);
963 	       case VVR_:
964 	       case CVVR_:
965 		 ASSIGNnotNULL (firstRec, VXR.First[entryN])
966 		 ASSIGNnotNULL (lastRec, VXR.Last[entryN])
967 		 ASSIGNnotNULL (offset, VXR.Offset[entryN])
968 		 ASSIGNnotNULL (found, TRUE)
969 		 return pStatus;
970 	       default:
971 		 return CORRUPTED_V2_CDF;
972 	     }
973 	   }
974 	   else {
975 	     ASSIGNnotNULL (found, FALSE)
976 	     return BOO(found == NULL,NO_SUCH_RECORD,pStatus);
977 	   }
978 	 }
979       }
980     }
981     vxrOffset = VXR.VXRnext;
982   }
983   /****************************************************************************
984   * No (more) VXRs.  The record number was never found.
985   ****************************************************************************/
986   ASSIGNnotNULL (found, FALSE)
987   return BOO(found == NULL,NO_SUCH_RECORD,pStatus);
988 }
989 
990 /******************************************************************************
991 * IndexingStatistics.
992 ******************************************************************************/
993 
IndexingStatistics(CDF,VDRoffset,zVar,nVXRsP,nEntriesP,nAllocP,nRecordsP,nLevelsP)994 STATICforIDL CDFstatus IndexingStatistics (CDF, VDRoffset, zVar, nVXRsP,
995 					   nEntriesP, nAllocP, nRecordsP,
996 					   nLevelsP)
997 struct CDFstruct *CDF;
998 Int32 VDRoffset;
999 Logical zVar;
1000 Int32 *nVXRsP;
1001 Int32 *nEntriesP;
1002 Int32 *nAllocP;
1003 Int32 *nRecordsP;
1004 Int32 *nLevelsP;
1005 {
1006   CDFstatus pStatus = CDF_OK; Int32 vxrOffset, maxRec; int level = 1;
1007   Int32 nVXRs = 0, nEntries = 0, nAlloc = 0, nRecords = 0, nLevels = 0;
1008   /****************************************************************************
1009   * Read the maximum record and the offset of the first VXR...
1010   ****************************************************************************/
1011   if (!sX(ReadVDR(CDF,CDF->fp,VDRoffset,zVar,
1012 		  VDR_VXRHEAD,&vxrOffset,
1013 		  VDR_MAXREC,&maxRec,
1014 		  VDR_NULL),&pStatus)) return pStatus;
1015   /****************************************************************************
1016   * ...and start there.
1017   ****************************************************************************/
1018   if (vxrOffset != ZERO_OFFSET) {
1019     if (!sX(IndexingStatistics_r(CDF->fp,vxrOffset,
1020 				 maxRec,level,&nLevels,
1021 				 &nVXRs,&nEntries,
1022 				 &nAlloc,&nRecords),&pStatus)) return pStatus;
1023   }
1024   /****************************************************************************
1025   * Pass back requested statistics.
1026   ****************************************************************************/
1027   ASSIGNnotNULL (nVXRsP, nVXRs)
1028   ASSIGNnotNULL (nEntriesP, nEntries)
1029   ASSIGNnotNULL (nAllocP, nAlloc)
1030   ASSIGNnotNULL (nRecordsP, nRecords)
1031   ASSIGNnotNULL (nLevelsP, nLevels)
1032   return pStatus;
1033 }
1034 
IndexingStatistics_r(fp,vxrOffset,maxRec,level,nLevels,nVXRs,nEntries,nAlloc,nRecords)1035 static CDFstatus IndexingStatistics_r (fp, vxrOffset, maxRec, level, nLevels,
1036 				       nVXRs, nEntries, nAlloc, nRecords)
1037 vFILE *fp;
1038 Int32 vxrOffset;
1039 Int32 maxRec;
1040 int level;
1041 Int32 *nLevels;
1042 Int32 *nVXRs;
1043 Int32 *nEntries;
1044 Int32 *nAlloc;
1045 Int32 *nRecords;
1046 {
1047   CDFstatus pStatus = CDF_OK;
1048   int e; Int32 irType; struct VXRstruct VXR;
1049   /****************************************************************************
1050   * Check if a new level has been reached.
1051   ****************************************************************************/
1052   *nLevels = MAXIMUM(*nLevels,level);
1053   /****************************************************************************
1054   * While more VXRs...
1055   ****************************************************************************/
1056   while (vxrOffset != ZERO_OFFSET) {
1057     /**************************************************************************
1058     * Read/tally the VXR.
1059     **************************************************************************/
1060     if (!sX(ReadVXR(fp,vxrOffset,
1061 		    VXR_RECORD,&VXR,
1062 		    VXR_NULL),&pStatus)) return pStatus;
1063     (*nVXRs)++;
1064     /**************************************************************************
1065     * Scan/count entries...
1066     **************************************************************************/
1067     for (e = 0; e < VXR.NusedEntries; e++) {
1068        (*nEntries)++;
1069        if (!sX(ReadIrType(fp,
1070 			  VXR.Offset[e],
1071 			  &irType),&pStatus)) return pStatus;
1072        switch (irType) {
1073 	 case VXR_:
1074 	   if (!sX(IndexingStatistics_r(fp,VXR.Offset[e],
1075 					maxRec,level+1,
1076 					nLevels,nVXRs,
1077 					nEntries,nAlloc,
1078 					nRecords),&pStatus)) return pStatus;
1079 	   break;
1080 	 case VVR_:
1081 	 case CVVR_:
1082 	   *nAlloc += (VXR.Last[e] - VXR.First[e] + 1);
1083 	   if (VXR.First[e] <= maxRec) {
1084 	     *nRecords += MINIMUM(maxRec,VXR.Last[e]) - VXR.First[e] + 1;
1085 	   }
1086 	   break;
1087 	 default:
1088 	   return CORRUPTED_V2_CDF;
1089        }
1090     }
1091     vxrOffset = VXR.VXRnext;
1092   }
1093   return pStatus;
1094 }
1095 
1096 /******************************************************************************
1097 * BuildPadBuffer.
1098 ******************************************************************************/
1099 
BuildPadBuffer(CDF,Var,nRecords,how,buffer,encode)1100 STATICforIDL CDFstatus BuildPadBuffer (CDF, Var, nRecords, how, buffer, encode)
1101 struct CDFstruct *CDF;
1102 struct VarStruct *Var;
1103 Int32 nRecords;
1104 int *how;
1105 void **buffer;
1106 Logical encode;         /* If TRUE, return values in CDF's encoding.  If FALSE,
1107 			   return values in host computer's encoding. */
1108 {
1109   Byte *ptr; Int32 nBytes, nValues, valueN; void *padValue;
1110   Int32 VDRflags, dataType, numElems; CDFstatus pStatus = CDF_OK;
1111   /****************************************************************************
1112   * Determine pad value.
1113   ****************************************************************************/
1114   if (!sX(ReadVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar,
1115 		  VDR_DATATYPE,&dataType,
1116 		  VDR_NUMELEMS,&numElems,
1117 		  VDR_FLAGS,&VDRflags,
1118 		  VDR_NULL),&pStatus)) return pStatus;
1119   padValue = (void *) cdf_AllocateMemory ((size_t) Var->NvalueBytes, NULL);
1120   if (padValue == NULL) return BAD_MALLOC;
1121   if (PADvalueBITset(VDRflags)) {
1122     if (!sX(ReadVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar,
1123 		    VDR_PADVALUE,padValue,
1124 		    VDR_NULL),&pStatus)) {
1125       cdf_FreeMemory (padValue, NULL);
1126       return pStatus;
1127     }
1128     if (!encode) {
1129       if (!sX(ConvertBuffer(CDF->encoding,HostDecoding(),
1130 			    CDF->negToPosFp0,dataType,
1131 			    numElems,padValue,padValue),&pStatus)) {
1132 	cdf_FreeMemory (padValue, NULL);
1133 	return pStatus;
1134       }
1135     }
1136   }
1137   else {
1138     DefaultPadValue (dataType, numElems, padValue);
1139     if (encode) {
1140       if (!sX(ConvertBuffer(HostEncoding(),CDF->encoding,
1141 			    CDF->negToPosFp0,dataType,
1142 			    numElems,padValue,padValue),&pStatus)) {
1143 	cdf_FreeMemory (padValue, NULL);
1144 	return pStatus;
1145       }
1146     }
1147   }
1148   /****************************************************************************
1149   * Try to allocate all of the records at once...
1150   ****************************************************************************/
1151   nValues = nRecords * Var->NphyRecValues;
1152   nBytes = nValues * Var->NvalueBytes;
1153 #if LIMITof64K
1154   if (nBytes < 65536L) {
1155 #endif
1156     *buffer = (void *) cdf_AllocateMemory ((size_t) nBytes, NULL);
1157     if (*buffer != NULL) {
1158       for (valueN = 0, ptr = (Byte *) *buffer;
1159 	   valueN < nValues; valueN++, ptr += (size_t) Var->NvalueBytes) {
1160 	 memmove (ptr, padValue, (size_t) Var->NvalueBytes);
1161       }
1162       cdf_FreeMemory (padValue, NULL);
1163       *how = ALLrecordsATonce;
1164       return pStatus;
1165     }
1166 #if LIMITof64K
1167   }
1168 #endif
1169   /****************************************************************************
1170   * Not enough memory for that, try allocating one record...
1171   ****************************************************************************/
1172 #if LIMITof64K
1173   if (Var->NphyRecBytes < 65536L) {
1174 #endif
1175     *buffer = (void *) cdf_AllocateMemory ((size_t) Var->NphyRecBytes, NULL);
1176     if (*buffer != NULL) {
1177       for (valueN = 0, ptr = (Byte *) *buffer;
1178 	   valueN < Var->NphyRecValues;
1179 	   valueN++, ptr += (size_t) Var->NvalueBytes) {
1180 	 memmove (ptr, padValue, (size_t) Var->NvalueBytes);
1181       }
1182       cdf_FreeMemory (padValue, NULL);
1183       *how = ONErecordATaTIME;
1184       return pStatus;
1185     }
1186 #if LIMITof64K
1187   }
1188 #endif
1189   /****************************************************************************
1190   * Not enough memory for that either, use the one allocated value...
1191   ****************************************************************************/
1192   *buffer = padValue;
1193   *how = ONEvalueATaTIME;
1194   return pStatus;
1195 }
1196 
1197 /******************************************************************************
1198 * ReadVarValues.
1199 *   NOTE: If more than one record is being read, full records are assumed
1200 * and the `offset' must be zero.
1201 ******************************************************************************/
1202 
ReadVarValues(CDF,Var,startRec,offset,nValues,buffer)1203 STATICforIDL CDFstatus ReadVarValues (CDF, Var, startRec, offset, nValues,
1204 				      buffer)
1205 struct CDFstruct *CDF;
1206 struct VarStruct *Var;
1207 Int32 startRec;         /* Physical record number at which to start reading. */
1208 Int32 offset;           /* Byte offset within (first) record at which to
1209 			   begin reading. */
1210 Int32 nValues;          /* Number of values to read. */
1211 void *buffer;
1212 {
1213   CDFstatus pStatus = CDF_OK; Int32 tOffset; Logical fullRecord;
1214   Int32 numElems, firstRec, lastRec, lastRecInVVR, nPadValues;
1215   Int32 readTo, recCount, nBytes;
1216   /****************************************************************************
1217   * Determine first/last record(s) being read and if full physical record(s).
1218   ****************************************************************************/
1219   firstRec = startRec;
1220   if (nValues < Var->NphyRecValues) {
1221     fullRecord = FALSE;
1222     lastRec = startRec;
1223   }
1224   else {
1225     fullRecord = TRUE;
1226     lastRec = startRec + ((nValues - 1) / Var->NphyRecValues);
1227   }
1228   /****************************************************************************
1229   * Read value(s).
1230   ****************************************************************************/
1231   switch (Var->vType) {
1232     /**************************************************************************
1233     * Standard variable in a single-file CDF...
1234     **************************************************************************/
1235     case STANDARD_:
1236       if (fullRecord) {
1237 	/**********************************************************************
1238 	* Full record(s) - read from contiguous groups...
1239 	**********************************************************************/
1240 	Byte *tBuffer = buffer; Int32 recNum = firstRec;
1241 	while (recNum <= lastRec) {
1242 	  if (recNum <= Var->maxRec) {
1243 	    if (!sX(SearchForRecord(CDF,Var->VDRoffset,
1244 				    Var->zVar,recNum,
1245 				    NULL,&lastRecInVVR,
1246 				    NULL,NULL),&pStatus)) return pStatus;
1247 	    readTo = MINIMUMof3(Var->maxRec,lastRec,lastRecInVVR);
1248 	    recCount = readTo - recNum + 1;
1249 	    if (!sX(RecordByteOffset(CDF,Var,
1250 				     recNum,
1251 				     &tOffset),&pStatus)) return pStatus;
1252 	    numElems = recCount * Var->NphyRecElems;
1253 	    if (!sX(ReadVarElems(Var,CDF->fp,tOffset,
1254 				 numElems,tBuffer),&pStatus)) return pStatus;
1255 	  }
1256 	  else {
1257 	    recCount = lastRec - recNum + 1;
1258 	    nPadValues = recCount * Var->NphyRecValues;
1259 	    if (!sX(PadBuffer(CDF,Var,
1260 			      nPadValues,
1261 			      tBuffer),&pStatus)) return pStatus;
1262 	    sX (VIRTUAL_RECORD_DATA, &pStatus);
1263 	  }
1264 	  recNum += recCount;
1265 	  tBuffer += (size_t) (recCount * Var->NphyRecBytes);
1266 	}
1267       }
1268       else {
1269 	/**********************************************************************
1270 	* Partial record...
1271 	**********************************************************************/
1272 	if (firstRec <= Var->maxRec) {
1273 	  if (!sX(RecordByteOffset(CDF,Var,
1274 				   firstRec,
1275 				   &tOffset),&pStatus)) return pStatus;
1276 	  tOffset += (Int32) offset;
1277 	  numElems = nValues * Var->NvalueElems;
1278 	  if (!sX(ReadVarElems(Var,CDF->fp,tOffset,
1279 			       numElems,buffer),&pStatus)) return pStatus;
1280 	}
1281 	else {
1282 	  if (!sX(PadBuffer(CDF,Var,nValues,buffer),&pStatus)) return pStatus;
1283 	  sX (VIRTUAL_RECORD_DATA, &pStatus);
1284 	}
1285       }
1286       break;
1287     /**************************************************************************
1288     * Sparse records...
1289     **************************************************************************/
1290     case SPARSE_RECORDS_: {
1291       if (fullRecord) {
1292 	if (!sX(ReadSparseFull(CDF,Var,firstRec,
1293 			       lastRec,buffer),&pStatus)) return pStatus;
1294       }
1295       else {
1296 	if (!sX(ReadSparsePartial(CDF,Var,
1297 				  startRec,offset,
1298 				  nValues,buffer),&pStatus)) return pStatus;
1299       }
1300       break;
1301     }
1302     /**************************************************************************
1303     * Compressed variable...
1304     **************************************************************************/
1305     case COMPRESSED_:
1306     case SPARSE_COMPRESSED_RECORDS_: {
1307       /************************************************************************
1308       * Initialize staging area.  Note that the staging area is only
1309       * initialized if records have been written.  This prevents the
1310       * CORRUPTED_V2_CDF error code from being returned if an explicit
1311       * blocking factor has not been specified for the variable.
1312       ************************************************************************/
1313       if (Var->stage.areaOffset == NO_OFFSET && Var->maxRec > NO_RECORD) {
1314 	if (Var->blockingFactor == 0) return CORRUPTED_V2_CDF;
1315 	nBytes = Var->blockingFactor * Var->NphyRecBytes;
1316 	if (!sX(InitVarStage(CDF,Var,nBytes),&pStatus)) return pStatus;
1317       }
1318       /************************************************************************
1319       * If full record(s) or partial record...
1320       ************************************************************************/
1321       if (fullRecord) {
1322 	if (!sX(ReadCompressedFull(CDF,Var,firstRec,
1323 				   lastRec,buffer),&pStatus)) return pStatus;
1324       }
1325       else {
1326 	if (!sX(ReadCompressedPartial(CDF,Var,startRec,
1327 				      offset,nValues,
1328 				      buffer),&pStatus)) return pStatus;
1329       }
1330       break;
1331     }
1332     /**************************************************************************
1333     * Can't do sparse arrays yet...
1334     **************************************************************************/
1335     case SPARSE_ARRAYS_:
1336     case SPARSE_RECORDS_AND_ARRAYS_:
1337       return UNKNOWN_SPARSENESS;
1338     case IN_MULTI_:
1339       if (fullRecord) {
1340 	/********************************************************************
1341 	* Full record(s).
1342 	********************************************************************/
1343 	Byte *tBuffer = buffer;
1344 	if (firstRec <= Var->maxRec) {
1345 	  if (!sX(RecordByteOffset(CDF,Var,
1346 				   firstRec,
1347 				   &tOffset),&pStatus)) return pStatus;
1348 	  recCount = MINIMUM(lastRec,Var->maxRec) - firstRec + 1;
1349 	  numElems = recCount * Var->NphyRecElems;
1350 	  if (!sX(ReadVarElems(Var,Var->fp,tOffset,
1351 			       numElems,tBuffer),&pStatus)) return pStatus;
1352 	  tBuffer += (size_t) (recCount * Var->NphyRecBytes);
1353 	}
1354 	if (lastRec > Var->maxRec) {
1355 	  recCount = BOO(Var->maxRec < firstRec,
1356 			 lastRec - firstRec + 1,
1357 			 lastRec - Var->maxRec);
1358 	  nPadValues = recCount * Var->NphyRecValues;
1359 	  if (!sX(PadBuffer(CDF,Var,
1360 			    nPadValues,
1361 			    tBuffer),&pStatus)) return pStatus;
1362 	  sX (VIRTUAL_RECORD_DATA, &pStatus);
1363 	}
1364       }
1365       else {
1366 	/********************************************************************
1367 	* Partial record.
1368 	********************************************************************/
1369 	if (firstRec <= Var->maxRec) {
1370 	  if (!sX(RecordByteOffset(CDF,Var,
1371 				   firstRec,
1372 				   &tOffset),&pStatus)) return pStatus;
1373 	  tOffset += (Int32) offset;
1374 	  numElems = nValues * Var->NvalueElems;
1375 	  if (!sX(ReadVarElems(Var,Var->fp,tOffset,
1376 			       numElems,buffer),&pStatus)) return pStatus;
1377 	}
1378 	else {
1379 	  if (!sX(PadBuffer(CDF,Var,nValues,buffer),&pStatus)) return pStatus;
1380 	  sX (VIRTUAL_RECORD_DATA, &pStatus);
1381 	}
1382       }
1383       break;
1384   }
1385   return pStatus;
1386 }
1387 
1388 /******************************************************************************
1389 * ReadVarElems.
1390 *   NOTE: On IBM PCs, it is assumed that the number of bytes being read
1391 * will not exceed 65535.
1392 ******************************************************************************/
1393 
ReadVarElems(Var,fp,offset,numElems,buffer)1394 STATICforIDL CDFstatus ReadVarElems (Var, fp, offset, numElems, buffer)
1395 struct VarStruct *Var;
1396 vFILE *fp;
1397 Int32 offset;
1398 Int32 numElems;
1399 void *buffer;
1400 {
1401   CDFstatus pStatus = CDF_OK; size_t nBytes;
1402   /****************************************************************************
1403   * Seek to the desired offset.
1404   ****************************************************************************/
1405   if (!SEEKv(fp,(long)offset,vSEEK_SET)) return VAR_READ_ERROR;
1406   /****************************************************************************
1407   * Read the value(s).
1408   ****************************************************************************/
1409   nBytes = (size_t) (numElems * Var->NelemBytes);
1410   if (!READv(buffer,nBytes,1,fp)) return VAR_READ_ERROR;
1411   /****************************************************************************
1412   * Decode value(s).
1413   ****************************************************************************/
1414   if (!sX(DECODE(Var->DecodeFunction,buffer,numElems),&pStatus)) {
1415     return pStatus;
1416   }
1417   return pStatus;
1418 }
1419 
1420 /******************************************************************************
1421 * ROWtoCOL.
1422 ******************************************************************************/
1423 
ROWtoCOL(iBuffer,oBuffer,numDims,dimSizes,nValueBytes)1424 VISIBLE_PREFIX void ROWtoCOL (iBuffer, oBuffer, numDims, dimSizes, nValueBytes)
1425 void *iBuffer;
1426 void *oBuffer;
1427 long numDims;
1428 long dimSizes[];
1429 long nValueBytes;
1430 {
1431   switch (numDims) {
1432     case 0:
1433     case 1: {
1434       long nValues; int dimN;
1435       for (dimN = 0, nValues = 1; dimN < numDims; dimN++) {
1436 	 nValues *= dimSizes[dimN];
1437       }
1438       memmove (oBuffer, iBuffer, (size_t) (nValues * nValueBytes));
1439       break;
1440     }
1441     default: {
1442       long products[CDF_MAX_DIMS];        /* Products, what each dimension is
1443 					     `worth'. */
1444       long iBoffset;                      /* Input buffer, byte offset. */
1445       long oBoffset;                      /* Output buffer, byte offset. */
1446       long oVoffset;                      /* Output buffer, value offset. */
1447       int dimN;                           /* Dimension number. */
1448       for (dimN = 1, products[0] = 1; dimN < numDims; dimN++) {
1449 	 products[dimN] = products[dimN-1] * dimSizes[dimN-1];
1450       }
1451       switch (numDims) {
1452 	case 2: {
1453 	  int d0, d1;                    /* Indices... */
1454 	  for (d0 = 0, iBoffset = 0; d0 < dimSizes[0]; d0++) {
1455 	     for (d1 = 0; d1 < dimSizes[1]; d1++) {
1456 		oVoffset = ((long) d0 * products[0]) + ((long) d1 * products[1]);
1457 		oBoffset = oVoffset * nValueBytes;
1458 		memmove ((Byte *) oBuffer + (size_t) oBoffset,
1459 			 (Byte *) iBuffer + (size_t) iBoffset,
1460 			 (size_t) nValueBytes);
1461 		iBoffset += nValueBytes;
1462 	     }
1463 	  }
1464 	  break;
1465 	}
1466 	case 3: {
1467 	  int d0, d1, d2;                /* Indices... */
1468 	  for (d0 = 0, iBoffset = 0; d0 < dimSizes[0]; d0++) {
1469 	     for (d1 = 0; d1 < dimSizes[1]; d1++) {
1470 		for (d2 = 0; d2 < dimSizes[2]; d2++) {
1471 		   oVoffset = ((long) d0 * products[0]) + ((long) d1 * products[1]) +
1472 			      ((long) d2 * products[2]);
1473 		   oBoffset = oVoffset * nValueBytes;
1474 		   memmove ((Byte *) oBuffer + (size_t) oBoffset,
1475 			    (Byte *) iBuffer + (size_t) iBoffset,
1476 			    (size_t) nValueBytes);
1477 		   iBoffset += nValueBytes;
1478 		}
1479 	     }
1480 	  }
1481 	  break;
1482 	}
1483 	default: {
1484 	  long indices[CDF_MAX_DIMS]; long nValues; int i;
1485 	  for (dimN = 0; dimN < numDims; dimN++) indices[dimN] = 0;
1486 	  for (dimN = 0, nValues = 1; dimN < numDims; dimN++) {
1487 	     nValues *= dimSizes[dimN];
1488 	  }
1489 	  for (i = 0, iBoffset = 0; i < (int) nValues; i++) {
1490 	     for (oVoffset = 0, dimN = 0; dimN < numDims; dimN++) {
1491 		oVoffset += indices[dimN] * products[dimN];
1492 	     }
1493 	     oBoffset = oVoffset * nValueBytes;
1494 	     memmove ((Byte *) oBuffer + (size_t) oBoffset,
1495 		      (Byte *) iBuffer + (size_t) iBoffset,
1496 		      (size_t) nValueBytes);
1497 	     iBoffset += nValueBytes;
1498 	     INCRindicesROW (numDims, dimSizes, indices);
1499 	  }
1500 	  break;
1501 	}
1502       }
1503       break;
1504     }
1505   }
1506   return;
1507 }
1508 
1509 /******************************************************************************
1510 * COLtoROW.
1511 ******************************************************************************/
1512 
COLtoROW(iBuffer,oBuffer,numDims,dimSizes,nValueBytes)1513 VISIBLE_PREFIX void COLtoROW (iBuffer, oBuffer, numDims, dimSizes, nValueBytes)
1514 void *iBuffer;
1515 void *oBuffer;
1516 long numDims;
1517 long dimSizes[];
1518 long nValueBytes;
1519 {
1520   switch (numDims) {
1521     case 0:
1522     case 1: {
1523       long nValues; int dimN;
1524       for (dimN = 0, nValues = 1; dimN < numDims; dimN++) {
1525 	 nValues *= dimSizes[dimN];
1526       }
1527       memmove (oBuffer, iBuffer, (size_t) (nValues * nValueBytes));
1528       break;
1529     }
1530     default: {
1531       long products[CDF_MAX_DIMS];        /* Products, what each dimension is
1532 					     `worth'. */
1533       long iBoffset;                      /* Input buffer, byte offset. */
1534       long oBoffset;                      /* Output buffer, byte offset. */
1535       long oVoffset;                      /* Output buffer, value offset. */
1536       int dimN;                           /* Dimension number. */
1537       products[(int)(numDims-1)] = 1;
1538       for (dimN = (int) (numDims - 2); dimN >= 0; dimN--) {
1539 	 products[dimN] = products[dimN+1] * dimSizes[dimN+1];
1540       }
1541       switch (numDims) {
1542 	case 2: {
1543 	  int d0, d1;                    /* Indices... */
1544 	  for (d1 = 0, iBoffset = 0; d1 < dimSizes[1]; d1++) {
1545 	     for (d0 = 0; d0 < dimSizes[0]; d0++) {
1546 		oVoffset = ((long) d0 * products[0]) + ((long) d1 * products[1]);
1547 		oBoffset = oVoffset * nValueBytes;
1548 		memmove ((Byte *) oBuffer + (size_t) oBoffset,
1549 			 (Byte *) iBuffer + (size_t) iBoffset,
1550 			 (size_t) nValueBytes);
1551 		iBoffset += nValueBytes;
1552 	     }
1553 	  }
1554 	  break;
1555 	}
1556 	case 3: {
1557 	  int d0, d1, d2;                /* Indices... */
1558 	  for (d2 = 0, iBoffset = 0; d2 < dimSizes[2]; d2++) {
1559 	     for (d1 = 0; d1 < dimSizes[1]; d1++) {
1560 		for (d0 = 0; d0 < dimSizes[0]; d0++) {
1561 		   oVoffset = ((long) d0 * products[0]) + ((long) d1 * products[1]) +
1562 			      ((long) d2 * products[2]);
1563 		   oBoffset = oVoffset * nValueBytes;
1564 		   memmove ((Byte *) oBuffer + (size_t) oBoffset,
1565 			    (Byte *) iBuffer + (size_t) iBoffset,
1566 			    (size_t) nValueBytes);
1567 		   iBoffset += nValueBytes;
1568 		}
1569 	     }
1570 	  }
1571 	  break;
1572 	}
1573 	default: {
1574 	  long indices[CDF_MAX_DIMS]; long nValues; int i;
1575 	  for (dimN = 0; dimN < numDims; dimN++) indices[dimN] = 0;
1576 	  for (dimN = 0, nValues = 1; dimN < numDims; dimN++) {
1577 	     nValues *= dimSizes[dimN];
1578 	  }
1579 	  for (i = 0, iBoffset = 0; i < (int) nValues; i++) {
1580 	     for (oVoffset = 0, dimN = 0; dimN < numDims; dimN++) {
1581 		oVoffset += indices[dimN] * products[dimN];
1582 	     }
1583 	     oBoffset = oVoffset * nValueBytes;
1584 	     memmove ((Byte *) oBuffer + (size_t) oBoffset,
1585 		      (Byte *) iBuffer + (size_t) iBoffset,
1586 		      (size_t) nValueBytes);
1587 	     iBoffset += nValueBytes;
1588 	     INCRindicesCOL (numDims, dimSizes, indices);
1589 	  }
1590 	  break;
1591 	}
1592       }
1593       break;
1594     }
1595   }
1596   return;
1597 }
1598 
1599 /******************************************************************************
1600 * INCRindicesROW.
1601 *    Increment to next set of indices, row majority.  When at the last set of
1602 * indices, roll over to 0,0,0,...
1603 ******************************************************************************/
1604 
INCRindicesROW(numDims,dimSizes,indices)1605 VISIBLE_PREFIX void INCRindicesROW (numDims, dimSizes, indices)
1606 long numDims;
1607 long dimSizes[];
1608 long indices[];
1609 {
1610   int dimN;
1611   for (dimN = (int) (numDims - 1); dimN >= 0; dimN--)
1612      if (indices[dimN] == dimSizes[dimN] - 1)
1613        indices[dimN] = 0;
1614      else {
1615        indices[dimN]++;
1616        break;
1617      }
1618   return;
1619 }
1620 
1621 /******************************************************************************
1622 * INCRindicesCOL.
1623 *    Increment to next set of indices, column majority.  When at the last set
1624 * of indices, roll over to 0,0,0,...
1625 ******************************************************************************/
1626 
INCRindicesCOL(numDims,dimSizes,indices)1627 VISIBLE_PREFIX void INCRindicesCOL (numDims, dimSizes, indices)
1628 long numDims;
1629 long dimSizes[];
1630 long indices[];
1631 {
1632   int dimN;
1633   for (dimN = 0; dimN < numDims; dimN++)
1634      if (indices[dimN] == dimSizes[dimN] - 1)
1635        indices[dimN] = 0;
1636      else {
1637        indices[dimN]++;
1638        break;
1639      }
1640   return;
1641 }
1642 
1643 /******************************************************************************
1644 * InitVarStage.
1645 ******************************************************************************/
1646 
InitVarStage(CDF,Var,nBytes)1647 STATICforIDL CDFstatus InitVarStage (CDF, Var, nBytes)
1648 struct CDFstruct *CDF;
1649 struct VarStruct *Var;
1650 Int32 nBytes;
1651 {
1652   if (CDF->stage.fp == NULL) {
1653     CDF->stage.fp = V_scratch (ScratchDirectory(CDF), "stg");
1654     if (CDF->stage.fp == NULL) return SCRATCH_CREATE_ERROR;
1655     if (!CACHEv(CDF->stage.fp,CDF->stage.cacheSize)) {
1656       V_delete (CDF->stage.fp, NULL);
1657       CDF->stage.fp = NULL;
1658       return BAD_CACHE_SIZE;
1659     }
1660     CDF->stage.mark = ZERO_OFFSET;
1661   }
1662   Var->stage.areaOffset = CDF->stage.mark;
1663   Var->stage.firstRec = NO_RECORD;
1664   Var->stage.lastRec = NO_RECORD;
1665   Var->stage.dotOffset = NO_OFFSET;
1666   Var->stage.modified = FALSE;
1667   CDF->stage.mark += nBytes;
1668   return CDF_OK;
1669 }
1670 
1671 /******************************************************************************
1672 * InitScratch.
1673 ******************************************************************************/
1674 
InitScratch(scratchDir,scratchFpH,cacheSize)1675 STATICforIDL CDFstatus InitScratch (scratchDir, scratchFpH, cacheSize)
1676 char *scratchDir;	/* Scratch directory to be used. */
1677 vFILE **scratchFpH;	/* Scratch file handle (pointer to pointer). */
1678 int cacheSize;		/* Number of cache buffers to request. */
1679 {
1680   if (*scratchFpH == NULL) {
1681     *scratchFpH = V_scratch (scratchDir, NULL);
1682     if (*scratchFpH == NULL) return SCRATCH_CREATE_ERROR;
1683     if (!CACHEv(*scratchFpH,cacheSize)) {
1684       V_delete (*scratchFpH, NULL);
1685       *scratchFpH = NULL;
1686       return BAD_CACHE_SIZE;
1687     }
1688   }
1689   else {
1690     if (V_clear(*scratchFpH) != 0) return SCRATCH_READ_ERROR;
1691     if (!SEEKv(*scratchFpH,0L,vSEEK_SET)) return SCRATCH_READ_ERROR;
1692   }
1693   return CDF_OK;
1694 }
1695 
1696 /******************************************************************************
1697 * ScratchDirectory.
1698 ******************************************************************************/
1699 
ScratchDirectory(CDF)1700 STATICforIDL char *ScratchDirectory (CDF)
1701 struct CDFstruct *CDF;	/* Pointer to CDF structure.  This might be NULL if a
1702 			   scratch directory is needed but a CDF has not yet
1703 			   been opened/created. */
1704 {
1705   char *envTmp = NULL;
1706   if (CDF != NULL) {
1707     if (CDF->scratchDir != NULL) return CDF->scratchDir;
1708   }
1709 #if defined(vms)
1710   envTmp = getenv ("CDF$TMP");
1711 #endif
1712 #if defined(unix) || defined(dos) || defined(posixSHELL) || defined(win32)
1713   envTmp = getenv ("CDF_TMP");
1714 #endif
1715   if (envTmp != NULL) return envTmp;
1716   return NULL;
1717 }
1718 
1719 /******************************************************************************
1720 * FlushStage.
1721 ******************************************************************************/
1722 
FlushStage(CDF,Var)1723 STATICforIDL CDFstatus FlushStage (CDF, Var)
1724 struct CDFstruct *CDF;
1725 struct VarStruct *Var;
1726 {
1727   CDFstatus pStatus = CDF_OK;
1728   /****************************************************************************
1729   * Based on the variable type...
1730   ****************************************************************************/
1731   switch (Var->vType) {
1732     case SPARSE_RECORDS_: {
1733       Int32 nRecords, nBytes, tOffset; struct AllocStruct alloc;
1734       /************************************************************************
1735       * First check if there are records to be flushed in the staging area.
1736       ************************************************************************/
1737       if (!Var->stage.modified) return pStatus;
1738       /************************************************************************
1739       * Allocate a new VVR.
1740       ************************************************************************/
1741       LoadAllocVVR (alloc, Var->stage.firstRec, Var->stage.lastRec, FALSE)
1742       if (!sX(AllocateRecords(CDF,Var,alloc),&pStatus)) return pStatus;
1743       Var->maxAllocated = MAXIMUM(Var->maxAllocated,Var->stage.lastRec);
1744       /************************************************************************
1745       * Copy the records to the new VVR.
1746       ************************************************************************/
1747       if (!sX(RecordByteOffset(CDF,Var,
1748 			       Var->stage.firstRec,
1749 			       &tOffset),&pStatus)) return pStatus;
1750       nRecords = Var->stage.lastRec - Var->stage.firstRec + 1;
1751       nBytes = nRecords * Var->NphyRecBytes;
1752       if (!sX(CopyBytes(CDF->stage.fp,Var->stage.areaOffset,
1753 			SCRATCH_READ_ERROR,nBytes,CDF->fp,
1754 			tOffset,CDF_WRITE_ERROR),&pStatus)) return pStatus;
1755       Var->maxWritten = MAXIMUM(Var->maxWritten,Var->stage.lastRec);
1756       /************************************************************************
1757       * Clear the staging area control.
1758       ************************************************************************/
1759       Var->stage.firstRec = NO_RECORD;
1760       Var->stage.lastRec = NO_RECORD;
1761       Var->stage.dotOffset = NO_OFFSET;
1762       Var->stage.modified = FALSE;
1763       break;
1764     }
1765     case COMPRESSED_:
1766     case SPARSE_COMPRESSED_RECORDS_: {
1767       Int32 cSize, xSize, irSize, newOffset, nRecords, uSize;
1768       struct CVVRstruct CVVR; struct VVRstruct VVR; struct AllocStruct alloc;
1769       /************************************************************************
1770       * First check if there are records to be flushed in the staging area.
1771       ************************************************************************/
1772       if (!Var->stage.modified) return pStatus;
1773       /************************************************************************
1774       * Check if the scratch file is created/initialized.
1775       ************************************************************************/
1776       if (!sX(InitScratch(ScratchDirectory(CDF),
1777 			  &(CDF->compressFp),
1778 			  CDF->compressCacheSize),&pStatus)) return pStatus;
1779       /************************************************************************
1780       * Compress the records in the stage.
1781       ************************************************************************/
1782       nRecords = Var->stage.lastRec - Var->stage.firstRec + 1;
1783       uSize = nRecords * Var->NphyRecBytes;
1784       if (!sX(Compress(CDF->stage.fp,Var->stage.areaOffset,
1785 		       uSize,SCRATCH_READ_ERROR,Var->cType,
1786 		       Var->cParms,CDF->compressFp,ZERO_OFFSET,
1787 		       &cSize,SCRATCH_WRITE_ERROR),&pStatus)) return pStatus;
1788       /************************************************************************
1789       * Does a VVR/CVVR for this block of records already exist?
1790       ************************************************************************/
1791       if (Var->stage.dotOffset != NO_OFFSET) {
1792 	/**********************************************************************
1793 	* Read the size of the existing VVR/CVVR.
1794 	**********************************************************************/
1795 	if (!sX(ReadIrSize(CDF->fp,
1796 			   Var->stage.dotOffset,
1797 			   &irSize),&pStatus)) return pStatus;
1798 	/**********************************************************************
1799 	* Will a CVVR fit?  Note that reserve space is only added to new CVVRs.
1800 	**********************************************************************/
1801 	if (CVVR_BASE_SIZE + cSize <= irSize) {
1802 	  LoadCVVRx (CVVR, irSize, cSize)
1803 	  if (!sX(WriteCVVR(CDF->fp,Var->stage.dotOffset,
1804 			    CVVR_RECORDx,&CVVR,
1805 			    CVVR_NULL),&pStatus)) return pStatus;
1806 	  if (!sX(CopyBytes(CDF->compressFp,ZERO_OFFSET,
1807 			    SCRATCH_READ_ERROR,cSize,CDF->fp,
1808 			    Var->stage.dotOffset + CVVR_BASE_SIZE,
1809 			    CDF_WRITE_ERROR),&pStatus)) return pStatus;
1810 	  Var->stage.modified = FALSE;
1811 	  return pStatus;
1812 	}
1813 	/**********************************************************************
1814 	* Will a VVR fit?
1815 	**********************************************************************/
1816 	if (VVR_BASE_SIZE + uSize <= irSize) {
1817 	  LoadVVRx (VVR, irSize)
1818 	  if (!sX(WriteVVR(CDF->fp,Var->stage.dotOffset,
1819 			   VVR_RECORDx,&VVR,
1820 			   VVR_NULL),&pStatus)) return pStatus;
1821 	  if (!sX(CopyBytes(CDF->stage.fp,Var->stage.areaOffset,
1822 			    SCRATCH_READ_ERROR,uSize,CDF->fp,
1823 			    Var->stage.dotOffset + VVR_BASE_SIZE,
1824 			    CDF_WRITE_ERROR),&pStatus)) return pStatus;
1825 	  Var->stage.modified = FALSE;
1826 	  sX (DID_NOT_COMPRESS, &pStatus);
1827 	  return pStatus;
1828 	}
1829 	/**********************************************************************
1830 	* The existing VVR/CVVR will have to be resized.  Will a CVVR be
1831 	* smaller than a VVR?  Note that reserve space is not added to the
1832 	* size of the CVVR because a new one isn't being created.
1833 	**********************************************************************/
1834 	if (CVVR_BASE_SIZE + cSize < VVR_BASE_SIZE + uSize) {
1835 	  if (!sX(ResizeIR(CDF,Var->stage.dotOffset,
1836 			   CVVR_BASE_SIZE + cSize,
1837 			   &newOffset,TRUE,NULL),&pStatus)) return pStatus;
1838 	  LoadCVVRx (CVVR, CVVR_BASE_SIZE + cSize, cSize)
1839 	  if (!sX(WriteCVVR(CDF->fp,newOffset,
1840 			    CVVR_RECORDx,&CVVR,
1841 			    CVVR_NULL),&pStatus)) return pStatus;
1842 	  if (!sX(CopyBytes(CDF->compressFp,ZERO_OFFSET,
1843 			    SCRATCH_READ_ERROR,cSize,
1844 			    CDF->fp,newOffset + CVVR_BASE_SIZE,
1845 			    CDF_WRITE_ERROR),&pStatus)) return pStatus;
1846 	}
1847 	else {
1848 	  if (!sX(ResizeIR(CDF,Var->stage.dotOffset,
1849 			   VVR_BASE_SIZE + uSize,
1850 			   &newOffset,TRUE,NULL),&pStatus)) return pStatus;
1851 	  LoadVVRx (VVR, VVR_BASE_SIZE + uSize)
1852 	  if (!sX(WriteVVR(CDF->fp,newOffset,
1853 			   VVR_RECORDx,&VVR,
1854 			   VVR_NULL),&pStatus)) return pStatus;
1855 	  if (!sX(CopyBytes(CDF->stage.fp,Var->stage.areaOffset,
1856 			    SCRATCH_READ_ERROR,uSize,
1857 			    CDF->fp,newOffset + VVR_BASE_SIZE,
1858 			    CDF_WRITE_ERROR),&pStatus)) return pStatus;
1859 	  sX (DID_NOT_COMPRESS, &pStatus);
1860 	}
1861 	if (!sX(ModIndexOffset(CDF,Var,
1862 			       Var->stage.firstRec,
1863 			       Var->stage.lastRec,
1864 			       newOffset),&pStatus)) return pStatus;
1865 	Var->stage.dotOffset = newOffset;
1866 	Var->stage.modified = FALSE;
1867 	return pStatus;
1868       }
1869       /************************************************************************
1870       * A new VVR/CVVR will have to be created.  First calculate the reserve
1871       * size.
1872       ************************************************************************/
1873       if (Var->reservePct <= 0)
1874 	xSize = 0;
1875       else {
1876 	if (Var->reservePct <= 100) {
1877 	  Int32 tSize = (Int32) ((uSize * (Var->reservePct/100.0)) + 0.5);
1878 	  xSize = MAXIMUM(cSize,tSize) - cSize;
1879 	}
1880 	else {
1881 	  Int32 tSize = (Int32) ((cSize * (Var->reservePct/100.0)) + 0.5);
1882 	  xSize = tSize - cSize;
1883 	}
1884       }
1885       /************************************************************************
1886       * Will a CVVR be smaller than a VVR?
1887       ************************************************************************/
1888       if (CVVR_BASE_SIZE + cSize + xSize < VVR_BASE_SIZE + uSize) {
1889 	LoadAllocCVVR (alloc, Var->stage.firstRec, Var->stage.lastRec,
1890 		       cSize, xSize)
1891 	if (!sX(AllocateRecords(CDF,Var,alloc),&pStatus)) return pStatus;
1892 	if (!sX(SearchForRecord(CDF,Var->VDRoffset,Var->zVar,
1893 				Var->stage.firstRec,NULL,NULL,
1894 				&newOffset,NULL),&pStatus)) return pStatus;
1895 	LoadCVVRx (CVVR, CVVR_BASE_SIZE + cSize + xSize, cSize)
1896 	if (!sX(WriteCVVR(CDF->fp,newOffset,
1897 			  CVVR_RECORDx,&CVVR,
1898 			  CVVR_NULL),&pStatus)) return pStatus;
1899 	if (!sX(CopyBytes(CDF->compressFp,ZERO_OFFSET,
1900 			  SCRATCH_READ_ERROR,cSize,
1901 			  CDF->fp,newOffset + CVVR_BASE_SIZE,
1902 			  CDF_WRITE_ERROR),&pStatus)) return pStatus;
1903 	Var->stage.dotOffset = newOffset;
1904 	Var->stage.modified = FALSE;
1905 	return pStatus;
1906       }
1907       /************************************************************************
1908       * The CVVR will be too big - create a VVR.
1909       ************************************************************************/
1910       LoadAllocVVR (alloc, Var->stage.firstRec, Var->stage.lastRec, TRUE)
1911       if (!sX(AllocateRecords(CDF,Var,alloc),&pStatus)) return pStatus;
1912       if (!sX(SearchForRecord(CDF,Var->VDRoffset,Var->zVar,
1913 				Var->stage.firstRec,NULL,NULL,
1914 				&newOffset,NULL),&pStatus)) return pStatus;
1915       LoadVVRx (VVR, VVR_BASE_SIZE + uSize)
1916       if (!sX(WriteVVR(CDF->fp,newOffset,
1917 		       VVR_RECORDx,&VVR,
1918 		       VVR_NULL),&pStatus)) return pStatus;
1919       if (!sX(CopyBytes(CDF->stage.fp,Var->stage.areaOffset,
1920 			SCRATCH_READ_ERROR,uSize,
1921 			CDF->fp,newOffset + VVR_BASE_SIZE,
1922 			CDF_WRITE_ERROR),&pStatus)) return pStatus;
1923       Var->stage.dotOffset = newOffset;
1924       Var->stage.modified = FALSE;
1925       sX (DID_NOT_COMPRESS, &pStatus);
1926       return pStatus;
1927     }
1928     default:
1929       return CDF_INTERNAL_ERROR;
1930   }
1931   return pStatus;
1932 }
1933 
1934 /******************************************************************************
1935 * BringToStage.
1936 ******************************************************************************/
1937 
BringToStage(CDF,Var,recNum,found)1938 static CDFstatus BringToStage (CDF, Var, recNum, found)
1939 struct CDFstruct *CDF;
1940 struct VarStruct *Var;
1941 Int32 recNum;
1942 Logical *found;
1943 {
1944   CDFstatus pStatus = CDF_OK;
1945   /****************************************************************************
1946   * First check if record is already in the stage.
1947   ****************************************************************************/
1948   if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) {
1949     ASSIGNnotNULL (found, TRUE)
1950     return pStatus;
1951   }
1952   /****************************************************************************
1953   * Then, based on variable type...
1954   ****************************************************************************/
1955   switch (Var->vType) {
1956     case COMPRESSED_:
1957     case SPARSE_COMPRESSED_RECORDS_: {
1958       Int32 firstRec, lastRec, offset, nRecords, uSize; Logical foundX;
1959       /************************************************************************
1960       * Determine if the record exists.
1961       ************************************************************************/
1962       if (!sX(SearchForRecord(CDF,Var->VDRoffset,Var->zVar,
1963 			      recNum,&firstRec,&lastRec,
1964 			      &offset,&foundX),&pStatus)) return pStatus;
1965       ASSIGNnotNULL (found, foundX)
1966       if (!foundX) return BOO(found == NULL,NO_SUCH_RECORD,pStatus);
1967       /************************************************************************
1968       * Flush the stage before...
1969       ************************************************************************/
1970       if (!sX(FlushStage(CDF,Var),&pStatus)) return pStatus;
1971       /************************************************************************
1972       * ...decompressing the CVVR (or VVR if the records did not compress) to
1973       * the staging area.
1974       ************************************************************************/
1975       nRecords = lastRec - firstRec + 1;
1976       uSize = nRecords * Var->NphyRecBytes;
1977       if (!sX(DecompressToStage(CDF,Var,
1978 				offset,uSize),&pStatus)) return pStatus;
1979       /************************************************************************
1980       * Update staging control.
1981       ************************************************************************/
1982       Var->stage.firstRec = firstRec;
1983       Var->stage.lastRec = lastRec;
1984       Var->stage.dotOffset = offset;
1985       Var->stage.modified = FALSE;
1986       break;
1987     }
1988     default:
1989       return CDF_INTERNAL_ERROR;
1990   }
1991   return pStatus;
1992 }
1993 
1994 /******************************************************************************
1995 * CopyBytes.
1996 ******************************************************************************/
1997 
CopyBytes(iFp,iStart,iError,nBytes,oFp,oStart,oError)1998 STATICforIDL CDFstatus CopyBytes (iFp, iStart, iError, nBytes, oFp, oStart,
1999 				  oError)
2000 vFILE *iFp;
2001 Int32 iStart;
2002 CDFstatus iError;
2003 Int32 nBytes;
2004 vFILE *oFp;
2005 Int32 oStart;
2006 CDFstatus oError;
2007 {
2008   Int32 nBlocks = nBytes / COPYblockSIZE;	/* Number of full blocks that
2009 						   can be copied. */
2010   Int32 lastCount = nBytes % COPYblockSIZE;	/* Number of bytes remaining
2011 						   to be copied after the full
2012 						   blocks have been copied. */
2013   Int32 i; Byte buffer[COPYblockSIZE];
2014   /****************************************************************************
2015   * If the copy is within the same file...
2016   ****************************************************************************/
2017   if (iFp == oFp) {
2018     /**************************************************************************
2019     * If the input group (of bytes) is before the output group start at the
2020     * end in case they overlap.
2021     **************************************************************************/
2022     if (iStart < oStart) {
2023       if (nBlocks > 0) {
2024 	Int32 iOffset = iStart + nBytes - COPYblockSIZE;
2025 	Int32 oOffset = oStart + nBytes - COPYblockSIZE;
2026 	for (i = 0; i < nBlocks; i++) {
2027 	   if (!SEEKv(iFp,(long)iOffset,vSEEK_SET)) return iError;
2028 	   if (!READv(buffer,(size_t)COPYblockSIZE,(size_t)1,iFp)) return
2029 								   iError;
2030 	   if (!SEEKv(oFp,(long)oOffset,vSEEK_SET)) return oError;
2031 	   if (!WRITEv(buffer,(size_t)COPYblockSIZE,(size_t)1,oFp)) return
2032 								    oError;
2033 	   iOffset -= COPYblockSIZE;
2034 	   oOffset -= COPYblockSIZE;
2035 	}
2036       }
2037       if (lastCount > 0) {
2038 	if (!SEEKv(iFp,(long)iStart,vSEEK_SET)) return iError;
2039 	if (!READv(buffer,(size_t)lastCount,(size_t)1,iFp)) return iError;
2040 	if (!SEEKv(oFp,(long)oStart,vSEEK_SET)) return oError;
2041 	if (!WRITEv(buffer,(size_t)lastCount,(size_t)1,oFp)) return oError;
2042       }
2043     }
2044     /**************************************************************************
2045     * If the input group (of bytes) is after the output group start at the
2046     * beginning in case they overlap.
2047     **************************************************************************/
2048     if (iStart > oStart) {
2049       Int32 iOffset = iStart;
2050       Int32 oOffset = oStart;
2051       if (nBlocks > 0) {
2052 	for (i = 0; i < nBlocks; i++) {
2053 	   if (!SEEKv(iFp,(long)iOffset,vSEEK_SET)) return iError;
2054 	   if (!READv(buffer,(size_t)COPYblockSIZE,(size_t)1,iFp)) return
2055 								   iError;
2056 	   if (!SEEKv(oFp,(long)oOffset,vSEEK_SET)) return oError;
2057 	   if (!WRITEv(buffer,(size_t)COPYblockSIZE,(size_t)1,oFp)) return
2058 								    oError;
2059 	   iOffset += COPYblockSIZE;
2060 	   oOffset += COPYblockSIZE;
2061 	}
2062       }
2063       if (lastCount > 0) {
2064 	if (!SEEKv(iFp,(long)iOffset,vSEEK_SET)) return iError;
2065 	if (!READv(buffer,(size_t)lastCount,(size_t)1,iFp)) return iError;
2066 	if (!SEEKv(oFp,(long)oOffset,vSEEK_SET)) return oError;
2067 	if (!WRITEv(buffer,(size_t)lastCount,(size_t)1,oFp)) return oError;
2068       }
2069     }
2070     /**************************************************************************
2071     * Offsets are the same - do nothing.
2072     **************************************************************************/
2073   }
2074   else {
2075     /**************************************************************************
2076     * Different files...
2077     **************************************************************************/
2078     if (!SEEKv(iFp,(long)iStart,vSEEK_SET)) return iError;
2079     if (!SEEKv(oFp,(long)oStart,vSEEK_SET)) return oError;
2080     for (i = 0; i < nBlocks; i++) {
2081        if (!READv(buffer,(size_t)COPYblockSIZE,(size_t)1,iFp)) return iError;
2082        if (!WRITEv(buffer,(size_t)COPYblockSIZE,(size_t)1,oFp)) return oError;
2083     }
2084     if (lastCount > 0) {
2085       if (!READv(buffer,(size_t)lastCount,(size_t)1,iFp)) return iError;
2086       if (!WRITEv(buffer,(size_t)lastCount,(size_t)1,oFp)) return oError;
2087     }
2088   }
2089   return CDF_OK;
2090 }
2091 
2092 /******************************************************************************
2093 * ModIndexOffset.
2094 ******************************************************************************/
2095 
ModIndexOffset(CDF,Var,firstRec,lastRec,newOffset)2096 STATICforIDL CDFstatus ModIndexOffset (CDF, Var, firstRec, lastRec, newOffset)
2097 struct CDFstruct *CDF;  /* Pointer to CDF. */
2098 struct VarStruct *Var;  /* Pointer to variable. */
2099 Int32 firstRec;         /* First record of entry. */
2100 Int32 lastRec;          /* Last record of entry. */
2101 Int32 newOffset;        /* New VVR/CVVR/SVVR offset. */
2102 {
2103   CDFstatus pStatus = CDF_OK; Int32 vxrOffset;
2104   /****************************************************************************
2105   * Read offset of first VXR...
2106   ****************************************************************************/
2107   if (!sX(ReadVDR(CDF,CDF->fp,Var->VDRoffset,Var->zVar,
2108 		  VDR_VXRHEAD,&vxrOffset,
2109 		  VDR_NULL),&pStatus)) return pStatus;
2110   /****************************************************************************
2111   * ...and start there.
2112   ****************************************************************************/
2113   if (!sX(ModIndexOffset_r(CDF->fp,vxrOffset,
2114 			   firstRec,lastRec,
2115 			   newOffset),&pStatus)) return pStatus;
2116   return pStatus;
2117 }
2118 
ModIndexOffset_r(fp,vxrOffset,firstRec,lastRec,newOffset)2119 static CDFstatus ModIndexOffset_r (fp, vxrOffset, firstRec, lastRec, newOffset)
2120 vFILE *fp;              /* File pointer to dotCDF file. */
2121 Int32 vxrOffset;        /* VXR at which to start. */
2122 Int32 firstRec;         /* First record of entry. */
2123 Int32 lastRec;          /* Last record of entry. */
2124 Int32 newOffset;        /* New VVR/CVVR/SVVR offset. */
2125 {
2126   CDFstatus pStatus = CDF_OK;
2127   struct VXRstruct VXR; int entryN; Int32 irType;
2128   /****************************************************************************
2129   * While more VXRs...
2130   ****************************************************************************/
2131   while (vxrOffset != ZERO_OFFSET) {
2132     /**************************************************************************
2133     * Read the VXR.
2134     **************************************************************************/
2135     if (!sX(ReadVXR(fp,vxrOffset,
2136 		    VXR_RECORD,&VXR,
2137 		    VXR_NULL),&pStatus)) return pStatus;
2138     /**************************************************************************
2139     * Search through index entries...
2140     **************************************************************************/
2141     for (entryN = 0; entryN < VXR.NusedEntries; entryN++) {
2142        if (VXR.First[entryN] <= firstRec && lastRec <= VXR.Last[entryN]) {
2143 	 if (!sX(ReadIrType(fp,
2144 			    VXR.Offset[entryN],
2145 			    &irType),&pStatus)) return pStatus;
2146 	 if (irType == VXR_) return ModIndexOffset_r(fp,VXR.Offset[entryN],
2147 						     firstRec,lastRec,
2148 						     newOffset);
2149 	 if (VXR.First[entryN] == firstRec && lastRec == VXR.Last[entryN]) {
2150 	   VXR.Offset[entryN] = newOffset;
2151 	   if (!sX(WriteVXR(fp,vxrOffset,
2152 			    VXR_RECORD,&VXR,
2153 			    VXR_NULL),&pStatus)) return pStatus;
2154 	   return pStatus;
2155 	 }
2156 	 return CDF_INTERNAL_ERROR;             /* or CORRUPTED_V2_CDF? */
2157        }
2158     }
2159     /**************************************************************************
2160     * Go to next VXR.
2161     **************************************************************************/
2162     vxrOffset = VXR.VXRnext;
2163   }
2164   /****************************************************************************
2165   * No more VXRs.
2166   ****************************************************************************/
2167   return CDF_INTERNAL_ERROR;
2168 }
2169 
2170 /******************************************************************************
2171 * WriteCompressedRecords.
2172 ******************************************************************************/
2173 
WriteCompressedRecords(CDF,Var,firstRec,lastRec,buffer,nValues,offset,fullRecord)2174 static CDFstatus WriteCompressedRecords (CDF, Var, firstRec, lastRec, buffer,
2175 					 nValues, offset, fullRecord)
2176 struct CDFstruct *CDF;  /* Pointer to CDF. */
2177 struct VarStruct *Var;  /* Pointer to variable. */
2178 Int32 firstRec;         /* First record being written. */
2179 Int32 lastRec;          /* Last record being written. */
2180 void *buffer;           /* Buffer of values. */
2181 Int32 nValues;          /* Number of values being written. */
2182 Int32 offset;           /* If not full record(s), byte offset in record at
2183 			   which to write. */
2184 Logical fullRecord;     /* Full record(s) being written? */
2185 {
2186   CDFstatus pStatus = CDF_OK; Logical found;
2187   Int32 recCount, tOffset, recordOffsetInStage, maxRecThisBlock;
2188   Int32 nextRec, writeTo, numElems; void *padBuffer; int how;
2189   Int32 recNum = firstRec; Byte *tBuffer = (Byte *) buffer;
2190   /****************************************************************************
2191   * From first to last record...
2192   ****************************************************************************/
2193   while (recNum <= lastRec) {
2194      /*************************************************************************
2195      * Check if this record is in the staging area.
2196      *************************************************************************/
2197      if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) {
2198        recordOffsetInStage = recNum - Var->stage.firstRec;
2199        tOffset = Var->stage.areaOffset;
2200        tOffset += (recordOffsetInStage * Var->NphyRecBytes);
2201        if (fullRecord) {
2202 	 if (Var->stage.dotOffset == NO_OFFSET) {
2203 	   maxRecThisBlock = Var->stage.firstRec + Var->blockingFactor - 1;
2204 	   if (!sX(NextRecord(CDF,Var->VDRoffset,
2205 			      Var->zVar,recNum,
2206 			      &nextRec,&found),&pStatus)) return pStatus;
2207 	   if (!found)
2208 	     writeTo = MINIMUM(maxRecThisBlock,lastRec);
2209 	   else {
2210 	     Int32 prevRecN = nextRec - 1;
2211 	     writeTo = MINIMUMof3(maxRecThisBlock,prevRecN,lastRec);
2212 	   }
2213 	 }
2214 	 else
2215 	   writeTo = MINIMUM(Var->stage.lastRec,lastRec);
2216 	 recCount = writeTo - recNum + 1;
2217 	 numElems = recCount * Var->NphyRecElems;
2218        }
2219        else {
2220 	 writeTo = recNum;
2221 	 recCount = 1;
2222 	 numElems = nValues * Var->NvalueElems;
2223 	 tOffset += offset;
2224        }
2225        if (!sX(WriteVarElems(Var,CDF->stage.fp,
2226 			     tOffset,numElems,
2227 			     tBuffer),&pStatus)) return pStatus;
2228        Var->stage.lastRec = MAXIMUM(Var->stage.lastRec,writeTo);
2229        Var->stage.modified = TRUE;
2230        tBuffer += (size_t) (numElems * Var->NelemBytes);
2231        recNum += recCount;
2232        continue;
2233      }
2234      /*************************************************************************
2235      * Not in the staging area...check if this record is in an existing CVVR.
2236      *************************************************************************/
2237      if (!sX(BringToStage(CDF,Var,recNum,&found),&pStatus)) return pStatus;
2238      if (found) {
2239        recordOffsetInStage = recNum - Var->stage.firstRec;
2240        tOffset = Var->stage.areaOffset;
2241        tOffset += (recordOffsetInStage * Var->NphyRecBytes);
2242        if (fullRecord) {
2243 	 writeTo = MINIMUM(Var->stage.lastRec,lastRec);
2244 	 recCount = writeTo - recNum + 1;
2245 	 numElems = recCount * Var->NphyRecElems;
2246        }
2247        else {
2248 	 writeTo = recNum;
2249 	 recCount = 1;
2250 	 numElems = nValues * Var->NvalueElems;
2251 	 tOffset += offset;
2252        }
2253        if (!sX(WriteVarElems(Var,CDF->stage.fp,
2254 			     tOffset,numElems,
2255 			     tBuffer),&pStatus)) return pStatus;
2256        Var->stage.modified = TRUE;
2257        tBuffer += (size_t) (numElems * Var->NelemBytes);
2258        recNum += recCount;
2259        continue;
2260      }
2261      /*************************************************************************
2262      * Not in an existing CVVR...this record does not exist.  First check
2263      * if the record(s) can be added to the records in the stage.
2264      *************************************************************************/
2265      if (Var->stage.firstRec != NO_RECORD) {
2266        if (Var->stage.dotOffset == NO_OFFSET) {
2267 	 if (recNum == Var->stage.lastRec + 1) {
2268 	   maxRecThisBlock = Var->stage.firstRec + Var->blockingFactor - 1;
2269 	   if (recNum <= maxRecThisBlock) {
2270 	     recordOffsetInStage = recNum - Var->stage.firstRec;
2271 	     tOffset = Var->stage.areaOffset;
2272 	     tOffset += (recordOffsetInStage * Var->NphyRecBytes);
2273 	     if (fullRecord) {
2274 	       if (!sX(NextRecord(CDF,Var->VDRoffset,
2275 				  Var->zVar,recNum,
2276 				  &nextRec,&found),&pStatus)) return pStatus;
2277 	       if (!found)
2278 		 writeTo = MINIMUM(maxRecThisBlock,lastRec);
2279 	       else {
2280 		 Int32 prevRecN = nextRec - 1;
2281 		 writeTo = MINIMUMof3(maxRecThisBlock,prevRecN,lastRec);
2282 	       }
2283 	       recCount = writeTo - recNum + 1;
2284 	       numElems = recCount * Var->NphyRecElems;
2285 	     }
2286 	     else {
2287 	       if (!sX(BuildPadBuffer(CDF,Var,INT32_ONE,
2288 				      &how,&padBuffer,
2289 				      TRUE),&pStatus)) return pStatus;
2290 	       if (!sX(WritePadValues(Var,CDF->stage.fp,
2291 				      tOffset,INT32_ONE,how,
2292 				      padBuffer),&pStatus)) return pStatus;
2293 	       cdf_FreeMemory (padBuffer, NULL);
2294 	       writeTo = recNum;
2295 	       recCount = 1;
2296 	       numElems = nValues * Var->NvalueElems;
2297 	       tOffset += offset;
2298 	     }
2299 	     if (!sX(WriteVarElems(Var,CDF->stage.fp,
2300 				   tOffset,numElems,
2301 				   tBuffer),&pStatus)) return pStatus;
2302 	     Var->stage.lastRec = MAXIMUM(Var->stage.lastRec,writeTo);
2303 	     Var->stage.modified = TRUE;
2304 	     tBuffer += (size_t) (numElems * Var->NelemBytes);
2305 	     recNum += recCount;
2306 	     continue;
2307 	   }
2308 	 }
2309        }
2310      }
2311      /*************************************************************************
2312      * This record cannot be added to the block of records currently in
2313      * the staging area.  Start a new block of records.
2314      *************************************************************************/
2315      if (!sX(FlushStage(CDF,Var),&pStatus)) return pStatus;
2316      tOffset = Var->stage.areaOffset;
2317      if (fullRecord) {
2318        maxRecThisBlock = recNum + Var->blockingFactor - 1;
2319        if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar,
2320 			  recNum,&nextRec,&found),&pStatus)) return pStatus;
2321        if (!found)
2322 	 writeTo = MINIMUM(maxRecThisBlock,lastRec);
2323        else {
2324 	 Int32 prevRecN = nextRec - 1;
2325 	 writeTo = MINIMUMof3(maxRecThisBlock,prevRecN,lastRec);
2326        }
2327        recCount = writeTo - recNum + 1;
2328        numElems = recCount * Var->NphyRecElems;
2329      }
2330      else {
2331        if (!sX(BuildPadBuffer(CDF,Var,INT32_ONE,
2332 			      &how,&padBuffer,
2333 			      TRUE),&pStatus)) return pStatus;
2334        if (!sX(WritePadValues(Var,CDF->stage.fp,
2335 			      tOffset,INT32_ONE,how,
2336 			      padBuffer),&pStatus)) return pStatus;
2337        cdf_FreeMemory (padBuffer, NULL);
2338        writeTo = recNum;
2339        recCount = 1;
2340        numElems = nValues * Var->NvalueElems;
2341        tOffset += offset;
2342      }
2343      if (!sX(WriteVarElems(Var,CDF->stage.fp,
2344 			   tOffset,numElems,
2345 			   tBuffer),&pStatus)) return pStatus;
2346      Var->stage.firstRec = recNum;
2347      Var->stage.lastRec = writeTo;
2348      Var->stage.dotOffset = NO_OFFSET;
2349      Var->stage.modified = TRUE;
2350      tBuffer += (size_t) (numElems * Var->NelemBytes);
2351      recNum += recCount;
2352   }
2353   return pStatus;
2354 }
2355 
2356 /******************************************************************************
2357 * CalcCompressionPct.
2358 ******************************************************************************/
2359 
CalcCompressionPct(CDF,vdrOffset,zVar,cPct)2360 STATICforIDL CDFstatus CalcCompressionPct (CDF, vdrOffset, zVar, cPct)
2361 struct CDFstruct *CDF;
2362 Int32 vdrOffset;
2363 Logical zVar;
2364 long *cPct;
2365 {
2366   CDFstatus pStatus = CDF_OK; Int32 vxrOffset;
2367   long uTotal = 0, cTotal = 0; Int32 nPhyRecBytes;
2368   /****************************************************************************
2369   * Calculate the number of bytes per physical record.
2370   ****************************************************************************/
2371   if (!sX(CalcPhyRecBytes(CDF,vdrOffset,
2372 			  zVar,&nPhyRecBytes),&pStatus)) return pStatus;
2373   /****************************************************************************
2374   * Read the offset of the first VXR (return 0% if no VXRs)...
2375   ****************************************************************************/
2376   if (!sX(ReadVDR(CDF,CDF->fp,vdrOffset,zVar,
2377 		  VDR_VXRHEAD,&vxrOffset,
2378 		  VDR_NULL),&pStatus)) return pStatus;
2379   if (vxrOffset == ZERO_OFFSET) {
2380     *cPct = 0;
2381     return pStatus;
2382   }
2383   /****************************************************************************
2384   * ...and start there.
2385   ****************************************************************************/
2386   if (!sX(CalcCompressionPct_r(CDF->fp,vxrOffset,
2387 			       nPhyRecBytes,
2388 			       &uTotal,&cTotal),&pStatus)) return pStatus;
2389   /****************************************************************************
2390   * Calculate percentage.
2391   ****************************************************************************/
2392   *cPct = (long) (((100.0*cTotal) / uTotal) + 0.5);
2393   return pStatus;
2394 }
2395 
CalcCompressionPct_r(fp,vxrOffset,nPhyRecBytes,uTotal,cTotal)2396 static CDFstatus CalcCompressionPct_r (fp, vxrOffset, nPhyRecBytes, uTotal,
2397 				       cTotal)
2398 vFILE *fp;
2399 Int32 vxrOffset;
2400 Int32 nPhyRecBytes;
2401 long *uTotal;
2402 long *cTotal;
2403 {
2404   CDFstatus pStatus = CDF_OK; struct VXRstruct VXR; int entryN;
2405   Int32 nRecords, uSize, irType, irSize;
2406   /****************************************************************************
2407   * While more VXRs...
2408   ****************************************************************************/
2409   while (vxrOffset != ZERO_OFFSET) {
2410     /**************************************************************************
2411     * Read the VXR.
2412     **************************************************************************/
2413     if (!sX(ReadVXR(fp,vxrOffset,
2414 		    VXR_RECORD,&VXR,
2415 		    VXR_NULL),&pStatus)) return pStatus;
2416     /**************************************************************************
2417     * Scan entries...
2418     **************************************************************************/
2419     for (entryN = 0; entryN < VXR.NusedEntries; entryN++) {
2420        if (!sX(ReadIrType(fp,VXR.Offset[entryN],&irType),&pStatus)) return
2421 								    pStatus;
2422        switch (irType) {
2423 	 case VXR_:
2424 	   if (!sX(CalcCompressionPct_r(fp,VXR.Offset[entryN],
2425 					nPhyRecBytes,uTotal,
2426 					cTotal),&pStatus)) return pStatus;
2427 	   break;
2428 	 case VVR_:
2429 	 case CVVR_:
2430 	   /*******************************************************************
2431 	   * Accumulate uncompressed size.
2432 	   *******************************************************************/
2433 	   nRecords = VXR.Last[entryN] - VXR.First[entryN] + 1;
2434 	   uSize = nRecords * nPhyRecBytes;
2435 	   *uTotal += uSize;
2436 	   /*******************************************************************
2437 	   * Accumulate compressed size.
2438 	   *******************************************************************/
2439 	   if (!sX(ReadIrSize(fp,VXR.Offset[entryN],&irSize),&pStatus)) return
2440 								       pStatus;
2441 	   *cTotal += irSize - BOO(irType == CVVR_,
2442 				   CVVR_BASE_SIZE,
2443 				   VVR_BASE_SIZE);
2444 	   break;
2445 	 default:
2446 	   return CORRUPTED_V2_CDF;
2447        }
2448     }
2449     vxrOffset = VXR.VXRnext;
2450   }
2451   return pStatus;
2452 }
2453 
2454 /******************************************************************************
2455 * CalcPhyRecBytes.
2456 ******************************************************************************/
2457 
CalcPhyRecBytes(CDF,vdrOffset,zVar,nPhyRecBytes)2458 STATICforIDL CDFstatus CalcPhyRecBytes (CDF, vdrOffset, zVar, nPhyRecBytes)
2459 struct CDFstruct *CDF;
2460 Int32 vdrOffset;
2461 Logical zVar;
2462 Int32 *nPhyRecBytes;
2463 {
2464   CDFstatus pStatus = CDF_OK; int dimN; Int32 dataType, numElems;
2465   Int32 numDims, dimSizes[CDF_MAX_DIMS], dimVarys[CDF_MAX_DIMS];
2466   if (!sX(CalcDimParms(CDF,vdrOffset,zVar,
2467 		       &numDims,dimSizes,dimVarys),&pStatus)) return pStatus;
2468   if (!sX(ReadVDR(CDF,CDF->fp,vdrOffset,zVar,
2469 		  VDR_DATATYPE,&dataType,
2470 		  VDR_NUMELEMS,&numElems,
2471 		  VDR_NULL),&pStatus)) return pStatus;
2472   *nPhyRecBytes = CDFelemSize((long)dataType) * numElems;
2473   for (dimN = 0; dimN < numDims; dimN++) {
2474      if (dimVarys[dimN]) *nPhyRecBytes *= dimSizes[dimN];
2475   }
2476   return pStatus;
2477 }
2478 
2479 /******************************************************************************
2480 * ReadSparseFull.
2481 ******************************************************************************/
2482 
ReadSparseFull(CDF,Var,firstRec,lastRec,buffer)2483 static CDFstatus ReadSparseFull (CDF, Var, firstRec, lastRec, buffer)
2484 struct CDFstruct *CDF;
2485 struct VarStruct *Var;
2486 Int32 firstRec;
2487 Int32 lastRec;
2488 void *buffer;
2489 {
2490   CDFstatus pStatus = CDF_OK; Logical found;
2491   Int32 readTo, recCount, numElems, recX, prevRecN;
2492   Int32 nextRec, padTo, tOffset, nPadValues;
2493   Int32 recNum = firstRec;
2494   Byte *tBuffer = (Byte *) buffer;
2495   /****************************************************************************
2496   * While there are more records to be read/generated...
2497   ****************************************************************************/
2498   while (recNum <= lastRec) {
2499     /**************************************************************************
2500     * Is the record in the staging area?
2501     **************************************************************************/
2502     if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) {
2503       readTo = MINIMUM(Var->stage.lastRec,lastRec);
2504       recCount = readTo - recNum + 1;
2505       numElems = recCount * Var->NphyRecElems;
2506       recX = recNum - Var->stage.firstRec;
2507       tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes);
2508       if (!sX(ReadVarElems(Var,CDF->stage.fp,
2509 			   tOffset,numElems,tBuffer),&pStatus)) return pStatus;
2510       tBuffer += (size_t) (recCount * Var->NphyRecBytes);
2511       recNum += recCount;
2512       continue;
2513     }
2514     /**************************************************************************
2515     * Does the record exist and has been written to (not just allocated)?
2516     **************************************************************************/
2517     if (recNum <= Var->maxRec) {
2518       Int32 firstRecInVVR, lastRecInVVR;
2519       if (!sX(SearchForRecord(CDF,Var->VDRoffset,
2520 			      Var->zVar,recNum,
2521 			      &firstRecInVVR,
2522 			      &lastRecInVVR,
2523 			      &tOffset,&found),&pStatus)) return pStatus;
2524       if (found) {
2525 	readTo = MINIMUMof3(Var->maxRec,lastRec,lastRecInVVR);
2526 	recCount = readTo - recNum + 1;
2527 	numElems = recCount * Var->NphyRecElems;
2528 	recX = recNum - firstRecInVVR;
2529 	tOffset += VVR_BASE_SIZE + (recX * Var->NphyRecBytes);
2530 	if (!sX(ReadVarElems(Var,CDF->fp,tOffset,
2531 			     numElems,tBuffer),&pStatus)) return pStatus;
2532 	tBuffer += (size_t) (recCount * Var->NphyRecBytes);
2533 	recNum += recCount;
2534 	continue;
2535       }
2536     }
2537     /**************************************************************************
2538     * Determine which records need to be padded.
2539     **************************************************************************/
2540     if (recNum <= Var->maxRec) {
2541       if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar,
2542 			 recNum,&nextRec,&found),&pStatus)) return pStatus;
2543       if (found) {
2544 	if (EXCLUSIVE(recNum,
2545 		      Var->stage.firstRec,
2546 		      nextRec)) nextRec = Var->stage.firstRec;
2547 	prevRecN = nextRec - 1;
2548 	padTo = MINIMUM(prevRecN,lastRec);
2549       }
2550       else {
2551 	prevRecN = Var->stage.firstRec - 1;
2552 	padTo = MINIMUM(prevRecN,lastRec);
2553       }
2554     }
2555     else
2556       padTo = lastRec;
2557     recCount = padTo - recNum + 1;
2558     /**************************************************************************
2559     * If sRecords.PREV...
2560     **************************************************************************/
2561     if (Var->prevIfMissing) {
2562       Int32 prevRec; Byte *destBuffer;
2563       if (!sX(PrevRecord(CDF,Var->VDRoffset,Var->zVar,
2564 			 MINIMUM(recNum,Var->maxRec),
2565 			 &prevRec,&found),&pStatus)) return pStatus;
2566       if (found) {
2567 	if (EXCLUSIVE(prevRec,Var->stage.lastRec,recNum)) {
2568 	  recX = Var->stage.lastRec - Var->stage.firstRec;
2569 	  tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes);
2570 	  if (!sX(ReadVarElems(Var,CDF->stage.fp,
2571 			       tOffset,Var->NphyRecElems,
2572 			       tBuffer),&pStatus)) return pStatus;
2573 	}
2574 	else {
2575 	  if (!sX(RecordByteOffset(CDF,Var,
2576 				   prevRec,
2577 				   &tOffset),&pStatus)) return pStatus;
2578 	  if (!sX(ReadVarElems(Var,CDF->fp,tOffset,
2579 			       Var->NphyRecElems,
2580 			       tBuffer),&pStatus)) return pStatus;
2581 	}
2582 	destBuffer = tBuffer + ((size_t) Var->NphyRecBytes);
2583 	for (recX = 1; recX < recCount; recX++) {
2584 	   memmove (destBuffer, tBuffer, (size_t) Var->NphyRecBytes);
2585 	   destBuffer += (size_t) Var->NphyRecBytes;
2586 	}
2587 	sX (VIRTUAL_RECORD_DATA, &pStatus);
2588 	tBuffer += (size_t) (recCount * Var->NphyRecBytes);
2589 	recNum += recCount;
2590 	continue;
2591       }
2592       if (EXCLUSIVE(NO_RECORD,Var->stage.lastRec,recNum)) {
2593 	recX = Var->stage.lastRec - Var->stage.firstRec;
2594 	tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes);
2595 	if (!sX(ReadVarElems(Var,CDF->stage.fp,
2596 			     tOffset,Var->NphyRecElems,
2597 			     tBuffer),&pStatus)) return pStatus;
2598 	destBuffer = tBuffer + ((size_t) Var->NphyRecBytes);
2599 	for (recX = 1; recX < recCount; recX++) {
2600 	   memmove (destBuffer, tBuffer, (size_t) Var->NphyRecBytes);
2601 	   destBuffer += (size_t) Var->NphyRecBytes;
2602 	}
2603 	sX (VIRTUAL_RECORD_DATA, &pStatus);
2604 	tBuffer += (size_t) (recCount * Var->NphyRecBytes);
2605 	recNum += recCount;
2606 	continue;
2607       }
2608     }
2609     /**************************************************************************
2610     * Pad with the variable's pad value.  This occurs if the variable is
2611     * sRecords.NO, sRecords.PAD, or if sRecords.PREV but a previous record
2612     * does not exist (in a VVR or the staging area).
2613     **************************************************************************/
2614     nPadValues = recCount * Var->NphyRecValues;
2615     if (!sX(PadBuffer(CDF,Var,nPadValues,tBuffer),&pStatus)) return pStatus;
2616     sX (VIRTUAL_RECORD_DATA, &pStatus);
2617     tBuffer += (size_t) (recCount * Var->NphyRecBytes);
2618     recNum += recCount;
2619   }
2620   return pStatus;
2621 }
2622 
2623 /******************************************************************************
2624 * ReadSparsePartial.
2625 ******************************************************************************/
2626 
ReadSparsePartial(CDF,Var,recNum,offset,nValues,buffer)2627 static CDFstatus ReadSparsePartial (CDF, Var, recNum, offset, nValues, buffer)
2628 struct CDFstruct *CDF;
2629 struct VarStruct *Var;
2630 Int32 recNum;
2631 Int32 offset;
2632 Int32 nValues;
2633 void *buffer;
2634 {
2635   CDFstatus pStatus = CDF_OK; Logical found;
2636   Int32 tOffset, firstRec, prevRec;
2637   Int32 numElems = nValues * Var->NvalueElems;
2638   /****************************************************************************
2639   * If the record is in the staging area...
2640   ****************************************************************************/
2641   if (INCLUSIVE(Var->stage.firstRec,recNum,Var->stage.lastRec)) {
2642     tOffset = Var->stage.areaOffset;
2643     tOffset += Var->NphyRecBytes * (recNum - Var->stage.firstRec);
2644     tOffset += offset;
2645     if (!sX(ReadVarElems(Var,CDF->stage.fp,
2646 			 tOffset,numElems,buffer),&pStatus)) return pStatus;
2647     return pStatus;
2648   }
2649   /****************************************************************************
2650   * If the record exists and has been written (ie. not just allocated)...
2651   ****************************************************************************/
2652   if (recNum <= Var->maxRec) {
2653     if (!sX(SearchForRecord(CDF,Var->VDRoffset,
2654 			    Var->zVar,recNum,&firstRec,
2655 			    NULL,&tOffset,&found),&pStatus)) return pStatus;
2656     if (found) {
2657       tOffset += VVR_BASE_SIZE;
2658       tOffset += Var->NphyRecBytes * (recNum - firstRec);
2659       tOffset += offset;
2660       if (!sX(ReadVarElems(Var,CDF->fp,
2661 			   tOffset,numElems,buffer),&pStatus)) return pStatus;
2662       return pStatus;
2663     }
2664   }
2665   /****************************************************************************
2666   * If missing records are to be read from the previous record...
2667   ****************************************************************************/
2668   if (Var->prevIfMissing) {
2669     /**************************************************************************
2670     * Check if a previous record exists in a VVR.
2671     **************************************************************************/
2672     if (!sX(PrevRecord(CDF,Var->VDRoffset,Var->zVar,
2673 		       MINIMUM(recNum,Var->maxRec),
2674 		       &prevRec,&found),&pStatus)) return pStatus;
2675     /**************************************************************************
2676     * If so, also make sure that the last record in the staging area isn't
2677     * really the previous record to use.
2678     **************************************************************************/
2679     if (found) {
2680       if (EXCLUSIVE(prevRec,Var->stage.lastRec,recNum)) {
2681 	Int32 recNumInStage = Var->stage.lastRec - Var->stage.firstRec;
2682 	tOffset = Var->stage.areaOffset;
2683 	tOffset += Var->NphyRecBytes * recNumInStage;
2684 	tOffset += offset;
2685 	if (!sX(ReadVarElems(Var,CDF->stage.fp,tOffset,
2686 			     numElems,buffer),&pStatus)) return pStatus;
2687       }
2688       else {
2689 	if (!sX(RecordByteOffset(CDF,Var,
2690 				 prevRec,
2691 				 &tOffset),&pStatus)) return pStatus;
2692 	tOffset += offset;
2693 	if (!sX(ReadVarElems(Var,CDF->fp,tOffset,
2694 			     numElems,buffer),&pStatus)) return pStatus;
2695       }
2696       sX (VIRTUAL_RECORD_DATA, &pStatus);
2697       return pStatus;
2698     }
2699     /**************************************************************************
2700     * A previous record does not exist in a VVR...check if the last record in
2701     * the staging area is the previous record.
2702     **************************************************************************/
2703     if (EXCLUSIVE(NO_RECORD,Var->stage.lastRec,recNum)) {
2704       Int32 recNumInStage = Var->stage.lastRec - Var->stage.firstRec;
2705       tOffset = Var->stage.areaOffset;
2706       tOffset += Var->NphyRecBytes * recNumInStage;
2707       tOffset += offset;
2708       if (!sX(ReadVarElems(Var,CDF->stage.fp,
2709 			   tOffset,numElems,buffer),&pStatus)) return pStatus;
2710       sX (VIRTUAL_RECORD_DATA, &pStatus);
2711       return pStatus;
2712     }
2713   }
2714   /****************************************************************************
2715   * Pad the buffer with the variable's pad value.  Note that this is also done
2716   * if the variable is sRecords.PREV but a previous record does not exist.
2717   ****************************************************************************/
2718   if (!sX(PadBuffer(CDF,Var,nValues,buffer),&pStatus)) return pStatus;
2719   sX (VIRTUAL_RECORD_DATA, &pStatus);
2720   return pStatus;
2721 }
2722 
2723 /******************************************************************************
2724 * ReadCompressedFull.
2725 ******************************************************************************/
2726 
ReadCompressedFull(CDF,Var,firstRec,lastRec,buffer)2727 static CDFstatus ReadCompressedFull (CDF, Var, firstRec, lastRec, buffer)
2728 struct CDFstruct *CDF;
2729 struct VarStruct *Var;
2730 Int32 firstRec;
2731 Int32 lastRec;
2732 void *buffer;
2733 {
2734   CDFstatus pStatus = CDF_OK; Logical found;
2735   Int32 readTo, recCount, numElems, recX, tOffset, nextRec;
2736   Int32 recNum = firstRec, nPadValues, prevRec, padTo;
2737   Byte *tBuffer = (Byte *) buffer, *destBuffer;
2738   /****************************************************************************
2739   * While there are more records to be read/generated...
2740   ****************************************************************************/
2741   while (recNum <= lastRec) {
2742     /**************************************************************************
2743     * Try to bring the record to the staging area.
2744     **************************************************************************/
2745     if (!sX(BringToStage(CDF,Var,recNum,&found),&pStatus)) return pStatus;
2746     if (found) {
2747       readTo = MINIMUM(Var->stage.lastRec,lastRec);
2748       recCount = readTo - recNum + 1;
2749       numElems = recCount * Var->NphyRecElems;
2750       recX = recNum - Var->stage.firstRec;
2751       tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes);
2752       if (!sX(ReadVarElems(Var,CDF->stage.fp,
2753 			   tOffset,numElems,tBuffer),&pStatus)) return pStatus;
2754       tBuffer += (size_t) (recCount * Var->NphyRecBytes);
2755       recNum += recCount;
2756       continue;
2757     }
2758     /**************************************************************************
2759     * Determine which records need to be padded.
2760     **************************************************************************/
2761     if (!sX(NextRecord(CDF,Var->VDRoffset,Var->zVar,
2762 		       recNum,&nextRec,&found),&pStatus)) return pStatus;
2763     if (found) {
2764       if (EXCLUSIVE(recNum,
2765 		    Var->stage.firstRec,
2766 		    nextRec)) nextRec = Var->stage.firstRec;
2767       prevRec = nextRec - 1;
2768       padTo = MINIMUM(prevRec,lastRec);
2769     }
2770     else
2771       padTo = BOO(Var->stage.firstRec > recNum,
2772 		  Var->stage.firstRec - 1,lastRec);
2773     recCount = padTo - recNum + 1;
2774     /**************************************************************************
2775     * If sRecords.PREV...
2776     **************************************************************************/
2777     if (Var->prevIfMissing) {
2778       if (!sX(PrevRecord(CDF,Var->VDRoffset,Var->zVar,
2779 			 recNum,&prevRec,&found),&pStatus)) return pStatus;
2780       if (!found) prevRec = NO_RECORD;
2781       if (EXCLUSIVE(prevRec,
2782 		    Var->stage.lastRec,
2783 		    recNum)) prevRec = Var->stage.lastRec;
2784       if (prevRec > NO_RECORD) {
2785 	if (!sX(BringToStage(CDF,Var,prevRec,NULL),&pStatus)) return pStatus;
2786 	recX = prevRec - Var->stage.firstRec;
2787 	tOffset = Var->stage.areaOffset + (recX * Var->NphyRecBytes);
2788 	if (!sX(ReadVarElems(Var,CDF->stage.fp,
2789 			     tOffset,Var->NphyRecElems,
2790 			     tBuffer),&pStatus)) return pStatus;
2791 	destBuffer = tBuffer + ((size_t) Var->NphyRecBytes);
2792 	for (recX = 1; recX < recCount; recX++) {
2793 	   memmove (destBuffer, tBuffer, (size_t) Var->NphyRecBytes);
2794 	   destBuffer += (size_t) Var->NphyRecBytes;
2795 	}
2796 	sX (VIRTUAL_RECORD_DATA, &pStatus);
2797 	tBuffer += (size_t) (recCount * Var->NphyRecBytes);
2798 	recNum += recCount;
2799 	continue;
2800       }
2801     }
2802     /**************************************************************************
2803     * Pad with the variable's pad value.  This occurs if the variable is
2804     * sRecords.NO, sRecords.PAD, or if sRecords.PREV but a previous record
2805     * does not exist (in a CVVR/VVR or the staging area).
2806     **************************************************************************/
2807     nPadValues = recCount * Var->NphyRecValues;
2808     if (!sX(PadBuffer(CDF,Var,nPadValues,tBuffer),&pStatus)) return pStatus;
2809     sX (VIRTUAL_RECORD_DATA, &pStatus);
2810     tBuffer += (size_t) (recCount * Var->NphyRecBytes);
2811     recNum += recCount;
2812   }
2813   return pStatus;
2814 }
2815 
2816 /******************************************************************************
2817 * ReadCompressedPartial.
2818 ******************************************************************************/
2819 
ReadCompressedPartial(CDF,Var,recNum,offset,nValues,buffer)2820 static CDFstatus ReadCompressedPartial (CDF, Var, recNum, offset, nValues,
2821 					buffer)
2822 struct CDFstruct *CDF;
2823 struct VarStruct *Var;
2824 Int32 recNum;
2825 Int32 offset;
2826 Int32 nValues;
2827 void *buffer;
2828 {
2829   CDFstatus pStatus = CDF_OK;
2830   Int32 numElems = nValues * Var->NvalueElems;
2831   Int32 tOffset, prevRec, recX; Logical found;
2832   /****************************************************************************
2833   * Try to bring the record to the staging area.
2834   ****************************************************************************/
2835   if (!sX(BringToStage(CDF,Var,recNum,&found),&pStatus)) return pStatus;
2836   if (found) {
2837     tOffset = Var->stage.areaOffset;
2838     tOffset += Var->NphyRecBytes * (recNum - Var->stage.firstRec);
2839     tOffset += offset;
2840     if (!sX(ReadVarElems(Var,CDF->stage.fp,
2841 			 tOffset,numElems,buffer),&pStatus)) return pStatus;
2842     return pStatus;
2843   }
2844   /****************************************************************************
2845   * If sRecords.PREV...
2846   ****************************************************************************/
2847   if (Var->prevIfMissing) {
2848     if (!sX(PrevRecord(CDF,Var->VDRoffset,
2849 		       Var->zVar,recNum,
2850 		       &prevRec,&found),&pStatus)) return pStatus;
2851     if (!found) prevRec = NO_RECORD;
2852     if (EXCLUSIVE(prevRec,
2853 		  Var->stage.lastRec,
2854 		  recNum)) prevRec = Var->stage.lastRec;
2855     if (prevRec > NO_RECORD) {
2856       if (!sX(BringToStage(CDF,Var,prevRec,NULL),&pStatus)) return pStatus;
2857       recX = Var->stage.lastRec - Var->stage.firstRec;
2858       tOffset = Var->stage.areaOffset + (Var->NphyRecBytes * recX) + offset;
2859       if (!sX(ReadVarElems(Var,CDF->stage.fp,
2860 			   tOffset,numElems,buffer),&pStatus)) return pStatus;
2861       sX (VIRTUAL_RECORD_DATA, &pStatus);
2862       return pStatus;
2863     }
2864   }
2865   /****************************************************************************
2866   * Pad the buffer with the variable's pad value.  Note that this is also done
2867   * if the variable is sRecords.PREV but a previous record does not exist.
2868   ****************************************************************************/
2869   if (!sX(PadBuffer(CDF,Var,nValues,buffer),&pStatus)) return pStatus;
2870   sX (VIRTUAL_RECORD_DATA, &pStatus);
2871   return pStatus;
2872 }
2873 
2874 #if defined(MSVC67)
2875 /******************************************************************************
2876 * Replace _ftol2 with _ftol on Windows as VC 6.0 doesn't have a such function.
2877 ******************************************************************************/
2878 
_ftol2(dblSource)2879 VISIBLE_PREFIX long _ftol2(dblSource)
2880 double dblSource;
2881 {
2882 	return (long) _ftol( dblSource );
2883 }
2884 #endif
2885