/src/netcdf-c/libdispatch/dinstance_intern.c
| Line | Count | Source | 
| 1 |  | /* | 
| 2 |  | Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata | 
| 3 |  | See COPYRIGHT for license information. | 
| 4 |  | */ | 
| 5 |  |  | 
| 6 |  | /** \internal | 
| 7 |  | This file contains various instance operations that operate | 
| 8 |  | on a deep level rather than the shallow level of e.g. nc_free_vlen_t. | 
| 9 |  | Currently two operations are defined: | 
| 10 |  | 1. reclaim a vector of instances | 
| 11 |  | 2. copy a vector of instances | 
| 12 |  | */ | 
| 13 |  |  | 
| 14 |  | #include "config.h" | 
| 15 |  | #include <stdlib.h> | 
| 16 |  | #include <string.h> | 
| 17 |  | #include <assert.h> | 
| 18 |  | #include "netcdf.h" | 
| 19 |  | #include "nc4internal.h" | 
| 20 |  | #include "nc4dispatch.h" | 
| 21 |  | #include "ncoffsets.h" | 
| 22 |  | #include "ncbytes.h" | 
| 23 |  |  | 
| 24 |  | #undef REPORT | 
| 25 |  | #undef DEBUG | 
| 26 |  |  | 
| 27 |  | /* It is helpful to have a structure that identifies a pointer into the overall memory */ | 
| 28 |  | typedef struct Position{char* memory;} Position; | 
| 29 |  |  | 
| 30 |  | static int type_alignment_initialized = 0; | 
| 31 |  |  | 
| 32 |  | /* Forward */ | 
| 33 |  | #ifdef USE_NETCDF4 | 
| 34 |  | static int reclaim_datar(NC_FILE_INFO_T* file, NC_TYPE_INFO_T* utype, Position instance); | 
| 35 |  | static int copy_datar(NC_FILE_INFO_T* file, NC_TYPE_INFO_T* utype, Position src, Position dst); | 
| 36 |  | #endif | 
| 37 |  |  | 
| 38 |  | int NC_print_data(NC_FILE_INFO_T* file, nc_type xtype, const void* memory, size_t count); | 
| 39 |  |  | 
| 40 |  | /** | 
| 41 |  | Reclaim a vector of instances of a type.  This recursively walks the | 
| 42 |  | top-level instances to reclaim any nested data such as vlen or strings | 
| 43 |  | or such. | 
| 44 |  |  | 
| 45 |  | Assumes it is passed a pointer to count instances of xtype. | 
| 46 |  | Reclaims any nested data. | 
| 47 |  |  | 
| 48 |  | These are the internal equivalents of nc_reclaim_data[_all] and | 
| 49 |  | nc_copy_data[_all] and as such operate using internal data structures. | 
| 50 |  |  | 
| 51 |  | WARNING: DOES NOT RECLAIM THE TOP-LEVEL MEMORY. | 
| 52 |  | The reason is that we do not know how it was allocated (e.g. static vs | 
| 53 |  | dynamic); only the caller can know that.  But note that it assumes all | 
| 54 |  | memory blocks other than the top were dynamically allocated, so they | 
| 55 |  | will be free'd. | 
| 56 |  |  | 
| 57 |  | Should work for any netcdf type. | 
| 58 |  |  | 
| 59 |  | Note that this has been optimized significantly, largely | 
| 60 |  | by unwinding various reclaim cliche procedures. | 
| 61 |  |  | 
| 62 |  | @param nc NC* structure | 
| 63 |  | @param xtype type id | 
| 64 |  | @param memory ptr to top-level memory to reclaim | 
| 65 |  | @param count number of instances of the type in memory block | 
| 66 |  | @return error code | 
| 67 |  | */ | 
| 68 |  |  | 
| 69 |  | int | 
| 70 |  | NC_reclaim_data(NC* nc, nc_type xtype, void* memory, size_t count) | 
| 71 | 0 | { | 
| 72 | 0 |     int stat = NC_NOERR; | 
| 73 | 0 |     size_t i; | 
| 74 | 0 |     Position instance; | 
| 75 | 0 |     NC_FILE_INFO_T* file = NULL; | 
| 76 | 0 |     NC_TYPE_INFO_T* utype = NULL; | 
| 77 |  | 
 | 
| 78 | 0 |     assert(nc != NULL); | 
| 79 | 0 |     assert((memory == NULL && count == 0) || (memory != NULL || count > 0)); | 
| 80 |  |  | 
| 81 |  |     /* Process atomic types */ | 
| 82 |  |  | 
| 83 |  |     /* Optimize: Vector of fixed size atomic types (always the case for netcdf-3)*/ | 
| 84 | 0 |     if(xtype < NC_STRING) goto done; | 
| 85 |  |  | 
| 86 | 0 | #ifdef USE_NETCDF4 | 
| 87 |  |     /* Optimize: Vector of strings */ | 
| 88 | 0 |     if(xtype == NC_STRING) { | 
| 89 | 0 |   char** ss = (char**)memory; | 
| 90 | 0 |         for(i=0;i<count;i++) { | 
| 91 | 0 |       nullfree(ss[i]); | 
| 92 | 0 |   } | 
| 93 | 0 |         goto done; | 
| 94 | 0 |     } | 
| 95 |  |  | 
| 96 |  |     /* Process User types */ | 
| 97 | 0 |     assert(USEFILEINFO(nc) != 0); | 
| 98 | 0 |     file = (NC_FILE_INFO_T*)(nc)->dispatchdata; | 
| 99 | 0 |     if((stat = nc4_find_type(file,xtype,&utype))) goto done; | 
| 100 |  |  | 
| 101 |  |     /* Optimize: vector of fixed sized compound type instances */ | 
| 102 | 0 |     if(!utype->varsized) goto done; /* no need to reclaim anything */ | 
| 103 |  |  | 
| 104 |  |     /* Remaining cases: vector of VLEN and vector of (transitive) variable sized compound types. | 
| 105 |  |        These all require potential recursion. | 
| 106 |  |     */ | 
| 107 |  |  | 
| 108 |  |     /* Build a memory walker object */ | 
| 109 | 0 |     instance.memory = (char*)memory; /* use char* so we can do pointer arithmetic */ | 
| 110 |  |     /* Walk each vector instance */ | 
| 111 |  |     /* Note that we avoid reclaiming the top level memory */ | 
| 112 | 0 |     for(i=0;i<count;i++) { | 
| 113 | 0 |         if((stat=reclaim_datar(file,utype,instance))) goto done; | 
| 114 | 0 |   instance.memory += utype->size; /* move to next entry */ | 
| 115 | 0 |     } | 
| 116 |  | #else | 
| 117 |  |     stat = NC_EBADTYPE; | 
| 118 |  | #endif | 
| 119 |  |  | 
| 120 | 0 | done: | 
| 121 | 0 |     return stat; | 
| 122 | 0 | } | 
| 123 |  |  | 
| 124 |  | #ifdef USE_NETCDF4 | 
| 125 |  | /* Recursive type walker: reclaim a single instance of a variable-sized user-defined type; | 
| 126 |  |    specifically a vlen or a variable-sized compound type instance | 
| 127 |  | */ | 
| 128 |  | static int | 
| 129 |  | reclaim_datar(NC_FILE_INFO_T* file, NC_TYPE_INFO_T* utype, Position instance) | 
| 130 | 0 | { | 
| 131 | 0 |     int i,stat = NC_NOERR; | 
| 132 | 0 |     nc_type basetypeid; | 
| 133 | 0 |     NC_TYPE_INFO_T* basetype = NULL; | 
| 134 | 0 |     size_t nfields; | 
| 135 | 0 |     nc_vlen_t* vlen; | 
| 136 | 0 |     size_t fid; | 
| 137 | 0 |     int ndims; | 
| 138 | 0 |     int dimsizes[NC_MAX_VAR_DIMS]; | 
| 139 | 0 |     size_t alignment = 0; | 
| 140 | 0 |     Position vinstance; /* walk the vlen instance memory */ | 
| 141 |  | 
 | 
| 142 | 0 |     assert(utype->varsized); /* All fixed size cases are optimized out */ | 
| 143 |  |  | 
| 144 |  |     /* Leaving VLEN or Compound */ | 
| 145 |  | 
 | 
| 146 | 0 |     if(utype->nc_type_class == NC_VLEN) { | 
| 147 | 0 |   basetypeid = utype->u.v.base_nc_typeid; /* Get basetype */ | 
| 148 | 0 |   vlen = (nc_vlen_t*)instance.memory;/* memory as vector of nc_vlen_t instances */ | 
| 149 |  |   /* Optimize: basetype is atomic fixed size */ | 
| 150 | 0 |   if(basetypeid < NC_STRING) { | 
| 151 | 0 |       goto out; | 
| 152 | 0 |     } | 
| 153 |  |   /* Optimize: basetype is string */ | 
| 154 | 0 |   if(basetypeid == NC_STRING) { | 
| 155 | 0 |             if(vlen->len > 0 && vlen->p != NULL) { | 
| 156 | 0 |           char** slist = (char**)vlen->p; /* vlen instance is a vector of string pointers */ | 
| 157 | 0 |     for(i=0;i<vlen->len;i++) {if(slist[i] != NULL) free(slist[i]);} | 
| 158 | 0 |       } | 
| 159 | 0 |       goto out; | 
| 160 | 0 |   } | 
| 161 |  |   /* Optimize: vlen basetype is a fixed-size user-type */ | 
| 162 | 0 |         if((stat = nc4_find_type(file,basetypeid,&basetype))) goto done; | 
| 163 | 0 |         if(!basetype->varsized) { | 
| 164 | 0 |       goto out; | 
| 165 | 0 |   } | 
| 166 |  |         /* Remaining case: basetype is itself variable size => recurse */ | 
| 167 | 0 |         if((stat = NC_type_alignment_internal(file,basetypeid,basetype,&alignment))) goto done;; | 
| 168 | 0 |         vinstance.memory = (char*)vlen->p; /* use char* so we can do pointer arithmetic */ | 
| 169 | 0 |         vinstance.memory = (void*)NC_read_align((uintptr_t)vinstance.memory,alignment); | 
| 170 | 0 |         for(i=0;i<vlen->len;i++) { | 
| 171 | 0 |             if((stat=reclaim_datar(file,basetype,vinstance))) goto done; /* reclaim one basetype instance */ | 
| 172 | 0 |       vinstance.memory += basetype->size; /* move to next base instance */ | 
| 173 | 0 |         } | 
| 174 | 0 | out: | 
| 175 | 0 |         if(vlen->len > 0 && vlen->p != NULL) {free(vlen->p);} | 
| 176 | 0 |         goto done;   | 
| 177 | 0 |     } else if(utype->nc_type_class == NC_COMPOUND) {     | 
| 178 | 0 |   Position finstance;  /* mark the fields's instance */ | 
| 179 | 0 |   nfields = nclistlength(utype->u.c.field); | 
| 180 |  |         /* Get info about each field in turn and reclaim it */ | 
| 181 | 0 |         for(fid=0;fid<nfields;fid++) { | 
| 182 | 0 |       NC_FIELD_INFO_T* field = NULL; | 
| 183 |  |        | 
| 184 |  |       /* Get field's dimension sizes */ | 
| 185 | 0 |       field = (NC_FIELD_INFO_T*)nclistget(utype->u.c.field,fid);     | 
| 186 | 0 |       ndims = field->ndims; | 
| 187 | 0 |       int arraycount = 1; | 
| 188 | 0 |       for(i=0;i<ndims;i++) {dimsizes[i] = field->dim_size[i]; arraycount *= dimsizes[i];} | 
| 189 | 0 |             if(field->ndims == 0) {ndims=1; dimsizes[0]=1;} /* fake the scalar case */ | 
| 190 |  |  | 
| 191 |  |             /* "Move" to start of this field's instance */ | 
| 192 | 0 |             finstance.memory = instance.memory + field->offset; /* includes proper alignment */ | 
| 193 |  |  | 
| 194 |  |       /* optimize: fixed length atomic type */ | 
| 195 | 0 |       if(field->nc_typeid < NC_STRING) continue; | 
| 196 |  |  | 
| 197 |  |       /* optimize: string field type */ | 
| 198 | 0 |       if(field->nc_typeid == NC_STRING) { | 
| 199 | 0 |           char** strvec = (char**)finstance.memory; | 
| 200 | 0 |     for(i=0;i<arraycount;i++) { | 
| 201 | 0 |         if(strvec[i] != NULL) free(strvec[i]); | 
| 202 | 0 |     } | 
| 203 | 0 |     continue; /* do next field */ | 
| 204 | 0 |       } | 
| 205 |  |        | 
| 206 |  |       /* optimize: fixed length compound base type */ | 
| 207 | 0 |             if((stat = nc4_find_type(file,field->nc_typeid,&basetype))) goto done; | 
| 208 | 0 |       if(!basetype->varsized) continue; | 
| 209 |  |  | 
| 210 |  |       /* Field is itself variable length (possibly transitively) */ | 
| 211 | 0 |       for(i=0;i<arraycount;i++) { | 
| 212 | 0 |                 if((stat = reclaim_datar(file, basetype, finstance))) goto done; | 
| 213 | 0 |     finstance.memory += basetype->size; | 
| 214 | 0 |             } | 
| 215 | 0 |         } | 
| 216 | 0 |   goto done; | 
| 217 | 0 |     } else {stat = NC_EBADTYPE; goto done;} | 
| 218 |  |  | 
| 219 | 0 | done: | 
| 220 | 0 |     return stat; | 
| 221 | 0 | } | 
| 222 |  | #endif | 
| 223 |  |  | 
| 224 |  | /**************************************************/ | 
| 225 |  |  | 
| 226 |  | /** | 
| 227 |  | Copy a vector of instances of a type.  This recursively walks | 
| 228 |  | the top-level instances to copy any nested data such as vlen or | 
| 229 |  | strings or such. | 
| 230 |  |  | 
| 231 |  | Assumes it is passed a pointer to count instances of xtype and a | 
| 232 |  | space into which to copy the instance.  Copys any nested data | 
| 233 |  | by calling malloc(). | 
| 234 |  |  | 
| 235 |  | WARNING: DOES NOT ALLOCATE THE TOP-LEVEL MEMORY (see the | 
| 236 |  | nc_copy_data_all function).  Note that all memory blocks other | 
| 237 |  | than the top are dynamically allocated. | 
| 238 |  |  | 
| 239 |  | Should work for any netcdf type. | 
| 240 |  |  | 
| 241 |  | @param file NC_FILE_INFO_T* structure | 
| 242 |  | @param xtype type id | 
| 243 |  | @param memory ptr to top-level memory to reclaim | 
| 244 |  | @param count number of instances of the type in memory block | 
| 245 |  | @param copy top-level space into which to copy the instance | 
| 246 |  | @return error code | 
| 247 |  | */ | 
| 248 |  |  | 
| 249 |  | int | 
| 250 |  | NC_copy_data(NC* nc, nc_type xtype, const void* memory, size_t count, void* copy) | 
| 251 | 0 | { | 
| 252 | 0 |     int stat = NC_NOERR; | 
| 253 | 0 |     size_t i; | 
| 254 | 0 |     Position src; | 
| 255 | 0 |     Position dst; | 
| 256 | 0 |     NC_FILE_INFO_T* file = NULL; | 
| 257 | 0 |     NC_TYPE_INFO_T* utype = NULL; | 
| 258 | 0 |     size_t typesize = 0; | 
| 259 |  | 
 | 
| 260 | 0 |     if(memory == NULL || count == 0) | 
| 261 | 0 |         goto done; /* ok, do nothing */ | 
| 262 |  |  | 
| 263 | 0 |     assert(nc != NULL); | 
| 264 | 0 |     assert(memory != NULL || count > 0); | 
| 265 | 0 |     assert(copy != NULL || count == 0); | 
| 266 |  |  | 
| 267 |  |     /* Process atomic types */ | 
| 268 |  |  | 
| 269 |  |     /* Optimize: Vector of fixed size atomic types */ | 
| 270 | 0 |     if(xtype < NC_STRING) { | 
| 271 | 0 |   typesize = NC_atomictypelen(xtype); | 
| 272 | 0 |         memcpy(copy,memory,count*typesize); | 
| 273 | 0 |   goto done; | 
| 274 | 0 |     } | 
| 275 |  |      | 
| 276 | 0 | #ifdef USE_NETCDF4 | 
| 277 |  |     /* Optimize: Vector of strings */ | 
| 278 | 0 |     if(xtype == NC_STRING) { | 
| 279 | 0 |   char** svec = (char**)memory; | 
| 280 | 0 |   char** dvec = (char**)copy; | 
| 281 | 0 |   size_t len; | 
| 282 | 0 |         for(i=0;i<count;i++) { | 
| 283 | 0 |       const char* ssrc = svec[i]; | 
| 284 | 0 |       char* sdst; | 
| 285 | 0 |       if(ssrc == NULL) | 
| 286 | 0 |     sdst = NULL; | 
| 287 | 0 |       else { | 
| 288 | 0 |           len = nulllen(ssrc); | 
| 289 | 0 |                 if((sdst = (char*)malloc(len+1))==NULL) {stat = NC_ENOMEM; goto done;} | 
| 290 | 0 |           memcpy(sdst,ssrc,len+1); /* +1 for trailing nul */ | 
| 291 | 0 |       } | 
| 292 | 0 |       dvec[i] = sdst; | 
| 293 | 0 |   } | 
| 294 | 0 |         goto done; | 
| 295 | 0 |     } | 
| 296 |  |  | 
| 297 | 0 |     assert(USEFILEINFO(nc) != 0); | 
| 298 | 0 |     file = (NC_FILE_INFO_T*)(nc)->dispatchdata; | 
| 299 |  |  | 
| 300 |  |     /* Process User types */ | 
| 301 | 0 |     if((stat = nc4_find_type(file,xtype,&utype))) goto done; | 
| 302 |  |  | 
| 303 |  |     /* Optimize: vector of fixed sized compound type instances */ | 
| 304 | 0 |     if(!utype->varsized) { | 
| 305 | 0 |         memcpy(copy,memory,count*utype->size); | 
| 306 | 0 |   goto done; | 
| 307 | 0 |     } | 
| 308 |  |  | 
| 309 |  |     /* Remaining cases: vector of VLEN and vector of variable sized compound types. | 
| 310 |  |        These all require potential recursion. | 
| 311 |  |     */ | 
| 312 |  |  | 
| 313 | 0 |     src.memory = (char*)memory; /* use char* so we can do pointer arithmetic */ | 
| 314 | 0 |     dst.memory = (char*)copy; /* use char* so we can do pointer arithmetic */ | 
| 315 |  |     /* Walk each vector instance */ | 
| 316 | 0 |     for(i=0;i<count;i++) { | 
| 317 | 0 |         if((stat=copy_datar(file,utype,src,dst))) goto done; | 
| 318 | 0 |   src.memory += utype->size; | 
| 319 | 0 |   dst.memory += utype->size; | 
| 320 | 0 |     } | 
| 321 |  | #else | 
| 322 |  |     stat = NC_EBADTYPE; | 
| 323 |  | #endif | 
| 324 |  |  | 
| 325 | 0 | done: | 
| 326 | 0 |     return stat; | 
| 327 | 0 | } | 
| 328 |  |  | 
| 329 |  | #ifdef USE_NETCDF4 | 
| 330 |  | /* Recursive type walker: reclaim an instance of variable-sized user-defined types; | 
| 331 |  |    specifically a vlen or a variable-sized compound type instance | 
| 332 |  | */ | 
| 333 |  | static int | 
| 334 |  | copy_datar(NC_FILE_INFO_T* file, NC_TYPE_INFO_T* utype, Position src, Position dst) | 
| 335 | 0 | { | 
| 336 | 0 |     int i, stat = NC_NOERR; | 
| 337 | 0 |     nc_type basetypeid; | 
| 338 | 0 |     NC_TYPE_INFO_T* basetype = NULL; | 
| 339 | 0 |     size_t nfields; | 
| 340 | 0 |     nc_vlen_t* srcvlens = NULL; | 
| 341 | 0 |     nc_vlen_t* dstvlens = NULL; | 
| 342 | 0 |     size_t fid, arraycount; | 
| 343 | 0 |     int ndims; | 
| 344 | 0 |     int dimsizes[NC_MAX_VAR_DIMS]; | 
| 345 | 0 |     Position vsrc, vdst; | 
| 346 | 0 |     size_t alignment = 0; | 
| 347 |  | 
 | 
| 348 | 0 |     assert(utype->varsized); /* All fixed size cases are optimized out */ | 
| 349 |  |  | 
| 350 |  |     /* Leaving VLEN or Compound */ | 
| 351 |  | 
 | 
| 352 | 0 |     if(utype->nc_type_class == NC_VLEN) { | 
| 353 | 0 |   size_t basetypesize = 0; | 
| 354 | 0 |   size_t copycount = 0; | 
| 355 |  | 
 | 
| 356 | 0 |   basetypeid = utype->u.v.base_nc_typeid; /* Get basetype */ | 
| 357 | 0 |   srcvlens = (nc_vlen_t*)src.memory; | 
| 358 | 0 |   dstvlens = (nc_vlen_t*)dst.memory; | 
| 359 | 0 |   dstvlens->len = srcvlens->len; /* always */ | 
| 360 |  | 
 | 
| 361 | 0 |   if(srcvlens->len == 0) { | 
| 362 | 0 |       dstvlens->p = NULL; | 
| 363 | 0 |       goto done; | 
| 364 | 0 |   } | 
| 365 |  |  | 
| 366 | 0 |   if(basetypeid <= NC_MAX_ATOMIC_TYPE) | 
| 367 | 0 |       basetypesize = NC_atomictypelen(basetypeid); | 
| 368 | 0 |         copycount = srcvlens->len*basetypesize; | 
| 369 |  |  | 
| 370 |  |   /* Optimize: basetype is atomic fixed size */ | 
| 371 | 0 |   if(basetypeid < NC_STRING) { | 
| 372 | 0 |       if((dstvlens->p = (void*)malloc(copycount))==NULL) {stat = NC_ENOMEM; goto done;} | 
| 373 | 0 |       memcpy(dstvlens->p,srcvlens->p,copycount); | 
| 374 | 0 |       goto done; | 
| 375 | 0 |     } | 
| 376 |  |  | 
| 377 |  |   /* Optimize: basetype is string */ | 
| 378 | 0 |   if(basetypeid == NC_STRING) { | 
| 379 | 0 |       char** srcstrvec = (char**)srcvlens->p; | 
| 380 | 0 |           char** dststrvec = NULL; | 
| 381 | 0 |       if((dststrvec = (void*)malloc(copycount))==NULL) {stat = NC_ENOMEM; goto done;} | 
| 382 | 0 |           dstvlens->p = (void*)dststrvec; | 
| 383 | 0 |       for(i=0;i<srcvlens->len;i++) { | 
| 384 | 0 |     if((dststrvec[i] = strdup(srcstrvec[i]))==NULL) {stat = NC_ENOMEM; goto done;} | 
| 385 | 0 |       } | 
| 386 | 0 |       goto done; | 
| 387 | 0 |   } | 
| 388 |  |  | 
| 389 |  |   /* User-defined type */ | 
| 390 |  |         /* Recompute base type size */ | 
| 391 | 0 |         if((stat = nc4_find_type(file,basetypeid,&basetype))) goto done; | 
| 392 | 0 |   basetypesize = basetype->size; | 
| 393 | 0 |         copycount = srcvlens->len*basetypesize; | 
| 394 |  |  | 
| 395 |  |   /* Optimize: basetype is user-type fixed size */ | 
| 396 | 0 |         if(!basetype->varsized) { | 
| 397 | 0 |       if((dstvlens->p = (void*)malloc(copycount))==NULL) {stat = NC_ENOMEM; goto done;} | 
| 398 | 0 |       memcpy(dstvlens->p,srcvlens->p,copycount); | 
| 399 | 0 |       goto done; | 
| 400 | 0 |   } | 
| 401 |  |  | 
| 402 |  |         /* Remaining case: basetype is itself variable size => recurse */ | 
| 403 | 0 |         if((stat = NC_type_alignment_internal(file,basetypeid,basetype,&alignment))) goto done;; | 
| 404 | 0 |         vsrc.memory = (char*)srcvlens->p; /* use char* so we can do pointer arithmetic */ | 
| 405 | 0 |         if((vdst.memory = (char*)malloc(copycount))==NULL) {stat = NC_ENOMEM; goto done;} | 
| 406 | 0 |         dstvlens->p = vdst.memory; /* don't lose it */ | 
| 407 | 0 |         vsrc.memory = (void*)NC_read_align((uintptr_t)vsrc.memory,alignment); | 
| 408 | 0 |   vdst.memory = (void*)NC_read_align((uintptr_t)vdst.memory,alignment); | 
| 409 | 0 |         for(i=0;i<srcvlens->len;i++) { | 
| 410 | 0 |             if((stat=copy_datar(file,basetype,vsrc,vdst))) goto done; | 
| 411 | 0 |       vsrc.memory += basetype->size; | 
| 412 | 0 |       vdst.memory += basetype->size; | 
| 413 | 0 |         } | 
| 414 | 0 |   goto done;  | 
| 415 | 0 |     } else if(utype->nc_type_class == NC_COMPOUND) {     | 
| 416 | 0 |   Position fsrc;  /* mark the src fields's instance */ | 
| 417 | 0 |   Position fdst;  /* mark the dst fields's instance */ | 
| 418 | 0 |   nfields = nclistlength(utype->u.c.field); | 
| 419 |  |         /* Get info about each field in turn and copy it */ | 
| 420 | 0 |         for(fid=0;fid<nfields;fid++) { | 
| 421 | 0 |       NC_FIELD_INFO_T* field = NULL; | 
| 422 |  |        | 
| 423 | 0 |       field = (NC_FIELD_INFO_T*)nclistget(utype->u.c.field,fid);     | 
| 424 | 0 |       ndims = field->ndims; | 
| 425 | 0 |       arraycount = 1; | 
| 426 | 0 |       for(i=0;i<ndims;i++) {dimsizes[i] = field->dim_size[i]; arraycount *= (size_t)dimsizes[i];} | 
| 427 | 0 |             if(field->ndims == 0) {ndims=1; dimsizes[0]=1;} /* fake the scalar case */ | 
| 428 |  |  | 
| 429 |  |             /* "move" to this field */ | 
| 430 | 0 |             fsrc.memory = src.memory + field->offset; | 
| 431 | 0 |             fdst.memory = dst.memory + field->offset; | 
| 432 |  |  | 
| 433 |  |       /* optimize: fixed length atomic type */ | 
| 434 | 0 |       if(field->nc_typeid < NC_STRING) { | 
| 435 | 0 |     size_t typesize = NC_atomictypelen(field->nc_typeid); | 
| 436 | 0 |     memcpy(fdst.memory,fsrc.memory,arraycount*typesize); | 
| 437 | 0 |     continue; /* move to next field */ | 
| 438 | 0 |       } | 
| 439 |  |  | 
| 440 |  |       /* optimize: string field type */ | 
| 441 | 0 |       if(field->nc_typeid == NC_STRING) { | 
| 442 | 0 |           char** srcstrvec = (char**)fsrc.memory; | 
| 443 | 0 |           char** dststrvec = (char**)fdst.memory; | 
| 444 | 0 |     for(i=0;i<arraycount;i++)  | 
| 445 | 0 |         {if(srcstrvec[i] != NULL) {dststrvec[i] = strdup(srcstrvec[i]);} else {dststrvec[i] = NULL;}} | 
| 446 | 0 |     continue; /* move to next field */ | 
| 447 | 0 |       } | 
| 448 |  |  | 
| 449 |  |       /* optimize: fixed length compound base type */ | 
| 450 | 0 |             if((stat = nc4_find_type(file,field->nc_typeid,&basetype))) goto done; | 
| 451 | 0 |       if(!basetype->varsized) { | 
| 452 | 0 |     memcpy(fdst.memory,fsrc.memory,arraycount*basetype->size); | 
| 453 | 0 |     continue; /* move to next field */ | 
| 454 | 0 |       } | 
| 455 |  |  | 
| 456 |  |       /* Remaining case; field type is variable type */ | 
| 457 | 0 |             for(i=0;i<arraycount;i++) { | 
| 458 | 0 |                 if((stat = copy_datar(file, basetype, fsrc, fdst))) goto done; | 
| 459 | 0 |     fsrc.memory += basetype->size; | 
| 460 | 0 |     fdst.memory += basetype->size; | 
| 461 | 0 |             } | 
| 462 | 0 |         } | 
| 463 | 0 |   goto done; | 
| 464 |  | 
 | 
| 465 | 0 |     } else {stat = NC_EBADTYPE; goto done;} | 
| 466 |  |  | 
| 467 | 0 | done: | 
| 468 | 0 |     return stat; | 
| 469 | 0 | } | 
| 470 |  | #endif | 
| 471 |  |  | 
| 472 |  | /**************************************************/ | 
| 473 |  | /* Alignment functions */ | 
| 474 |  |  | 
| 475 |  | #ifdef USE_NETCDF4 | 
| 476 |  | uintptr_t | 
| 477 |  | NC_read_align(uintptr_t addr, size_t alignment) | 
| 478 | 0 | { | 
| 479 | 0 |   size_t loc_align = (alignment == 0 ? 1 : alignment); | 
| 480 | 0 |   size_t delta = (addr % loc_align); | 
| 481 | 0 |   if(delta == 0) return addr; | 
| 482 | 0 |   return (addr + (alignment - delta)); | 
| 483 | 0 | } | 
| 484 |  |  | 
| 485 |  |  | 
| 486 |  | /** | 
| 487 |  |  * Compute proper data alignment for a type | 
| 488 |  |  * @param file - only needed for a compound type | 
| 489 |  |  * @param xtype - type for which alignment is requested | 
| 490 |  |  * @param utype - if known | 
| 491 |  |  * @return 0 if not found | 
| 492 |  |  */ | 
| 493 |  | int | 
| 494 |  | NC_type_alignment_internal(NC_FILE_INFO_T* file, nc_type xtype, NC_TYPE_INFO_T* utype, size_t* alignp) | 
| 495 | 0 | { | 
| 496 | 0 |     int stat = NC_NOERR; | 
| 497 | 0 |     size_t align = 0; | 
| 498 | 0 |     int klass; | 
| 499 |  | 
 | 
| 500 | 0 |     if(!type_alignment_initialized) { | 
| 501 | 0 |   NC_compute_alignments(); | 
| 502 | 0 |   type_alignment_initialized = 1; | 
| 503 | 0 |     } | 
| 504 | 0 |     if(xtype <= NC_MAX_ATOMIC_TYPE) | 
| 505 | 0 |         {stat = NC_class_alignment(xtype,&align); goto done;} | 
| 506 | 0 |     else {/* Presumably a user type */ | 
| 507 | 0 |   if(utype == NULL) { | 
| 508 | 0 |             if((stat = nc4_find_type(file,xtype,&utype))) goto done; | 
| 509 | 0 |   } | 
| 510 | 0 |   klass = utype->nc_type_class; | 
| 511 | 0 |   switch(klass) { | 
| 512 | 0 |         case NC_VLEN: stat = NC_class_alignment(klass,&align); break; | 
| 513 | 0 |         case NC_OPAQUE: stat = NC_class_alignment(klass,&align); break; | 
| 514 | 0 |         case NC_COMPOUND: {/* get alignment of the first field of the compound */ | 
| 515 | 0 |       NC_FIELD_INFO_T* field = NULL; | 
| 516 | 0 |       NC_TYPE_INFO_T* basetype = NULL; | 
| 517 | 0 |       if(nclistlength(utype->u.c.field) == 0) {stat = NC_EINVAL; goto done;} | 
| 518 | 0 |           field = (NC_FIELD_INFO_T*)nclistget(utype->u.c.field,0); | 
| 519 | 0 |       if(field->nc_typeid <= NC_MAX_ATOMIC_TYPE) { | 
| 520 | 0 |           if((stat = nc4_find_type(file,field->nc_typeid,&basetype))) goto done; | 
| 521 | 0 |       } | 
| 522 | 0 |       stat =  NC_type_alignment_internal(file,field->nc_typeid,basetype,&align); /* may recurse repeatedly */ | 
| 523 | 0 |   } break; | 
| 524 | 0 |         default: break; | 
| 525 | 0 |   } | 
| 526 | 0 |     } | 
| 527 | 0 |     if(alignp) *alignp = align; | 
| 528 |  | 
 | 
| 529 | 0 | done: | 
| 530 |  | #if 0 | 
| 531 |  | Why was this here? | 
| 532 |  |     if(stat == NC_NOERR && align == 0) stat = NC_EINVAL; | 
| 533 |  | #endif | 
| 534 | 0 |     return stat; | 
| 535 | 0 | } | 
| 536 |  | #endif | 
| 537 |  |  | 
| 538 |  | /**************************************************/ | 
| 539 |  |  | 
| 540 |  | /* Internal versions of the XX_all functions */ | 
| 541 |  |  | 
| 542 |  | /* Alternate entry point: includes recovering the top-level memory */ | 
| 543 |  | int | 
| 544 |  | NC_reclaim_data_all(NC* nc, nc_type xtypeid, void* memory, size_t count) | 
| 545 | 0 | { | 
| 546 | 0 |     int stat = NC_NOERR; | 
| 547 |  | 
 | 
| 548 | 0 |     assert(nc != NULL); | 
| 549 |  | 
 | 
| 550 | 0 |     stat = NC_reclaim_data(nc,xtypeid,memory,count); | 
| 551 | 0 |     if(stat == NC_NOERR && memory != NULL) | 
| 552 | 0 |         free(memory); | 
| 553 | 0 |     return stat; | 
| 554 | 0 | } | 
| 555 |  |  | 
| 556 |  | /* Alternate entry point: includes recovering the top-level memory */ | 
| 557 |  | int | 
| 558 |  | NC_copy_data_all(NC* nc, nc_type xtype, const void* memory, size_t count, void** copyp) | 
| 559 | 0 | { | 
| 560 | 0 |     int stat = NC_NOERR; | 
| 561 | 0 |     size_t xsize = 0; | 
| 562 | 0 |     void* copy = NULL; | 
| 563 | 0 |     NC_FILE_INFO_T* file = NULL; | 
| 564 | 0 |     NC_TYPE_INFO_T* utype = NULL; | 
| 565 |  | 
 | 
| 566 | 0 |     assert(nc != NULL); | 
| 567 |  | 
 | 
| 568 | 0 |     if(xtype <= NC_STRING && count > 0) { | 
| 569 | 0 |         xsize = NC_atomictypelen(xtype); | 
| 570 | 0 |         if((copy = calloc(count,xsize))==NULL) {stat = NC_ENOMEM; goto done;} | 
| 571 | 0 |   if(xtype < NC_STRING) /* fixed-size atomic type */ | 
| 572 | 0 |         memcpy(copy,memory,xsize*count); | 
| 573 | 0 |   else { /* string type */ | 
| 574 | 0 |       size_t i; | 
| 575 | 0 |       char** strvec = (char**)memory; | 
| 576 | 0 |       char** scopyvec = (char**)copy; | 
| 577 | 0 |       for(i=0;i<count;i++) { | 
| 578 | 0 |     char* s = strvec[i]; | 
| 579 | 0 |     char* sdup = NULL; | 
| 580 | 0 |     if(s != NULL) sdup = strdup(s); | 
| 581 | 0 |     scopyvec[i] = sdup; | 
| 582 | 0 |       } | 
| 583 | 0 |   } | 
| 584 | 0 |     } | 
| 585 | 0 | #ifdef USE_NETCDF4 | 
| 586 | 0 |     else { | 
| 587 | 0 |         file = (NC_FILE_INFO_T*)(nc)->dispatchdata; | 
| 588 | 0 |         if((stat = nc4_find_type(file,xtype,&utype))) goto done; | 
| 589 | 0 |         xsize = utype->size; | 
| 590 |  |         /* allocate the top-level */ | 
| 591 | 0 |         if(count > 0) { | 
| 592 | 0 |             if((copy = calloc(count,xsize))==NULL) {stat = NC_ENOMEM; goto done;} | 
| 593 | 0 |         } | 
| 594 | 0 |         if((stat = NC_copy_data(nc,xtype,memory,count,copy))) | 
| 595 | 0 |             (void)NC_reclaim_data_all(nc,xtype,copy,count); | 
| 596 | 0 |     } | 
| 597 | 0 | #endif | 
| 598 | 0 |     if(copyp) {*copyp = copy; copy = NULL;} | 
| 599 | 0 | done: | 
| 600 | 0 |     return stat; | 
| 601 | 0 | } | 
| 602 |  |  | 
| 603 |  | /* Alternate entry point: includes recovering the top-level memory */ | 
| 604 |  | int | 
| 605 |  | NC_print_data(NC_FILE_INFO_T* file, nc_type xtype, const void* memory, size_t count) | 
| 606 | 0 | { | 
| 607 | 0 |     EXTERNL int nc_print_data(int ncid, nc_type xtype, const void* memory, size_t count); | 
| 608 | 0 |     return nc_print_data(file->controller->ext_ncid,xtype,memory,count); | 
| 609 | 0 | } | 
| 610 |  |  |