Coverage Report

Created: 2025-07-23 09:13

/src/gdal/netcdf-c-4.7.4/libsrc/v1hpg.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Copyright 2018, University Corporation for Atmospheric Research
3
 *      See netcdf/COPYRIGHT file for copying and redistribution conditions.
4
 */
5
6
#if HAVE_CONFIG_H
7
#include <config.h>
8
#endif
9
10
#include <stdlib.h>
11
#include <stdio.h>
12
#include <string.h>
13
#include <assert.h>
14
#include "nc3internal.h"
15
#include "rnd.h"
16
#include "ncx.h"
17
18
/*
19
 * This module defines the external representation
20
 * of the "header" of a netcdf version one file and
21
 * the version two variant that uses 64-bit file
22
 * offsets instead of the 32-bit file offsets in version
23
 * one files.
24
 * For each of the components of the NC structure,
25
 * There are (static) ncx_len_XXX(), v1h_put_XXX()
26
 * and v1h_get_XXX() functions. These define the
27
 * external representation of the components.
28
 * The exported entry points for the whole NC structure
29
 * are built up from these.
30
 */
31
32
33
/*
34
 * "magic number" at beginning of file: 0x43444601 (big endian)
35
 * assert(sizeof(ncmagic) % X_ALIGN == 0);
36
 */
37
static const schar ncmagic[] = {'C', 'D', 'F', 0x02};
38
static const schar ncmagic1[] = {'C', 'D', 'F', 0x01};
39
static const schar ncmagic5[] = {'C', 'D', 'F', 0x05};
40
41
/*
42
 * v1hs == "Version 1 Header Stream"
43
 *
44
 * The netcdf file version 1 header is
45
 * of unknown and potentially unlimited size.
46
 * So, we don't know how much to get() on
47
 * the initial read. We build a stream, 'v1hs'
48
 * on top of ncio to do the header get.
49
 */
50
typedef struct v1hs {
51
  ncio *nciop;
52
  off_t offset; /* argument to nciop->get() */
53
  size_t extent;  /* argument to nciop->get() */
54
  int flags;  /* set to RGN_WRITE for write */
55
        int version;    /* format variant: NC_FORMAT_CLASSIC, NC_FORMAT_64BIT_OFFSET or NC_FORMAT_CDF5 */
56
  void *base; /* beginning of current buffer */
57
  void *pos;  /* current position in buffer */
58
  void *end;  /* end of current buffer = base + extent */
59
} v1hs;
60
61
62
/*
63
 * Release the stream, invalidate buffer
64
 */
65
static int
66
rel_v1hs(v1hs *gsp)
67
38.2k
{
68
38.2k
  int status;
69
38.2k
  if(gsp->offset == OFF_NONE || gsp->base == NULL)
70
0
        return NC_NOERR;
71
38.2k
  status = ncio_rel(gsp->nciop, gsp->offset,
72
38.2k
       gsp->flags == RGN_WRITE ? RGN_MODIFIED : 0);
73
38.2k
  gsp->end = NULL;
74
38.2k
  gsp->pos = NULL;
75
38.2k
  gsp->base = NULL;
76
38.2k
  return status;
77
38.2k
}
78
79
80
/*
81
 * Release the current chunk and get the next one.
82
 * Also used for initialization when gsp->base == NULL.
83
 */
84
static int
85
fault_v1hs(v1hs *gsp, size_t extent)
86
28.1k
{
87
28.1k
  int status;
88
89
28.1k
  if(gsp->base != NULL)
90
8.14k
  {
91
8.14k
    const ptrdiff_t incr = (char *)gsp->pos - (char *)gsp->base;
92
8.14k
    status = rel_v1hs(gsp);
93
8.14k
    if(status)
94
0
      return status;
95
8.14k
    gsp->offset += incr;
96
8.14k
  }
97
98
28.1k
  if(extent > gsp->extent)
99
10.0k
    gsp->extent = extent;
100
101
28.1k
  status = ncio_get(gsp->nciop,
102
28.1k
      gsp->offset, gsp->extent,
103
28.1k
      gsp->flags, &gsp->base);
104
28.1k
  if(status)
105
0
    return status;
106
107
28.1k
  gsp->pos = gsp->base;
108
109
28.1k
  gsp->end = (char *)gsp->base + gsp->extent;
110
28.1k
    return NC_NOERR;
111
28.1k
}
112
113
114
/*
115
 * Ensure that 'nextread' bytes are available.
116
 */
117
static int
118
check_v1hs(v1hs *gsp, size_t nextread)
119
2.02M
{
120
121
#if 0 /* DEBUG */
122
fprintf(stderr, "nextread %lu, remaining %lu\n",
123
  (unsigned long)nextread,
124
  (unsigned long)((char *)gsp->end - (char *)gsp->pos));
125
#endif
126
2.02M
    if((char *)gsp->pos + nextread <= (char *)gsp->end)
127
2.01M
  return NC_NOERR;
128
129
8.14k
    return fault_v1hs(gsp, nextread);
130
2.02M
}
131
132
/* End v1hs */
133
134
/* Write a size_t to the header */
135
static int
136
v1h_put_size_t(v1hs *psp, const size_t *sp)
137
465k
{
138
465k
  int status;
139
465k
  if (psp->version == 5) /* all integers in CDF-5 are 64 bits */
140
0
    status = check_v1hs(psp, X_SIZEOF_INT64);
141
465k
  else
142
465k
    status = check_v1hs(psp, X_SIZEOF_SIZE_T);
143
465k
  if(status != NC_NOERR)
144
0
    return status;
145
465k
        if (psp->version == 5) {
146
0
                unsigned long long tmp = (unsigned long long) (*sp);
147
0
    return ncx_put_uint64(&psp->pos, tmp);
148
0
        }
149
465k
        else
150
465k
      return ncx_put_size_t(&psp->pos, sp);
151
465k
}
152
153
/* Read a size_t from the header */
154
static int
155
v1h_get_size_t(v1hs *gsp, size_t *sp)
156
434k
{
157
434k
  int status;
158
434k
  if (gsp->version == 5) /* all integers in CDF-5 are 64 bits */
159
0
    status = check_v1hs(gsp, X_SIZEOF_INT64);
160
434k
  else
161
434k
    status = check_v1hs(gsp, X_SIZEOF_SIZE_T);
162
434k
  if(status != NC_NOERR)
163
0
    return status;
164
434k
        if (gsp->version == 5) {
165
0
    unsigned long long tmp=0;
166
0
    status = ncx_get_uint64((const void **)(&gsp->pos), &tmp);
167
0
    *sp = (size_t)tmp;
168
0
    return status;
169
0
        }
170
434k
        else
171
434k
      return ncx_get_size_t((const void **)(&gsp->pos), sp);
172
434k
}
173
174
/* Begin nc_type */
175
176
253k
#define X_SIZEOF_NC_TYPE X_SIZEOF_INT
177
178
/* Write a nc_type to the header */
179
static int
180
v1h_put_nc_type(v1hs *psp, const nc_type *typep)
181
126k
{
182
126k
    const unsigned int itype = (unsigned int) *typep;
183
126k
    int status = check_v1hs(psp, X_SIZEOF_INT);
184
126k
    if(status != NC_NOERR) return status;
185
126k
    status =  ncx_put_uint32(&psp->pos, itype);
186
126k
    return status;
187
126k
}
188
189
190
/* Read a nc_type from the header */
191
static int
192
v1h_get_nc_type(v1hs *gsp, nc_type *typep)
193
126k
{
194
126k
    unsigned int type = 0;
195
126k
    int status = check_v1hs(gsp, X_SIZEOF_INT);
196
126k
    if(status != NC_NOERR) return status;
197
126k
    status =  ncx_get_uint32((const void**)(&gsp->pos), &type);
198
126k
    if(status != NC_NOERR)
199
0
    return status;
200
201
126k
  assert(type == NC_BYTE
202
126k
    || type == NC_CHAR
203
126k
    || type == NC_SHORT
204
126k
    || type == NC_INT
205
126k
    || type == NC_FLOAT
206
126k
    || type == NC_DOUBLE
207
126k
    || type == NC_UBYTE
208
126k
    || type == NC_USHORT
209
126k
    || type == NC_UINT
210
126k
    || type == NC_INT64
211
126k
    || type == NC_UINT64
212
126k
    || type == NC_STRING);
213
214
  /* else */
215
126k
  *typep = (nc_type) type;
216
217
126k
    return NC_NOERR;
218
126k
}
219
220
/* End nc_type */
221
/* Begin NCtype (internal tags) */
222
223
206k
#define X_SIZEOF_NCTYPE X_SIZEOF_INT
224
225
/* Write a NCtype to the header */
226
static int
227
v1h_put_NCtype(v1hs *psp, NCtype type)
228
118k
{
229
118k
    const unsigned int itype = (unsigned int) type;
230
118k
    int status = check_v1hs(psp, X_SIZEOF_INT);
231
118k
    if(status != NC_NOERR) return status;
232
118k
    status = ncx_put_uint32(&psp->pos, itype);
233
118k
    return status;
234
118k
}
235
236
/* Read a NCtype from the header */
237
static int
238
v1h_get_NCtype(v1hs *gsp, NCtype *typep)
239
88.2k
{
240
88.2k
    unsigned int type = 0;
241
88.2k
    int status = check_v1hs(gsp, X_SIZEOF_INT);
242
88.2k
    if(status != NC_NOERR) return status;
243
88.2k
    status =  ncx_get_uint32((const void**)(&gsp->pos), &type);
244
88.2k
    if(status != NC_NOERR) return status;
245
    /* else */
246
88.2k
    *typep = (NCtype) type;
247
88.2k
    return NC_NOERR;
248
88.2k
}
249
250
/* End NCtype */
251
/* Begin NC_string */
252
253
/*
254
 * How much space will the xdr'd string take.
255
 * Formerly
256
NC_xlen_string(cdfstr)
257
 */
