Coverage Report

Created: 2025-10-28 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/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
318k
{
27
318k
  if(dimp == NULL)
28
0
    return;
29
318k
  free_NC_string(dimp->name);
30
318k
  free(dimp);
31
318k
}
32
33
34
NC_dim *
35
new_x_NC_dim(NC_string *name)
36
318k
{
37
318k
  NC_dim *dimp;
38
39
318k
  dimp = (NC_dim *) malloc(sizeof(NC_dim));
40
318k
  if(dimp == NULL)
41
0
    return NULL;
42
43
318k
  dimp->name = name;
44
318k
  dimp->size = 0;
45
46
318k
  return(dimp);
47
318k
}
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
0
{
57
0
  NC_string *strp;
58
0
  NC_dim *dimp = NULL;
59
0
  int stat = NC_NOERR;
60
0
  char* name = NULL;
61
62
0
  stat = nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name);
63
0
  if(stat != NC_NOERR)
64
0
      goto done;
65
0
  strp = new_NC_string(strlen(name), name);
66
0
  if(strp == NULL)
67
0
    {stat = NC_ENOMEM; goto done;}
68
69
0
  dimp = new_x_NC_dim(strp);
70
0
  if(dimp == NULL)
71
0
  {
72
0
    free_NC_string(strp);
73
0
    goto done;
74
0
  }
75
76
0
  dimp->size = size;
77
78
0
done:
79
0
  if(name) free(name);
80
0
  return (dimp);
81
0
}
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
0
{
100
0
  assert(ncap != NULL);
101
102
0
  if(ncap->nelems == 0)
103
0
    return -1;
104
105
0
  {
106
0
  int dimid = 0;
107
0
  NC_dim **loc = ncap->value;
108
109
0
  for(; (size_t) dimid < ncap->nelems
110
0
       && (*loc)->size != NC_UNLIMITED; dimid++, loc++)
111
0
  {
112
    /*EMPTY*/
113
0
  }
114
0
  if(dimid >= ncap->nelems)
115
0
    return(-1); /* not found */
116
  /* else, normal return */
117
0
  if(dimpp != NULL)
118
0
    *dimpp = *loc;
119
0
  return dimid;
120
0
  }
121
0
}
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
0
{
133
0
   int dimid = -1;
134
0
   char *name = NULL;
135
0
   uintptr_t data;
136
137
0
   assert(ncap != NULL);
138
0
   if(ncap->nelems == 0)
139
0
  goto done;
140
   /* normalized version of uname */
141
0
  if(nc_utf8_normalize((const unsigned char *)uname,(unsigned char **)&name))
142
0
  goto done;  
143
0
  if(NC_hashmapget(ncap->hashmap, name, strlen(name), &data) == 0)
144
0
  goto done;
145
0
  dimid = (int)data;
146
0
  if(dimpp) *dimpp = ncap->value[dimid];
147
148
0
done:
149
0
   if(name) free(name);
150
0
   return dimid;
151
0
}
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
73
{
164
73
  assert(ncap != NULL);
165
166
73
  if(ncap->nelems == 0)
167
0
    return;
168
169
73
  assert(ncap->value != NULL);
170
171
73
  {
172
73
    NC_dim **dpp = ncap->value;
173
73
    NC_dim *const *const end = &dpp[ncap->nelems];
174
318k
    for( /*NADA*/; dpp < end; dpp++)
175
318k
    {
176
318k
      free_NC_dim(*dpp);
177
318k
      *dpp = NULL;
178
318k
    }
179
73
  }
180
73
  ncap->nelems = 0;
181
73
}
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
355
{
192
355
  assert(ncap != NULL);
193
194
355
  if(ncap->nalloc == 0)
195
282
    return;
196
197
73
  NC_hashmapfree(ncap->hashmap);
198
73
  ncap->hashmap = NULL;
199
200
73
  assert(ncap->value != NULL);
201
202
73
  free_NC_dimarrayV0(ncap);
203
204
73
  free(ncap->value);
205
73
  ncap->value = NULL;
206
73
  ncap->nalloc = 0;
207
73
}
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
    if(dpp != NULL)
232
0
    {
233
0
      const NC_dim **drpp = (const NC_dim **)ref->value;
234
0
      NC_dim *const *const end = &dpp[ref->nelems];
235
0
      for( /*NADA*/; dpp < end; drpp++, dpp++, ncap->nelems++)
236
0
      {
237
0
        *dpp = dup_NC_dim(*drpp);
238
0
        if(*dpp == NULL)
239
0
        {
240
0
          status = NC_ENOMEM;
241
0
          break;
242
0
        }
243
0
      }
244
0
    }
245
0
  }
246
247
0
  if(status != NC_NOERR)
248
0
  {
249
0
    free_NC_dimarrayV(ncap);
250
0
    return status;
251
0
  }
252
253
0
  assert(ncap->nelems == ref->nelems);
254
255
0
  return NC_NOERR;
256
0
}
257
258
259
/*
260
 * Add a new handle on the end of an array of handles
261
 * Formerly
262
NC_incr_array(array, tail)
263
 */
