/src/netcdf-c/libsrc/v1hpg.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 |  |  | 
| 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 | 4.99k | { | 
| 68 | 4.99k |   int status; | 
| 69 | 4.99k |   if(gsp->offset == OFF_NONE || gsp->base == NULL) | 
| 70 | 200 |         return NC_NOERR; | 
| 71 | 4.79k |   status = ncio_rel(gsp->nciop, gsp->offset, | 
| 72 | 4.79k |        gsp->flags == RGN_WRITE ? RGN_MODIFIED : 0); | 
| 73 | 4.79k |   gsp->end = NULL; | 
| 74 | 4.79k |   gsp->pos = NULL; | 
| 75 | 4.79k |   gsp->base = NULL; | 
| 76 | 4.79k |   return status; | 
| 77 | 4.99k | } | 
| 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 | 4.99k | { | 
| 87 | 4.99k |   int status; | 
| 88 |  |  | 
| 89 | 4.99k |   if(gsp->base != NULL) | 
| 90 | 4.70k |   { | 
| 91 | 4.70k |     const ptrdiff_t incr = (char *)gsp->pos - (char *)gsp->base; | 
| 92 | 4.70k |     status = rel_v1hs(gsp); | 
| 93 | 4.70k |     if(status) | 
| 94 | 0 |       return status; | 
| 95 | 4.70k |     gsp->offset += incr; | 
| 96 | 4.70k |   } | 
| 97 |  |  | 
| 98 | 4.99k |   if(extent > gsp->extent) | 
| 99 | 397 |     gsp->extent = extent; | 
| 100 |  |  | 
| 101 | 4.99k |   status = ncio_get(gsp->nciop, | 
| 102 | 4.99k |       gsp->offset, gsp->extent, | 
| 103 | 4.99k |       gsp->flags, &gsp->base); | 
| 104 | 4.99k |   if(status) | 
| 105 | 200 |     return status; | 
| 106 |  |  | 
| 107 | 4.79k |   gsp->pos = gsp->base; | 
| 108 |  |  | 
| 109 | 4.79k |   gsp->end = (char *)gsp->base + gsp->extent; | 
| 110 | 4.79k |     return NC_NOERR; | 
| 111 | 4.99k | } | 
| 112 |  |  | 
| 113 |  |  | 
| 114 |  | /* | 
| 115 |  |  * Ensure that 'nextread' bytes are available. | 
| 116 |  |  */ | 
| 117 |  | static int | 
| 118 |  | check_v1hs(v1hs *gsp, size_t nextread) | 
| 119 | 2.37M | { | 
| 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.37M |     if((char *)gsp->pos + nextread <= (char *)gsp->end) | 
| 127 | 2.37M |   return NC_NOERR; | 
| 128 |  |  | 
| 129 | 4.70k |     return fault_v1hs(gsp, nextread); | 
| 130 | 2.37M | } | 
| 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 | 0 | { | 
| 138 | 0 |   int status; | 
| 139 | 0 |   if (psp->version == 5) /* all integers in CDF-5 are 64 bits */ | 
| 140 | 0 |     status = check_v1hs(psp, X_SIZEOF_INT64); | 
| 141 | 0 |   else | 
| 142 | 0 |     status = check_v1hs(psp, X_SIZEOF_SIZE_T); | 
| 143 | 0 |   if(status != NC_NOERR) | 
| 144 | 0 |     return status; | 
| 145 | 0 |         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 | 0 |         else | 
| 150 | 0 |       return ncx_put_size_t(&psp->pos, sp); | 
| 151 | 0 | } | 
| 152 |  |  | 
| 153 |  | /* Read a size_t from the header */ | 
| 154 |  | static int | 
| 155 |  | v1h_get_size_t(v1hs *gsp, size_t *sp) | 
| 156 | 1.26M | { | 
| 157 | 1.26M |   int status; | 
| 158 | 1.26M |   if (gsp->version == 5) /* all integers in CDF-5 are 64 bits */ | 
| 159 | 279k |     status = check_v1hs(gsp, X_SIZEOF_INT64); | 
| 160 | 982k |   else | 
| 161 | 982k |     status = check_v1hs(gsp, X_SIZEOF_SIZE_T); | 
| 162 | 1.26M |   if(status != NC_NOERR) | 
| 163 | 65 |     return status; | 
| 164 | 1.26M |         if (gsp->version == 5) { | 
| 165 | 279k |     unsigned long long tmp=0; | 
| 166 | 279k |     status = ncx_get_uint64((const void **)(&gsp->pos), &tmp); | 
| 167 | 279k |     *sp = (size_t)tmp; | 
| 168 | 279k |     return status; | 
| 169 | 279k |         } | 
| 170 | 982k |         else | 
| 171 | 982k |       return ncx_get_size_t((const void **)(&gsp->pos), sp); | 
| 172 | 1.26M | } | 
| 173 |  |  | 
| 174 |  | /* Begin nc_type */ | 
| 175 |  |  | 
| 176 | 819 | #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 | 0 | { | 
| 182 | 0 |     const unsigned int itype = (unsigned int) *typep; | 
| 183 | 0 |     int status = check_v1hs(psp, X_SIZEOF_INT); | 
| 184 | 0 |     if(status != NC_NOERR) return status; | 
| 185 | 0 |     status =  ncx_put_uint32(&psp->pos, itype); | 
| 186 | 0 |     return status; | 
| 187 | 0 | } | 
| 188 |  |  | 
| 189 |  |  | 
| 190 |  | /* Read a nc_type from the header */ | 
| 191 |  | static int | 
| 192 |  | v1h_get_nc_type(v1hs *gsp, nc_type *typep) | 
| 193 | 169k | { | 
| 194 | 169k |     unsigned int type = 0; | 
| 195 | 169k |     int status = check_v1hs(gsp, X_SIZEOF_INT); | 
| 196 | 169k |     if(status != NC_NOERR) return status; | 
| 197 | 169k |     status =  ncx_get_uint32((const void**)(&gsp->pos), &type); | 
| 198 | 169k |     if(status != NC_NOERR) | 
| 199 | 0 |     return status; | 
| 200 |  | /* Fix 35382 | 
| 201 |  |   assert(type == NC_BYTE | 
| 202 |  |     || type == NC_CHAR | 
| 203 |  |     || type == NC_SHORT | 
| 204 |  |     || type == NC_INT | 
| 205 |  |     || type == NC_FLOAT | 
| 206 |  |     || type == NC_DOUBLE | 
| 207 |  |     || type == NC_UBYTE | 
| 208 |  |     || type == NC_USHORT | 
| 209 |  |     || type == NC_UINT | 
| 210 |  |     || type == NC_INT64 | 
| 211 |  |     || type == NC_UINT64 | 
| 212 |  |     || type == NC_STRING); | 
| 213 |  | */ | 
| 214 | 169k |     if(type == NC_NAT || type > NC_MAX_ATOMIC_TYPE) | 
| 215 | 17 |         return NC_EINVAL; | 
| 216 | 169k |     else | 
| 217 | 169k |   *typep = (nc_type) type; | 
| 218 |  |  | 
| 219 | 169k |     return NC_NOERR; | 
| 220 | 169k | } | 
| 221 |  |  | 
| 222 |  | /* End nc_type */ | 
| 223 |  | /* Begin NCtype (internal tags) */ | 
| 224 |  |  | 
| 225 | 876 | #define X_SIZEOF_NCTYPE X_SIZEOF_INT | 
| 226 |  |  | 
| 227 |  | /* Write a NCtype to the header */ | 
| 228 |  | static int | 
| 229 |  | v1h_put_NCtype(v1hs *psp, NCtype type) | 
| 230 | 0 | { | 
| 231 | 0 |     const unsigned int itype = (unsigned int) type; | 
| 232 | 0 |     int status = check_v1hs(psp, X_SIZEOF_INT); | 
| 233 | 0 |     if(status != NC_NOERR) return status; | 
| 234 | 0 |     status = ncx_put_uint32(&psp->pos, itype); | 
| 235 | 0 |     return status; | 
| 236 | 0 | } | 
| 237 |  |  | 
| 238 |  | /* Read a NCtype from the header */ | 
| 239 |  | static int | 
| 240 |  | v1h_get_NCtype(v1hs *gsp, NCtype *typep) | 
| 241 | 143k | { | 
| 242 | 143k |     unsigned int type = 0; | 
| 243 | 143k |     int status = check_v1hs(gsp, X_SIZEOF_INT); | 
| 244 | 143k |     if(status != NC_NOERR) return status; | 
| 245 | 143k |     status =  ncx_get_uint32((const void**)(&gsp->pos), &type); | 
| 246 | 143k |     if(status != NC_NOERR) return status; | 
| 247 |  |     /* else */ | 
| 248 | 143k |     *typep = (NCtype) type; | 
| 249 | 143k |     return NC_NOERR; | 
| 250 | 143k | } | 
| 251 |  |  | 
| 252 |  | /* End NCtype */ | 
| 253 |  | /* Begin NC_string */ | 
| 254 |  |  | 
| 255 |  | /* | 
| 256 |  |  * How much space will the xdr'd string take. | 
| 257 |  |  * Formerly | 
| 258 |  | NC_xlen_string(cdfstr) | 
| 259 |  |  */ | 
| 260 |  | static size_t | 
| 261 |  | ncx_len_NC_string(const NC_string *ncstrp, int version) | 
| 262 | 1.32k | { | 
| 263 | 1.32k |   size_t sz = (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_INT; /* nchars */ | 
| 264 |  |  | 
| 265 | 1.32k |   assert(ncstrp != NULL); | 
| 266 |  |  | 
| 267 | 1.32k |   if(ncstrp->nchars != 0) | 
| 268 | 372 |   { | 
| 269 |  | #if 0 | 
| 270 |  |     assert(ncstrp->nchars % X_ALIGN == 0); | 
| 271 |  |     sz += ncstrp->nchars; | 
| 272 |  | #else | 
| 273 | 372 |     sz += _RNDUP(ncstrp->nchars, X_ALIGN); | 
| 274 | 372 | #endif | 
| 275 | 372 |   } | 
| 276 | 1.32k |   return sz; | 
| 277 | 1.32k | } | 
| 278 |  |  | 
| 279 |  |  | 
| 280 |  | /* Write a NC_string to the header */ | 
| 281 |  | static int | 
| 282 |  | v1h_put_NC_string(v1hs *psp, const NC_string *ncstrp) | 
| 283 | 0 | { | 
| 284 | 0 |   int status; | 
| 285 |  | 
 | 
| 286 |  | #if 0 | 
| 287 |  |   assert(ncstrp->nchars % X_ALIGN == 0); | 
| 288 |  | #endif | 
| 289 |  | 
 | 
| 290 | 0 |   status = v1h_put_size_t(psp, &ncstrp->nchars); | 
| 291 | 0 |     if(status != NC_NOERR) | 
| 292 | 0 |     return status; | 
| 293 | 0 |   status = check_v1hs(psp, _RNDUP(ncstrp->nchars, X_ALIGN)); | 
| 294 | 0 |     if(status != NC_NOERR) | 
| 295 | 0 |     return status; | 
| 296 | 0 |   status = ncx_pad_putn_text(&psp->pos, ncstrp->nchars, ncstrp->cp); | 
| 297 | 0 |     if(status != NC_NOERR) | 
| 298 | 0 |     return status; | 
| 299 |  |  | 
| 300 | 0 |     return NC_NOERR; | 
| 301 | 0 | } | 
| 302 |  |  | 
| 303 |  |  | 
| 304 |  | /* Read a NC_string from the header */ | 
| 305 |  | static int | 
| 306 |  | v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp) | 
| 307 | 488k | { | 
| 308 | 488k |   int status = 0; | 
| 309 | 488k |   size_t nchars = 0; | 
| 310 | 488k |   NC_string *ncstrp = NULL; | 
| 311 |  | #if USE_STRICT_NULL_BYTE_HEADER_PADDING | 
| 312 |  |         size_t padding = 0;         | 
| 313 |  | #endif /* USE_STRICT_NULL_BYTE_HEADER_PADDING */ | 
| 314 |  |  | 
| 315 | 488k |   status = v1h_get_size_t(gsp, &nchars); | 
| 316 | 488k |   if(status != NC_NOERR) | 
| 317 | 24 |     return status; | 
| 318 |  |  | 
| 319 | 488k |   ncstrp = new_NC_string(nchars, NULL); | 
| 320 | 488k |   if(ncstrp == NULL) | 
| 321 | 10 |   { | 
| 322 | 10 |     return NC_ENOMEM; | 
| 323 | 10 |   } | 
| 324 |  |  | 
| 325 |  | #if 0 | 
| 326 |  | /* assert(ncstrp->nchars == nchars || ncstrp->nchars - nchars < X_ALIGN); */ | 
| 327 |  |   assert(ncstrp->nchars % X_ALIGN == 0); | 
| 328 |  |   status = check_v1hs(gsp, ncstrp->nchars); | 
| 329 |  | #else | 
| 330 |  |  | 
| 331 | 488k |   status = check_v1hs(gsp, _RNDUP(ncstrp->nchars, X_ALIGN)); | 
| 332 | 488k | #endif | 
| 333 | 488k |   if(status != NC_NOERR) | 
| 334 | 44 |     goto unwind_alloc; | 
| 335 |  |  | 
| 336 | 488k |   status = ncx_pad_getn_text((const void **)(&gsp->pos), | 
| 337 | 488k |      nchars, ncstrp->cp); | 
| 338 | 488k |   if(status != NC_NOERR) | 
| 339 | 0 |     goto unwind_alloc; | 
| 340 |  |  | 
| 341 |  | #if USE_STRICT_NULL_BYTE_HEADER_PADDING | 
| 342 |  |   padding = _RNDUP(X_SIZEOF_CHAR * ncstrp->nchars, X_ALIGN) | 
| 343 |  |     - X_SIZEOF_CHAR * ncstrp->nchars; | 
| 344 |  |  | 
| 345 |  |   if (padding > 0) { | 
| 346 |  |     /* CDF specification: Header padding uses null (\x00) bytes. */ | 
| 347 |  |     char pad[X_ALIGN-1]; | 
| 348 |  |     memset(pad, 0, X_ALIGN-1); | 
| 349 |  |     if (memcmp((char*)gsp->pos-padding, pad, padding) != 0) { | 
| 350 |  |       free_NC_string(ncstrp); | 
| 351 |  |       return NC_ENULLPAD; | 
| 352 |  |     } | 
| 353 |  |   } | 
| 354 |  | #endif | 
| 355 |  |  | 
| 356 | 488k |   *ncstrpp = ncstrp; | 
| 357 |  |  | 
| 358 | 488k |   return NC_NOERR; | 
| 359 |  |  | 
| 360 | 44 | unwind_alloc: | 
| 361 | 44 |   free_NC_string(ncstrp); | 
| 362 | 44 |   return status; | 
| 363 | 488k | } | 
| 364 |  |  | 
| 365 |  | /* End NC_string */ | 
| 366 |  | /* Begin NC_dim */ | 
| 367 |  |  | 
| 368 |  | /* | 
| 369 |  |  * How much space will the xdr'd dim take. | 
| 370 |  |  * Formerly | 
| 371 |  | NC_xlen_dim(dpp) | 
| 372 |  |  */ | 
| 373 |  | static size_t | 
| 374 |  | ncx_len_NC_dim(const NC_dim *dimp, int version) | 
| 375 | 510 | { | 
| 376 | 510 |   size_t sz; | 
| 377 |  |  | 
| 378 | 510 |   assert(dimp != NULL); | 
| 379 |  |  | 
| 380 | 510 |   sz = ncx_len_NC_string(dimp->name, version); | 
| 381 | 510 |   sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; | 
| 382 |  |  | 
| 383 | 510 |   return(sz); | 
| 384 | 510 | } | 
| 385 |  |  | 
| 386 |  |  | 
| 387 |  | /* Write a NC_dim to the header */ | 
| 388 |  | static int | 
| 389 |  | v1h_put_NC_dim(v1hs *psp, const NC_dim *dimp) | 
| 390 | 0 | { | 
| 391 | 0 |   int status; | 
| 392 |  | 
 | 
| 393 | 0 |   status = v1h_put_NC_string(psp, dimp->name); | 
| 394 | 0 |     if(status != NC_NOERR) | 
| 395 | 0 |     return status; | 
| 396 |  |  | 
| 397 | 0 |   status = v1h_put_size_t(psp, &dimp->size); | 
| 398 | 0 |     if(status != NC_NOERR) | 
| 399 | 0 |     return status; | 
| 400 |  |  | 
| 401 | 0 |     return NC_NOERR; | 
| 402 | 0 | } | 
| 403 |  |  | 
| 404 |  | /* Read a NC_dim from the header */ | 
| 405 |  | static int | 
| 406 |  | v1h_get_NC_dim(v1hs *gsp, NC_dim **dimpp) | 
| 407 | 318k | { | 
| 408 | 318k |   int status; | 
| 409 | 318k |   NC_string *ncstrp; | 
| 410 | 318k |   NC_dim *dimp; | 
| 411 |  |  | 
| 412 | 318k |   status = v1h_get_NC_string(gsp, &ncstrp); | 
| 413 | 318k |     if(status != NC_NOERR) | 
| 414 | 49 |     return status; | 
| 415 |  |  | 
| 416 | 318k |   dimp = new_x_NC_dim(ncstrp); | 
| 417 | 318k |   if(dimp == NULL) | 
| 418 | 0 |   { | 
| 419 | 0 |     status = NC_ENOMEM; | 
| 420 | 0 |     goto unwind_name; | 
| 421 | 0 |   } | 
| 422 |  |  | 
| 423 | 318k |   status = v1h_get_size_t(gsp, &dimp->size); | 
| 424 | 318k |     if(status != NC_NOERR) | 
| 425 | 15 |   { | 
| 426 | 15 |     free_NC_dim(dimp); /* frees name */ | 
| 427 | 15 |     return status; | 
| 428 | 15 |   } | 
| 429 |  |  | 
| 430 | 318k |   *dimpp = dimp; | 
| 431 |  |  | 
| 432 | 318k |     return NC_NOERR; | 
| 433 |  |  | 
| 434 | 0 | unwind_name: | 
| 435 | 0 |   free_NC_string(ncstrp); | 
| 436 | 0 |   return status; | 
| 437 | 318k | } | 
| 438 |  |  | 
| 439 |  |  | 
| 440 |  | /* How much space in the header is required for this NC_dimarray? */ | 
| 441 |  | static size_t | 
| 442 |  | ncx_len_NC_dimarray(const NC_dimarray *ncap, int version) | 
| 443 | 19 | { | 
| 444 | 19 |   size_t xlen = X_SIZEOF_NCTYPE; /* type */ | 
| 445 | 19 |   xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */ | 
| 446 | 19 |   if(ncap == NULL) | 
| 447 | 0 |     return xlen; | 
| 448 |  |   /* else */ | 
| 449 | 19 |   { | 
| 450 | 19 |     const NC_dim **dpp = (const NC_dim **)ncap->value; | 
| 451 | 19 |     if (dpp) | 
| 452 | 2 |     { | 
| 453 | 2 |       const NC_dim *const *const end = &dpp[ncap->nelems]; | 
| 454 | 512 |       for(  /*NADA*/; dpp < end; dpp++) | 
| 455 | 510 |       { | 
| 456 | 510 |         xlen += ncx_len_NC_dim(*dpp,version); | 
| 457 | 510 |       } | 
| 458 | 2 |     } | 
| 459 | 19 |   } | 
| 460 | 19 |   return xlen; | 
| 461 | 19 | } | 
| 462 |  |  | 
| 463 |  |  | 
| 464 |  | /* Write a NC_dimarray to the header */ | 
| 465 |  | static int | 
| 466 |  | v1h_put_NC_dimarray(v1hs *psp, const NC_dimarray *ncap) | 
| 467 | 0 | { | 
| 468 | 0 |   int status; | 
| 469 |  | 
 | 
| 470 | 0 |   assert(psp != NULL); | 
| 471 |  | 
 | 
| 472 | 0 |   if(ncap == NULL | 
| 473 | 0 | #if 1 | 
| 474 |  |     /* Backward: | 
| 475 |  |      * This clause is for 'byte for byte' | 
| 476 |  |      * backward compatibility. | 
| 477 |  |      * Strickly speaking, it is 'bug for bug'. | 
| 478 |  |      */ | 
| 479 | 0 |     || ncap->nelems == 0 | 
| 480 | 0 | #endif | 
| 481 | 0 |     ) | 
| 482 | 0 |   { | 
| 483 |  |     /* | 
| 484 |  |      * Handle empty netcdf | 
| 485 |  |      */ | 
| 486 | 0 |     const size_t nosz = 0; | 
| 487 |  | 
 | 
| 488 | 0 |     status = v1h_put_NCtype(psp, NC_UNSPECIFIED); | 
| 489 | 0 |         if(status != NC_NOERR) | 
| 490 | 0 |       return status; | 
| 491 | 0 |     status = v1h_put_size_t(psp, &nosz); | 
| 492 | 0 |         if(status != NC_NOERR) | 
| 493 | 0 |       return status; | 
| 494 | 0 |         return NC_NOERR; | 
| 495 | 0 |   } | 
| 496 |  |   /* else */ | 
| 497 |  |  | 
| 498 | 0 |   status = v1h_put_NCtype(psp, NC_DIMENSION); | 
| 499 | 0 |     if(status != NC_NOERR) | 
| 500 | 0 |     return status; | 
| 501 | 0 |   status = v1h_put_size_t(psp, &ncap->nelems); | 
| 502 | 0 |     if(status != NC_NOERR) | 
| 503 | 0 |     return status; | 
| 504 |  |  | 
| 505 | 0 |   { | 
| 506 | 0 |     const NC_dim **dpp = (const NC_dim **)ncap->value; | 
| 507 | 0 |     const NC_dim *const *const end = &dpp[ncap->nelems]; | 
| 508 | 0 |     for( /*NADA*/; dpp < end; dpp++) | 
| 509 | 0 |     { | 
| 510 | 0 |       status = v1h_put_NC_dim(psp, *dpp); | 
| 511 | 0 |       if(status) | 
| 512 | 0 |         return status; | 
| 513 | 0 |     } | 
| 514 | 0 |   } | 
| 515 | 0 |     return NC_NOERR; | 
| 516 | 0 | } | 
| 517 |  |  | 
| 518 |  |  | 
| 519 |  | /* Read a NC_dimarray from the header */ | 
| 520 |  | static int | 
| 521 |  | v1h_get_NC_dimarray(v1hs *gsp, NC_dimarray *ncap) | 
| 522 | 291 | { | 
| 523 | 291 |   int status; | 
| 524 | 291 |   NCtype type = NC_UNSPECIFIED; | 
| 525 |  |  | 
| 526 | 291 |   assert(gsp != NULL && gsp->pos != NULL); | 
| 527 | 291 |   assert(ncap != NULL); | 
| 528 | 291 |   assert(ncap->value == NULL); | 
| 529 |  |  | 
| 530 | 291 |   status = v1h_get_NCtype(gsp, &type); | 
| 531 | 291 |     if(status != NC_NOERR) | 
| 532 | 0 |     return status; | 
| 533 |  |  | 
| 534 | 291 |   status = v1h_get_size_t(gsp, &ncap->nelems); | 
| 535 | 291 |     if(status != NC_NOERR) | 
| 536 | 0 |     return status; | 
| 537 |  |  | 
| 538 | 291 |   if(ncap->nelems == 0) | 
| 539 | 208 |         return NC_NOERR; | 
| 540 |  |   /* else */ | 
| 541 | 83 |   if(type != NC_DIMENSION) | 
| 542 | 10 |     return EINVAL; | 
| 543 |  |  | 
| 544 | 73 |   if (ncap->nelems > SIZE_MAX / sizeof(NC_dim *)) | 
| 545 | 0 |     return NC_ERANGE; | 
| 546 | 73 |   ncap->value = (NC_dim **) calloc(1,ncap->nelems * sizeof(NC_dim *)); | 
| 547 | 73 |   if(ncap->value == NULL) | 
| 548 | 0 |     return NC_ENOMEM; | 
| 549 | 73 |   ncap->nalloc = ncap->nelems; | 
| 550 |  |  | 
| 551 | 73 |   ncap->hashmap = NC_hashmapnew(ncap->nelems); | 
| 552 |  |  | 
| 553 | 73 |   { | 
| 554 | 73 |     NC_dim **dpp = ncap->value; | 
| 555 | 73 |     NC_dim *const *const end = &dpp[ncap->nelems]; | 
| 556 | 318k |     for( /*NADA*/; dpp < end; dpp++) | 
| 557 | 318k |     { | 
| 558 | 318k |       status = v1h_get_NC_dim(gsp, dpp); | 
| 559 | 318k |       if(status) | 
| 560 | 64 |       { | 
| 561 | 64 |         ncap->nelems = (size_t)(dpp - ncap->value); | 
| 562 | 64 |         free_NC_dimarrayV(ncap); | 
| 563 | 64 |         return status; | 
| 564 | 64 |       } | 
| 565 | 318k |       { | 
| 566 | 318k |         uintptr_t dimid = (uintptr_t)(dpp - ncap->value); | 
| 567 | 318k |         NC_hashmapadd(ncap->hashmap, dimid, (*dpp)->name->cp, strlen((*dpp)->name->cp)); | 
| 568 | 318k |       } | 
| 569 | 318k |     } | 
| 570 | 73 |   } | 
| 571 |  |  | 
| 572 | 9 |     return NC_NOERR; | 
| 573 | 73 | } | 
| 574 |  |  | 
| 575 |  |  | 
| 576 |  | /* End NC_dim */ | 
| 577 |  | /* Begin NC_attr */ | 
| 578 |  |  | 
| 579 |  |  | 
| 580 |  | /* | 
| 581 |  |  * How much space will 'attrp' take in external representation? | 
| 582 |  |  * Formerly | 
| 583 |  | NC_xlen_attr(app) | 
| 584 |  |  */ | 
| 585 |  | static size_t | 
| 586 |  | ncx_len_NC_attr(const NC_attr *attrp, int version) | 
| 587 | 0 | { | 
| 588 | 0 |   size_t sz; | 
| 589 |  | 
 | 
| 590 | 0 |   assert(attrp != NULL); | 
| 591 |  | 
 | 
| 592 | 0 |   sz = ncx_len_NC_string(attrp->name, version); | 
| 593 | 0 |   sz += X_SIZEOF_NC_TYPE; /* type */ | 
| 594 | 0 |   sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* nelems */ | 
| 595 | 0 |   sz += attrp->xsz; | 
| 596 |  | 
 | 
| 597 | 0 |   return(sz); | 
| 598 | 0 | } | 
| 599 |  |  | 
| 600 |  |  | 
| 601 |  | #undef MIN | 
| 602 | 28.2k | #define MIN(mm,nn) (((mm) < (nn)) ? (mm) : (nn)) | 
| 603 |  |  | 
| 604 |  | /*----< ncmpix_len_nctype() >------------------------------------------------*/ | 
| 605 |  | /* return the length of external data type */ | 
| 606 |  | static size_t | 
| 607 | 0 | ncmpix_len_nctype(nc_type type) { | 
| 608 | 0 |     switch(type) { | 
| 609 | 0 |         case NC_BYTE: | 
| 610 | 0 |         case NC_CHAR: | 
| 611 | 0 |         case NC_UBYTE:  return X_SIZEOF_CHAR; | 
| 612 | 0 |         case NC_SHORT:  return X_SIZEOF_SHORT; | 
| 613 | 0 |         case NC_USHORT: return X_SIZEOF_USHORT; | 
| 614 | 0 |         case NC_INT:    return X_SIZEOF_INT; | 
| 615 | 0 |         case NC_UINT:   return X_SIZEOF_UINT; | 
| 616 | 0 |         case NC_FLOAT:  return X_SIZEOF_FLOAT; | 
| 617 | 0 |         case NC_DOUBLE: return X_SIZEOF_DOUBLE; | 
| 618 | 0 |         case NC_INT64:  return X_SIZEOF_INT64; | 
| 619 | 0 |         case NC_UINT64: return X_SIZEOF_UINT64; | 
| 620 | 0 |         default: fprintf(stderr,"ncmpix_len_nctype bad type %d\n",type); | 
| 621 | 0 |                  assert(0); | 
| 622 | 0 |     } | 
| 623 | 0 |     return 0; | 
| 624 | 0 | } | 
| 625 |  |  | 
| 626 |  | /* | 
| 627 |  |  * Put the values of an attribute | 
| 628 |  |  * The loop is necessary since attrp->nelems | 
| 629 |  |  * could potentially be quite large. | 
| 630 |  |  */ | 
| 631 |  | static int | 
| 632 |  | v1h_put_NC_attrV(v1hs *psp, const NC_attr *attrp) | 
| 633 | 0 | { | 
| 634 | 0 |   int status = 0; | 
| 635 | 0 |   const size_t perchunk =  psp->extent; | 
| 636 | 0 |   size_t remaining = attrp->xsz; | 
| 637 | 0 |   void *value = attrp->xvalue; | 
| 638 | 0 |   size_t nbytes = 0, padding = 0; | 
| 639 |  | 
 | 
| 640 | 0 |   assert(psp->extent % X_ALIGN == 0); | 
| 641 |  | 
 | 
| 642 | 0 |   do { | 
| 643 | 0 |     nbytes = MIN(perchunk, remaining); | 
| 644 |  | 
 | 
| 645 | 0 |     status = check_v1hs(psp, nbytes); | 
| 646 | 0 |     if(status != NC_NOERR) | 
| 647 | 0 |       return status; | 
| 648 |  |  | 
| 649 | 0 |     if (value) { | 
| 650 | 0 |       (void) memcpy(psp->pos, value, nbytes); | 
| 651 | 0 |       value = (void *)((char *)value + nbytes); | 
| 652 | 0 |     } | 
| 653 |  |      | 
| 654 | 0 |     psp->pos = (void *)((char *)psp->pos + nbytes); | 
| 655 | 0 |     remaining -= nbytes; | 
| 656 |  | 
 | 
| 657 | 0 |   } while(remaining != 0); | 
| 658 |  |  | 
| 659 |  |  | 
| 660 | 0 |   padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems; | 
| 661 | 0 |   if (padding > 0) { | 
| 662 |  |     /* CDF specification: Header padding uses null (\x00) bytes. */ | 
| 663 | 0 |     memset((char*)psp->pos-padding, 0, padding); | 
| 664 | 0 |   } | 
| 665 |  | 
 | 
| 666 | 0 |   return NC_NOERR; | 
| 667 | 0 | } | 
| 668 |  |  | 
| 669 |  | /* Write a NC_attr to the header */ | 
| 670 |  | static int | 
| 671 |  | v1h_put_NC_attr(v1hs *psp, const NC_attr *attrp) | 
| 672 | 0 | { | 
| 673 | 0 |   int status; | 
| 674 |  | 
 | 
| 675 | 0 |   status = v1h_put_NC_string(psp, attrp->name); | 
| 676 | 0 |     if(status != NC_NOERR) | 
| 677 | 0 |     return status; | 
| 678 |  |  | 
| 679 | 0 |   status = v1h_put_nc_type(psp, &attrp->type); | 
| 680 | 0 |     if(status != NC_NOERR) | 
| 681 | 0 |     return status; | 
| 682 |  |  | 
| 683 | 0 |   status = v1h_put_size_t(psp, &attrp->nelems); | 
| 684 | 0 |     if(status != NC_NOERR) | 
| 685 | 0 |     return status; | 
| 686 |  |  | 
| 687 | 0 |   status = v1h_put_NC_attrV(psp, attrp); | 
| 688 | 0 |     if(status != NC_NOERR) | 
| 689 | 0 |     return status; | 
| 690 |  |  | 
| 691 | 0 |     return NC_NOERR; | 
| 692 | 0 | } | 
| 693 |  |  | 
| 694 |  |  | 
| 695 |  | /* | 
| 696 |  |  * Get the values of an attribute | 
| 697 |  |  * The loop is necessary since attrp->nelems | 
| 698 |  |  * could potentially be quite large. | 
| 699 |  |  */ | 
| 700 |  | static int | 
| 701 |  | v1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp) | 
| 702 | 26.8k | { | 
| 703 | 26.8k |   int status; | 
| 704 | 26.8k |   const size_t perchunk =  gsp->extent; | 
| 705 | 26.8k |   size_t remaining = attrp->xsz; | 
| 706 | 26.8k |   void *value = attrp->xvalue; | 
| 707 | 26.8k |   size_t nget; | 
| 708 |  | #if USE_STRICT_NULL_BYTE_HEADER_PADDING | 
| 709 |  |   size_t padding; | 
| 710 |  | #endif /* USE_STRICT_NULL_BYTE_HEADER_PADDING */ | 
| 711 |  |  | 
| 712 | 28.2k |   do { | 
| 713 | 28.2k |     nget = MIN(perchunk, remaining); | 
| 714 |  |  | 
| 715 | 28.2k |     status = check_v1hs(gsp, nget); | 
| 716 | 28.2k |     if(status != NC_NOERR) | 
| 717 | 40 |       return status; | 
| 718 |  |  | 
| 719 | 28.2k |     if (value) { | 
| 720 | 3.38k |       (void) memcpy(value, gsp->pos, nget); | 
| 721 | 3.38k |       value = (void *)((signed char *)value + nget); | 
| 722 | 3.38k |     } | 
| 723 |  |      | 
| 724 | 28.2k |     gsp->pos = (void*)((unsigned char *)gsp->pos + nget); | 
| 725 |  |  | 
| 726 | 28.2k |     remaining -= nget; | 
| 727 |  |  | 
| 728 | 28.2k |   } while(remaining != 0); | 
| 729 |  |  | 
| 730 |  | #if USE_STRICT_NULL_BYTE_HEADER_PADDING | 
| 731 |  |   padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems; | 
| 732 |  |   if (padding > 0) { | 
| 733 |  |     /* CDF specification: Header padding uses null (\x00) bytes. */ | 
| 734 |  |     char pad[X_ALIGN-1]; | 
| 735 |  |     memset(pad, 0, X_ALIGN-1); | 
| 736 |  |     if (memcmp((char*)gsp->pos-padding, pad, (size_t)padding) != 0) | 
| 737 |  |       return NC_ENULLPAD; | 
| 738 |  |   } | 
| 739 |  | #endif | 
| 740 |  |  | 
| 741 | 26.8k |   return NC_NOERR; | 
| 742 | 26.8k | } | 
| 743 |  |  | 
| 744 |  |  | 
| 745 |  | /* Read a NC_attr from the header */ | 
| 746 |  | static int | 
| 747 |  | v1h_get_NC_attr(v1hs *gsp, NC_attr **attrpp) | 
| 748 | 26.9k | { | 
| 749 | 26.9k |   NC_string *strp; | 
| 750 | 26.9k |   int status; | 
| 751 | 26.9k |   nc_type type; | 
| 752 | 26.9k |   size_t nelems; | 
| 753 | 26.9k |   NC_attr *attrp; | 
| 754 |  |  | 
| 755 | 26.9k |   status = v1h_get_NC_string(gsp, &strp); | 
| 756 | 26.9k |     if(status != NC_NOERR) | 
| 757 | 17 |     return status; | 
| 758 |  |  | 
| 759 | 26.9k |   status = v1h_get_nc_type(gsp, &type); | 
| 760 | 26.9k |     if(status != NC_NOERR) | 
| 761 | 24 |     goto unwind_name; | 
| 762 |  |  | 
| 763 | 26.8k |   status = v1h_get_size_t(gsp, &nelems); | 
| 764 | 26.8k |     if(status != NC_NOERR) | 
| 765 | 7 |     goto unwind_name; | 
| 766 |  |  | 
| 767 | 26.8k |   attrp = new_x_NC_attr(strp, type, nelems); | 
| 768 | 26.8k |   if(attrp == NULL) | 
| 769 | 5 |   { | 
| 770 | 5 |     status = NC_ENOMEM; | 
| 771 | 5 |     goto unwind_name; | 
| 772 | 5 |   } | 
| 773 |  |  | 
| 774 | 26.8k |   status = v1h_get_NC_attrV(gsp, attrp); | 
| 775 | 26.8k |         if(status != NC_NOERR) | 
| 776 | 40 |   { | 
| 777 | 40 |     free_NC_attr(attrp); /* frees strp */ | 
| 778 | 40 |     return status; | 
| 779 | 40 |   } | 
| 780 |  |  | 
| 781 | 26.8k |   *attrpp = attrp; | 
| 782 |  |  | 
| 783 | 26.8k |     return NC_NOERR; | 
| 784 |  |  | 
| 785 | 36 | unwind_name: | 
| 786 | 36 |   free_NC_string(strp); | 
| 787 | 36 |   return status; | 
| 788 | 26.8k | } | 
| 789 |  |  | 
| 790 |  |  | 
| 791 |  | /* How much space in the header is required for this NC_attrarray? */ | 
| 792 |  | static size_t | 
| 793 |  | ncx_len_NC_attrarray(const NC_attrarray *ncap, int version) | 
| 794 | 838 | { | 
| 795 | 838 |   size_t xlen = X_SIZEOF_NCTYPE; /* type */ | 
| 796 | 838 |   xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */ | 
| 797 | 838 |   if(ncap == NULL) | 
| 798 | 0 |     return xlen; | 
| 799 |  |   /* else */ | 
| 800 | 838 |   { | 
| 801 | 838 |     const NC_attr **app = (const NC_attr **)ncap->value; | 
| 802 | 838 |     if (app) | 
| 803 | 0 |     { | 
| 804 | 0 |       const NC_attr *const *const end = &app[ncap->nelems]; | 
| 805 | 0 |       for( /*NADA*/; app < end; app++) | 
| 806 | 0 |       { | 
| 807 | 0 |         xlen += ncx_len_NC_attr(*app,version); | 
| 808 | 0 |       } | 
| 809 | 0 |     } | 
| 810 | 838 |   } | 
| 811 | 838 |   return xlen; | 
| 812 | 838 | } | 
| 813 |  |  | 
| 814 |  |  | 
| 815 |  | /* Write a NC_attrarray to the header */ | 
| 816 |  | static int | 
| 817 |  | v1h_put_NC_attrarray(v1hs *psp, const NC_attrarray *ncap) | 
| 818 | 0 | { | 
| 819 | 0 |   int status; | 
| 820 |  | 
 | 
| 821 | 0 |   assert(psp != NULL); | 
| 822 |  | 
 | 
| 823 | 0 |   if(ncap == NULL | 
| 824 | 0 | #if 1 | 
| 825 |  |     /* Backward: | 
| 826 |  |      * This clause is for 'byte for byte' | 
| 827 |  |      * backward compatibility. | 
| 828 |  |      * Strickly speaking, it is 'bug for bug'. | 
| 829 |  |      */ | 
| 830 | 0 |     || ncap->nelems == 0 | 
| 831 | 0 | #endif | 
| 832 | 0 |     ) | 
| 833 | 0 |   { | 
| 834 |  |     /* | 
| 835 |  |      * Handle empty netcdf | 
| 836 |  |      */ | 
| 837 | 0 |     const size_t nosz = 0; | 
| 838 |  | 
 | 
| 839 | 0 |     status = v1h_put_NCtype(psp, NC_UNSPECIFIED); | 
| 840 | 0 |         if(status != NC_NOERR) | 
| 841 | 0 |       return status; | 
| 842 | 0 |     status = v1h_put_size_t(psp, &nosz); | 
| 843 | 0 |         if(status != NC_NOERR) | 
| 844 | 0 |       return status; | 
| 845 | 0 |         return NC_NOERR; | 
| 846 | 0 |   } | 
| 847 |  |   /* else */ | 
| 848 |  |  | 
| 849 | 0 |   status = v1h_put_NCtype(psp, NC_ATTRIBUTE); | 
| 850 | 0 |     if(status != NC_NOERR) | 
| 851 | 0 |     return status; | 
| 852 | 0 |   status = v1h_put_size_t(psp, &ncap->nelems); | 
| 853 | 0 |     if(status != NC_NOERR) | 
| 854 | 0 |     return status; | 
| 855 |  |  | 
| 856 | 0 |   { | 
| 857 | 0 |     const NC_attr **app = (const NC_attr **)ncap->value; | 
| 858 | 0 |     const NC_attr *const *const end = &app[ncap->nelems]; | 
| 859 | 0 |     for( /*NADA*/; app < end; app++) | 
| 860 | 0 |     { | 
| 861 | 0 |       status = v1h_put_NC_attr(psp, *app); | 
| 862 | 0 |       if(status) | 
| 863 | 0 |         return status; | 
| 864 | 0 |     } | 
| 865 | 0 |   } | 
| 866 | 0 |     return NC_NOERR; | 
| 867 | 0 | } | 
| 868 |  |  | 
| 869 |  |  | 
| 870 |  | /* Read a NC_attrarray from the header */ | 
| 871 |  | static int | 
| 872 |  | v1h_get_NC_attrarray(v1hs *gsp, NC_attrarray *ncap) | 
| 873 | 142k | { | 
| 874 | 142k |   int status; | 
| 875 | 142k |   NCtype type = NC_UNSPECIFIED; | 
| 876 |  |  | 
| 877 | 142k |   assert(gsp != NULL && gsp->pos != NULL); | 
| 878 | 142k |   assert(ncap != NULL); | 
| 879 | 142k |   assert(ncap->value == NULL); | 
| 880 |  |  | 
| 881 | 142k |   status = v1h_get_NCtype(gsp, &type); | 
| 882 | 142k |     if(status != NC_NOERR) | 
| 883 | 16 |     return status; | 
| 884 | 142k |   status = v1h_get_size_t(gsp, &ncap->nelems); | 
| 885 | 142k |     if(status != NC_NOERR) | 
| 886 | 8 |     return status; | 
| 887 |  |  | 
| 888 | 142k |   if(ncap->nelems == 0) | 
| 889 | 142k |         return NC_NOERR; | 
| 890 |  |   /* else */ | 
| 891 | 232 |   if(type != NC_ATTRIBUTE) | 
| 892 | 8 |     return EINVAL; | 
| 893 |  |  | 
| 894 | 224 |   ncap->value = (NC_attr **) malloc(ncap->nelems * sizeof(NC_attr *)); | 
| 895 | 224 |   if(ncap->value == NULL) | 
| 896 | 0 |     return NC_ENOMEM; | 
| 897 | 224 |   ncap->nalloc = ncap->nelems; | 
| 898 |  |  | 
| 899 | 224 |   { | 
| 900 | 224 |     NC_attr **app = ncap->value; | 
| 901 | 224 |     NC_attr *const *const end = &app[ncap->nelems]; | 
| 902 | 27.0k |     for( /*NADA*/; app < end; app++) | 
| 903 | 26.9k |     { | 
| 904 | 26.9k |       status = v1h_get_NC_attr(gsp, app); | 
| 905 | 26.9k |       if(status) | 
| 906 | 93 |       { | 
| 907 | 93 |         ncap->nelems = (size_t)(app - ncap->value); | 
| 908 | 93 |         free_NC_attrarrayV(ncap); | 
| 909 | 93 |         return status; | 
| 910 | 93 |       } | 
| 911 | 26.9k |     } | 
| 912 | 224 |   } | 
| 913 |  |  | 
| 914 | 131 |     return NC_NOERR; | 
| 915 | 224 | } | 
| 916 |  |  | 
| 917 |  | /* End NC_attr */ | 
| 918 |  | /* Begin NC_var */ | 
| 919 |  |  | 
| 920 |  | /* | 
| 921 |  |  * How much space will the xdr'd var take. | 
| 922 |  |  * Formerly | 
| 923 |  | NC_xlen_var(vpp) | 
| 924 |  |  */ | 
| 925 |  | static size_t | 
| 926 |  | ncx_len_NC_var(const NC_var *varp, size_t sizeof_off_t, int version) | 
| 927 | 819 | { | 
| 928 | 819 |   size_t sz; | 
| 929 |  |  | 
| 930 | 819 |   assert(varp != NULL); | 
| 931 | 819 |   assert(sizeof_off_t != 0); | 
| 932 |  |  | 
| 933 | 819 |   sz = ncx_len_NC_string(varp->name, version); | 
| 934 | 819 |         if (version == 5) { | 
| 935 | 315 |       sz += X_SIZEOF_INT64; /* ndims */ | 
| 936 | 315 |       sz += ncx_len_int64(varp->ndims); /* dimids */ | 
| 937 | 315 |         } | 
| 938 | 504 |         else { | 
| 939 | 504 |       sz += X_SIZEOF_SIZE_T; /* ndims */ | 
| 940 | 504 |       sz += ncx_len_int(varp->ndims); /* dimids */ | 
| 941 | 504 |   } | 
| 942 | 819 |   sz += ncx_len_NC_attrarray(&varp->attrs, version); | 
| 943 | 819 |   sz += X_SIZEOF_NC_TYPE; /* nc_type */ | 
| 944 | 819 |   sz += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* vsize */ | 
| 945 | 819 |   sz += sizeof_off_t; /* begin */ | 
| 946 |  |  | 
| 947 | 819 |   return(sz); | 
| 948 | 819 | } | 
| 949 |  |  | 
| 950 |  |  | 
| 951 |  | /* Write a NC_var to the header */ | 
| 952 |  | static int | 
| 953 |  | v1h_put_NC_var(v1hs *psp, const NC_var *varp) | 
| 954 | 0 | { | 
| 955 | 0 |   int status; | 
| 956 | 0 |     size_t vsize; | 
| 957 |  | 
 | 
| 958 | 0 |   status = v1h_put_NC_string(psp, varp->name); | 
| 959 | 0 |     if(status != NC_NOERR) | 
| 960 | 0 |     return status; | 
| 961 |  |  | 
| 962 | 0 |   status = v1h_put_size_t(psp, &varp->ndims); | 
| 963 | 0 |     if(status != NC_NOERR) | 
| 964 | 0 |     return status; | 
| 965 |  |  | 
| 966 | 0 |   if (psp->version == 5) { | 
| 967 | 0 |     status = check_v1hs(psp, ncx_len_int64(varp->ndims)); | 
| 968 | 0 |         if(status != NC_NOERR) | 
| 969 | 0 |       return status; | 
| 970 | 0 |     status = ncx_putn_longlong_int(&psp->pos, | 
| 971 | 0 |         varp->ndims, varp->dimids, NULL); | 
| 972 | 0 |         if(status != NC_NOERR) | 
| 973 | 0 |       return status; | 
| 974 | 0 |   } | 
| 975 | 0 |   else { | 
| 976 | 0 |         status = check_v1hs(psp, ncx_len_int(varp->ndims)); | 
| 977 | 0 |         if(status != NC_NOERR) | 
| 978 | 0 |     return status; | 
| 979 | 0 |       status = ncx_putn_int_int(&psp->pos, | 
| 980 | 0 |       varp->ndims, varp->dimids, NULL); | 
| 981 | 0 |         if(status != NC_NOERR) | 
| 982 | 0 |     return status; | 
| 983 | 0 |   } | 
| 984 |  |  | 
| 985 | 0 |   status = v1h_put_NC_attrarray(psp, &varp->attrs); | 
| 986 | 0 |     if(status != NC_NOERR) | 
| 987 | 0 |     return status; | 
| 988 |  |  | 
| 989 | 0 |   status = v1h_put_nc_type(psp, &varp->type); | 
| 990 | 0 |     if(status != NC_NOERR) | 
| 991 | 0 |     return status; | 
| 992 |  |  | 
| 993 |  |     /* write vsize to header. | 
| 994 |  |      * CDF format specification: The vsize field is actually redundant, because | 
| 995 |  |      * its value may be computed from other information in the header. The | 
| 996 |  |      * 32-bit vsize field is not large enough to contain the size of variables | 
| 997 |  |      * that require more than 2^32 - 4 bytes, so 2^32 - 1 is used in the vsize | 
| 998 |  |      * field for such variables. | 
| 999 |  |      */ | 
| 1000 | 0 |     vsize = varp->len; | 
| 1001 | 0 |     if (varp->len > 4294967292UL && (psp->version == NC_FORMAT_CLASSIC || | 
| 1002 | 0 |                                      psp->version == NC_FORMAT_64BIT_OFFSET)) | 
| 1003 | 0 |         vsize = 4294967295UL; /* 2^32-1 */ | 
| 1004 | 0 |     status = v1h_put_size_t(psp, &vsize); | 
| 1005 | 0 |     if(status != NC_NOERR) return status; | 
| 1006 |  |  | 
| 1007 | 0 |   status = check_v1hs(psp, psp->version == 1 ? 4 : 8); /*begin*/ | 
| 1008 | 0 |     if(status != NC_NOERR) | 
| 1009 | 0 |      return status; | 
| 1010 | 0 |   status = ncx_put_off_t(&psp->pos, &varp->begin, psp->version == 1 ? 4 : 8); | 
| 1011 | 0 |     if(status != NC_NOERR) | 
| 1012 | 0 |     return status; | 
| 1013 |  |  | 
| 1014 | 0 |     return NC_NOERR; | 
| 1015 | 0 | } | 
| 1016 |  |  | 
| 1017 |  |  | 
| 1018 |  | /* Read a NC_var from the header */ | 
| 1019 |  | static int | 
| 1020 |  | v1h_get_NC_var(v1hs *gsp, NC_var **varpp) | 
| 1021 | 142k | { | 
| 1022 | 142k |   NC_string *strp; | 
| 1023 | 142k |   int status; | 
| 1024 | 142k |   size_t ndims; | 
| 1025 | 142k |   NC_var *varp; | 
| 1026 |  |  | 
| 1027 | 142k |   status = v1h_get_NC_string(gsp, &strp); | 
| 1028 | 142k |     if(status != NC_NOERR) | 
| 1029 | 12 |     return status; | 
| 1030 |  |  | 
| 1031 | 142k |   status = v1h_get_size_t(gsp, &ndims); | 
| 1032 | 142k |     if(status != NC_NOERR) | 
| 1033 | 6 |     goto unwind_name; | 
| 1034 |  |  | 
| 1035 | 142k |   varp = new_x_NC_var(strp, ndims); | 
| 1036 | 142k |   if(varp == NULL) | 
| 1037 | 0 |   { | 
| 1038 | 0 |     status = NC_ENOMEM; | 
| 1039 | 0 |     goto unwind_name; | 
| 1040 | 0 |   } | 
| 1041 |  |  | 
| 1042 | 142k |   if (gsp->version == 5) { | 
| 1043 | 1.07k |     status = check_v1hs(gsp, ncx_len_int64(ndims)); | 
| 1044 | 1.07k |         if(status != NC_NOERR) | 
| 1045 | 3 |       goto unwind_alloc; | 
| 1046 | 1.07k |     status = ncx_getn_longlong_int((const void **)(&gsp->pos), | 
| 1047 | 1.07k |         ndims, varp->dimids); | 
| 1048 | 1.07k |         if(status != NC_NOERR) | 
| 1049 | 17 |       goto unwind_alloc; | 
| 1050 | 1.07k |   } | 
| 1051 | 141k |   else { | 
| 1052 | 141k |       status = check_v1hs(gsp, ncx_len_int(ndims)); | 
| 1053 | 141k |         if(status != NC_NOERR) | 
| 1054 | 6 |     goto unwind_alloc; | 
| 1055 | 141k |       status = ncx_getn_int_int((const void **)(&gsp->pos), | 
| 1056 | 141k |       ndims, varp->dimids); | 
| 1057 | 141k |         if(status != NC_NOERR) | 
| 1058 | 0 |     goto unwind_alloc; | 
| 1059 | 141k |   } | 
| 1060 | 142k |   status = v1h_get_NC_attrarray(gsp, &varp->attrs); | 
| 1061 | 142k |     if(status != NC_NOERR) | 
| 1062 | 32 |     goto unwind_alloc; | 
| 1063 | 142k |   status = v1h_get_nc_type(gsp, &varp->type); | 
| 1064 | 142k |     if(status != NC_NOERR) | 
| 1065 | 12 |      goto unwind_alloc; | 
| 1066 |  |  | 
| 1067 | 142k |     size_t tmp; | 
| 1068 | 142k |     status = v1h_get_size_t(gsp, &tmp); | 
| 1069 | 142k |     varp->len = tmp; | 
| 1070 | 142k |     if(status != NC_NOERR) | 
| 1071 | 5 |      goto unwind_alloc; | 
| 1072 |  |  | 
| 1073 | 142k |   status = check_v1hs(gsp, gsp->version == 1 ? 4 : 8); | 
| 1074 | 142k |     if(status != NC_NOERR) | 
| 1075 | 7 |      goto unwind_alloc; | 
| 1076 | 142k |   status = ncx_get_off_t((const void **)&gsp->pos, | 
| 1077 | 142k |              &varp->begin, gsp->version == 1 ? 4 : 8); | 
| 1078 | 142k |     if(status != NC_NOERR) | 
| 1079 | 0 |      goto unwind_alloc; | 
| 1080 |  |  | 
| 1081 | 142k |   *varpp = varp; | 
| 1082 | 142k |     return NC_NOERR; | 
| 1083 |  |  | 
| 1084 | 82 | unwind_alloc: | 
| 1085 | 82 |   free_NC_var(varp); /* frees name */ | 
| 1086 | 82 |   return status; | 
| 1087 |  |  | 
| 1088 | 6 | unwind_name: | 
| 1089 | 6 |   free_NC_string(strp); | 
| 1090 | 6 |   return status; | 
| 1091 | 142k | } | 
| 1092 |  |  | 
| 1093 |  |  | 
| 1094 |  | /* How much space in the header is required for this NC_vararray? */ | 
| 1095 |  | static size_t | 
| 1096 |  | ncx_len_NC_vararray(const NC_vararray *ncap, size_t sizeof_off_t, int version) | 
| 1097 | 19 | { | 
| 1098 | 19 |   size_t xlen = X_SIZEOF_NCTYPE; /* type */ | 
| 1099 | 19 |   xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* count */ | 
| 1100 | 19 |   if(ncap == NULL) | 
| 1101 | 0 |     return xlen; | 
| 1102 |  |   /* else */ | 
| 1103 | 19 |   { | 
| 1104 | 19 |     const NC_var **vpp = (const NC_var **)ncap->value; | 
| 1105 | 19 |     if (vpp) | 
| 1106 | 8 |     { | 
| 1107 | 8 |       const NC_var *const *const end = &vpp[ncap->nelems]; | 
| 1108 | 827 |       for( /*NADA*/; vpp < end; vpp++) | 
| 1109 | 819 |       { | 
| 1110 | 819 |         xlen += ncx_len_NC_var(*vpp, sizeof_off_t, version); | 
| 1111 | 819 |       } | 
| 1112 | 8 |     } | 
| 1113 | 19 |   } | 
| 1114 | 19 |   return xlen; | 
| 1115 | 19 | } | 
| 1116 |  |  | 
| 1117 |  |  | 
| 1118 |  | /* Write a NC_vararray to the header */ | 
| 1119 |  | static int | 
| 1120 |  | v1h_put_NC_vararray(v1hs *psp, const NC_vararray *ncap) | 
| 1121 | 0 | { | 
| 1122 | 0 |   int status; | 
| 1123 |  | 
 | 
| 1124 | 0 |   assert(psp != NULL); | 
| 1125 |  | 
 | 
| 1126 | 0 |   if(ncap == NULL | 
| 1127 | 0 | #if 1 | 
| 1128 |  |     /* Backward: | 
| 1129 |  |      * This clause is for 'byte for byte' | 
| 1130 |  |      * backward compatibility. | 
| 1131 |  |      * Strickly speaking, it is 'bug for bug'. | 
| 1132 |  |      */ | 
| 1133 | 0 |     || ncap->nelems == 0 | 
| 1134 | 0 | #endif | 
| 1135 | 0 |     ) | 
| 1136 | 0 |   { | 
| 1137 |  |     /* | 
| 1138 |  |      * Handle empty netcdf | 
| 1139 |  |      */ | 
| 1140 | 0 |     const size_t nosz = 0; | 
| 1141 |  | 
 | 
| 1142 | 0 |     status = v1h_put_NCtype(psp, NC_UNSPECIFIED); | 
| 1143 | 0 |         if(status != NC_NOERR) | 
| 1144 | 0 |       return status; | 
| 1145 | 0 |     status = v1h_put_size_t(psp, &nosz); | 
| 1146 | 0 |         if(status != NC_NOERR) | 
| 1147 | 0 |       return status; | 
| 1148 | 0 |         return NC_NOERR; | 
| 1149 | 0 |   } | 
| 1150 |  |   /* else */ | 
| 1151 |  |  | 
| 1152 | 0 |   status = v1h_put_NCtype(psp, NC_VARIABLE); | 
| 1153 | 0 |     if(status != NC_NOERR) | 
| 1154 | 0 |     return status; | 
| 1155 | 0 |   status = v1h_put_size_t(psp, &ncap->nelems); | 
| 1156 | 0 |     if(status != NC_NOERR) | 
| 1157 | 0 |     return status; | 
| 1158 |  |  | 
| 1159 | 0 |   { | 
| 1160 | 0 |     const NC_var **vpp = (const NC_var **)ncap->value; | 
| 1161 | 0 |     const NC_var *const *const end = &vpp[ncap->nelems]; | 
| 1162 | 0 |     for( /*NADA*/; vpp < end; vpp++) | 
| 1163 | 0 |     { | 
| 1164 | 0 |       status = v1h_put_NC_var(psp, *vpp); | 
| 1165 | 0 |       if(status) | 
| 1166 | 0 |         return status; | 
| 1167 | 0 |     } | 
| 1168 | 0 |   } | 
| 1169 | 0 |     return NC_NOERR; | 
| 1170 | 0 | } | 
| 1171 |  |  | 
| 1172 |  |  | 
| 1173 |  | /* Read a NC_vararray from the header */ | 
| 1174 |  | static int | 
| 1175 |  | v1h_get_NC_vararray(v1hs *gsp, NC_vararray *ncap) | 
| 1176 | 124 | { | 
| 1177 | 124 |   int status; | 
| 1178 | 124 |   NCtype type = NC_UNSPECIFIED; | 
| 1179 |  |  | 
| 1180 | 124 |   assert(gsp != NULL && gsp->pos != NULL); | 
| 1181 | 124 |   assert(ncap != NULL); | 
| 1182 | 124 |   assert(ncap->value == NULL); | 
| 1183 |  |  | 
| 1184 | 124 |   status = v1h_get_NCtype(gsp, &type); | 
| 1185 | 124 |     if(status != NC_NOERR) | 
| 1186 | 0 |     return status; | 
| 1187 |  |  | 
| 1188 | 124 |   status = v1h_get_size_t(gsp, &ncap->nelems); | 
| 1189 | 124 |     if(status != NC_NOERR) | 
| 1190 | 0 |     return status; | 
| 1191 |  |  | 
| 1192 | 124 |   if(ncap->nelems == 0) | 
| 1193 | 11 |         return NC_NOERR; | 
| 1194 |  |   /* else */ | 
| 1195 | 113 |   if(type != NC_VARIABLE) | 
| 1196 | 0 |     return EINVAL; | 
| 1197 |  |    | 
| 1198 | 113 |   if (ncap->nelems > SIZE_MAX / sizeof(NC_var *)) | 
| 1199 | 5 |     return NC_ERANGE; | 
| 1200 | 108 |   ncap->value = (NC_var **) calloc(1,ncap->nelems * sizeof(NC_var *)); | 
| 1201 | 108 |   if(ncap->value == NULL) | 
| 1202 | 0 |     return NC_ENOMEM; | 
| 1203 | 108 |   ncap->nalloc = ncap->nelems; | 
| 1204 |  |  | 
| 1205 | 108 |   ncap->hashmap = NC_hashmapnew(ncap->nelems); | 
| 1206 | 108 |   if (ncap->hashmap == NULL) | 
| 1207 | 0 |     return NC_ENOMEM; | 
| 1208 | 108 |   { | 
| 1209 | 108 |     NC_var **vpp = ncap->value; | 
| 1210 | 108 |     NC_var *const *const end = &vpp[ncap->nelems]; | 
| 1211 | 142k |     for( /*NADA*/; vpp < end; vpp++) | 
| 1212 | 142k |     { | 
| 1213 | 142k |       status = v1h_get_NC_var(gsp, vpp); | 
| 1214 | 142k |       if(status) | 
| 1215 | 100 |       { | 
| 1216 | 100 |         ncap->nelems = (size_t)(vpp - ncap->value); | 
| 1217 | 100 |         free_NC_vararrayV(ncap); | 
| 1218 | 100 |         return status; | 
| 1219 | 100 |       } | 
| 1220 | 142k |       { | 
| 1221 | 142k |         uintptr_t varid = (uintptr_t)(vpp - ncap->value); | 
| 1222 | 142k |         NC_hashmapadd(ncap->hashmap, varid, (*vpp)->name->cp, strlen((*vpp)->name->cp)); | 
| 1223 | 142k |       } | 
| 1224 | 142k |     } | 
| 1225 | 108 |   } | 
| 1226 |  |  | 
| 1227 | 8 |     return NC_NOERR; | 
| 1228 | 108 | } | 
| 1229 |  |  | 
| 1230 |  |  | 
| 1231 |  | /* End NC_var */ | 
| 1232 |  | /* Begin NC */ | 
| 1233 |  |  | 
| 1234 |  | /* | 
| 1235 |  |  * Recompute the shapes of all variables | 
| 1236 |  |  * Sets ncp->begin_var to start of first variable. | 
| 1237 |  |  * Sets ncp->begin_rec to start of first record variable. | 
| 1238 |  |  * Returns -1 on error. The only possible error is a reference | 
| 1239 |  |  * to a non existent dimension, which could occur for a corrupted | 
| 1240 |  |  * netcdf file. | 
| 1241 |  |  */ | 
| 1242 |  | static int | 
| 1243 |  | NC_computeshapes(NC3_INFO* ncp) | 
| 1244 | 19 | { | 
| 1245 | 19 |   NC_var **vpp = (NC_var **)ncp->vars.value; | 
| 1246 | 19 |   NC_var *first_var = NULL; /* first "non-record" var */ | 
| 1247 | 19 |   NC_var *first_rec = NULL; /* first "record" var */ | 
| 1248 | 19 |   int status; | 
| 1249 |  |  | 
| 1250 | 19 |   ncp->begin_var = (off_t) ncp->xsz; | 
| 1251 | 19 |   ncp->begin_rec = (off_t) ncp->xsz; | 
| 1252 | 19 |   ncp->recsize = 0; | 
| 1253 |  |  | 
| 1254 | 19 |   if(ncp->vars.nelems == 0) | 
| 1255 | 11 |     return(0); | 
| 1256 |  |  | 
| 1257 | 8 |   if (vpp) | 
| 1258 | 8 |   { | 
| 1259 | 8 |     NC_var *const *const end = &vpp[ncp->vars.nelems]; | 
| 1260 | 821 |     for( /*NADA*/; vpp < end; vpp++) | 
| 1261 | 815 |     { | 
| 1262 | 815 |       status = NC_var_shape(*vpp, &ncp->dims); | 
| 1263 | 815 |             if(status != NC_NOERR) | 
| 1264 | 2 |         return(status); | 
| 1265 |  |  | 
| 1266 | 813 |         if(IS_RECVAR(*vpp)) | 
| 1267 | 0 |       { | 
| 1268 | 0 |           if(first_rec == NULL) | 
| 1269 | 0 |           first_rec = *vpp; | 
| 1270 | 0 |         ncp->recsize += (*vpp)->len; | 
| 1271 | 0 |       } | 
| 1272 | 813 |       else | 
| 1273 | 813 |       { | 
| 1274 | 813 |                 if(first_var == NULL) | 
| 1275 | 7 |               first_var = *vpp; | 
| 1276 |  |           /* | 
| 1277 |  |            * Overwritten each time thru. | 
| 1278 |  |            * Usually overwritten in first_rec != NULL clause below. | 
| 1279 |  |            */ | 
| 1280 | 813 |           ncp->begin_rec = (*vpp)->begin + (off_t)(*vpp)->len; | 
| 1281 | 813 |       } | 
| 1282 | 813 |     } | 
| 1283 | 8 |   } | 
| 1284 |  |  | 
| 1285 | 6 |   if(first_rec != NULL) | 
| 1286 | 0 |   { | 
| 1287 | 0 |     if(ncp->begin_rec > first_rec->begin) | 
| 1288 | 0 |         return(NC_ENOTNC); /* not a netCDF file or corrupted */ | 
| 1289 | 0 |     ncp->begin_rec = first_rec->begin; | 
| 1290 |  |     /* | 
| 1291 |  |      * for special case of exactly one record variable, pack value | 
| 1292 |  |      */ | 
| 1293 | 0 |     if(ncp->recsize == first_rec->len) | 
| 1294 | 0 |       ncp->recsize = *first_rec->dsizes * first_rec->xsz; | 
| 1295 | 0 |   } | 
| 1296 |  |  | 
| 1297 | 6 |   if(first_var != NULL) | 
| 1298 | 6 |   { | 
| 1299 | 6 |     ncp->begin_var = first_var->begin; | 
| 1300 | 6 |   } | 
| 1301 | 0 |   else | 
| 1302 | 0 |   { | 
| 1303 | 0 |     ncp->begin_var = ncp->begin_rec; | 
| 1304 | 0 |   } | 
| 1305 |  |  | 
| 1306 | 6 |   if(ncp->begin_var <= 0 || | 
| 1307 | 4 |      ncp->xsz > (size_t)ncp->begin_var || | 
| 1308 | 4 |      ncp->begin_rec <= 0 || | 
| 1309 | 4 |      ncp->begin_var > ncp->begin_rec) | 
| 1310 | 4 |       return(NC_ENOTNC); /* not a netCDF file or corrupted */ | 
| 1311 |  |  | 
| 1312 | 2 |     return(NC_NOERR); | 
| 1313 | 6 | } | 
| 1314 |  |  | 
| 1315 |  | /* How much space in the header is required for the NC data structure? */ | 
| 1316 |  | size_t | 
| 1317 |  | ncx_len_NC(const NC3_INFO* ncp, size_t sizeof_off_t) | 
| 1318 | 19 | { | 
| 1319 | 19 |   int version=1; | 
| 1320 | 19 |   size_t xlen = sizeof(ncmagic); | 
| 1321 |  |  | 
| 1322 | 19 |   assert(ncp != NULL); | 
| 1323 | 19 |   if (fIsSet(ncp->flags, NC_64BIT_DATA)) /* CDF-5 */ | 
| 1324 | 3 |     version = 5; | 
| 1325 | 16 |       else if (fIsSet(ncp->flags, NC_64BIT_OFFSET)) /* CDF-2 */ | 
| 1326 | 4 |     version = 2; | 
| 1327 |  |  | 
| 1328 | 19 |   xlen += (version == 5) ? X_SIZEOF_INT64 : X_SIZEOF_SIZE_T; /* numrecs */ | 
| 1329 | 19 |   xlen += ncx_len_NC_dimarray(&ncp->dims, version); | 
| 1330 | 19 |   xlen += ncx_len_NC_attrarray(&ncp->attrs, version); | 
| 1331 | 19 |   xlen += ncx_len_NC_vararray(&ncp->vars, sizeof_off_t, version); | 
| 1332 |  |  | 
| 1333 | 19 |   return xlen; | 
| 1334 | 19 | } | 
| 1335 |  |  | 
| 1336 |  |  | 
| 1337 |  | /* Write the file header */ | 
| 1338 |  | int | 
| 1339 |  | ncx_put_NC(const NC3_INFO* ncp, void **xpp, off_t offset, size_t extent) | 
| 1340 | 0 | { | 
| 1341 | 0 |     int status = NC_NOERR; | 
| 1342 | 0 |   v1hs ps; /* the get stream */ | 
| 1343 |  | 
 | 
| 1344 | 0 |   assert(ncp != NULL); | 
| 1345 |  |  | 
| 1346 |  |   /* Initialize stream ps */ | 
| 1347 |  | 
 | 
| 1348 | 0 |   ps.nciop = ncp->nciop; | 
| 1349 | 0 |   ps.flags = RGN_WRITE; | 
| 1350 |  | 
 | 
| 1351 | 0 |   if (ncp->flags & NC_64BIT_DATA) | 
| 1352 | 0 |     ps.version = 5; | 
| 1353 | 0 |   else if (ncp->flags & NC_64BIT_OFFSET) | 
| 1354 | 0 |     ps.version = 2; | 
| 1355 | 0 |   else | 
| 1356 | 0 |     ps.version = 1; | 
| 1357 |  | 
 | 
| 1358 | 0 |   if(xpp == NULL) | 
| 1359 | 0 |   { | 
| 1360 |  |     /* | 
| 1361 |  |      * Come up with a reasonable stream read size. | 
| 1362 |  |      */ | 
| 1363 | 0 |     extent = ncp->xsz; | 
| 1364 | 0 |     if(extent <= ((ps.version==5)?MIN_NC5_XSZ:MIN_NC3_XSZ)) | 
| 1365 | 0 |     { | 
| 1366 |  |       /* first time read */ | 
| 1367 | 0 |       extent = ncp->chunk; | 
| 1368 |  |       /* Protection for when ncp->chunk is huge; | 
| 1369 |  |        * no need to read hugely. */ | 
| 1370 | 0 |             if(extent > 4096) | 
| 1371 | 0 |         extent = 4096; | 
| 1372 | 0 |     } | 
| 1373 | 0 |     else if(extent > ncp->chunk) | 
| 1374 | 0 |         extent = ncp->chunk; | 
| 1375 |  | 
 | 
| 1376 | 0 |     ps.offset = 0; | 
| 1377 | 0 |     ps.extent = extent; | 
| 1378 | 0 |     ps.base = NULL; | 
| 1379 | 0 |     ps.pos = ps.base; | 
| 1380 |  | 
 | 
| 1381 | 0 |     status = fault_v1hs(&ps, extent); | 
| 1382 | 0 |     if(status) | 
| 1383 | 0 |       return status; | 
| 1384 | 0 |   } | 
| 1385 | 0 |   else | 
| 1386 | 0 |   { | 
| 1387 | 0 |     ps.offset = offset; | 
| 1388 | 0 |     ps.extent = extent; | 
| 1389 | 0 |     ps.base = *xpp; | 
| 1390 | 0 |     ps.pos = ps.base; | 
| 1391 | 0 |     ps.end = (char *)ps.base + ps.extent; | 
| 1392 | 0 |   } | 
| 1393 |  |  | 
| 1394 | 0 |   if (ps.version == 5) | 
| 1395 | 0 |     status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic5), ncmagic5, NULL); | 
| 1396 | 0 |   else if (ps.version == 2) | 
| 1397 | 0 |     status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic), ncmagic, NULL); | 
| 1398 | 0 |   else | 
| 1399 | 0 |     status = ncx_putn_schar_schar(&ps.pos, sizeof(ncmagic1), ncmagic1, NULL); | 
| 1400 | 0 |   if(status != NC_NOERR) | 
| 1401 | 0 |     goto release; | 
| 1402 |  |  | 
| 1403 | 0 |   { | 
| 1404 | 0 |   const size_t nrecs = NC_get_numrecs(ncp); | 
| 1405 | 0 |   if (ps.version == 5) { | 
| 1406 | 0 |             unsigned long long tmp = (unsigned long long) nrecs; | 
| 1407 | 0 |       status = ncx_put_uint64(&ps.pos, tmp); | 
| 1408 | 0 |         } | 
| 1409 | 0 |         else | 
| 1410 | 0 |       status = ncx_put_size_t(&ps.pos, &nrecs); | 
| 1411 | 0 |   if(status != NC_NOERR) | 
| 1412 | 0 |     goto release; | 
| 1413 | 0 |   } | 
| 1414 |  |  | 
| 1415 | 0 |   assert((char *)ps.pos < (char *)ps.end); | 
| 1416 |  | 
 | 