258
static size_t
259
ncx_len_NC_string(const NC_string *ncstrp, int version)
260
288k
{
261
288k
  size_t sz = (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_INT; /* nchars */
262
263
288k
  assert(ncstrp != NULL);
264
265
288k
  if(ncstrp->nchars != 0)
266
288k
  {
267
#if 0
268
    assert(ncstrp->nchars % X_ALIGN == 0);
269
    sz += ncstrp->nchars;
270
#else
271
288k
    sz += _RNDUP(ncstrp->nchars, X_ALIGN);
272
288k
#endif
273
288k
  }
274
288k
  return sz;
275
288k
}
276
277
278
/* Write a NC_string to the header */
279
static int
280
v1h_put_NC_string(v1hs *psp, const NC_string *ncstrp)
281
144k
{
282
144k
  int status;
283
284
#if 0
285
  assert(ncstrp->nchars % X_ALIGN == 0);
286
#endif
287
288
144k
  status = v1h_put_size_t(psp, &ncstrp->nchars);
289
144k
    if(status != NC_NOERR)
290
0
    return status;
291
144k
  status = check_v1hs(psp, _RNDUP(ncstrp->nchars, X_ALIGN));
292
144k
    if(status != NC_NOERR)
293
0
    return status;
294
144k
  status = ncx_pad_putn_text(&psp->pos, ncstrp->nchars, ncstrp->cp);
295
144k
    if(status != NC_NOERR)
296
0
    return status;
297
298
144k
    return NC_NOERR;
299
144k
}
300
301
302
/* Read a NC_string from the header */
303
static int
304
v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp)
305
144k
{
306
144k
  int status = 0;
307
144k
  size_t nchars = 0;
308
144k
  NC_string *ncstrp = NULL;
309
#if USE_STRICT_NULL_BYTE_HEADER_PADDING
310
        size_t padding = 0;        
311
#endif /* USE_STRICT_NULL_BYTE_HEADER_PADDING */
312
313
144k
  status = v1h_get_size_t(gsp, &nchars);
314
144k
  if(status != NC_NOERR)
315
0
    return status;
316
317
144k
  ncstrp = new_NC_string(nchars, NULL);
318
144k
  if(ncstrp == NULL)
319
0
  {
320
0
    return NC_ENOMEM;
321
0
  }
322
323
#if 0
324
/* assert(ncstrp->nchars == nchars || ncstrp->nchars - nchars < X_ALIGN); */
325
  assert(ncstrp->nchars % X_ALIGN == 0);
326
  status = check_v1hs(gsp, ncstrp->nchars);
327
#else
328
329
144k
  status = check_v1hs(gsp, _RNDUP(ncstrp->nchars, X_ALIGN));
330
144k
#endif
331
144k
  if(status != NC_NOERR)
332
0
    goto unwind_alloc;
333
334
144k
  status = ncx_pad_getn_text((const void **)(&gsp->pos),
335
144k
     nchars, ncstrp->cp);
336
144k
  if(status != NC_NOERR)
337
0
    goto unwind_alloc;
338
339
#if USE_STRICT_NULL_BYTE_HEADER_PADDING
340
  padding = _RNDUP(X_SIZEOF_CHAR * ncstrp->nchars, X_ALIGN)
341
    - X_SIZEOF_CHAR * ncstrp->nchars;
342
343
  if (padding > 0) {
344
    /* CDF specification: Header padding uses null (\x00) bytes. */
345
    char pad[X_ALIGN-1];
346
    memset(pad, 0, X_ALIGN-1);
347
    if (memcmp((char*)gsp->pos-padding, pad, padding) != 0) {
348
      free_NC_string(ncstrp);
349
      return NC_ENULLPAD;
350
    }
351
  }
352
#endif
353
354
144k
  *ncstrpp = ncstrp;
355
356
144k
  return NC_NOERR;
357
358
0
unwind_alloc:
359
0
  free_NC_string(ncstrp);
360
0
  return status;
361
144k
}
362
363
/* End NC_string */
364
/* Begin NC_dim */
365
366
/*
367
 * How much space will the xdr'd dim take.
368
 * Formerly
369
NC_xlen_dim(dpp)
370
 */