264
static int
265
incr_NC_dimarray(NC_dimarray *ncap, NC_dim *newelemp)
266
0
{
267
0
  NC_dim **vp;
268
269
0
  assert(ncap != NULL);
270
271
0
  if(ncap->nalloc == 0)
272
0
  {
273
0
    assert(ncap->nelems == 0);
274
0
    vp = (NC_dim **) malloc(NC_ARRAY_GROWBY * sizeof(NC_dim *));
275
0
    if(vp == NULL)
276
0
      return NC_ENOMEM;
277
0
    ncap->value = vp;
278
0
    ncap->nalloc = NC_ARRAY_GROWBY;
279
0
    ncap->hashmap = NC_hashmapnew(0);
280
0
  }
281
0
  else if(ncap->nelems +1 > ncap->nalloc)
282
0
  {
283
0
    vp = (NC_dim **) realloc(ncap->value,
284
0
      (ncap->nalloc + NC_ARRAY_GROWBY) * sizeof(NC_dim *));
285
0
    if(vp == NULL)
286
0
      return NC_ENOMEM;
287
0
    ncap->value = vp;
288
0
    ncap->nalloc += NC_ARRAY_GROWBY;
289
0
  }
290
291
0
  if(newelemp != NULL)
292
0
  {
293
0
           uintptr_t intdata = ncap->nelems;
294
0
     NC_hashmapadd(ncap->hashmap, intdata, newelemp->name->cp, strlen(newelemp->name->cp));
295
0
     ncap->value[ncap->nelems] = newelemp;
296
0
     ncap->nelems++;
297
0
  }
298
0
  return NC_NOERR;
299
0
}
300
301
302
NC_dim *
303
elem_NC_dimarray(const NC_dimarray *ncap, size_t elem)
304
0
{
305
0
  assert(ncap != NULL);
306
    /* cast needed for braindead systems with signed size_t */
307
0
  if(ncap->nelems == 0 || (unsigned long) elem >= ncap->nelems)
308
0
    return NULL;
309
310
0
  assert(ncap->value != NULL);
311
312
0
  return ncap->value[elem];
313
0
}
314
315
316
/* Public */
317
318
int
319
NC3_def_dim(int ncid, const char *name, size_t size, int *dimidp)
320
0
{
321
0
  int status;
322
0
  NC *nc;
323
0
  NC3_INFO* ncp;
324
0
  int dimid;
325
0
  NC_dim *dimp;
326
327
0
  status = NC_check_id(ncid, &nc);
328
0
  if(status != NC_NOERR)
329
0
    return status;
330
0
  ncp = NC3_DATA(nc);
331
332
0
  if(!NC_indef(ncp))
333
0
    return NC_ENOTINDEFINE;
334
335
0
  status = NC_check_name(name);
336
0
  if(status != NC_NOERR)
337
0
    return status;
338
339
0
  if(ncp->flags & NC_64BIT_DATA) {/*CDF-5*/
340
0
      if((sizeof(size_t) > 4) && (size > X_UINT64_MAX - 3)) /* "- 3" handles rounded-up size */
341
0
    return NC_EDIMSIZE;
342
0
  } else if(ncp->flags & NC_64BIT_OFFSET) {/* CDF2 format and LFS */
343
0
      if((sizeof(size_t) > 4) && (size > X_UINT_MAX - 3)) /* "- 3" handles rounded-up size */
344
0
    return NC_EDIMSIZE;
345
0
  } else {/*CDF-1*/
346
0
      if(size > X_INT_MAX - 3)
347
0
    return NC_EDIMSIZE;
348
0
  }
349
350
0
  if(size == NC_UNLIMITED)
351
0
  {
352
0
    dimid = find_NC_Udim(&ncp->dims, &dimp);
353
0
    if(dimid != -1)
354
0
    {
355
0
      assert(dimid != -1);
356
0
      return NC_EUNLIMIT;
357
0
    }
358
0
  }
359
360
0
  dimid = NC_finddim(&ncp->dims, name, &dimp);
361
0
  if(dimid != -1)
362
0
    return NC_ENAMEINUSE;
363
364
0
  dimp = new_NC_dim(name, size);
365
0
  if(dimp == NULL)
366
0
    return NC_ENOMEM;
367
0
  status = incr_NC_dimarray(&ncp->dims, dimp);
368
0
  if(status != NC_NOERR)
369
0
  {
370
0
    free_NC_dim(dimp);
371
0
    return status;
372
0
  }
373
374
0
  if(dimidp != NULL)
375
0
    *dimidp = (int)ncp->dims.nelems -1;
376
0
  return NC_NOERR;
377
0
}
378
379
380
int
381
NC3_inq_dimid(int ncid, const char *name, int *dimid_ptr)
382
0
{
383
0
  int status;
384
0
  NC *nc;
385
0
  NC3_INFO* ncp;
386
0
  int dimid;
387
388
0
  status = NC_check_id(ncid, &nc);
389
0
  if(status != NC_NOERR)
390
0
    return status;
391
0
  ncp = NC3_DATA(nc);
392
393
0
  dimid = NC_finddim(&ncp->dims, name, NULL);
394
395
0
  if(dimid == -1)
396
0
    return NC_EBADDIM;
397
398
0
  if (dimid_ptr)
399
0
     *dimid_ptr = dimid;
400
0
  return NC_NOERR;
401
0
}
402
403
int
404
NC3_inq_dim(int ncid, int dimid, char *name, size_t *sizep)
405
0
{
406
0
  int status;
407
0
  NC *nc;
408
0
  NC3_INFO* ncp;
409
0
  NC_dim *dimp;
410
411
0
  status = NC_check_id(ncid, &nc);
412
0
  if(status != NC_NOERR)
413
0
    return status;
414
0
  ncp = NC3_DATA(nc);
415
416
0
  dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid);
