Coverage Report

Created: 2025-06-09 07:43

/src/gdal/netcdf-c-4.7.4/libsrc/dim.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
/* $Id: dim.c,v 1.83 2010/05/25 17:54:15 dmh Exp $ */
6
7
#if HAVE_CONFIG_H
8
#include <config.h>
9
#endif
10
11
#include "nc3internal.h"
12
#include <stdlib.h>
13
#include <string.h>
14
#include <assert.h>
15
#include "ncx.h"
16
#include "fbits.h"
17
#include "ncutf8.h"
18
19
/*
20
 * Free dim
21
 * Formerly
22
NC_free_dim(dim)
23
 */
24
void
25
free_NC_dim(NC_dim *dimp)
26
2.99k
{
27
2.99k
  if(dimp == NULL)
28
0
    return;
29
2.99k
  free_NC_string(dimp->name);
30
2.99k
  free(dimp);
31
2.99k
}
32
33
34
NC_dim *
35
new_x_NC_dim(NC_string *name)
36
2.99k
{
37
2.99k
  NC_dim *dimp;
38
39
2.99k
  dimp = (NC_dim *) malloc(sizeof(NC_dim));
40
2.99k
  if(dimp == NULL)
41
0
    return NULL;
42
43
2.99k
  dimp->name = name;
44
2.99k
  dimp->size = 0;
45
46
2.99k
  return(dimp);
47
2.99k
}
48
49
50
/*
51
 * Formerly
52
NC_new_dim(const char *uname, long size)
53
 */
54
static NC_dim *
55
new_NC_dim(const char *uname, size_t size)
56
1.49k
{
57
1.49k
  NC_string *strp;
58
1.49k
  NC_dim *dimp = NULL;
59
1.49k
  int stat = NC_NOERR;
60
1.49k
  char* name = NULL;
61
62
1.49k
  stat = nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name);
63
1.49k
  if(stat != NC_NOERR)
64
0
      goto done;
65
1.49k
  strp = new_NC_string(strlen(name), name);
66
1.49k
  if(strp == NULL)
67
0
    {stat = NC_ENOMEM; goto done;}
68
69
1.49k
  dimp = new_x_NC_dim(strp);
70
1.49k
  if(dimp == NULL)
71
0
  {
72
0
    free_NC_string(strp);
73
0
    goto done;
74
0
  }
75
76
1.49k
  dimp->size = size;
77
78
1.49k
done:
79
1.49k
  if(name) free(name);
80
1.49k
  return (dimp);
81
1.49k
}
82
83
84
static NC_dim *
85
dup_NC_dim(const NC_dim *dimp)
86
0
{
87
0
  return new_NC_dim(dimp->name->cp, dimp->size);
88
0
}
89
90
/*
91
 * Step thru NC_DIMENSION array, seeking the UNLIMITED dimension.
92
 * Return dimid or -1 on not found.
93
 * *dimpp is set to the appropriate NC_dim.
94
 * The loop structure is odd. In order to parallelize,
95
 * we moved a clearer 'break' inside the loop body to the loop test.
96
 */
97
int
98
find_NC_Udim(const NC_dimarray *ncap, NC_dim **dimpp)
99
3.11k
{
100
3.11k
  assert(ncap != NULL);
101
102
3.11k
  if(ncap->nelems == 0)
103
223
    return -1;
104
105
2.89k
  {
106
2.89k
  int dimid = 0;
107
2.89k
  NC_dim **loc = ncap->value;
108
109
4.60k
  for(; (size_t) dimid < ncap->nelems
110
4.60k
       && (*loc)->size != NC_UNLIMITED; dimid++, loc++)
111
1.70k
  {
112
    /*EMPTY*/
113
1.70k
  }
114
2.89k
  if(dimid >= ncap->nelems)
115
382
    return(-1); /* not found */
116
  /* else, normal return */
117
2.51k
  if(dimpp != NULL)
118
2.27k
    *dimpp = *loc;
119
2.51k
  return dimid;
120
2.89k
  }
121
2.89k
}
122
123
/*
124
 * Step thru NC_DIMENSION array, seeking match on uname.
125
 * Return dimid or -1 on not found.
126
 * *dimpp is set to the appropriate NC_dim.
127
 * The loop structure is odd. In order to parallelize,
128
 * we moved a clearer 'break' inside the loop body to the loop test.
129
 */
130
static int
131
NC_finddim(const NC_dimarray *ncap, const char *uname, NC_dim **dimpp)
132
2.56k
{
133
2.56k
   int dimid = -1;
134
2.56k
   char *name = NULL;
135
2.56k
   uintptr_t data;
136
137
2.56k
   assert(ncap != NULL);
138
2.56k
   if(ncap->nelems == 0)
139
459
  goto done;
140
   /* normalized version of uname */
141
2.11k
  if(nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name))