371
static size_t
372
ncx_len_NC_dim(const NC_dim *dimp, int version)
373
35.4k
{
374
35.4k
  size_t sz;
375
376
35.4k
  assert(dimp != NULL);
377
378
35.4k
  sz = ncx_len_NC_string(dimp->name, version);
379
35.4k
  sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T;
380
381
35.4k
  return(sz);
382
35.4k
}
383
384
385
/* Write a NC_dim to the header */
386
static int
387
v1h_put_NC_dim(v1hs *psp, const NC_dim *dimp)
388
17.7k
{
389
17.7k
  int status;
390
391
17.7k
  status = v1h_put_NC_string(psp, dimp->name);
392
17.7k
    if(status != NC_NOERR)
393
0
    return status;
394
395
17.7k
  status = v1h_put_size_t(psp, &dimp->size);
396
17.7k
    if(status != NC_NOERR)
397
0
    return status;
398
399
17.7k
    return NC_NOERR;
400
17.7k
}
401
402
/* Read a NC_dim from the header */
403
static int
404
v1h_get_NC_dim(v1hs *gsp, NC_dim **dimpp)
405
17.7k
{
406
17.7k
  int status;
407
17.7k
  NC_string *ncstrp;
408
17.7k
  NC_dim *dimp;
409
410
17.7k
  status = v1h_get_NC_string(gsp, &ncstrp);
411
17.7k
    if(status != NC_NOERR)
412
0
    return status;
413
414
17.7k
  dimp = new_x_NC_dim(ncstrp);
415
17.7k
  if(dimp == NULL)
416
0
  {
417
0
    status = NC_ENOMEM;
418
0
    goto unwind_name;
419
0
  }
420
421
17.7k
  status = v1h_get_size_t(gsp, &dimp->size);
422
17.7k
    if(status != NC_NOERR)
423
0
  {
424
0
    free_NC_dim(dimp); /* frees name */
425
0
    return status;
426
0
  }
427
428
17.7k
  *dimpp = dimp;
429
430
17.7k
    return NC_NOERR;
431
432
0
unwind_name:
433
0
  free_NC_string(ncstrp);
434
0
  return status;
435
17.7k
}
436
437
438
/* How much space in the header is required for this NC_dimarray? */
439
static size_t
440
ncx_len_NC_dimarray(const NC_dimarray *ncap, int version)
441
30.0k
{
442
30.0k
  size_t xlen = X_SIZEOF_NCTYPE; /* type */
443
30.0k
  xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */
444
30.0k
  if(ncap == NULL)
445
0
    return xlen;
446
  /* else */
447
30.0k
  {
448
30.0k
    const NC_dim **dpp = (const NC_dim **)ncap->value;
449
30.0k
    const NC_dim *const *const end = &dpp[ncap->nelems];
450
65.5k
    for(  /*NADA*/; dpp < end; dpp++)
451
35.4k
    {
452
35.4k
      xlen += ncx_len_NC_dim(*dpp,version);
453
35.4k
    }
454
30.0k
  }
455
30.0k
  return xlen;
456
30.0k
}
457
458
459
/* Write a NC_dimarray to the header */
460
static int
461
v1h_put_NC_dimarray(v1hs *psp, const NC_dimarray *ncap)
462
20.0k
{
463
20.0k
  int status;
464
465
20.0k
  assert(psp != NULL);
466
467
20.0k
  if(ncap == NULL
468
20.0k
#if 1
469
    /* Backward:
470
     * This clause is for 'byte for byte'
471
     * backward compatibility.
472
     * Strickly speaking, it is 'bug for bug'.
473
     */
474
20.0k
    || ncap->nelems == 0
475
20.0k
#endif
476
20.0k
    )
477
13.2k
  {
478
    /*
479
     * Handle empty netcdf
480
     */
481
13.2k
    const size_t nosz = 0;
482
483
13.2k
    status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
484
13.2k
        if(status != NC_NOERR)
485
0
      return status;
486
13.2k
    status = v1h_put_size_t(psp, &nosz);
487
13.2k
        if(status != NC_NOERR)
488
0
      return status;
489
13.2k
        return NC_NOERR;
490
13.2k
  }
491
  /* else */
492
493
6.83k
  status = v1h_put_NCtype(psp, NC_DIMENSION);
494
6.83k
    if(status != NC_NOERR)
495
0
    return status;
496
6.83k
  status = v1h_put_size_t(psp, &ncap->nelems);
497
6.83k
    if(status != NC_NOERR)
498
0
    return status;
499
500
6.83k
  {
501
6.83k
    const NC_dim **dpp = (const NC_dim **)ncap->value;
502
6.83k
    const NC_dim *const *const end = &dpp[ncap->nelems];
503
24.5k
    for( /*NADA*/; dpp < end; dpp++)
504
17.7k
    {
505
17.7k
      status = v1h_put_NC_dim(psp, *dpp);
506
17.7k
      if(status)
507
0
        return status;
508
17.7k
    }
509
6.83k
  }
510
6.83k
    return NC_NOERR;
511
6.83k
}
512
513
514
/* Read a NC_dimarray from the header */
515
static int
516
v1h_get_NC_dimarray(v1hs *gsp, NC_dimarray *ncap)
517
10.0k
{
518
10.0k
  int status;
519
10.0k
  NCtype type = NC_UNSPECIFIED;
520
521
10.0k
  assert(gsp != NULL && gsp->pos != NULL);
522
10.0k
  assert(ncap != NULL);
523
10.0k
  assert(ncap->value == NULL);
524
525
10.0k
  status = v1h_get_NCtype(gsp, &type);
526
10.0k
    if(status != NC_NOERR)
527
0
    return status;
528
529
10.0k
  status = v1h_get_size_t(gsp, &ncap->nelems);
530
10.0k
    if(status != NC_NOERR)
531
0
    return status;
532
533
10.0k
  if(ncap->nelems == 0)
534
3.18k
        return NC_NOERR;
535
  /* else */
536
6.83k
  if(type != NC_DIMENSION)
537
0
    return EINVAL;
538
539
6.83k
  ncap->value = (NC_dim **) calloc(1,ncap->nelems * sizeof(NC_dim *));
540
6.83k
  if(ncap->value == NULL)
541
0
    return NC_ENOMEM;
542
6.83k
  ncap->nalloc = ncap->nelems;
543
544
6.83k
  ncap->hashmap = NC_hashmapnew(ncap->nelems);
545
546
6.83k
  {
547
6.83k
    NC_dim **dpp = ncap->value;
548
6.83k
    NC_dim *const *const end = &dpp[ncap->nelems];
549
24.5k
    for( /*NADA*/; dpp < end; dpp++)
550
17.7k
    {
551
17.7k
      status = v1h_get_NC_dim(gsp, dpp);
552
17.7k
      if(status)
553
0
      {
554
0
        ncap->nelems = (size_t)(dpp - ncap->value);
555
0
        free_NC_dimarrayV(ncap);
556
0
        return status;
557
0
      }
558
17.7k
      {
559
17.7k
        int dimid = (size_t)(dpp - ncap->value);
560
17.7k
        NC_hashmapadd(ncap->hashmap, (uintptr_t)dimid, (*dpp)->name->cp,strlen((*dpp)->name->cp));
561
17.7k
      }
562
17.7k
    }
563
6.83k
  }
564
565
6.83k
    return NC_NOERR;
566
6.83k
}
567
568
569
/* End NC_dim */
570
/* Begin NC_attr */
571
572
573
/*
574
 * How much space will 'attrp' take in external representation?
575
 * Formerly
576
NC_xlen_attr(app)
577
 */
578
static size_t
579
ncx_len_NC_attr(const NC_attr *attrp, int version)
580
136k
{
581
136k
  size_t sz;
582
583
136k
  assert(attrp != NULL);
584
585
136k
  sz = ncx_len_NC_string(attrp->name, version);
586
136k
  sz += X_SIZEOF_NC_TYPE; /* type */
587
136k
  sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* nelems */
588
136k
  sz += attrp->xsz;
589
590
136k
  return(sz);
591
136k
}
592
593
594
#undef MIN
595
143k
#define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn))
596
597
/*----< ncmpix_len_nctype() >------------------------------------------------*/
598
/* return the length of external data type */
599
static int
600
68.3k
ncmpix_len_nctype(nc_type type) {
601
68.3k
    switch(type) {
602
9.30k
        case NC_BYTE:
603
30.5k
        case NC_CHAR:
604
30.5k
        case NC_UBYTE:  return X_SIZEOF_CHAR;
605
9.40k
        case NC_SHORT:  return X_SIZEOF_SHORT;
606
0
        case NC_USHORT: return X_SIZEOF_USHORT;
607
22.9k
        case NC_INT:    return X_SIZEOF_INT;
608
0
        case NC_UINT:   return X_SIZEOF_UINT;
609
0
        case NC_FLOAT:  return X_SIZEOF_FLOAT;
610
5.44k
        case NC_DOUBLE: return X_SIZEOF_DOUBLE;
611
0
        case NC_INT64:  return X_SIZEOF_INT64;
612
0
        case NC_UINT64: return X_SIZEOF_UINT64;
613
0
        default: fprintf(stderr,"ncmpix_len_nctype bad type %d\n",type);
614
0
                 assert(0);
615
68.3k
    }
616
0
    return 0;
617
68.3k
}
618
619
/*
620
 * Put the values of an attribute
621
 * The loop is necessary since attrp->nelems
622
 * could potentially be quite large.
623
 */
