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