142
0
  goto done;  
143
2.11k
  if(NC_hashmapget(ncap->hashmap, name, strlen(name), &data) == 0)
144
1.03k
  goto done;
145
1.07k
  dimid = (int)data;
146
1.07k
  if(dimpp) *dimpp = ncap->value[dimid];
147
148
2.56k
done:
149
2.56k
   if(name) free(name);
150
2.56k
   return dimid;
151
1.07k
}
152
153
154
/* dimarray */
155
156
157
/*
158
 * Free the stuff "in" (referred to by) an NC_dimarray.
159
 * Leaves the array itself allocated.
160
 */
161
void
162
free_NC_dimarrayV0(NC_dimarray *ncap)
163
918
{
164
918
  assert(ncap != NULL);
165
166
918
  if(ncap->nelems == 0)
167
0
    return;
168
169
918
  assert(ncap->value != NULL);
170
171
918
  {
172
918
    NC_dim **dpp = ncap->value;
173
918
    NC_dim *const *const end = &dpp[ncap->nelems];
174
3.91k
    for( /*NADA*/; dpp < end; dpp++)
175
2.99k
    {
176
2.99k
      free_NC_dim(*dpp);
177
2.99k
      *dpp = NULL;
178
2.99k
    }
179
918
  }
180
918
  ncap->nelems = 0;
181
918
}
182
183
184
/*
185
 * Free NC_dimarray values.
186
 * formerly
187
NC_free_array()
188
 */
189
void
190
free_NC_dimarrayV(NC_dimarray *ncap)
191
970
{
192
970
  assert(ncap != NULL);
193
194
970
  if(ncap->nalloc == 0)
195
52
    return;
196
197
918
  NC_hashmapfree(ncap->hashmap);
198
918
  ncap->hashmap = NULL;
199
200
918
  assert(ncap->value != NULL);
201
202
918
  free_NC_dimarrayV0(ncap);
203
204
918
  free(ncap->value);
205
918
  ncap->value = NULL;
206
918
  ncap->nalloc = 0;
207
918
}
208
209
210
int
211
dup_NC_dimarrayV(NC_dimarray *ncap, const NC_dimarray *ref)
212
0
{
213
0
  int status = NC_NOERR;
214
215
0
  assert(ref != NULL);
216
0
  assert(ncap != NULL);
217
218
0
  if(ref->nelems != 0)
219
0
  {
220
0
    const size_t sz = ref->nelems * sizeof(NC_dim *);
221
0
    ncap->value = (NC_dim **) malloc(sz);
222
0
    if(ncap->value == NULL)
223
0
      return NC_ENOMEM;
224
0
    (void) memset(ncap->value, 0, sz);
225
0
    ncap->nalloc = ref->nelems;
226
0
  }
227
228
0
  ncap->nelems = 0;
229
0
  {
230
0
    NC_dim **dpp = ncap->value;
231
0
    const NC_dim **drpp = (const NC_dim **)ref->value;
232
0
    NC_dim *const *const end = &dpp[ref->nelems];
233
0
    for( /*NADA*/; dpp < end; drpp++, dpp++, ncap->nelems++)
234
0
    {
235
0
      *dpp = dup_NC_dim(*drpp);
236
0
      if(*dpp == NULL)
237
0
      {
238
0
        status = NC_ENOMEM;
239
0
        break;
240
0
      }
241
0
    }
242
0
  }
243
244
0
  if(status != NC_NOERR)
245
0
  {
246
0
    free_NC_dimarrayV(ncap);
247
0
    return status;
248
0
  }
249
250
0
  assert(ncap->nelems == ref->nelems);
251
252
0
  return NC_NOERR;
253
0
}
254
255
256
/*
257
 * Add a new handle on the end of an array of handles
258
 * Formerly
259
NC_incr_array(array, tail)
260
 */