624
static int
625
v1h_put_NC_attrV(v1hs *psp, const NC_attr *attrp)
626
68.3k
{
627
68.3k
  int status = 0;
628
68.3k
  const size_t perchunk =  psp->extent;
629
68.3k
  size_t remaining = attrp->xsz;
630
68.3k
  void *value = attrp->xvalue;
631
68.3k
  size_t nbytes = 0, padding = 0;
632
633
68.3k
  assert(psp->extent % X_ALIGN == 0);
634
635
70.6k
  do {
636
70.6k
    nbytes = MIN(perchunk, remaining);
637
638
70.6k
    status = check_v1hs(psp, nbytes);
639
70.6k
    if(status != NC_NOERR)
640
0
      return status;
641
642
70.6k
    (void) memcpy(psp->pos, value, nbytes);
643
644
70.6k
    psp->pos = (void *)((char *)psp->pos + nbytes);
645
70.6k
    value = (void *)((char *)value + nbytes);
646
70.6k
          remaining -= nbytes;
647
648
70.6k
  } while(remaining != 0);
649
650
651
68.3k
  padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems;
652
68.3k
  if (padding > 0) {
653
    /* CDF specification: Header padding uses null (\x00) bytes. */
654
31.0k
    memset((char*)psp->pos-padding, 0, padding);
655
31.0k
  }
656
657
68.3k
  return NC_NOERR;
658
68.3k
}
659
660
/* Write a NC_attr to the header */
661
static int
662
v1h_put_NC_attr(v1hs *psp, const NC_attr *attrp)
663
68.3k
{
664
68.3k
  int status;
665
666
68.3k
  status = v1h_put_NC_string(psp, attrp->name);
667
68.3k
    if(status != NC_NOERR)
668
0
    return status;
669
670
68.3k
  status = v1h_put_nc_type(psp, &attrp->type);
671
68.3k
    if(status != NC_NOERR)
672
0
    return status;
673
674
68.3k
  status = v1h_put_size_t(psp, &attrp->nelems);
675
68.3k
    if(status != NC_NOERR)
676
0
    return status;
677
678
68.3k
  status = v1h_put_NC_attrV(psp, attrp);
679
68.3k
    if(status != NC_NOERR)
680
0
    return status;
681
682
68.3k
    return NC_NOERR;
683
68.3k
}
684
685
686
/*
687
 * Get the values of an attribute
688
 * The loop is necessary since attrp->nelems
689
 * could potentially be quite large.
690
 */
691
static int
692
v1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp)
693
68.3k
{
694
68.3k
  int status;
695
68.3k
  const size_t perchunk =  gsp->extent;
696
68.3k
  size_t remaining = attrp->xsz;
697
68.3k
  void *value = attrp->xvalue;
698
68.3k
  size_t nget;
699
#if USE_STRICT_NULL_BYTE_HEADER_PADDING
700
  size_t padding;
701
#endif /* USE_STRICT_NULL_BYTE_HEADER_PADDING */
702
703
73.0k
  do {
704
73.0k
    nget = MIN(perchunk, remaining);
705
706
73.0k
    status = check_v1hs(gsp, nget);
707
73.0k
    if(status != NC_NOERR)
708
0
      return status;
709
710
73.0k
    (void) memcpy(value, gsp->pos, nget);
711
73.0k
    gsp->pos = (void*)((unsigned char *)gsp->pos + nget);
712
713
73.0k
    value = (void *)((signed char *)value + nget);
714
715
73.0k
    remaining -= nget;
716
717
73.0k
  } while(remaining != 0);
718
719
#if USE_STRICT_NULL_BYTE_HEADER_PADDING
720
  padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems;
721
  if (padding > 0) {
722
    /* CDF specification: Header padding uses null (\x00) bytes. */
723
    char pad[X_ALIGN-1];
724
    memset(pad, 0, X_ALIGN-1);
725
    if (memcmp((char*)gsp->pos-padding, pad, (size_t)padding) != 0)
726
      return NC_ENULLPAD;
727
  }
728
#endif
729
730
68.3k
  return NC_NOERR;
731
68.3k
}
732
733
734
/* Read a NC_attr from the header */
735
static int
736
v1h_get_NC_attr(v1hs *gsp, NC_attr **attrpp)
737
68.3k
{
738
68.3k
  NC_string *strp;
739
68.3k
  int status;
740
68.3k
  nc_type type;
741
68.3k
  size_t nelems;
742
68.3k
  NC_attr *attrp;
743
744
68.3k
  status = v1h_get_NC_string(gsp, &strp);
745
68.3k
    if(status != NC_NOERR)
746
0
    return status;
747
748
68.3k
  status = v1h_get_nc_type(gsp, &type);
749
68.3k
    if(status != NC_NOERR)
750
0
    goto unwind_name;
751
752
68.3k
  status = v1h_get_size_t(gsp, &nelems);
753
68.3k
    if(status != NC_NOERR)
754
0
    goto unwind_name;
755
756
68.3k
  attrp = new_x_NC_attr(strp, type, nelems);
757
68.3k
  if(attrp == NULL)
758
0
  {
759
0
    status = NC_ENOMEM;
760
0
    goto unwind_name;
761
0
  }
762
763
68.3k
  status = v1h_get_NC_attrV(gsp, attrp);
764
68.3k
    if(status != NC_NOERR)
765
0
  {
766
0
    free_NC_attr(attrp); /* frees strp */
767
0
    return status;
768
0
  }
769
770
68.3k
  *attrpp = attrp;
771
772
68.3k
    return NC_NOERR;
773
774
0
unwind_name:
775
0
  free_NC_string(strp);
776
0
  return status;
777
68.3k
}
778
779
780
/* How much space in the header is required for this NC_attrarray? */
781
static size_t
782
ncx_len_NC_attrarray(const NC_attrarray *ncap, int version)
783
146k
{
784
146k
  size_t xlen = X_SIZEOF_NCTYPE; /* type */
785
146k
  xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */
786
146k
  if(ncap == NULL)
787
0
    return xlen;
788
  /* else */
789
146k
  {
790
146k
    const NC_attr **app = (const NC_attr **)ncap->value;
791
146k
    const NC_attr *const *const end = &app[ncap->nelems];
792
283k
    for( /*NADA*/; app < end; app++)
793
136k
    {
794
136k
      xlen += ncx_len_NC_attr(*app,version);
795
136k
    }
796
146k
  }
797
146k
  return xlen;
798
146k
}
799
800
801
/* Write a NC_attrarray to the header */
802
static int
803
v1h_put_NC_attrarray(v1hs *psp, const NC_attrarray *ncap)
804
78.2k
{
805
78.2k
  int status;
806
807
78.2k
  assert(psp != NULL);
808
809
78.2k
  if(ncap == NULL
810
78.2k
#if 1
811
    /* Backward:
812
     * This clause is for 'byte for byte'
813
     * backward compatibility.
814
     * Strickly speaking, it is 'bug for bug'.
815
     */
816
78.2k
    || ncap->nelems == 0
817
78.2k
#endif
818
78.2k
    )
819
70.4k
  {
820
    /*
821
     * Handle empty netcdf
822
     */
823
70.4k
    const size_t nosz = 0;
824
825
70.4k
    status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
826
70.4k
        if(status != NC_NOERR)
827
0
      return status;
828
70.4k
    status = v1h_put_size_t(psp, &nosz);
829
70.4k
        if(status != NC_NOERR)
830
0
      return status;
831
70.4k
        return NC_NOERR;
832
70.4k
  }
833
  /* else */
834
835
7.70k
  status = v1h_put_NCtype(psp, NC_ATTRIBUTE);
836
7.70k
    if(status != NC_NOERR)
837
0
    return status;
838
7.70k
  status = v1h_put_size_t(psp, &ncap->nelems);
839
7.70k
    if(status != NC_NOERR)
840
0
    return status;
841
842
7.70k
  {
843
7.70k
    const NC_attr **app = (const NC_attr **)ncap->value;
844
7.70k
    const NC_attr *const *const end = &app[ncap->nelems];
845
76.0k
    for( /*NADA*/; app < end; app++)
846
68.3k
    {
847
68.3k
      status = v1h_put_NC_attr(psp, *app);
848
68.3k
      if(status)
849
0
        return status;
850
68.3k
    }
851
7.70k
  }
852
7.70k
    return NC_NOERR;
853
7.70k
}
854
855
856
/* Read a NC_attrarray from the header */
857
static int
858
v1h_get_NC_attrarray(v1hs *gsp, NC_attrarray *ncap)
859
68.1k
{
860
68.1k
  int status;
861
68.1k
  NCtype type = NC_UNSPECIFIED;
862
863
68.1k
  assert(gsp != NULL && gsp->pos != NULL);
864
68.1k
  assert(ncap != NULL);
865
68.1k
  assert(ncap->value == NULL);
866
867
68.1k
  status = v1h_get_NCtype(gsp, &type);
868
68.1k
    if(status != NC_NOERR)
869
0
    return status;
870
68.1k
  status = v1h_get_size_t(gsp, &ncap->nelems);
871
68.1k
    if(status != NC_NOERR)
872
0
    return status;
873
874
68.1k
  if(ncap->nelems == 0)
875
60.4k
        return NC_NOERR;
876
  /* else */
877
7.70k
  if(type != NC_ATTRIBUTE)
878
0
    return EINVAL;
879
880
7.70k
  ncap->value = (NC_attr **) malloc(ncap->nelems * sizeof(NC_attr *));
881
7.70k
  if(ncap->value == NULL)
882
0
    return NC_ENOMEM;
883
7.70k
  ncap->nalloc = ncap->nelems;
884
885
7.70k
  {
886
7.70k
    NC_attr **app = ncap->value;
887
7.70k
    NC_attr *const *const end = &app[ncap->nelems];
888
76.0k
    for( /*NADA*/; app < end; app++)
889
68.3k
    {
890
68.3k
      status = v1h_get_NC_attr(gsp, app);
891
68.3k
      if(status)
892
0
      {
893
0
        ncap->nelems = (size_t)(app - ncap->value);
894
0
        free_NC_attrarrayV(ncap);
895
0
        return status;
896
0
      }
897
68.3k
    }
898
7.70k
  }
899
900
7.70k
    return NC_NOERR;
901
7.70k
}
902
903
/* End NC_attr */
904
/* Begin NC_var */
905
906
/*
907
 * How much space will the xdr'd var take.
908
 * Formerly
909
NC_xlen_var(vpp)
910
 */