417
0
  if(dimp == NULL)
418
0
    return NC_EBADDIM;
419
420
0
  if(name != NULL)
421
0
  {
422
0
    (void)strncpy(name, dimp->name->cp,
423
0
      dimp->name->nchars);
424
0
    name[dimp->name->nchars] = 0;
425
0
  }
426
0
  if(sizep != NULL)
427
0
  {
428
0
    if(dimp->size == NC_UNLIMITED)
429
0
      *sizep = NC_get_numrecs(ncp);
430
0
    else
431
0
      *sizep = dimp->size;
432
0
  }
433
0
  return NC_NOERR;
434
0
}
435
436
int
437
NC3_rename_dim( int ncid, int dimid, const char *unewname)
438
0
{
439
0
  int status = NC_NOERR;
440
0
  NC *nc;
441
0
  NC3_INFO* ncp;
442
0
  int existid;
443
0
  NC_dim *dimp;
444
0
  char *newname = NULL; /* normalized */
445
0
  NC_string *old = NULL;
446
0
  uintptr_t intdata;
447
448
449
0
  status = NC_check_id(ncid, &nc);
450
0
  if(status != NC_NOERR)
451
0
    goto done;
452
0
  ncp = NC3_DATA(nc);
453
454
0
  if(NC_readonly(ncp))
455
0
    {status = NC_EPERM; goto done;}
456
457
0
  status = NC_check_name(unewname);
458
0
  if(status != NC_NOERR)
459
0
    goto done;
460
461
0
  existid = NC_finddim(&ncp->dims, unewname, &dimp);
462
0
  if(existid != -1)
463
0
    {status = NC_ENAMEINUSE; goto done;}
464
465
0
  dimp = elem_NC_dimarray(&ncp->dims, (size_t)dimid);
466
0
  if(dimp == NULL)
467
0
    {status = NC_EBADDIM; goto done;}
468
469
0
    old = dimp->name;
470
0
    status = nc_utf8_normalize((const unsigned char *)unewname,(unsigned char **)&newname);
471
0
    if(status != NC_NOERR)
472
0
  goto done;
473
0
    if(NC_indef(ncp))
474
0
  {
475
0
    NC_string *newStr = new_NC_string(strlen(newname), newname);
476
0
    if(newStr == NULL)
477
0
      {status = NC_ENOMEM; goto done;}
478
479
    /* Remove old name from hashmap; add new... */
480
0
          NC_hashmapremove(ncp->dims.hashmap, old->cp, strlen(old->cp), NULL);
481
0
    dimp->name = newStr;
482
483
0
    intdata = (uintptr_t)dimid;
484
0
    NC_hashmapadd(ncp->dims.hashmap, intdata, newStr->cp, strlen(newStr->cp));
485
0
    free_NC_string(old);
486
0
    goto done;
487
0
  }
488
489
  /* else, not in define mode */
490
491
  /* If new name is longer than old, then complain,
492
           but otherwise, no change (test is same as set_NC_string)*/
493
0
  if(dimp->name->nchars < strlen(newname)) {
494
0
      {status = NC_ENOTINDEFINE; goto done;}
495
0
  }
496
497
  /* Remove old name from hashmap; add new... */
498
  /* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
499
0
  NC_hashmapremove(ncp->dims.hashmap, old->cp, strlen(old->cp), NULL);
500
501
  /* WARNING: strlen(NC_string.cp) may be less than NC_string.nchars */
502
0
  status = set_NC_string(dimp->name, newname);
503
0
  if(status != NC_NOERR)
504
0
    goto done;
505
506
0
        intdata = (uintptr_t)dimid;
507
0
  NC_hashmapadd(ncp->dims.hashmap, intdata, dimp->name->cp, strlen(dimp->name->cp));
508
509
0
  set_NC_hdirty(ncp);
510
511
0
  if(NC_doHsync(ncp))
512
0
  {
513
0
    status = NC_sync(ncp);
514
0
    if(status != NC_NOERR)
515
0
      goto done;
516
0
  }
517
518
0
done:
519
0
  if(newname) free(newname);
520
0
  return status;
521
0
}