| 1417 | 0 |   status = v1h_put_NC_dimarray(&ps, &ncp->dims); | 
| 1418 | 0 |     if(status != NC_NOERR) | 
| 1419 | 0 |     goto release; | 
| 1420 |  |  | 
| 1421 | 0 |   status = v1h_put_NC_attrarray(&ps, &ncp->attrs); | 
| 1422 | 0 |     if(status != NC_NOERR) | 
| 1423 | 0 |     goto release; | 
| 1424 |  |  | 
| 1425 | 0 |   status = v1h_put_NC_vararray(&ps, &ncp->vars); | 
| 1426 | 0 |     if(status != NC_NOERR) | 
| 1427 | 0 |     goto release; | 
| 1428 |  |  | 
| 1429 | 0 | release: | 
| 1430 | 0 |   (void) rel_v1hs(&ps); | 
| 1431 |  | 
 | 
| 1432 | 0 |   return status; | 
| 1433 | 0 | } | 
| 1434 |  |  | 
| 1435 |  |  | 
| 1436 |  | /* Make the in-memory NC structure from reading the file header */ | 
| 1437 |  | int | 
| 1438 |  | nc_get_NC(NC3_INFO* ncp) | 
| 1439 | 291 | { | 
| 1440 | 291 |   int status; | 
| 1441 | 291 |   v1hs gs; /* the get stream */ | 
| 1442 |  |  | 
| 1443 | 291 |   assert(ncp != NULL); | 
| 1444 |  |  | 
| 1445 |  |   /* Initialize stream gs */ | 
| 1446 |  |  | 
| 1447 | 291 |   gs.nciop = ncp->nciop; | 
| 1448 | 291 |   gs.offset = 0; /* beginning of file */ | 
| 1449 | 291 |   gs.extent = 0; | 
| 1450 | 291 |   gs.flags = 0; | 
| 1451 | 291 |   gs.version = 0; | 
| 1452 | 291 |   gs.base = NULL; | 
| 1453 | 291 |   gs.pos = gs.base; | 
| 1454 |  |  | 
| 1455 | 291 |   { | 
| 1456 |  |     /* | 
| 1457 |  |      * Come up with a reasonable stream read size. | 
| 1458 |  |      */ | 
| 1459 | 291 |           off_t filesize; | 
| 1460 | 291 |     size_t extent = ncp->xsz; | 
| 1461 |  |  | 
| 1462 | 291 |     if(extent <= ((fIsSet(ncp->flags, NC_64BIT_DATA))?MIN_NC5_XSZ:MIN_NC3_XSZ)) | 
| 1463 | 291 |     { | 
| 1464 | 291 |             status = ncio_filesize(ncp->nciop, &filesize); | 
| 1465 | 291 |       if(status) | 
| 1466 | 0 |           return status; | 
| 1467 | 291 |       if(filesize < sizeof(ncmagic)) { /* too small, not netcdf */ | 
| 1468 |  | 
 | 
| 1469 | 0 |           status = NC_ENOTNC; | 
| 1470 | 0 |           return status; | 
| 1471 | 0 |       } | 
| 1472 |  |       /* first time read */ | 
| 1473 | 291 |       extent = ncp->chunk; | 
| 1474 |  |       /* Protection for when ncp->chunk is huge; | 
| 1475 |  |        * no need to read hugely. */ | 
| 1476 | 291 |             if(extent > 4096) | 
| 1477 | 199 |         extent = 4096; | 
| 1478 | 291 |       if(extent > filesize) | 
| 1479 | 0 |               extent = (size_t)filesize; | 
| 1480 | 291 |     } | 
| 1481 | 0 |     else if(extent > ncp->chunk) | 
| 1482 | 0 |         extent = ncp->chunk; | 
| 1483 |  |  | 
| 1484 |  |     /* | 
| 1485 |  |      * Invalidate the I/O buffers to force a read of the header | 
| 1486 |  |      * region. | 
| 1487 |  |      */ | 
| 1488 | 291 |     status = ncio_sync(gs.nciop); | 
| 1489 | 291 |     if(status) | 
| 1490 | 0 |       return status; | 
| 1491 |  |  | 
| 1492 | 291 |     status = fault_v1hs(&gs, extent); | 
| 1493 | 291 |     if(status) | 
| 1494 | 0 |       return status; | 
| 1495 | 291 |   } | 
| 1496 |  |  | 
| 1497 |  |   /* get the header from the stream gs */ | 
| 1498 |  |  | 
| 1499 | 291 |   { | 
| 1500 |  |     /* Get & check magic number */ | 
| 1501 | 291 |     schar magic[sizeof(ncmagic)]; | 
| 1502 | 291 |     (void) memset(magic, 0, sizeof(magic)); | 
| 1503 |  |  | 
| 1504 | 291 |     status = ncx_getn_schar_schar( | 
| 1505 | 291 |       (const void **)(&gs.pos), sizeof(magic), magic); | 
| 1506 | 291 |         if(status != NC_NOERR) | 
| 1507 | 0 |       goto unwind_get; | 
| 1508 |  |  | 
| 1509 | 291 |     if(memcmp(magic, ncmagic, sizeof(ncmagic)-1) != 0) | 
| 1510 | 0 |     { | 
| 1511 | 0 |       status = NC_ENOTNC; | 
| 1512 | 0 |       goto unwind_get; | 
| 1513 | 0 |     } | 
| 1514 |  |     /* Check version number in last byte of magic */ | 
| 1515 | 291 |     if (magic[sizeof(ncmagic)-1] == 0x1) { | 
| 1516 | 93 |       gs.version = 1; | 
| 1517 | 198 |     } else if (magic[sizeof(ncmagic)-1] == 0x2) { | 
| 1518 | 100 |       gs.version = 2; | 
| 1519 | 100 |       fSet(ncp->flags, NC_64BIT_OFFSET); | 
| 1520 |  |       /* Now we support version 2 file access on non-LFS systems -- rkr */ | 
| 1521 |  | #if 0 | 
| 1522 |  |       if (sizeof(off_t) != 8) { | 
| 1523 |  |         fprintf(stderr, "NETCDF WARNING: Version 2 file on 32-bit system.\n"); | 
| 1524 |  |       } | 
| 1525 |  | #endif | 
| 1526 | 100 |     } else if (magic[sizeof(ncmagic)-1] == 0x5) { | 
| 1527 | 98 |       gs.version = 5; | 
| 1528 | 98 |       fSet(ncp->flags, NC_64BIT_DATA); | 
| 1529 | 98 |     } else { | 
| 1530 | 0 |       status = NC_ENOTNC; | 
| 1531 | 0 |       goto unwind_get; | 
| 1532 | 0 |     } | 
| 1533 | 291 |   } | 
| 1534 |  |  | 
| 1535 | 291 |   { | 
| 1536 | 291 |   size_t nrecs = 0; | 
| 1537 | 291 |         if (gs.version == 5) { | 
| 1538 | 98 |     unsigned long long tmp = 0; | 
| 1539 | 98 |     status = ncx_get_uint64((const void **)(&gs.pos), &tmp); | 
| 1540 | 98 |     nrecs = (size_t)tmp; | 
| 1541 | 98 |         } | 
| 1542 | 193 |         else | 
| 1543 | 193 |       status = ncx_get_size_t((const void **)(&gs.pos), &nrecs); | 
| 1544 | 291 |     if(status != NC_NOERR) | 
| 1545 | 0 |     goto unwind_get; | 
| 1546 | 291 |   NC_set_numrecs(ncp, nrecs); | 
| 1547 | 291 |   } | 
| 1548 |  |  | 
| 1549 | 291 |   assert((char *)gs.pos < (char *)gs.end); | 
| 1550 |  |  | 
| 1551 | 291 |   status = v1h_get_NC_dimarray(&gs, &ncp->dims); | 
| 1552 | 291 |     if(status != NC_NOERR) | 
| 1553 | 74 |     goto unwind_get; | 
| 1554 |  |  | 
| 1555 | 217 |   status = v1h_get_NC_attrarray(&gs, &ncp->attrs); | 
| 1556 | 217 |     if(status != NC_NOERR) | 
| 1557 | 93 |     goto unwind_get; | 
| 1558 |  |  | 
| 1559 | 124 |   status = v1h_get_NC_vararray(&gs, &ncp->vars); | 
| 1560 | 124 |     if(status != NC_NOERR) | 
| 1561 | 105 |     goto unwind_get; | 
| 1562 |  |  | 
| 1563 | 19 |   ncp->xsz = ncx_len_NC(ncp, (gs.version == 1) ? 4 : 8); | 
| 1564 |  |  | 
| 1565 | 19 |   status = NC_computeshapes(ncp); | 
| 1566 | 19 |     if(status != NC_NOERR) | 
| 1567 | 6 |     goto unwind_get; | 
| 1568 |  |  | 
| 1569 | 13 |   status = NC_check_vlens(ncp); | 
| 1570 | 13 |     if(status != NC_NOERR) | 
| 1571 | 0 |     goto unwind_get; | 
| 1572 |  |  | 
| 1573 | 13 |   status = NC_check_voffs(ncp); | 
| 1574 | 13 |     if(status != NC_NOERR) | 
| 1575 | 2 |     goto unwind_get; | 
| 1576 |  |  | 
| 1577 | 291 | unwind_get: | 
| 1578 | 291 |   (void) rel_v1hs(&gs); | 
| 1579 | 291 |   return status; | 
| 1580 | 13 | } |