911
static size_t
912
ncx_len_NC_var(const NC_var *varp, size_t sizeof_off_t, int version)
913
116k
{
914
116k
  size_t sz;
915
916
116k
  assert(varp != NULL);
917
116k
  assert(sizeof_off_t != 0);
918
919
116k
  sz = ncx_len_NC_string(varp->name, version);
920
116k
        if (version == 5) {
921
0
      sz += X_SIZEOF_INT64; /* ndims */
922
0
      sz += ncx_len_int64(varp->ndims); /* dimids */
923
0
        }
924
116k
        else {
925
116k
      sz += X_SIZEOF_SIZE_T; /* ndims */
926
116k
      sz += ncx_len_int(varp->ndims); /* dimids */
927
116k
  }
928
116k
  sz += ncx_len_NC_attrarray(&varp->attrs, version);
929
116k
  sz += X_SIZEOF_NC_TYPE; /* nc_type */
930
116k
  sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* vsize */
931
116k
  sz += sizeof_off_t; /* begin */
932
933
116k
  return(sz);
934
116k
}
935
936
937
/* Write a NC_var to the header */
938
static int
939
v1h_put_NC_var(v1hs *psp, const NC_var *varp)
940
58.1k
{
941
58.1k
  int status;
942
58.1k
    size_t vsize;
943
944
58.1k
  status = v1h_put_NC_string(psp, varp->name);
945
58.1k
    if(status != NC_NOERR)
946
0
    return status;
947
948
58.1k
  status = v1h_put_size_t(psp, &varp->ndims);
949
58.1k
    if(status != NC_NOERR)
950
0
    return status;
951
952
58.1k
  if (psp->version == 5) {
953
0
    status = check_v1hs(psp, ncx_len_int64(varp->ndims));
954
0
        if(status != NC_NOERR)
955
0
      return status;
956
0
    status = ncx_putn_longlong_int(&psp->pos,
957
0
        varp->ndims, varp->dimids, NULL);
958
0
        if(status != NC_NOERR)
959
0
      return status;
960
0
  }
961
58.1k
  else {
962
58.1k
        status = check_v1hs(psp, ncx_len_int(varp->ndims));
963
58.1k
        if(status != NC_NOERR)
964
0
    return status;
965
58.1k
      status = ncx_putn_int_int(&psp->pos,
966
58.1k
      varp->ndims, varp->dimids, NULL);
967
58.1k
        if(status != NC_NOERR)
968
0
    return status;
969
58.1k
  }
970
971
58.1k
  status = v1h_put_NC_attrarray(psp, &varp->attrs);
972
58.1k
    if(status != NC_NOERR)
973
0
    return status;
974
975
58.1k
  status = v1h_put_nc_type(psp, &varp->type);
976
58.1k
    if(status != NC_NOERR)
977
0
    return status;
978
979
    /* write vsize to header.
980
     * CDF format specification: The vsize field is actually redundant, because
981
     * its value may be computed from other information in the header. The
982
     * 32-bit vsize field is not large enough to contain the size of variables
983
     * that require more than 2^32 - 4 bytes, so 2^32 - 1 is used in the vsize
984
     * field for such variables.
985
     */
986
58.1k
    vsize = varp->len;
987
58.1k
    if (varp->len > 4294967292UL && (psp->version == NC_FORMAT_CLASSIC ||
988
0
                                     psp->version == NC_FORMAT_64BIT_OFFSET))
989
0
        vsize = 4294967295UL; /* 2^32-1 */
990
58.1k
    status = v1h_put_size_t(psp, &vsize);
991
58.1k
    if(status != NC_NOERR) return status;
992
993
58.1k
  status = check_v1hs(psp, psp->version == 1 ? 4 : 8); /*begin*/
994
58.1k
    if(status != NC_NOERR)
995
0
     return status;
996
58.1k
  status = ncx_put_off_t(&psp->pos, &varp->begin, psp->version == 1 ? 4 : 8);
997
58.1k
    if(status != NC_NOERR)
998
0
    return status;
999
1000
58.1k
    return NC_NOERR;
1001
58.1k
}
1002
1003
1004
/* Read a NC_var from the header */
1005
static int
1006
v1h_get_NC_var(v1hs *gsp, NC_var **varpp)
1007
58.1k
{
1008
58.1k
  NC_string *strp;
1009
58.1k
  int status;
1010
58.1k
  size_t ndims;
1011
58.1k
  NC_var *varp;
1012
1013
58.1k
  status = v1h_get_NC_string(gsp, &strp);
1014
58.1k
    if(status != NC_NOERR)
1015
0
    return status;
1016
1017
58.1k
  status = v1h_get_size_t(gsp, &ndims);
1018
58.1k
    if(status != NC_NOERR)
1019
0
    goto unwind_name;
1020
1021
58.1k
  varp = new_x_NC_var(strp, ndims);
1022
58.1k
  if(varp == NULL)
1023
0
  {
1024
0
    status = NC_ENOMEM;
1025
0
    goto unwind_name;
1026
0
  }
1027
1028
58.1k
  if (gsp->version == 5) {
1029
0
    status = check_v1hs(gsp, ncx_len_int64(ndims));
1030
0
        if(status != NC_NOERR)
1031
0
      goto unwind_alloc;
1032
0
    status = ncx_getn_longlong_int((const void **)(&gsp->pos),
1033
0
        ndims, varp->dimids);
1034
0
        if(status != NC_NOERR)
1035
0
      goto unwind_alloc;
1036
0
  }
1037
58.1k
  else {
1038
58.1k
      status = check_v1hs(gsp, ncx_len_int(ndims));
1039
58.1k
        if(status != NC_NOERR)
1040
0
    goto unwind_alloc;
1041
58.1k
      status = ncx_getn_int_int((const void **)(&gsp->pos),
1042
58.1k
      ndims, varp->dimids);
1043
58.1k
        if(status != NC_NOERR)
1044
0
    goto unwind_alloc;
1045
58.1k
  }
1046
58.1k
  status = v1h_get_NC_attrarray(gsp, &varp->attrs);
1047
58.1k
    if(status != NC_NOERR)
1048
0
    goto unwind_alloc;
1049
58.1k
  status = v1h_get_nc_type(gsp, &varp->type);
1050
58.1k
    if(status != NC_NOERR)
1051
0
     goto unwind_alloc;
1052
1053
58.1k
    size_t tmp;
1054
58.1k
    status = v1h_get_size_t(gsp, &tmp);
1055
58.1k
    varp->len = tmp;
1056
58.1k
    if(status != NC_NOERR)
1057
0
     goto unwind_alloc;
1058
1059
58.1k
  status = check_v1hs(gsp, gsp->version == 1 ? 4 : 8);
1060
58.1k
    if(status != NC_NOERR)
1061
0
     goto unwind_alloc;
1062
58.1k
  status = ncx_get_off_t((const void **)&gsp->pos,
1063
58.1k
             &varp->begin, gsp->version == 1 ? 4 : 8);
1064
58.1k
    if(status != NC_NOERR)
1065
0
     goto unwind_alloc;
1066
1067
58.1k
  *varpp = varp;
1068
58.1k
    return NC_NOERR;
1069
1070
0
unwind_alloc:
1071
0
  free_NC_var(varp); /* frees name */
1072
0
  return status;
1073
1074
0
unwind_name:
1075
0
  free_NC_string(strp);
1076
0
  return status;
1077
58.1k
}
1078
1079
1080
/* How much space in the header is required for this NC_vararray? */
1081
static size_t
1082
ncx_len_NC_vararray(const NC_vararray *ncap, size_t sizeof_off_t, int version)
1083
30.0k
{
1084
30.0k
  size_t xlen = X_SIZEOF_NCTYPE; /* type */
1085
30.0k
  xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */
1086
30.0k
  if(ncap == NULL)
1087
0
    return xlen;
1088
  /* else */
1089
30.0k
  {
1090
30.0k
    const NC_var **vpp = (const NC_var **)ncap->value;
1091
30.0k
    const NC_var *const *const end = &vpp[ncap->nelems];
1092
146k
    for( /*NADA*/; vpp < end; vpp++)
1093
116k
    {
1094
116k
      xlen += ncx_len_NC_var(*vpp, sizeof_off_t, version);
1095
116k
    }
1096
30.0k
  }
1097
30.0k
  return xlen;
1098
30.0k
}
1099
1100
1101
/* Write a NC_vararray to the header */
1102
static int
1103
v1h_put_NC_vararray(v1hs *psp, const NC_vararray *ncap)
1104
20.0k
{
1105
20.0k
  int status;
1106
1107
20.0k
  assert(psp != NULL);
1108
1109
20.0k
  if(ncap == NULL
1110
20.0k
#if 1
1111
    /* Backward:
1112
     * This clause is for 'byte for byte'
1113
     * backward compatibility.
1114
     * Strickly speaking, it is 'bug for bug'.
1115
     */
1116
20.0k
    || ncap->nelems == 0
1117
20.0k
#endif
1118
20.0k
    )
1119
13.4k
  {
1120
    /*
1121
     * Handle empty netcdf
1122
     */
1123
13.4k
    const size_t nosz = 0;
1124
1125
13.4k
    status = v1h_put_NCtype(psp, NC_UNSPECIFIED);
1126
13.4k
        if(status != NC_NOERR)
1127
0
      return status;
1128
13.4k
    status = v1h_put_size_t(psp, &nosz);
1129
13.4k
        if(status != NC_NOERR)
1130
0
      return status;
1131
13.4k
        return NC_NOERR;
1132
13.4k
  }
1133
  /* else */
1134
1135
6.56k
  status = v1h_put_NCtype(psp, NC_VARIABLE);
1136
6.56k
    if(status != NC_NOERR)
1137
0
    return status;
1138
6.56k
  status = v1h_put_size_t(psp, &ncap->nelems);
1139
6.56k
    if(status != NC_NOERR)
1140
0
    return status;
1141
1142
6.56k
  {
1143
6.56k
    const NC_var **vpp = (const NC_var **)ncap->value;
1144
6.56k
    const NC_var *const *const end = &vpp[ncap->nelems];
1145
64.7k
    for( /*NADA*/; vpp < end; vpp++)
1146
58.1k
    {
1147
58.1k
      status = v1h_put_NC_var(psp, *vpp);
1148
58.1k
      if(status)
1149
0
        return status;
1150
58.1k
    }
1151
6.56k
  }
1152
6.56k
    return NC_NOERR;
1153
6.56k
}
1154
1155
1156
/* Read a NC_vararray from the header */
1157
static int
1158
v1h_get_NC_vararray(v1hs *gsp, NC_vararray *ncap)
1159
10.0k
{
1160
10.0k
  int status;
1161
10.0k
  NCtype type = NC_UNSPECIFIED;
1162
1163
10.0k
  assert(gsp != NULL && gsp->pos != NULL);
1164
10.0k
  assert(ncap != NULL);
1165
10.0k
  assert(ncap->value == NULL);
1166
1167
10.0k
  status = v1h_get_NCtype(gsp, &type);
1168
10.0k
    if(status != NC_NOERR)
1169
0
    return status;
1170
1171
10.0k
  status = v1h_get_size_t(gsp, &ncap->nelems);
1172
10.0k
    if(status != NC_NOERR)
1173
0
    return status;
1174
1175
10.0k
  if(ncap->nelems == 0)
1176
3.46k
        return NC_NOERR;
1177
  /* else */
1178
6.56k
  if(type != NC_VARIABLE)
1179
0
    return EINVAL;
1180
1181
6.56k
  ncap->value = (NC_var **) calloc(1,ncap->nelems * sizeof(NC_var *));
1182
6.56k
  if(ncap->value == NULL)
1183
0
    return NC_ENOMEM;
1184
6.56k
  ncap->nalloc = ncap->nelems;
1185
1186
6.56k
  ncap->hashmap = NC_hashmapnew(ncap->nelems);
1187
6.56k
  {
1188
6.56k
    NC_var **vpp = ncap->value;
1189
6.56k
    NC_var *const *const end = &vpp[ncap->nelems];
1190
64.7k
    for( /*NADA*/; vpp < end; vpp++)
1191
58.1k
    {
1192
58.1k
      status = v1h_get_NC_var(gsp, vpp);
1193
58.1k
      if(status)
1194
0
      {
1195
0
        ncap->nelems = (size_t)(vpp - ncap->value);
1196
0
        free_NC_vararrayV(ncap);
1197
0
        return status;
1198
0
      }
1199
58.1k
      {
1200
58.1k
        int varid = (size_t)(vpp - ncap->value);
1201
58.1k
        NC_hashmapadd(ncap->hashmap, (uintptr_t)varid, (*vpp)->name->cp,strlen((*vpp)->name->cp));
1202
58.1k
      }
1203
58.1k
    }
1204
6.56k
  }
1205
1206
6.56k
    return NC_NOERR;
1207
6.56k
}
1208
1209
1210
/* End NC_var */
1211
/* Begin NC */
1212
1213
/*
1214
 * Recompute the shapes of all variables
1215
 * Sets ncp->begin_var to start of first variable.
1216
 * Sets ncp->begin_rec to start of first record variable.
1217
 * Returns -1 on error. The only possible error is a reference
1218
 * to a non existent dimension, which could occur for a corrupted
1219
 * netcdf file.
1220
 */
