ocnode.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. /* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
  2. See the COPYRIGHT file for more information. */
  3. #include "config.h"
  4. #include "ocinternal.h"
  5. #include "ocdebug.h"
  6. static const unsigned int MAX_UINT = 0xffffffff;
  7. static OCerror occomputeskipdatar(OCstate*, OCnode*, ocoffset_t offset);
  8. static int mergedas1(OCnode* dds, OCnode* das);
  9. static int converttype(OCtype etype, char* value, char* memory);
  10. static char* pathtostring(OClist* path, char* separator, int usecdfname);
  11. static void computefullname(OCnode* node);
  12. /* Process ocnodes to fix various semantic issues*/
  13. void
  14. occomputesemantics(OClist* ocnodes)
  15. {
  16. unsigned int i;
  17. OCASSERT((ocnodes != NULL));
  18. for(i=0;i<oclistlength(ocnodes);i++) {
  19. OCnode* node = (OCnode*)oclistget(ocnodes,i);
  20. /* set the container for dims*/
  21. if(node->octype == OC_Dimension && node->dim.array != NULL) {
  22. node->container = node->dim.array->container;
  23. }
  24. }
  25. }
  26. void
  27. occomputefullnames(OCnode* root)
  28. {
  29. unsigned int i;
  30. if(root->name != NULL) computefullname(root);
  31. if(root->subnodes != NULL) { /* recurse*/
  32. for(i=0;i<oclistlength(root->subnodes);i++) {
  33. OCnode* node = (OCnode*)oclistget(root->subnodes,i);
  34. occomputefullnames(node);
  35. }
  36. }
  37. }
  38. static void
  39. computefullname(OCnode* node)
  40. {
  41. char* tmp;
  42. char* fullname;
  43. OClist* path;
  44. OCASSERT((node->name != NULL));
  45. path = oclistnew();
  46. occollectpathtonode(node,path);
  47. tmp = pathtostring(path,PATHSEPARATOR,1);
  48. if(tmp == NULL) {
  49. fullname = nulldup(node->name);
  50. } else {
  51. fullname = tmp;
  52. }
  53. node->fullname = fullname;
  54. oclistfree(path);
  55. }
  56. /* Convert path to a string; leave off the dataset name*/
  57. static char*
  58. pathtostring(OClist* path, char* separator, int usecdfname)
  59. {
  60. int slen,i,len;
  61. char* pathname;
  62. if(path == NULL || (len = oclistlength(path))==0) return NULL;
  63. for(slen=0,i=0;i<len;i++) {
  64. OCnode* node = (OCnode*)oclistget(path,i);
  65. if(node->container == NULL || node->name == NULL) continue;
  66. slen += strlen(node->name);
  67. }
  68. slen += ((len-1)*strlen(separator));
  69. slen += 1; /* for null terminator*/
  70. pathname = (char*)ocmalloc(slen);
  71. MEMCHECK(pathname,NULL);
  72. pathname[0] = '\0';
  73. for(i=0;i<len;i++) {
  74. OCnode* node = (OCnode*)oclistget(path,i);
  75. if(node->container == NULL || node->name == NULL) continue;
  76. if(strlen(pathname) > 0) strcat(pathname,separator);
  77. strcat(pathname,node->name);
  78. }
  79. return pathname;
  80. }
  81. /* Collect the set of nodes ending in "node"*/
  82. void
  83. occollectpathtonode(OCnode* node, OClist* path)
  84. {
  85. if(node == NULL) return;
  86. occollectpathtonode(node->container,path);
  87. oclistpush(path,(ocelem)node);
  88. }
  89. OCnode*
  90. ocmakenode(char* name, OCtype ptype, OCnode* root)
  91. {
  92. OCnode* cdf = (OCnode*)ocmalloc(sizeof(OCnode));
  93. MEMCHECK(cdf,(OCnode*)NULL);
  94. memset((void*)cdf,0,sizeof(OCnode));
  95. cdf->magic = OCMAGIC;
  96. cdf->name = (name?nulldup(name):NULL);
  97. cdf->octype = ptype;
  98. cdf->array.dimensions = NULL;
  99. cdf->root = root;
  100. return cdf;
  101. }
  102. OCattribute*
  103. makeattribute(char* name, OCtype ptype, OClist* values)
  104. {
  105. OCattribute* att = (OCattribute*)ocmalloc(sizeof(OCattribute)); /* ocmalloc zeros*/
  106. MEMCHECK(att,(OCattribute*)NULL);
  107. att->name = nulldup(name);
  108. att->etype = ptype;
  109. att->nvalues = oclistlength(values);
  110. att->values = NULL;
  111. if(att->nvalues > 0) {
  112. int i;
  113. att->values = (char**)ocmalloc(sizeof(char*)*att->nvalues);
  114. for(i=0;i<att->nvalues;i++)
  115. att->values[i] = nulldup((char*)oclistget(values,i));
  116. }
  117. return att;
  118. }
  119. static void
  120. marklostattribute(OCnode* att)
  121. {
  122. oc_log(LOGWARN,"Lost attribute: %s",att->name);
  123. }
  124. void*
  125. oclinearize(OCtype etype, unsigned int nstrings, char** strings)
  126. {
  127. int i;
  128. size_t typesize;
  129. char* memp;
  130. char* memory;
  131. if(nstrings == 0) return NULL;
  132. typesize = octypesize(etype);
  133. memory = (char*)ocmalloc(nstrings*typesize);
  134. MEMCHECK(memory,NULL);
  135. memp = memory;
  136. for(i=0;i<nstrings;i++) {
  137. char* value = strings[i];
  138. converttype(etype,value,memp);
  139. memp += typesize;
  140. }
  141. return memory;
  142. }
  143. static int
  144. converttype(OCtype etype, char* value, char* memory)
  145. {
  146. long iv;
  147. unsigned long uiv;
  148. double dv;
  149. char c[1];
  150. int outofrange = 0;
  151. #ifdef HAVE_LONG_LONG_INT
  152. long long llv;
  153. unsigned long long ullv;
  154. #endif
  155. switch (etype) {
  156. case OC_Char:
  157. if(sscanf(value,"%c",c) != 1) goto fail;
  158. *((char*)memory) = c[0];
  159. break;
  160. case OC_Byte:
  161. if(sscanf(value,"%ld",&iv) != 1) goto fail;
  162. else if(iv > OC_BYTE_MAX || iv < OC_BYTE_MIN) {iv = OC_BYTE_MAX; outofrange = 1;}
  163. *((signed char*)memory) = (signed char)iv;
  164. break;
  165. case OC_UByte:
  166. if(sscanf(value,"%lu",&uiv) != 1) goto fail;
  167. else if(uiv > OC_UBYTE_MAX) {uiv = OC_UBYTE_MAX; outofrange = 1;}
  168. *((unsigned char*)memory) = (unsigned char)uiv;
  169. break;
  170. case OC_Int16:
  171. if(sscanf(value,"%ld",&iv) != 1) goto fail;
  172. else if(iv > OC_INT16_MAX || iv < OC_INT16_MIN) {iv = OC_INT16_MAX; outofrange = 1;}
  173. *((signed short*)memory) = (signed short)iv;
  174. break;
  175. case OC_UInt16:
  176. if(sscanf(value,"%lu",&uiv) != 1) goto fail;
  177. else if(uiv > OC_UINT16_MAX) {uiv = OC_UINT16_MAX; outofrange = 1;}
  178. *((unsigned short*)memory) = (unsigned short)uiv;
  179. break;
  180. case OC_Int32:
  181. if(sscanf(value,"%ld",&iv) != 1) goto fail;
  182. else if(iv > OC_INT32_MAX || iv < OC_INT32_MIN) {iv = OC_INT32_MAX; outofrange = 1;}
  183. *((signed int*)memory) = (signed int)iv;
  184. break;
  185. case OC_UInt32:
  186. if(sscanf(value,"%lu",&uiv) != 1) goto fail;
  187. else if(uiv > OC_UINT32_MAX) {uiv = OC_UINT32_MAX; outofrange = 1;}
  188. *((unsigned char*)memory) = (unsigned int)uiv;
  189. break;
  190. #ifdef HAVE_LONG_LONG_INT
  191. case OC_Int64:
  192. if(sscanf(value,"%lld",&llv) != 1) goto fail;
  193. /*else if(iv > OC_INT64_MAX || iv < OC_INT64_MIN) goto fail;*/
  194. *((signed long long*)memory) = (signed long long)llv;
  195. break;
  196. case OC_UInt64:
  197. if(sscanf(value,"%llu",&ullv) != 1) goto fail;
  198. *((unsigned long long*)memory) = (unsigned long long)ullv;
  199. break;
  200. #endif
  201. case OC_Float32:
  202. if(sscanf(value,"%lf",&dv) != 1) goto fail;
  203. *((float*)memory) = (float)dv;
  204. break;
  205. case OC_Float64:
  206. if(sscanf(value,"%lf",&dv) != 1) goto fail;
  207. *((double*)memory) = (double)dv;
  208. break;
  209. case OC_String: case OC_URL:
  210. *((char**)memory) = nulldup(value);
  211. break;
  212. default:
  213. goto fail;
  214. }
  215. if(outofrange)
  216. oc_log(LOGWARN,"converttype range failure: %d: %s",etype,value);
  217. return 1;
  218. fail:
  219. oc_log(LOGERR,"converttype bad value: %d: %s",etype,value);
  220. return 0;
  221. }
  222. void
  223. ocfreeroot(OCnode* root)
  224. {
  225. OCtree* tree;
  226. OCstate* state;
  227. int i;
  228. if(root == NULL || root->tree == NULL) return;
  229. tree = root->tree;
  230. /* Remove the root from the state->trees list */
  231. state = tree->state;
  232. for(i=0;i<oclistlength(state->trees);i++) {
  233. OCnode* node = (OCnode*)oclistget(state->trees,i);
  234. if(root == node)
  235. oclistremove(state->trees,i);
  236. }
  237. /* Note: it is ok if state->trees does not contain this root */
  238. ocfreetree(tree);
  239. }
  240. void
  241. ocfreetree(OCtree* tree)
  242. {
  243. if(tree == NULL) return;
  244. ocfreenodes(tree->nodes);
  245. ocfree(tree->constraint);
  246. ocfree(tree->text);
  247. if(tree->data.xdrs != NULL) {
  248. xxdr_free(tree->data.xdrs);
  249. }
  250. ocfree(tree->data.filename); /* may be null */
  251. if(tree->data.file != NULL) fclose(tree->data.file);
  252. ocfree(tree->data.memory);
  253. ocfree(tree);
  254. }
  255. void
  256. ocfreenodes(OClist* nodes)
  257. {
  258. unsigned int i,j;
  259. for(i=0;i<oclistlength(nodes);i++) {
  260. OCnode* node = (OCnode*)oclistget(nodes,i);
  261. ocfree(node->name);
  262. ocfree(node->fullname);
  263. while(oclistlength(node->att.values) > 0) {
  264. char* value = (char*)oclistpop(node->att.values);
  265. ocfree(value);
  266. }
  267. while(oclistlength(node->attributes) > 0) {
  268. OCattribute* attr = (OCattribute*)oclistpop(node->attributes);
  269. ocfree(attr->name);
  270. /* If the attribute type is string, then we need to free them*/
  271. if(attr->etype == OC_String || attr->etype == OC_URL) {
  272. char** strings = (char**)attr->values;
  273. for(j=0;j<attr->nvalues;j++) {ocfree(*strings); strings++;}
  274. }
  275. ocfree(attr->values);
  276. ocfree(attr);
  277. }
  278. if(node->array.dimensions != NULL) oclistfree(node->array.dimensions);
  279. if(node->subnodes != NULL) oclistfree(node->subnodes);
  280. if(node->att.values != NULL) oclistfree(node->att.values);
  281. if(node->attributes != NULL) oclistfree(node->attributes);
  282. ocfree(node);
  283. }
  284. oclistfree(nodes);
  285. }
  286. /*
  287. In order to be as compatible as possible with libdap,
  288. we try to use the same algorithm for DAS->DDS matching.
  289. As described there, the algorithm is as follows.
  290. If the [attribute] name contains one or
  291. more field separators then look for a [DDS]variable whose
  292. name matches exactly. If the name contains no field separators then
  293. the look first in the top level [of the DDS] and then in all subsequent
  294. levels and return the first occurrence found. In general, this
  295. searches constructor types in the order in which they appear
  296. in the DDS, but there is no requirement that it do so.
  297. Note: If a dataset contains two constructor types which have field names
  298. that are the same (say point.x and pair.x) one should use fully qualified
  299. names to get each of those variables.
  300. */
  301. int
  302. ocddsdasmerge(OCstate* state, OCnode* dasroot, OCnode* ddsroot)
  303. {
  304. OClist* dasglobals = oclistnew();
  305. OClist* dasnodes = oclistnew();
  306. OClist* varnodes = oclistnew();
  307. OClist* ddsnodes;
  308. unsigned int i,j;
  309. if(dasroot->tree == NULL || dasroot->tree->dxdclass != OCDAS)
  310. return OCTHROW(OC_EINVAL);
  311. if(ddsroot->tree == NULL || (ddsroot->tree->dxdclass != OCDDS
  312. && ddsroot->tree->dxdclass != OCDATADDS))
  313. return OCTHROW(OC_EINVAL);
  314. ddsnodes = ddsroot->tree->nodes;
  315. /* 1. collect all the relevant DAS nodes;
  316. namely those that contain at least one
  317. attribute value.
  318. Simultaneously look for potential ambiguities
  319. if found; complain but continue: result are indeterminate.
  320. also collect globals separately*/
  321. for(i=0;i<oclistlength(dasroot->tree->nodes);i++) {
  322. OCnode* das = (OCnode*)oclistget(dasroot->tree->nodes,i);
  323. int hasattributes = 0;
  324. if(das->octype == OC_Attribute) continue; /* ignore these for now*/
  325. if(das->name == NULL || das->att.isglobal) {
  326. oclistpush(dasglobals,(ocelem)das);
  327. continue;
  328. }
  329. for(j=0;j<oclistlength(das->subnodes);j++) {
  330. OCnode* subnode = (OCnode*)oclistget(das->subnodes,j);
  331. if(subnode->octype == OC_Attribute) {hasattributes = 1; break;}
  332. }
  333. if(hasattributes) {
  334. /* Look for previously collected nodes with same name*/
  335. for(j=0;j<oclistlength(dasnodes);j++) {
  336. OCnode* das2 = (OCnode*)oclistget(dasnodes,j);
  337. if(das->name == NULL || das2->name == NULL) continue;
  338. if(strcmp(das->name,das2->name)==0) {
  339. oc_log(LOGWARN,"oc_mergedas: potentially ambiguous DAS name: %s",das->name);
  340. }
  341. }
  342. oclistpush(dasnodes,(ocelem)das);
  343. }
  344. }
  345. /* 2. collect all the leaf DDS nodes (of type OC_Primitive)*/
  346. for(i=0;i<oclistlength(ddsnodes);i++) {
  347. OCnode* dds = (OCnode*)oclistget(ddsnodes,i);
  348. if(dds->octype == OC_Primitive) oclistpush(varnodes,(ocelem)dds);
  349. }
  350. /* 3. For each das node, locate matching DDS node(s) and attach
  351. attributes to the DDS node(s).
  352. Match means:
  353. 1. DAS->fullname :: DDS->fullname
  354. 2. DAS->name :: DDS->fullname (support DAS names with embedded '.'
  355. 3. DAS->name :: DDS->name
  356. */
  357. for(i=0;i<oclistlength(dasnodes);i++) {
  358. OCnode* das = (OCnode*)oclistget(dasnodes,i);
  359. for(j=0;j<oclistlength(varnodes);j++) {
  360. OCnode* dds = (OCnode*)oclistget(varnodes,j);
  361. if(strcmp(das->fullname,dds->fullname)==0
  362. || strcmp(das->name,dds->fullname)==0
  363. || strcmp(das->name,dds->name)==0) {
  364. mergedas1(dds,das);
  365. /* remove from dasnodes list*/
  366. oclistset(dasnodes,i,(ocelem)NULL);
  367. }
  368. }
  369. }
  370. /* 4. If there are attributes left, then complain about them being lost.*/
  371. for(i=0;i<oclistlength(dasnodes);i++) {
  372. OCnode* das = (OCnode*)oclistget(dasnodes,i);
  373. if(das != NULL) marklostattribute(das);
  374. }
  375. /* 5. Assign globals*/
  376. for(i=0;i<oclistlength(dasglobals);i++) {
  377. OCnode* das = (OCnode*)oclistget(dasglobals,i);
  378. mergedas1(ddsroot,das);
  379. }
  380. /* cleanup*/
  381. oclistfree(dasglobals);
  382. oclistfree(dasnodes);
  383. oclistfree(varnodes);
  384. return OCTHROW(OC_NOERR);
  385. }
  386. static int
  387. mergedas1(OCnode* dds, OCnode* das)
  388. {
  389. unsigned int i;
  390. int stat = OC_NOERR;
  391. if(das == NULL) return OC_NOERR; /* nothing to do */
  392. if(dds->attributes == NULL) dds->attributes = oclistnew();
  393. /* assign the simple attributes in the das set to this dds node*/
  394. for(i=0;i<oclistlength(das->subnodes);i++) {
  395. OCnode* attnode = (OCnode*)oclistget(das->subnodes,i);
  396. if(attnode->octype == OC_Attribute) {
  397. OCattribute* att = makeattribute(attnode->name,
  398. attnode->etype,
  399. attnode->att.values);
  400. oclistpush(dds->attributes,(ocelem)att);
  401. }
  402. }
  403. return OCTHROW(stat);
  404. }
  405. #ifdef OCIGNORE
  406. int
  407. ocddsdasmerge(OCstate* state, OCnode* ddsroot, OCnode* dasroot)
  408. {
  409. int i,j;
  410. int stat = OC_NOERR;
  411. OClist* globals = oclistnew();
  412. if(dasroot == NULL) return OCTHROW(stat);
  413. /* Start by looking for global attributes*/
  414. for(i=0;i<oclistlength(dasroot->subnodes);i++) {
  415. OCnode* node = (OCnode*)oclistget(dasroot->subnodes,i);
  416. if(node->att.isglobal) {
  417. for(j=0;j<oclistlength(node->subnodes);j++) {
  418. OCnode* attnode = (OCnode*)oclistget(node->subnodes,j);
  419. Attribute* att = makeattribute(attnode->name,
  420. attnode->etype,
  421. attnode->att.values);
  422. oclistpush(globals,(ocelem)att);
  423. }
  424. }
  425. }
  426. ddsroot->attributes = globals;
  427. /* Now try to match subnode names with attribute set names*/
  428. for(i=0;i<oclistlength(dasroot->subnodes);i++) {
  429. OCnode* das = (OCnode*)oclistget(dasroot->subnodes,i);
  430. int match = 0;
  431. if(das->att.isglobal) continue;
  432. if(das->octype == OC_Attributeset) {
  433. for(j=0;j<oclistlength(ddsroot->subnodes) && !match;j++) {
  434. OCnode* dds = (OCnode*)oclistget(ddsroot->subnodes,j);
  435. if(strcmp(das->name,dds->name) == 0) {
  436. match = 1;
  437. stat = mergedas1(dds,das);
  438. if(stat != OC_NOERR) break;
  439. }
  440. }
  441. }
  442. if(!match) {marklostattribute(das);}
  443. }
  444. if(stat == OC_NOERR) ddsroot->attributed = 1;
  445. return OCTHROW(stat);
  446. }
  447. /* Merge das attributes into the dds node*/
  448. static int
  449. mergedas1(OCnode* dds, OCnode* das)
  450. {
  451. int i,j;
  452. int stat = OC_NOERR;
  453. if(dds->attributes == NULL) dds->attributes = oclistnew();
  454. /* assign the simple attributes in the das set to this dds node*/
  455. for(i=0;i<oclistlength(das->subnodes);i++) {
  456. OCnode* attnode = (OCnode*)oclistget(das->subnodes,i);
  457. if(attnode->octype == OC_Attribute) {
  458. Attribute* att = makeattribute(attnode->name,
  459. attnode->etype,
  460. attnode->att.values);
  461. oclistpush(dds->attributes,(ocelem)att);
  462. }
  463. }
  464. /* Try to merge any enclosed sets with subnodes of dds*/
  465. for(i=0;i<oclistlength(das->subnodes);i++) {
  466. OCnode* dasnode = (OCnode*)oclistget(das->subnodes,i);
  467. int match = 0;
  468. if(dasnode->octype == OC_Attribute) continue; /* already dealt with above*/
  469. for(j=0;j<oclistlength(dds->subnodes) && !match;j++) {
  470. OCnode* ddsnode = (OCnode*)oclistget(dds->subnodes,j);
  471. if(strcmp(dasnode->name,ddsnode->name) == 0) {
  472. match = 1;
  473. stat = mergedas1(ddsnode,dasnode);
  474. if(stat != OC_NOERR) break;
  475. }
  476. }
  477. if(!match) {marklostattribute(dasnode);}
  478. }
  479. return OCTHROW(stat);
  480. }
  481. #endif
  482. static void
  483. ocuncorrelate(OCnode* root)
  484. {
  485. OCtree* tree = root->tree;
  486. unsigned int i;
  487. if(tree == NULL) return;
  488. for(i=0;i<oclistlength(tree->nodes);i++) {
  489. OCnode* node = (OCnode*)oclistget(tree->nodes,i);
  490. node->datadds = NULL;
  491. }
  492. }
  493. static OCerror
  494. occorrelater(OCnode* dds, OCnode* dxd)
  495. {
  496. int i,j;
  497. OCerror ocstat = OC_NOERR;
  498. if(dds->octype != dxd->octype) {
  499. OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
  500. }
  501. if(dxd->name != NULL && dxd->name != NULL
  502. && strcmp(dxd->name,dds->name) != 0) {
  503. OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
  504. } else if(dxd->name != dxd->name) { /* test NULL==NULL */
  505. OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
  506. }
  507. if(dxd->array.rank != dds->array.rank) {
  508. OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
  509. }
  510. dds->datadds = dxd;
  511. switch (dds->octype) {
  512. case OC_Dataset:
  513. case OC_Structure:
  514. case OC_Grid:
  515. case OC_Sequence:
  516. /* Remember: there may be fewer datadds fields than dds fields */
  517. for(i=0;i<oclistlength(dxd->subnodes);i++) {
  518. OCnode* dxd1 = (OCnode*)oclistget(dxd->subnodes,i);
  519. for(j=0;j<oclistlength(dds->subnodes);j++) {
  520. OCnode* dds1 = (OCnode*)oclistget(dds->subnodes,j);
  521. if(strcmp(dxd1->name,dds1->name) == 0) {
  522. ocstat = occorrelater(dds1,dxd1);
  523. if(ocstat != OC_NOERR) {OCTHROWCHK(ocstat); goto fail;}
  524. break;
  525. }
  526. }
  527. }
  528. break;
  529. case OC_Dimension:
  530. case OC_Primitive:
  531. break;
  532. default: OCPANIC1("unexpected node type: %d",dds->octype);
  533. }
  534. /* Correlate the dimensions */
  535. if(dds->array.rank > 0) {
  536. for(i=0;i<oclistlength(dxd->subnodes);i++) {
  537. OCnode* ddsdim = (OCnode*)oclistget(dds->array.dimensions,i);
  538. OCnode* dxddim = (OCnode*)oclistget(dxd->array.dimensions,i);
  539. ocstat = occorrelater(ddsdim,dxddim);
  540. if(!ocstat) goto fail;
  541. }
  542. }
  543. fail:
  544. return OCTHROW(ocstat);
  545. }
  546. OCerror
  547. occorrelate(OCnode* dds, OCnode* dxd)
  548. {
  549. if(dds == NULL || dxd == NULL) return OC_EINVAL;
  550. ocuncorrelate(dds);
  551. return occorrelater(dds,dxd);
  552. }
  553. /*
  554. Mark cacheable those primitive String/URL typed nodes
  555. that are contained only in structures with rank > 0.
  556. */
  557. void
  558. ocmarkcacheable(OCstate* state, OCnode* ddsroot)
  559. {
  560. int i,j;
  561. #ifdef OCIGNORE
  562. int ok;
  563. #endif
  564. OClist* treenodes = ddsroot->tree->nodes;
  565. OClist* path = oclistnew();
  566. for(i=0;i<oclistlength(treenodes);i++) {
  567. OCnode* node = (OCnode*)oclistget(treenodes,i);
  568. if(node->octype != OC_Primitive) continue;
  569. if(node->etype != OC_String && node->etype != OC_URL) continue;
  570. /* collect node path */
  571. oclistclear(path);
  572. occollectpathtonode(node,path);
  573. #ifdef OCIGNORE
  574. ok = 1;
  575. #endif
  576. for(j=1;j<oclistlength(path)-1;j++) {/* skip top level dataset and node itself*/
  577. OCnode* pathnode = (OCnode*)oclistget(path,j);
  578. if(pathnode->octype != OC_Structure
  579. || pathnode->array.rank > 0) {
  580. #ifdef OCIGNORE
  581. ok=0;
  582. #endif
  583. break;
  584. }
  585. }
  586. #ifdef OCIGNORE
  587. if(ok) {
  588. node->cache.cacheable = 1;
  589. node->cache.valid = 0;
  590. }
  591. #endif
  592. }
  593. oclistfree(path);
  594. }
  595. /*
  596. Fill in the OCnode.skip fields
  597. */
  598. OCerror
  599. occomputeskipdata(OCstate* state, OCnode* ddsroot)
  600. {
  601. OCerror stat = OC_NOERR;
  602. OCASSERT(ddsroot->octype == OC_Dataset);
  603. stat = occomputeskipdatar(state,ddsroot,0);
  604. return stat;
  605. }
  606. /* Recursive helper for computeskipdata */
  607. static OCerror
  608. occomputeskipdatar(OCstate* state, OCnode* xnode, ocoffset_t offset)
  609. {
  610. OCerror stat = OC_NOERR;
  611. int i,nfields;
  612. int scalar = 0;
  613. ocoffset_t instancesize = 0;
  614. ocoffset_t totalsize = 0;
  615. scalar = (xnode->array.rank == 0 ? 1 : 0);
  616. /* Set skip count and offset*/
  617. if(xnode->octype == OC_Sequence)
  618. xnode->skip.count = OCINDETERMINATE;
  619. else
  620. xnode->skip.count = totaldimsize(xnode);
  621. xnode->skip.offset = offset; /* possibly overridden below */
  622. switch (xnode->octype) {
  623. case OC_Primitive:
  624. switch(xnode->etype) {
  625. case OC_String: case OC_URL:
  626. instancesize = OCINDETERMINATE;
  627. totalsize = OCINDETERMINATE;
  628. break;
  629. case OC_Char: case OC_Byte: case OC_UByte:
  630. if(!scalar) {/*=>packed*/
  631. instancesize = octypesize(xnode->etype);
  632. totalsize = instancesize * xnode->skip.count;
  633. totalsize = RNDUP(totalsize);
  634. totalsize += 2*XDRUNIT; /* overhead is double count */
  635. break;
  636. }
  637. /* !packed => singleton char object */
  638. /* fall thru */
  639. case OC_Int16: case OC_UInt16:
  640. case OC_Int32: case OC_UInt32:
  641. case OC_Int64: case OC_UInt64:
  642. case OC_Float32: case OC_Float64:
  643. instancesize = octypesize(xnode->etype);
  644. instancesize = RNDUP(instancesize); /* make multiple of XDRUNIT */
  645. totalsize = (instancesize*xnode->skip.count); /* overhead is double count */
  646. if(!scalar)
  647. totalsize += 2*XDRUNIT; /* overhead is double count */
  648. break;
  649. default:
  650. OCPANIC("unexpected etype"); /* better not happen */
  651. }
  652. break;
  653. case OC_Sequence:
  654. offset = (xnode->skip.offset = OCINDETERMINATE); /* do not know field offsets for arbitrary record */
  655. case OC_Dataset:
  656. case OC_Grid:
  657. case OC_Structure:
  658. /* Compute size of each field and sum */
  659. nfields = oclistlength(xnode->subnodes);
  660. instancesize = 0; /* of structure as a whole */
  661. for(i=0;i<nfields;i++) {
  662. OCnode* subnode = (OCnode*)oclistget(xnode->subnodes,i);
  663. ocoffset_t fieldsize;
  664. if(offset == OCINDETERMINATE || instancesize == OCINDETERMINATE)
  665. stat = occomputeskipdatar(state,subnode,OCINDETERMINATE);
  666. else
  667. stat = occomputeskipdatar(state,subnode,offset+instancesize);
  668. if(stat != OC_NOERR) goto done;
  669. fieldsize = subnode->skip.totalsize;
  670. if(instancesize == OCINDETERMINATE || fieldsize == OCINDETERMINATE)
  671. instancesize = OCINDETERMINATE;
  672. else
  673. instancesize += fieldsize;
  674. }
  675. if(instancesize != OCINDETERMINATE) {
  676. instancesize = RNDUP(instancesize); /* make multiple of XDRUNIT */
  677. totalsize = (instancesize*xnode->skip.count); /* overhead is single count */
  678. if(!scalar)
  679. totalsize += XDRUNIT; /* overhead is single count */
  680. } else {
  681. totalsize = OCINDETERMINATE;
  682. }
  683. if(xnode->octype == OC_Sequence) {
  684. totalsize = OCINDETERMINATE;
  685. offset = OCINDETERMINATE;
  686. }
  687. break;
  688. default: OCPANIC("unexpected octype"); /* better not happen */
  689. }
  690. xnode->skip.offset = offset;
  691. xnode->skip.instancesize = instancesize;
  692. xnode->skip.totalsize = totalsize;
  693. done:
  694. return stat;
  695. }