/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 | } |