1221
static int
1222
NC_computeshapes(NC3_INFO* ncp)
1223
10.0k
{
1224
10.0k
  NC_var **vpp = (NC_var **)ncp->vars.value;
1225
10.0k
  NC_var *const *const end = &vpp[ncp->vars.nelems];
1226
10.0k
  NC_var *first_var = NULL; /* first "non-record" var */
1227
10.0k
  NC_var *first_rec = NULL; /* first "record" var */
1228
10.0k
  int status;
1229
1230
10.0k
  ncp->begin_var = (off_t) ncp->xsz;
1231
10.0k
  ncp->begin_rec = (off_t) ncp->xsz;
1232
10.0k
  ncp->recsize = 0;
1233
1234
10.0k
  if(ncp->vars.nelems == 0)
1235
3.46k
    return(0);
1236
1237
64.7k
  for( /*NADA*/; vpp < end; vpp++)
1238
58.1k
  {
1239
58.1k
    status = NC_var_shape(*vpp, &ncp->dims);
1240
58.1k
        if(status != NC_NOERR)
1241
0
      return(status);
1242
1243
58.1k
      if(IS_RECVAR(*vpp))
1244
2.00k
    {
1245
2.00k
        if(first_rec == NULL)
1246
655
        first_rec = *vpp;
1247
2.00k
          ncp->recsize += (*vpp)->len;
1248
2.00k
    }
1249
56.1k
    else
1250
56.1k
    {
1251
56.1k
            if(first_var == NULL)
1252
6.47k
              first_var = *vpp;
1253
      /*
1254
       * Overwritten each time thru.
1255
       * Usually overwritten in first_rec != NULL clause below.
1256
       */
1257
56.1k
      ncp->begin_rec = (*vpp)->begin + (off_t)(*vpp)->len;
1258
56.1k
    }
1259
58.1k
  }
1260
1261
6.56k
  if(first_rec != NULL)
1262
655
  {
1263
655
    if(ncp->begin_rec > first_rec->begin)
1264
0
        return(NC_ENOTNC); /* not a netCDF file or corrupted */
1265
655
    ncp->begin_rec = first_rec->begin;
1266
    /*
1267
     * for special case of exactly one record variable, pack value
1268
     */
1269
655
    if(ncp->recsize == first_rec->len)
1270
445
      ncp->recsize = *first_rec->dsizes * first_rec->xsz;
1271
655
  }
1272
1273
6.56k
  if(first_var != NULL)
1274
6.47k
  {
1275
6.47k
    ncp->begin_var = first_var->begin;
1276
6.47k
  }
1277
90
  else
1278
90
  {
1279
90
    ncp->begin_var = ncp->begin_rec;
1280
90
  }
1281
1282
6.56k
  if(ncp->begin_var <= 0 ||
1283
6.56k
     ncp->xsz > (size_t)ncp->begin_var ||
1284
6.56k
     ncp->begin_rec <= 0 ||
1285
6.56k
     ncp->begin_var > ncp->begin_rec)
1286
0
      return(NC_ENOTNC); /* not a netCDF file or corrupted */
1287
1288
6.56k
    return(NC_NOERR);
1289
6.56k
}
1290
1291
/* How much space in the header is required for the NC data structure? */
1292
size_t
1293
ncx_len_NC(const NC3_INFO* ncp, size_t sizeof_off_t)
1294
30.0k
{
1295
30.0k
  int version=1;
1296
30.0k
  size_t xlen = sizeof(ncmagic);
1297
1298
30.0k
  assert(ncp != NULL);
1299
30.0k
  if (fIsSet(ncp->flags, NC_64BIT_DATA)) /* CDF-5 */
1300
0
    version = 5;
1301
30.0k
      else if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) /* CDF-2 */
