Coverage Report

Created: 2025-11-15 08:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/netcdf-c-4.7.4/libsrc/dim.c
Line
Count
Source
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
37.3k
{
27
37.3k
  if(dimp == NULL)
28
0
    return;
29
37.3k
  free_NC_string(dimp->name);
30
37.3k
  free(dimp);
31
37.3k
}
32
33
34
NC_dim *
35
new_x_NC_dim(NC_string *name)
36
37.3k
{
37
37.3k
  NC_dim *dimp;
38
39
37.3k
  dimp = (NC_dim *) malloc(sizeof(NC_dim));
40
37.3k
  if(dimp == NULL)
41
0
    return NULL;
42
43
37.3k
  dimp->name = name;
44
37.3k
  dimp->size = 0;
45
46
37.3k
  return(dimp);
47
37.3k
}
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
18.6k
{
57
18.6k
  NC_string *strp;
58
18.6k
  NC_dim *dimp = NULL;
59
18.6k
  int stat = NC_NOERR;
60
18.6k
  char* name = NULL;
61
62
18.6k
  stat = nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name);
63
18.6k
  if(stat != NC_NOERR)
64
0
      goto done;
65
18.6k
  strp = new_NC_string(strlen(name), name);
66
18.6k
  if(strp == NULL)
67
0
    {stat = NC_ENOMEM; goto done;}
68
69
18.6k
  dimp = new_x_NC_dim(strp);
70
18.6k
  if(dimp == NULL)
71
0
  {
72
0
    free_NC_string(strp);
73
0
    goto done;
74
0
  }
75
76
18.6k
  dimp->size = size;
77
78
18.6k
done:
79
18.6k
  if(name) free(name);
80
18.6k
  return (dimp);
81
18.6k
}
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
76.9k
{
100
76.9k
  assert(ncap != NULL);
101
102
76.9k
  if(ncap->nelems == 0)
103
6.89k
    return -1;
104
105
70.1k
  {
106
70.1k
  int dimid = 0;
107
70.1k
  NC_dim **loc = ncap->value;
108
109
125k
  for(; (size_t) dimid < ncap->nelems
110
120k
       && (*loc)->size != NC_UNLIMITED; dimid++, loc++)
111
55.7k
  {
112
    /*EMPTY*/
113
55.7k
  }
114
70.1k
  if(dimid >= ncap->nelems)
115
4.88k
    return(-1); /* not found */
116
  /* else, normal return */
117
65.2k
  if(dimpp != NULL)
118
60.3k
    *dimpp = *loc;
119
65.2k
  return dimid;
120
70.1k
  }
121
70.1k
}
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
39.1k
{
133
39.1k
   int dimid = -1;
134
39.1k
   char *name = NULL;
135
39.1k
   uintptr_t data;
136
137
39.1k
   assert(ncap != NULL);
138
39.1k
   if(ncap->nelems == 0)
139
7.08k
  goto done;
140
   /* normalized version of uname */
141
32.0k
  if(nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name))
142
0
  goto done;  
143
32.0k
  if(NC_hashmapget(ncap->hashmap, name, strlen(name), &data) == 0)
144
11.5k
  goto done;
145
20.4k
  dimid = (int)data;
146
20.4k
  if(dimpp) *dimpp = ncap->value[dimid];
147
148
39.1k
done:
149
39.1k
   if(name) free(name);
150
39.1k
   return dimid;