261
static int
262
incr_NC_dimarray(NC_dimarray *ncap, NC_dim *newelemp)
263
1.49k
{
264
1.49k
  NC_dim **vp;
265
266
1.49k
  assert(ncap != NULL);
267
268
1.49k
  if(ncap->nalloc == 0)
269
459
  {
270
459
    assert(ncap->nelems == 0);
271
459
    vp = (NC_dim **) malloc(NC_ARRAY_GROWBY * sizeof(NC_dim *));
272
459
    if(vp == NULL)
273
0
      return NC_ENOMEM;
274
459
    ncap->value = vp;
275
459
    ncap->nalloc = NC_ARRAY_GROWBY;
276
459
    ncap->hashmap = NC_hashmapnew(0);
277
459
  }
278
1.03k
  else if(ncap->nelems +1 > ncap->nalloc)
279
120
  {
280
120
    vp = (NC_dim **) realloc(ncap->value,
281
120
      (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_dim *));
282
120
    if(vp == NULL)
283
0
      return NC_ENOMEM;
284
120
    ncap->value = vp;
285
120
    ncap->nalloc += NC_ARRAY_GROWBY;
286
120
  }
287
288
1.49k
  if(newelemp != NULL)
289
1.49k
  {
290
1.49k
           uintptr_t intdata = ncap->nelems;
291
1.49k
     NC_hashmapadd(ncap->hashmap, intdata, newelemp->name->cp, strlen(newelemp->name->cp));
292
1.49k
     ncap->value[ncap->nelems] = newelemp;
293
1.49k
     ncap->nelems++;
294
1.49k
  }
295
1.49k
  return NC_NOERR;
296
1.49k
}
297
298
299
NC_dim *
300
elem_NC_dimarray(const NC_dimarray *ncap, size_t elem)
301
5.45k
{
302
5.45k
  assert(ncap != NULL);
303
    /* cast needed for braindead systems with signed size_t */
304
5.45k
  if(ncap->nelems == 0 || (unsigned long) elem >= ncap->nelems)
305
0
    return NULL;
306
307
5.45k
  assert(ncap->value != NULL);
308
309
5.45k
  return ncap->value[elem];
310
5.45k
}
311
312
313
/* Public */
314
315
int
316
NC3_def_dim(int ncid, const char *name, size_t size, int *dimidp)
317
6.20k
{
318
6.20k
  int status;
319
6.20k
  NC *nc;
320
6.20k
  NC3_INFO* ncp;
321
6.20k
  int dimid;
322
6.20k
  NC_dim *dimp;
323
324
6.20k
  status = NC_check_id(ncid, &nc);
325
6.20k
  if(status != NC_NOERR)
326
0
    return status;
327
6.20k
  ncp = NC3_DATA(nc);
328
329
6.20k
  if(!NC_indef(ncp))
330
0
    return NC_ENOTINDEFINE;
331
332
6.20k
  status = NC_check_name(name);
333
6.20k
  if(status != NC_NOERR)
334
1.36k
    return status;
335
336
4.83k
  if(ncp->flags & NC_64BIT_DATA) {/*CDF-5*/
337
0
      if((sizeof(size_t) > 4) && (size > X_UINT64_MAX - 3)) /* "- 3" handles rounded-up size */
338
0
    return NC_EDIMSIZE;
339
4.83k
  } else if(ncp->flags & NC_64BIT_OFFSET) {/* CDF2 format and LFS */
340
0
      if((sizeof(size_t) > 4) && (size > X_UINT_MAX - 3)) /* "- 3" handles rounded-up size */
341
0
    return NC_EDIMSIZE;
342
4.83k
  } else {/*CDF-1*/
343
4.83k
      if(size > X_INT_MAX - 3)
344
0
    return NC_EDIMSIZE;
345
4.83k
  }
346
347
4.83k
  if(size == NC_UNLIMITED)
348
2.63k
  {
349
2.63k
    dimid = find_NC_Udim(&ncp->dims, &dimp);
350
2.63k
    if(dimid != -1)
351
2.27k
    {
352
2.27k
      assert(dimid != -1);
353
2.27k
      return NC_EUNLIMIT;
354
2.27k
    }
355
2.63k
  }
356
357
2.56k
  dimid = NC_finddim(&ncp->dims, name, &dimp);
358
2.56k
  if(dimid != -1)
359
1.07k
    return NC_ENAMEINUSE;
360
361
1.49k
  dimp = new_NC_dim(name, size);
362
1.49k
  if(dimp == NULL)
363
0
    return NC_ENOMEM;
364
1.49k
  status = incr_NC_dimarray(&ncp->dims, dimp);
365
1.49k
  if(status != NC_NOERR)
366
0
  {
367
0
    free_NC_dim(dimp);
368
0
    return status;
369
0
  }
370
371
1.49k
  if(dimidp != NULL)
372
1.49k
    *dimidp = (int)ncp->dims.nelems -1;
373
1.49k
  return NC_NOERR;
374
1.49k
}
375
376
377
int
378
NC3_inq_dimid(int ncid, const char *name, int *dimid_ptr)
379
0
{
380
0
  int status;
381
0
  NC *nc;
382
0
  NC3_INFO* ncp;
383
0
  int dimid;
384
385
0
  status = NC_check_id(ncid, &nc);
386
0
  if(status != NC_NOERR)
387
0
    return status;
388
0
  ncp = NC3_DATA(nc);
389
390
0
  dimid = NC_finddim(&ncp->dims, name, NULL);
391
392
0
  if(dimid == -1)
393
0
    return NC_EBADDIM;
394
395
0
  if (dimid_ptr)
396
0
     *dimid_ptr = dimid;
397
0
  return NC_NOERR;
398
0
}
399
400
int
401
NC3_inq_dim(int ncid, int dimid, char *name, size_t *sizep)
402
1.43k
{
403
1.43k
  int status;
404
1.43k
  NC *nc;
405
1.43k
  NC3_INFO* ncp;
406
1.43k
  NC_dim *dimp;
407
408
1.43k
  status = NC_check_id(ncid, &nc);
409
1.43k
  if(status != NC_NOERR)
410
0
    return status;
411
1.43k
  ncp = NC3_DATA(nc);
412
413
1.43k
  dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid);