1302
0
    version = 2;
1303
1304
30.0k
  xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* numrecs */
1305
30.0k
  xlen += ncx_len_NC_dimarray(&ncp->dims, version);
1306
30.0k
  xlen += ncx_len_NC_attrarray(&ncp->attrs, version);
1307
30.0k
  xlen += ncx_len_NC_vararray(&ncp->vars, sizeof_off_t, version);
1308
1309
30.0k
  return xlen;
1310
30.0k
}
1311
1312
1313
/* Write the file header */
1314
int
1315
ncx_put_NC(const NC3_INFO* ncp, void **xpp, off_t offset, size_t extent)
1316
20.0k
{
1317
20.0k
    int status = NC_NOERR;
1318
20.0k
  v1hs ps; /* the get stream */
1319
1320
20.0k
  assert(ncp != NULL);
1321
1322
  /* Initialize stream ps */
1323
1324
20.0k
  ps.nciop = ncp->nciop;
1325
20.0k
  ps.flags = RGN_WRITE;
1326
1327
20.0k
  if (ncp->flags & NC_64BIT_DATA)
1328
0
    ps.version = 5;
1329
20.0k
  else if (ncp->flags & NC_64BIT_OFFSET)
1330
0
    ps.version = 2;
1331
20.0k
  else
1332
20.0k
    ps.version = 1;
1333
1334
20.0k
  if(xpp == NULL)
1335
10.0k
  {
1336
    /*
1337
     * Come up with a reasonable stream read size.
1338
     */
1339
10.0k
    extent = ncp->xsz;
1340
10.0k
    if(extent <= ((ps.version==5)?MIN_NC5_XSZ:MIN_NC3_XSZ))
1341
987
    {
1342
      /* first time read */
1343
987
      extent = ncp->chunk;
1344
      /* Protection for when ncp->chunk is huge;
1345
       * no need to read hugely. */
1346
987
            if(extent > 4096)
1347
987
        extent = 4096;
1348
987
    }
1349
9.03k
    else if(extent > ncp->chunk)
1350
356
        extent = ncp->chunk;
1351
1352
10.0k
    ps.offset = 0;
1353
10.0k
    ps.extent = extent;
1354
10.0k
    ps.base = NULL;
1355
10.0k
    ps.pos = ps.base;
1356
1357
10.0k
    status = fault_v1hs(&ps, extent);
1358
10.0k
    if(status)
1359
0
      return status;
1360
10.0k
  }
1361
10.0k
  else
1362
10.0k
  {
1363
10.0k
    ps.offset = offset;
1364
10.0k
    ps.extent = extent;
1365
10.0k
    ps.base = *xpp;
1366
10.0k
    ps.pos = ps.base;
1367
10.0k
    ps.end = (char *)ps.base + ps.extent;
1368
10.0k
  }
1369
1370
20.0k
  if (ps.version == 5)
1371
0
    status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic5), ncmagic5, NULL);
1372
20.0k
  else if (ps.version == 2)
1373
0
    status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic), ncmagic, NULL);
1374
20.0k
  else
1375
20.0k
    status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic1), ncmagic1, NULL);