151
20.4k
}
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
14.1k
{
164
14.1k
  assert(ncap != NULL);
165
166
14.1k
  if(ncap->nelems == 0)
167
0
    return;
168
169
14.1k
  assert(ncap->value != NULL);
170
171
14.1k
  {
172
14.1k
    NC_dim **dpp = ncap->value;
173
14.1k
    NC_dim *const *const end = &dpp[ncap->nelems];
174
51.4k
    for( /*NADA*/; dpp < end; dpp++)
175
37.3k
    {
176
37.3k
      free_NC_dim(*dpp);
177
37.3k
      *dpp = NULL;
178
37.3k
    }
179
14.1k
  }
180
14.1k
  ncap->nelems = 0;
181
14.1k
}
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
21.7k
{
192
21.7k
  assert(ncap != NULL);
193
194
21.7k
  if(ncap->nalloc == 0)
195
7.57k
    return;
196
197
14.1k
  NC_hashmapfree(ncap->hashmap);
198
14.1k
  ncap->hashmap = NULL;
199
200
14.1k
  assert(ncap->value != NULL);
201
202
14.1k
  free_NC_dimarrayV0(ncap);
203
204
14.1k
  free(ncap->value);
205
14.1k
  ncap->value = NULL;
206
14.1k
  ncap->nalloc = 0;
207
14.1k
}
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
18.6k
{
264
18.6k
  NC_dim **vp;
265
266
18.6k
  assert(ncap != NULL);
267
268
18.6k
  if(ncap->nalloc == 0)
269
7.08k
  {
270
7.08k
    assert(ncap->nelems == 0);
271
7.08k
    vp = (NC_dim **) malloc(NC_ARRAY_GROWBY * sizeof(NC_dim *));
272
7.08k
    if(vp == NULL)
273
0
      return NC_ENOMEM;
274
7.08k
    ncap->value = vp;
275
7.08k
    ncap->nalloc = NC_ARRAY_GROWBY;
276
7.08k
    ncap->hashmap = NC_hashmapnew(0);
277
7.08k
  }
278
11.5k
  else if(ncap->nelems +1 > ncap->nalloc)
279
1.12k
  {
280
1.12k
    vp = (NC_dim **) realloc(ncap->value,
281
1.12k
      (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_dim *));
282
1.12k
    if(vp == NULL)
283
0
      return NC_ENOMEM;
284
1.12k
    ncap->value = vp;
285
1.12k
    ncap->nalloc += NC_ARRAY_GROWBY;
286
1.12k
  }
287
288
18.6k
  if(newelemp != NULL)
289
18.6k
  {
290
18.6k
           uintptr_t intdata = ncap->nelems;
291
18.6k
     NC_hashmapadd(ncap->hashmap, intdata, newelemp->name->cp, strlen(newelemp->name->cp));
292
18.6k
     ncap->value[ncap->nelems] = newelemp;
293
18.6k
     ncap->nelems++;
294
18.6k
  }
295
18.6k
  return NC_NOERR;
296
18.6k
}
297
298
299
NC_dim *
300
elem_NC_dimarray(const NC_dimarray *ncap, size_t elem)
301
1.62M
{
302
1.62M
  assert(ncap != NULL);
303
    /* cast needed for braindead systems with signed size_t */
304
1.62M
  if(ncap->nelems == 0 || (unsigned long) elem >= ncap->nelems)
305
0
    return NULL;
306
307
1.62M
  assert(ncap->value != NULL);
308
309
1.62M
  return ncap->value[elem];
310
1.62M
}
311
312
313
/* Public */
314
315
int
316
NC3_def_dim(int ncid, const char *name, size_t size, int *dimidp)
317
145k
{
318
145k
  int status;
319
145k
  NC *nc;
320
145k
  NC3_INFO* ncp;
321
145k
  int dimid;
322
145k
  NC_dim *dimp;
323
324
145k
  status = NC_check_id(ncid, &nc);
325
145k
  if(status != NC_NOERR)
326
0
    return status;
327
145k
  ncp = NC3_DATA(nc);
328
329
145k
  if(!NC_indef(ncp))
330
0
    return NC_ENOTINDEFINE;
331
332
145k
  status = NC_check_name(name);
333
145k
  if(status != NC_NOERR)
334
45.9k
    return status;
335
336
99.5k
  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
99.5k
  } 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
99.5k
  } else {/*CDF-1*/
343
99.5k
      if(size > X_INT_MAX - 3)
344
0
    return NC_EDIMSIZE;
345
99.5k
  }
346
347
99.5k
  if(size == NC_UNLIMITED)
348
66.1k
  {
349
66.1k
    dimid = find_NC_Udim(&ncp->dims, &dimp);
350
66.1k
    if(dimid != -1)
351
60.3k
    {
352
60.3k
      assert(dimid != -1);
353
60.3k
      return NC_EUNLIMIT;
354
60.3k
    }
355
66.1k
  }
356
357
39.1k
  dimid = NC_finddim(&ncp->dims, name, &dimp);
358
39.1k
  if(dimid != -1)
359
20.4k
    return NC_ENAMEINUSE;
360
361
18.6k
  dimp = new_NC_dim(name, size);
362
18.6k
  if(dimp == NULL)
363
0
    return NC_ENOMEM;
364
18.6k
  status = incr_NC_dimarray(&ncp->dims, dimp);
365
18.6k
  if(status != NC_NOERR)
366
0
  {
367
0
    free_NC_dim(dimp);
368
0
    return status;
369
0
  }
370
371
18.6k
  if(dimidp != NULL)
372
18.6k
    *dimidp = (int)ncp->dims.nelems -1;
373
18.6k
  return NC_NOERR;
374
18.6k
}
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.53M
{
403
1.53M
  int status;
404
1.53M
  NC *nc;
405
1.53M
  NC3_INFO* ncp;
406
1.53M
  NC_dim *dimp;
407
408
1.53M
  status = NC_check_id(ncid, &nc);
409
1.53M
  if(status != NC_NOERR)
410
0
    return status;
411
1.53M
  ncp = NC3_DATA(nc);
412
413
1.53M
  dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid);
414
1.53M
  if(dimp == NULL)
415
0
    return NC_EBADDIM;
416
417
1.53M
  if(name != NULL)
418
10.5k
  {
419
10.5k
    (void)strncpy(name, dimp->name->cp,
420
10.5k
      dimp->name->nchars);
421
10.5k
    name[dimp->name->nchars] = 0;
422
10.5k
  }
423
1.53M
  if(sizep != NULL)
424
1.52M
  {
425
1.52M
    if(dimp->size == NC_UNLIMITED)
426
318
      *sizep = NC_get_numrecs(ncp);
427
1.52M
    else
428
1.52M
      *sizep = dimp->size;
429
1.52M
  }
430
1.53M
  return NC_NOERR;
431
1.53M
}
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
}