414
1.43k
  if(dimp == NULL)
415
0
    return NC_EBADDIM;
416
417
1.43k
  if(name != NULL)
418
763
  {
419
763
    (void)strncpy(name, dimp->name->cp,
420
763
      dimp->name->nchars);
421
763
    name[dimp->name->nchars] = 0;
422
763
  }
423
1.43k
  if(sizep != NULL)
424
675
  {
425
675
    if(dimp->size == NC_UNLIMITED)
426
109
      *sizep = NC_get_numrecs(ncp);
427
566
    else
428
566
      *sizep = dimp->size;
429
675
  }
430
1.43k
  return NC_NOERR;
431
1.43k
}
432
433
int
434
NC3_rename_dim( int ncid, int dimid, const char *unewname)
435
0
{
436
0
  int status = NC_NOERR;
437
0
  NC *nc;
438
0
  NC3_INFO* ncp;
439
0
  int existid;
440
0
  NC_dim *dimp;
441
0
  char *newname = NULL; /* normalized */
442
0
  NC_string *old = NULL;
443
0
  uintptr_t intdata;
444
445
446
0
  status = NC_check_id(ncid, &nc);
447
0
  if(status != NC_NOERR)
448
0
    goto done;
449
0
  ncp = NC3_DATA(nc);
450
451
0
  if(NC_readonly(ncp))
452
0
    {status = NC_EPERM; goto done;}
453
454
0
  status = NC_check_name(unewname);
455
0
  if(status != NC_NOERR)
456
0
    goto done;
457
458
0
  existid = NC_finddim(&ncp->dims, unewname, &dimp);
459
0
  if(existid != -1)
460
0
    {status = NC_ENAMEINUSE; goto done;}
461
462
0
  dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid);
463
0
  if(dimp == NULL)
464
0
    {status = NC_EBADDIM; goto done;}
465
466
0
    old = dimp->name;
467
0
    status = nc_utf8_normalize((const unsigned char *)unewname,(unsigned char **)&newname);
468
0
    if(status != NC_NOERR)
469
0
  goto done;
470
0
    if(NC_indef(ncp))
471
0
  {
472
0
    NC_string *newStr = new_NC_string(strlen(newname), newname);
473
0
    if(newStr == NULL)
474
0
      {status = NC_ENOMEM; goto done;}
475
476
    /* Remove old name from hashmap; add new... */
477
0
          NC_hashmapremove(ncp->dims.hashmap, old->cp, strlen(old->cp), NULL);
478
0
    dimp->name = newStr;
479
480
0
    intdata = dimid;
481
0
    NC_hashmapadd(ncp->dims.hashmap, intdata, newStr->cp, strlen(newStr->cp));
482
0
    free_NC_string(old);
483
0
    goto done;
484
0
  }
485
486
  /* else, not in define mode */
487
488
  /* If new name is longer than old, then complain,
489
           but otherwise, no change (test is same as set_NC_string)*/
490
0
  if(dimp->name->nchars < strlen(newname)) {
491
0
      {status = NC_ENOTINDEFINE; goto done;}
492
0
  }
493
494
  /* Remove old name from hashmap; add new... */
495
  /* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
496
0
  NC_hashmapremove(ncp->dims.hashmap, old->cp, strlen(old->cp), NULL);
497
498
  /* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
499
0
  status = set_NC_string(dimp->name, newname);
500
0
  if(status != NC_NOERR)
501
0
    goto done;
502
503
0
        intdata = (uintptr_t)dimid;
504
0
  NC_hashmapadd(ncp->dims.hashmap, intdata, dimp->name->cp, strlen(dimp->name->cp));
505
506
0
  set_NC_hdirty(ncp);
507
508
0
  if(NC_doHsync(ncp))
509
0
  {
510
0
    status = NC_sync(ncp);
511
0
    if(status != NC_NOERR)
512
0
      goto done;
513
0
  }
514
515
0
done:
516
0
  if(newname) free(newname);
517
0
  return status;
518
0
}