1376
20.0k
  if(status != NC_NOERR)
1377
0
    goto release;
1378
1379
20.0k
  {
1380
20.0k
  const size_t nrecs = NC_get_numrecs(ncp);
1381
20.0k
  if (ps.version == 5) {
1382
0
            unsigned long long tmp = (unsigned long long) nrecs;
1383
0
      status = ncx_put_uint64(&ps.pos, tmp);
1384
0
        }
1385
20.0k
        else
1386
20.0k
      status = ncx_put_size_t(&ps.pos, &nrecs);
1387
20.0k
  if(status != NC_NOERR)
1388
0
    goto release;
1389
20.0k
  }
1390
1391
20.0k
  assert((char *)ps.pos < (char *)ps.end);
1392
1393
20.0k
  status = v1h_put_NC_dimarray(&ps, &ncp->dims);
1394
20.0k
    if(status != NC_NOERR)
1395
0
    goto release;
1396
1397
20.0k
  status = v1h_put_NC_attrarray(&ps, &ncp->attrs);
1398
20.0k
    if(status != NC_NOERR)
1399
0
    goto release;
1400
1401
20.0k
  status = v1h_put_NC_vararray(&ps, &ncp->vars);
1402
20.0k
    if(status != NC_NOERR)
1403
0
    goto release;
1404
1405
20.0k
release:
1406
20.0k
  (void) rel_v1hs(&ps);
1407
1408
20.0k
  return status;
1409
20.0k
}
1410
1411
1412
/* Make the in-memory NC structure from reading the file header */
1413
int
1414
nc_get_NC(NC3_INFO* ncp)
1415
10.0k
{
1416
10.0k
  int status;
1417
10.0k
  v1hs gs; /* the get stream */
1418
1419
10.0k
  assert(ncp != NULL);
1420
1421
  /* Initialize stream gs */
1422
1423
10.0k
  gs.nciop = ncp->nciop;
1424
10.0k
  gs.offset = 0; /* beginning of file */
1425
10.0k
  gs.extent = 0;
1426
10.0k
  gs.flags = 0;
1427
10.0k
  gs.version = 0;
1428
10.0k
  gs.base = NULL;
1429
10.0k
  gs.pos = gs.base;
1430
1431
10.0k
  {
1432
    /*
1433
     * Come up with a reasonable stream read size.
1434
     */
1435
10.0k
          off_t filesize;
1436
10.0k
    size_t extent = ncp->xsz;
1437
1438
10.0k
    if(extent <= ((fIsSet(ncp->flags, NC_64BIT_DATA))?MIN_NC5_XSZ:MIN_NC3_XSZ))
1439
10.0k
    {
1440
10.0k
            status = ncio_filesize(ncp->nciop, &filesize);
1441
10.0k
      if(status)
1442
0
          return status;
1443
10.0k
      if(filesize < sizeof(ncmagic)) { /* too small, not netcdf */
1444
1445
0
          status = NC_ENOTNC;
1446
0
          return status;
1447
0
      }
1448
      /* first time read */
1449
10.0k
      extent = ncp->chunk;
1450
      /* Protection for when ncp->chunk is huge;
1451
       * no need to read hugely. */
1452
10.0k
            if(extent > 4096)
1453
10.0k
        extent = 4096;
1454
10.0k
      if(extent > filesize)
1455
7.06k
              extent = filesize;
1456
10.0k
    }
1457
0
    else if(extent > ncp->chunk)
1458
0
        extent = ncp->chunk;
1459
1460
    /*
1461
     * Invalidate the I/O buffers to force a read of the header
1462
     * region.
1463
     */
1464
10.0k
    status = ncio_sync(gs.nciop);
1465
10.0k
    if(status)
1466
0
      return status;
1467
1468
10.0k
    status = fault_v1hs(&gs, extent);
1469
10.0k
    if(status)
1470
0
      return status;
1471
10.0k
  }
1472
1473
  /* get the header from the stream gs */
1474
1475
10.0k
  {
1476
    /* Get & check magic number */
1477
10.0k
    schar magic[sizeof(ncmagic)];
1478
10.0k
    (void) memset(magic, 0, sizeof(magic));
1479
1480
10.0k
    status = ncx_getn_schar_schar(
1481
10.0k
      (const void **)(&gs.pos), sizeof(magic), magic);
1482
10.0k
        if(status != NC_NOERR)
1483
0
      goto unwind_get;
1484
1485
10.0k
    if(memcmp(magic, ncmagic, sizeof(ncmagic)-1) != 0)
1486
0
    {
1487
0
      status = NC_ENOTNC;
1488
0
      goto unwind_get;
1489
0
    }
1490
    /* Check version number in last byte of magic */
1491
10.0k
    if (magic[sizeof(ncmagic)-1] == 0x1) {
1492
10.0k
      gs.version = 1;
1493
10.0k
    } else if (magic[sizeof(ncmagic)-1] == 0x2) {
1494
0
      gs.version = 2;
1495
0
      fSet(ncp->flags, NC_64BIT_OFFSET);
1496
      /* Now we support version 2 file access on non-LFS systems -- rkr */
1497
#if 0
1498
      if (sizeof(off_t) != 8) {
1499
        fprintf(stderr, "NETCDF WARNING: Version 2 file on 32-bit system.\n");
1500
      }
1501
#endif
1502
0
    } else if (magic[sizeof(ncmagic)-1] == 0x5) {
1503
0
      gs.version = 5;
1504
0
      fSet(ncp->flags, NC_64BIT_DATA);
1505
0
    } else {
1506
0
      status = NC_ENOTNC;
1507
0
      goto unwind_get;
1508
0
    }
1509
10.0k
  }
1510
1511
10.0k
  {
1512
10.0k
  size_t nrecs = 0;
1513
10.0k
        if (gs.version == 5) {
1514
0
    unsigned long long tmp = 0;
1515
0
    status = ncx_get_uint64((const void **)(&gs.pos), &tmp);
1516
0
    nrecs = (size_t)tmp;
1517
0
        }
1518
10.0k
        else
1519
10.0k
      status = ncx_get_size_t((const void **)(&gs.pos), &nrecs);
1520
10.0k
    if(status != NC_NOERR)
1521
0
    goto unwind_get;
1522
10.0k
  NC_set_numrecs(ncp, nrecs);
1523
10.0k
  }
1524
1525
0
  assert((char *)gs.pos < (char *)gs.end);
1526
1527
10.0k
  status = v1h_get_NC_dimarray(&gs, &ncp->dims);
1528
10.0k
    if(status != NC_NOERR)
1529
0
    goto unwind_get;
1530
1531
10.0k
  status = v1h_get_NC_attrarray(&gs, &ncp->attrs);
1532
10.0k
    if(status != NC_NOERR)
1533
0
    goto unwind_get;
1534
1535
10.0k
  status = v1h_get_NC_vararray(&gs, &ncp->vars);
1536
10.0k
    if(status != NC_NOERR)
1537
0
    goto unwind_get;
1538
1539
10.0k
  ncp->xsz = ncx_len_NC(ncp, (gs.version == 1) ? 4 : 8);
1540
1541
10.0k
  status = NC_computeshapes(ncp);
1542
10.0k
    if(status != NC_NOERR)
1543
0
    goto unwind_get;
1544
1545
10.0k
  status = NC_check_vlens(ncp);
1546
10.0k
    if(status != NC_NOERR)
1547
0
    goto unwind_get;
1548
1549
10.0k
  status = NC_check_voffs(ncp);
1550
10.0k
    if(status != NC_NOERR)
1551
0
    goto unwind_get;
1552
1553
10.0k
unwind_get:
1554
10.0k
  (void) rel_v1hs(&gs);
1555
10.0k
  return status;
1556
10.0k
}