occontent.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  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 "occontent.h"
  6. #include "ocdebug.h"
  7. /* Mnemonic*/
  8. #define ISPACKED 1
  9. /* Define the skipstate flags */
  10. #ifdef OCDEBUG
  11. typedef enum Skipstate {
  12. SKIPFIELDS = 1, /* skip instance without leading tag or arraycount */
  13. SKIPINSTANCE = 2, /*skip leading sequence tag or array counts */
  14. SKIPWHOLE = 4 /* skip complete object */
  15. } Skipstate;
  16. #else
  17. #define SKIPFIELDS 1 /* skip instance without leading tag or arraycount */
  18. #define SKIPINSTANCE 2 /*skip leading sequence tag or array counts */
  19. #define SKIPWHOLE 4 /* skip complete object */
  20. #endif
  21. /* Forward*/
  22. static OCmode modetransition(OCnode*,OCmode);
  23. static int ocgetsequencetag(XXDR* xdrs);
  24. static int ocskipcounts(XXDR* xdrs, OCnode*, off_t expected);
  25. static int ocarrayith(OCstate*, OCcontent*, OCcontent*, size_t);
  26. static int ocsequenceith(OCstate*, OCcontent*, OCcontent*, size_t);
  27. static int ocfieldith(OCstate*, OCcontent*, OCcontent*, size_t);
  28. static size_t ocarraycount(OCstate*, struct OCcontent*);
  29. static size_t ocsequencecount(OCstate*, struct OCcontent*);
  30. static size_t ocfieldcount(OCstate*, struct OCcontent*);
  31. static size_t ocprimcount(OCstate*, struct OCcontent*);
  32. static OCcontent* occlearcontent(struct OCstate* state, OCcontent* content);
  33. #ifdef OCDEBUG
  34. static void
  35. report(size_t memsize, char* memory)
  36. {
  37. #ifdef OCIGNORE
  38. switch(memsize) {
  39. case 1:
  40. oc_log(LOGNOTE,"reading xdr: %lu bytes = |%2x|",(unsigned long)memsize,memory[0]);
  41. break;
  42. case 4:
  43. oc_log(LOGNOTE,"reading xdr: %lu bytes = |%4lu|",(unsigned long)memsize,*(unsigned int*)memory);
  44. break;
  45. case 8:
  46. oc_log(LOGNOTE,"reading xdr: %lu bytes = |%8lu|",(unsigned long)memsize,*(unsigned long long*)memory);
  47. break;
  48. default:
  49. oc_log(LOGNOTE,"reading xdr: %lu bytes",(unsigned long)memsize);
  50. break;
  51. }
  52. oc_log(LOGNOTE,"reading xdr: %lu bytes",(unsigned long)memsize);
  53. #endif
  54. }
  55. static char*
  56. modestring(OCmode mode)
  57. {
  58. switch(mode) {
  59. case OCFIELDMODE: return "FIELD";
  60. case OCSEQUENCEMODE: return "SEQUENCE";
  61. case OCARRAYMODE: return "ARRAY";
  62. case OCPRIMITIVEMODE: return "PRIMITIVE";
  63. case OCNULLMODE: return "NULL";
  64. case OCEMPTYMODE: return "EMPTY";
  65. }
  66. return "?";
  67. }
  68. void
  69. octrace1(char* proc, OCstate* state, OCcontent* content, int start, int count)
  70. {
  71. unsigned long pos = xxdr_getpos(content->tree->data.xdrs);
  72. fprintf(stderr,"trace: %s mode=%s node=%s (%s)",
  73. proc,modestring(content->mode),content->node->fullname,
  74. octypetostring(content->node->octype));
  75. if(content->packed)
  76. fprintf(stderr," packed=%d",content->packed);
  77. if(count >= 0)
  78. fprintf(stderr," start=%lu count=%lu",
  79. (unsigned long)start,(unsigned long)count);
  80. else
  81. fprintf(stderr," index=%lu",(unsigned long)start);
  82. fprintf(stderr," xdrs.pos=%lu",pos);
  83. fprintf(stderr,"\n");
  84. if(content->cache.valid) {
  85. fprintf(stderr,"\tcache{index=%lu maxindex=%lu offset=%lu}\n",
  86. (unsigned long)content->cache.index,
  87. (unsigned long)content->cache.maxindex,
  88. (unsigned long)content->cache.offset);
  89. }
  90. fflush(stderr);
  91. }
  92. void
  93. octrace(char* proc, OCstate* state, OCcontent* content, int index)
  94. {
  95. octrace1(proc,state,content,index,-1);
  96. }
  97. #else
  98. #define octrace(proc,state,content,index)
  99. #define octrace1(proc,state,content,start,count)
  100. #define report(memsize,memory)
  101. #endif /*OCDEBUG*/
  102. OCmode
  103. ocgetmode(OCcontent* content)
  104. {
  105. return (content == NULL ? OCNULLMODE : content->mode);
  106. }
  107. OCcontent*
  108. ocnewcontent(OCstate* state)
  109. {
  110. OCcontent* content;
  111. if(state == NULL) return NULL;
  112. content = state->contentlist;
  113. /* Search for an unused content node*/
  114. while(content != NULL && content->mode != OCEMPTYMODE) {
  115. content = content->next;
  116. }
  117. if(content == NULL) {
  118. content = (OCcontent*)ocmalloc(sizeof(OCcontent));
  119. MEMCHECK(content,(OCcontent*)NULL);
  120. content->magic = OCMAGIC;
  121. content->next = state->contentlist;
  122. state->contentlist = content;
  123. }
  124. return occlearcontent(state,content);
  125. }
  126. void
  127. ocfreecontent(OCstate* state, OCcontent* content)
  128. {
  129. if(content != NULL) {content->mode = OCEMPTYMODE;}
  130. }
  131. static OCcontent*
  132. occlearcontent(struct OCstate* state, OCcontent* content)
  133. {
  134. /* save fields that should not be cleared */
  135. unsigned int magic = content->magic;
  136. OCcontent* next = content->next;
  137. memset((void*)content,sizeof(OCcontent),0);
  138. /* set/restore non-null fields */
  139. content->magic = magic;
  140. content->next = next;
  141. content->state = state;
  142. content->mode = OCNULLMODE;
  143. return content;
  144. }
  145. static OCcontent*
  146. ocsetcontent(OCcontent* childcontent, OCcontent* parent, OCnode* node, int packed)
  147. {
  148. childcontent->state = parent->state;
  149. childcontent->cache.valid = 0;
  150. childcontent->node = node;
  151. childcontent->tree = node->root->tree;
  152. childcontent->mode = modetransition(node,parent->mode);
  153. childcontent->packed = packed;
  154. return childcontent;
  155. }
  156. #ifdef OCIGNORE
  157. static OCcontent*
  158. occlonecontent(OCstate* state, OCcontent* content)
  159. {
  160. OCcontent* clone = ocnewcontent(state);
  161. clone->mode = content->mode;
  162. clone->node = content->node;
  163. clone->cache = content->indexcache;
  164. return clone;
  165. }
  166. #endif
  167. OCerror
  168. ocdataith(OCstate* state, OCcontent* parent, size_t index, OCcontent* child)
  169. {
  170. OCerror ocerr = OC_NOERR;
  171. switch (parent->mode) {
  172. case OCARRAYMODE:
  173. ocerr = ocarrayith(state,parent,child,index);
  174. break;
  175. case OCSEQUENCEMODE:
  176. ocerr = ocsequenceith(state,parent,child,index);
  177. break;
  178. case OCFIELDMODE:
  179. ocerr = ocfieldith(state,parent,child,index);
  180. break;
  181. default: return OC_EINVAL;
  182. }
  183. if(ocerr == OC_EDATADDS)
  184. ocdataddsmsg(state,parent->tree);
  185. return ocerr;
  186. }
  187. OCerror
  188. ocdatacount(OCstate* state, OCcontent* current, size_t* sizep)
  189. {
  190. OCerror ocerr = OC_NOERR;
  191. size_t count = 0;
  192. switch(current->mode) {
  193. case OCARRAYMODE:
  194. count = ocarraycount(state,current);
  195. break;
  196. case OCSEQUENCEMODE:
  197. count = ocsequencecount(state,current);
  198. break;
  199. case OCFIELDMODE:
  200. count = ocfieldcount(state,current);
  201. break;
  202. case OCPRIMITIVEMODE:
  203. count = ocprimcount(state,current);
  204. break;
  205. default:
  206. return OC_EINVAL;
  207. }
  208. current->cache.maxindex = ocmax(count,current->cache.maxindex);
  209. if(sizep) *sizep = count;
  210. return ocerr;
  211. }
  212. OCerror
  213. ocrootdata(OCstate* state, OCnode* root, OCcontent* content)
  214. {
  215. OCtree* tree;
  216. if(state == NULL || root == NULL || content == NULL)
  217. return OCTHROW(OC_EINVAL);
  218. if(root->tree == NULL) return OCTHROW(OC_EINVAL);
  219. tree = root->tree;
  220. if(tree->dxdclass != OCDATADDS) return OCTHROW(OC_ENODATA);
  221. if(tree->nodes == NULL) return OCTHROW(OC_EINVAL);
  222. if(tree->data.xdrs == NULL)
  223. return OCTHROW(OC_EXDR);
  224. occlearcontent(state,content);
  225. content->mode = OCFIELDMODE;
  226. content->node = root;
  227. content->tree = tree;
  228. content->cache.index = 0;
  229. content->cache.maxindex = oclistlength(content->node->subnodes);
  230. content->cache.offset = 0;
  231. content->cache.valid = 1;
  232. return OCTHROW(OC_NOERR);
  233. }
  234. /* Remember: we are operating wrt the datadds count, not the dds count */
  235. static OCerror
  236. ocarrayith(OCstate* state, OCcontent* content, OCcontent* elemcontent, size_t index)
  237. {
  238. unsigned int i;
  239. int stat = OC_NOERR;
  240. XXDR* xdrs;
  241. int packed, scalar;
  242. OCtype etype,octype;
  243. OCnode* node;
  244. int startindex = 0;
  245. octrace("ocarrayith", state, content, index);
  246. if(state == NULL || content == NULL) return OCTHROW(OC_EINVAL);
  247. if(content->mode != OCARRAYMODE) return OCTHROW(OC_EINVAL);
  248. etype = content->node->etype;
  249. octype = content->node->octype;
  250. node = content->node;
  251. scalar = (node->array.rank == 0 ? 1 : 0);
  252. packed = (!scalar && octype == OC_Primitive &&
  253. (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
  254. xdrs = content->tree->data.xdrs;
  255. if(xdrs == NULL) return OCTHROW(OC_EXDR);
  256. if(!content->cache.valid) {
  257. content->cache.index = 0; /* because we will have to walk to index'th data */
  258. content->cache.maxindex = totaldimsize(node);
  259. content->cache.valid = 1;
  260. /* skip past the initial counts, if any */
  261. if(!scalar) {
  262. if(!ocskipcounts(xdrs,node,node->skip.count)) return OCTHROW(OC_EDATADDS);
  263. }
  264. /* checkpoint xdr position */
  265. content->cache.offset = xxdr_getpos(xdrs);
  266. }
  267. /* move to the checkpoint position */
  268. startindex = content->cache.index;
  269. if(!xxdr_setpos(xdrs,content->cache.offset)) return xdrerror();
  270. /* skip to the index'th item */
  271. if(packed) {
  272. content->cache.index = 0; /* keep at beginning */
  273. } else {
  274. for(i=startindex;i<index;i++) {
  275. stat = ocskipinstance(node,xdrs,SKIPINSTANCE,NULL);
  276. if(stat != OC_NOERR) return OCTHROW(stat);
  277. }
  278. content->cache.index = index; /* now we are at the index'th item */
  279. }
  280. /* update cache */
  281. content->cache.index = index;
  282. content->cache.offset = xxdr_getpos(xdrs);
  283. /* set up the content for the current item in the array */
  284. ocsetcontent(elemcontent,content,node,packed); /*keep same node */
  285. if (index == content->cache.maxindex) {
  286. /* mark eod */
  287. elemcontent->mode = OCNULLMODE;
  288. }
  289. return OCTHROW(stat);
  290. }
  291. static int
  292. ocsequenceith(OCstate* state, OCcontent* content, OCcontent* structcontent, size_t index)
  293. {
  294. unsigned int i;
  295. int stat = OC_NOERR;
  296. XXDR* xdrs;
  297. OCtype octype,etype;
  298. int packed,scalar;
  299. OCnode* node = content->node;
  300. int startindex, tag;
  301. octrace("ocsequenceith", state, content, index);
  302. if(state == NULL || content == NULL) goto einval;
  303. if(content->mode != OCSEQUENCEMODE) goto einval;
  304. if(node->octype != OC_Sequence) goto einval;
  305. octype = node->octype;
  306. etype = node->etype;
  307. scalar = (node->array.rank == 0 ? 1 : 0);
  308. packed = (!scalar && octype == OC_Primitive &&
  309. (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
  310. xdrs = content->tree->data.xdrs;
  311. if(xdrs == NULL) goto exdr;
  312. if(!content->cache.valid) {
  313. content->cache.valid = 1;
  314. content->cache.index = 0;
  315. content->cache.maxindex = 0;
  316. content->cache.offset = xxdr_getpos(xdrs);
  317. }
  318. /* move to checkpoint position*/
  319. startindex = content->cache.index;
  320. if(!xxdr_setpos(xdrs,content->cache.offset)) goto exdr;
  321. /* Walk past the first (index-1) records */
  322. for(tag=StartOfSequence,i=startindex;i<index;i++) {
  323. /* skip instance, including tag, but leave xdr at next tag */
  324. stat = ocskipinstance(node,xdrs,SKIPINSTANCE,&tag);
  325. if(stat != OC_NOERR) goto done;
  326. if(tag == EndOfSequence)
  327. break;
  328. if(tag != StartOfSequence) {
  329. oc_log(LOGERR,"missing/invalid begin/end record marker\n");
  330. goto einvalcoords;
  331. }
  332. }
  333. if(stat != OC_NOERR) goto done;
  334. /* update cache; should be pointing to index'th record tag */
  335. content->cache.index = index;
  336. content->cache.maxindex = ocmax(index,content->cache.index);
  337. /* this is a bit (too) tricky */
  338. /* move to point to fields */
  339. tag = ocgetsequencetag(xdrs);
  340. if(tag == EndOfSequence) {
  341. /* point past end of sequence */
  342. content->cache.offset = xxdr_getpos(xdrs);
  343. } else {/*tag == StartOfSequence*/
  344. /* point to (next) start of sequence */
  345. content->cache.offset = xxdr_getpos(xdrs) - XDRUNIT;
  346. }
  347. /* at this point, xdrs should point unconditionally
  348. past the index'th tag */
  349. /* Set state of new content: keep same node */
  350. ocsetcontent(structcontent,content,node,packed);
  351. if(tag == EndOfSequence) {
  352. /* mark eod */
  353. structcontent->mode = OCNULLMODE;
  354. }
  355. done:
  356. return OCTHROW(stat);
  357. einval:
  358. stat = OC_EINVAL;
  359. goto done;
  360. exdr:
  361. stat = OC_EXDR;
  362. goto done;
  363. einvalcoords:
  364. stat = OC_EINVALCOORDS;
  365. goto done;
  366. }
  367. /*
  368. The ocfieldcontent procedure has to deal with the fact
  369. that the dap constraints may have removed some fields
  370. from the datadds and hence some fields may have no
  371. representation in the xdr data (or compiled data).
  372. Assume that xdr points to start of 0th field.
  373. */
  374. static int
  375. ocfieldith(OCstate* state, OCcontent* content, OCcontent* fieldcontent, size_t index)
  376. {
  377. unsigned int i;
  378. int stat = OC_NOERR;
  379. XXDR* xdrs;
  380. OCtype octype,etype;
  381. int packed;
  382. int isscalar;
  383. OCnode* node;
  384. int startindex;
  385. octrace("ocfieldith", state, content, index);
  386. if(state == NULL || content == NULL) return OCTHROW(OC_EINVAL);
  387. if(content->mode != OCFIELDMODE) return OCTHROW(OC_EINVAL);
  388. node = content->node;
  389. octype = node->octype;
  390. etype = node->etype;
  391. isscalar = (node->array.rank == 0 ? 1 : 0);
  392. packed = (!isscalar && octype == OC_Primitive
  393. && (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
  394. xdrs = content->tree->data.xdrs;
  395. if(xdrs == NULL) return OCTHROW(OC_EXDR);
  396. if(!content->cache.valid) {
  397. content->cache.index = 0;
  398. content->cache.maxindex = oclistlength(node->subnodes);
  399. content->cache.valid = 1;
  400. /* checkpoint xdr position */
  401. content->cache.offset = xxdr_getpos(xdrs);
  402. }
  403. /* move to the checkpoint position */
  404. startindex = content->cache.index;
  405. if(!xxdr_setpos(xdrs,content->cache.offset)) return xdrerror();
  406. switch (octype) {
  407. case OC_Sequence: /* assume xdrs points past sequence tag */
  408. case OC_Grid: /* Note that the Grid array is field 0 and the maps are 1..nsubnodes*/
  409. case OC_Dataset:
  410. case OC_Structure:
  411. /* walk to (i-1)'th field */
  412. for(i=startindex;i<index;i++) { /* walk field by field */
  413. OCnode* ithfield = (OCnode*)oclistget(node->subnodes,i);
  414. stat = ocskipinstance(ithfield,xdrs,SKIPWHOLE,NULL);
  415. if(stat != OC_NOERR) return OCTHROW(stat);
  416. }
  417. break;
  418. default: return OCTHROW(OC_EINVAL);
  419. }
  420. /* update cache */
  421. content->cache.index = index;
  422. content->cache.offset = xxdr_getpos(xdrs);
  423. /* Set state of new content: node changes to field node */
  424. ocsetcontent(fieldcontent,content,
  425. (OCnode*)oclistget(node->subnodes,index),
  426. packed);
  427. if(index >= content->cache.maxindex) {
  428. /* mark eod */
  429. fieldcontent->mode = OCNULLMODE;
  430. }
  431. return OCTHROW(stat);
  432. }
  433. /*
  434. In order to actually extract data,
  435. one must move to the specific primitive typed
  436. field containing the data of interest by using
  437. ocfieldcontent().
  438. Then, oc_getcontent() is invoked to extract
  439. some subsequence of items from the field.
  440. Note that oc_getcontent() will also work for scalars,
  441. but the start must be zero and the count must be one.
  442. */
  443. int
  444. ocgetcontent(OCstate* state, OCcontent* content, void* memory, size_t memsize,
  445. size_t start, size_t count)
  446. {
  447. int stat = OC_NOERR;
  448. XXDR* xdrs;
  449. OCtype etype, octype;
  450. int isscalar, packed;
  451. size_t elemsize, totalsize;
  452. OCnode* node = content->node;
  453. octrace1("ocgetcontent", state, content, start, count);
  454. if(state == NULL || content == NULL || memory == NULL)
  455. {OCTHROWCHK(stat=OC_EINVAL); goto done;}
  456. if(content->mode != OCPRIMITIVEMODE || node->octype != OC_Primitive)
  457. {OCTHROWCHK(stat=OC_EINVAL); goto done;}
  458. octype = node->octype;
  459. etype = node->etype;
  460. isscalar = (node->array.rank == 0);
  461. packed = (!isscalar && octype == OC_Primitive
  462. && (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
  463. if(isscalar && (start != 0 || count != 1))
  464. {OCTHROWCHK(stat=OC_EINVALCOORDS); goto done;}
  465. /* validate memory space*/
  466. elemsize = octypesize(etype);
  467. totalsize = elemsize*count;
  468. if(memsize < totalsize) return OCTHROW(OC_EINVAL);
  469. xdrs = content->tree->data.xdrs;
  470. if(xdrs == NULL) return OCTHROW(OC_EXDR);
  471. /* Need to setup the cache */
  472. if(!content->cache.valid) {
  473. content->cache.valid = 1;
  474. content->cache.index = 0;
  475. content->cache.maxindex = totaldimsize(content->node);
  476. if(!ocskipcounts(xdrs,content->node,content->cache.maxindex))
  477. return OCTHROW(OC_EXDR);
  478. content->cache.offset = xxdr_getpos(xdrs);
  479. }
  480. if(content->cache.valid && content->cache.maxindex < (start+count))
  481. return OCTHROW(OC_ENODATA);
  482. /* utilize the cache */
  483. if(!xxdr_setpos(xdrs,content->cache.offset)) return OCTHROW(OC_EXDR);
  484. /* Extract the data */
  485. stat = ocxdrread(content,xdrs,(char*)memory,memsize,start,count);
  486. #ifdef OCDEBUG
  487. report(memsize,memory+start);
  488. #endif
  489. /* Update the cache */
  490. if(!packed) {
  491. content->cache.index = (start+count);
  492. content->cache.offset = xxdr_getpos(xdrs);
  493. }
  494. done:
  495. return OCTHROW(stat);
  496. }
  497. static size_t
  498. ocfieldcount(OCstate* state, OCcontent* content)
  499. {
  500. OCnode* node = content->node;
  501. size_t count;
  502. OCASSERT((node != NULL));
  503. count = oclistlength(node->subnodes);
  504. return count;
  505. }
  506. static size_t
  507. ocarraycount(OCstate* state, OCcontent* content)
  508. {
  509. unsigned int count;
  510. OCnode* node = content->node;
  511. OCASSERT((node != NULL));
  512. OCASSERT((content->mode == OCARRAYMODE));
  513. count = totaldimsize(node);
  514. #ifdef VERIFY
  515. if(node->array.rank > 0) {
  516. off_t checkpoint;
  517. XXDR* xdrs;
  518. unsigned int xdrcount;
  519. /* verify against xdr */
  520. xdrs = content->tree->data.xdrs;
  521. OCASSERT((xdrs != NULL));
  522. /* checkpoint current location */
  523. checkpoint = xxdr_getpos(xdrs);
  524. /* extract the count*/
  525. if(!xxdr_uint(xdrs,&xdrcount)) return 0;
  526. if(xdrcount != count) return 0;
  527. /* return to checkpoint position*/
  528. if(!xxdr_setpos(xdrs,checkpoint)) return 0;
  529. }
  530. #endif /*VERIFY*/
  531. return (size_t)count;
  532. }
  533. /* Counting records actually requires walking the xdr packet
  534. so it is not necessarily cheap*/
  535. static size_t
  536. ocsequencecount(OCstate* state, OCcontent* content)
  537. {
  538. size_t count;
  539. OCnode* node = content->node;
  540. XXDR* xdrs;
  541. off_t checkpoint;
  542. OCASSERT((node != NULL));
  543. OCASSERT((node->octype == OC_Sequence));
  544. OCASSERT((content->mode == OCSEQUENCEMODE));
  545. xdrs = content->tree->data.xdrs;
  546. OCASSERT((xdrs != NULL));
  547. /* checkpoint location */
  548. checkpoint = xxdr_getpos(xdrs);
  549. for(count=0;;count++) {
  550. int tag;
  551. OCerror stat = ocskipinstance(node,xdrs,SKIPINSTANCE,&tag);
  552. if(stat != OC_NOERR) {count = 0; break;}
  553. if(tag == EndOfSequence) {
  554. break; /* done with the count*/
  555. } else if(tag != StartOfSequence) {
  556. oc_log(LOGERR,"missing/invalid begin/end record marker\n");
  557. return 0;
  558. }
  559. }
  560. /* move back to checkpoint position*/
  561. if(!xxdr_setpos(xdrs,checkpoint)) return 0;
  562. return count;
  563. }
  564. static size_t
  565. ocprimcount(OCstate* state, OCcontent* content)
  566. {
  567. unsigned int count;
  568. OCnode* node = content->node;
  569. OCASSERT((node != NULL));
  570. OCASSERT((content->mode == OCPRIMITIVEMODE));
  571. count = totaldimsize(node);
  572. #ifdef VERIFY
  573. if(node->array.rank > 0) {
  574. off_t checkpoint;
  575. XXDR* xdrs;
  576. unsigned int xdrcount;
  577. /* verify against xdr */
  578. xdrs = content->tree->data.xdrs;
  579. OCASSERT((xdrs != NULL));
  580. /* checkpoint current location */
  581. checkpoint = xxdr_getpos(xdrs);
  582. /* extract the count*/
  583. if(!xxdr_uint(xdrs,&xdrcount)) return 0;
  584. if(xdrcount != count) return 0;
  585. /* return to checkpoint position*/
  586. if(!xxdr_setpos(xdrs,checkpoint)) return 0;
  587. }
  588. #endif /*VERIFY*/
  589. return (size_t)count;
  590. }
  591. static OCmode
  592. modetransition(OCnode* node, OCmode srcmode)
  593. {
  594. OCmode newmode = OCNULLMODE;
  595. switch (srcmode) {
  596. case OCARRAYMODE:
  597. switch (node->octype) {
  598. case OC_Sequence:
  599. newmode = OCSEQUENCEMODE;
  600. break;
  601. case OC_Grid:
  602. case OC_Structure:
  603. newmode = OCFIELDMODE;
  604. break;
  605. default:
  606. break;
  607. }
  608. break;
  609. case OCSEQUENCEMODE:
  610. switch (node->octype) {
  611. default:
  612. newmode = OCFIELDMODE;
  613. break;
  614. }
  615. break;
  616. case OCFIELDMODE:
  617. switch (node->octype) {
  618. case OC_Sequence:
  619. case OC_Grid:
  620. case OC_Structure:
  621. newmode = OCARRAYMODE;
  622. break;
  623. case OC_Primitive:
  624. newmode = OCPRIMITIVEMODE;
  625. break;
  626. default:
  627. break;
  628. }
  629. break;
  630. case OCPRIMITIVEMODE:
  631. case OCNULLMODE:
  632. case OCEMPTYMODE:
  633. default:
  634. newmode = OCNULLMODE;
  635. break;
  636. }
  637. if(newmode == OCNULLMODE)
  638. OCPANIC1("No defined mode transition: %d",(int)srcmode);
  639. return newmode;
  640. }
  641. /* get the presumed current sequence tag */
  642. static int
  643. ocgetsequencetag(XXDR* xdrs)
  644. {
  645. char tag[XDRUNIT];
  646. if(!xxdr_getbytes(xdrs,tag,sizeof(tag))) return 0;
  647. return tag[0];
  648. }
  649. static int
  650. ocskipcounts(XXDR* xdrs, OCnode* node, off_t expected)
  651. {
  652. if(node->array.rank == 0) return 1; /* simple scalar */
  653. #ifdef VERIFY
  654. unsigned int xdrcount0,xdrcount1;
  655. /* Collect the dimension count from the xdr data packet*/
  656. if(!xxdr_uint(xdrs,&xdrcount0)) OCGOTO(shortxdr);
  657. if(expected >= 0 && xdrcount0 != expected) return 0;
  658. /* pull out redundant second count*/
  659. /* (note that String/URL do not have redundant count)*/
  660. if(node->octype == OC_Primitive
  661. && node->etype != OC_String && node->etype != OC_URL) {
  662. if(!xxdr_uint(xdrs,&xdrcount1)) return 0;
  663. if(xdrcount0 != xdrcount1) return 0;
  664. }
  665. #else
  666. /* skip the counts */
  667. expected = expected; /*shut up compiler*/
  668. if(node->octype == OC_Primitive
  669. && node->etype != OC_String && node->etype != OC_URL) {
  670. if(!xxdr_skip(xdrs,2*XDRUNIT)) return 0;
  671. } else {
  672. if(!xxdr_skip(xdrs,XDRUNIT)) return 0;
  673. }
  674. #endif
  675. return 1;
  676. }
  677. /**************************************************/
  678. /* Moved ocdata.c here */
  679. /**************************************************/
  680. const char StartOfSequence = '\x5A';
  681. const char EndOfSequence = '\xA5';
  682. static int ocerrorstring(XXDR* xdrs);
  683. #define LOCALMEMMAX 1024
  684. /*
  685. Skip arbitrary object based on its octype
  686. and a state
  687. Cases:
  688. octype Skip State actions
  689. -------------------------------------------
  690. Structure
  691. |Grid
  692. |DataSet SKIPINSTANCE Skip single instance
  693. |SKIPFIELDS
  694. SKIPWHOLE Skip array of instances
  695. including leading counts
  696. Sequence SKIPFIELDS Skip single record
  697. (assume leading tag already skipped)
  698. SKIPINSTANCE Skip single record
  699. (including leading tag)
  700. SKIPWHOLE Skip all records
  701. including leading tags
  702. and trailing end marker
  703. Primitive <any> Skip whole primitive array
  704. including leading counts
  705. Notes:
  706. 1. unlisted combinations are not legal/possible.
  707. 2. assume that xxdr_getpos is properly positioned.
  708. 3. If octype is OC_Sequence, tagp will be set with the
  709. last tag encountered.
  710. */
  711. OCerror
  712. ocskipinstance(OCnode* node, XXDR* xdrs, int state, int* tagp)
  713. {
  714. int i,tag;
  715. int stat = OC_NOERR;
  716. /* Support switch on combination of octype X state to simply code */
  717. #define CASE(octype,state) ((octype)<<3 | state)
  718. switch (CASE(node->octype,state)) {
  719. case CASE(OC_Dataset,SKIPINSTANCE):
  720. case CASE(OC_Grid,SKIPINSTANCE):
  721. case CASE(OC_Structure,SKIPINSTANCE):
  722. case CASE(OC_Dataset,SKIPFIELDS):
  723. case CASE(OC_Grid,SKIPFIELDS):
  724. case CASE(OC_Structure,SKIPFIELDS):
  725. case CASE(OC_Sequence,SKIPFIELDS): /* NOTE this special case */
  726. if(node->skip.instancesize != OCINDETERMINATE) {
  727. if(!xxdr_skip(xdrs,node->skip.instancesize)) OCGOTO(shortxdr);
  728. } else {/* skip field by field */
  729. for(i=0;i<oclistlength(node->subnodes);i++) {
  730. OCnode* field = (OCnode*)oclistget(node->subnodes,i);
  731. stat = ocskipinstance(field, xdrs, SKIPWHOLE,NULL);
  732. if(stat != OC_NOERR) {OCTHROWCHK(stat); goto done;}
  733. }
  734. }
  735. break;
  736. case CASE(OC_Dataset,SKIPWHOLE):
  737. case CASE(OC_Grid,SKIPWHOLE):
  738. case CASE(OC_Structure,SKIPWHOLE):
  739. OCASSERT(node->skip.count != OCINDETERMINATE);
  740. if(node->skip.totalsize != OCINDETERMINATE) {
  741. if(!xxdr_skip(xdrs,node->skip.totalsize)) goto badxdr;
  742. } else {/* skip each instance */
  743. if(node->array.rank > 0) {
  744. if(!ocskipcounts(xdrs,node,node->skip.count)) goto badxdr;
  745. for(i=0;i<node->skip.count;i++) {
  746. stat = ocskipinstance(node, xdrs, SKIPFIELDS,NULL);
  747. if(stat != OC_NOERR) {OCTHROWCHK(stat); goto done;}
  748. }
  749. } else { /* scalar */
  750. stat = ocskipinstance(node, xdrs, SKIPINSTANCE,NULL);
  751. if(stat != OC_NOERR) {OCTHROWCHK(stat); goto done;}
  752. }
  753. }
  754. break;
  755. case CASE(OC_Sequence,SKIPINSTANCE): /* Skip record including tag */
  756. tag = ocgetsequencetag(xdrs); /* always read the tag */
  757. if(tagp) *tagp = tag;
  758. if(tag == StartOfSequence) { /* skip record fields */
  759. stat = ocskipinstance(node, xdrs, SKIPFIELDS,NULL);
  760. if(stat != OC_NOERR) {OCTHROWCHK(stat); break;}
  761. } /* let caller handle */
  762. break;
  763. case CASE(OC_Sequence,SKIPWHOLE): /* Skip multiple records including tags */
  764. for(i=0;;i++) {
  765. stat = ocskipinstance(node, xdrs, SKIPINSTANCE, &tag);
  766. if(stat != OC_NOERR) {OCTHROWCHK(stat); break;}
  767. if(tag == EndOfSequence) break; /* done */
  768. if(tag != StartOfSequence) goto badxdr; /* malformed */
  769. }
  770. break;
  771. case CASE(OC_Primitive,SKIPWHOLE):
  772. case CASE(OC_Primitive,SKIPINSTANCE):
  773. case CASE(OC_Primitive,SKIPFIELDS):
  774. OCASSERT(node->skip.count != OCINDETERMINATE);
  775. if(node->skip.totalsize != OCINDETERMINATE) {
  776. /* skip directly past it */
  777. if(!xxdr_skip(xdrs,node->skip.totalsize)) goto badxdr;
  778. } else {/* Walk instance by instance */
  779. if(state == SKIPWHOLE) {
  780. /* read the counts */
  781. if(!ocskipcounts(xdrs,node,node->skip.count))
  782. goto badxdr;
  783. }
  784. OCASSERT(node->etype == OC_String || node->etype == OC_URL);
  785. /* get the count */
  786. for(i=0;i<node->skip.count;i++) {
  787. /* read and skip the string */
  788. unsigned int len;
  789. /* read string size */
  790. if(!xxdr_uint(xdrs,&len)) OCGOTO(shortxdr);
  791. /* round up to next XDRUNIT and skip string contents */
  792. len = RNDUP(len);
  793. if(!xxdr_skip(xdrs,(size_t)len)) OCGOTO(shortxdr);
  794. }
  795. }
  796. break;
  797. default:
  798. OCPANIC2("ocskipinstance: encountered unexpected node type or state: %d,%d",
  799. node->octype,state);
  800. break;
  801. }
  802. done:
  803. return OCTHROW(stat);
  804. shortxdr:
  805. oc_log(LOGERR,"short xdr packet");
  806. stat = OC_EXDR;
  807. goto done;
  808. badxdr:
  809. oc_log(LOGERR,"malformed xdr packet");
  810. stat = OC_EXDR;
  811. goto done;
  812. }
  813. /*
  814. Extract data from the xdr packet into a chunk of memory.
  815. Normally, it is assumed that we are (at least virtually)
  816. "at" a single instance in the xdr packet; which we read.
  817. Virtually because for packed data, we need to point to
  818. the beginning of the packed data and use the index to indicate
  819. which packed element to get. Assume that in any case,
  820. any leading counts have been passed.
  821. */
  822. OCerror
  823. ocxdrread(OCcontent* content, XXDR* xdrs, char* memory, size_t memsize,
  824. ocindex_t start, ocindex_t count)
  825. {
  826. int stat = OC_NOERR;
  827. unsigned int i;
  828. size_t elemsize;
  829. size_t readsize;
  830. size_t skipsize;
  831. char localmem[LOCALMEMMAX];
  832. char* srcmem;
  833. unsigned int* p;
  834. int packed;
  835. int scalar;
  836. OCtype octype,etype;
  837. ocindex_t localstart = start; /* will change if node is cacheing */
  838. OCnode* node;
  839. node = content->node;
  840. octype = node->octype;
  841. etype = node->etype;
  842. elemsize = octypesize(etype);
  843. scalar = (node->array.rank == 0 ? 1 : 0);
  844. /* check if the data is packed*/
  845. packed = (octype == OC_Primitive && !scalar
  846. && (etype == OC_Byte || etype == OC_UByte || etype == OC_Char));
  847. /* validate memory space*/
  848. if(memsize < elemsize*count) return OCTHROW(OC_EINVAL);
  849. #ifdef OCIGNORE
  850. if(!scalar && (!node->cache.cacheable || !node->cache.valid)) {
  851. unsigned int xdrcount0,xdrcount1;
  852. /* assume xdr position is correct */
  853. /* Read leading double count if ! scalar*/
  854. if(!xxdr_uint(xdrs,&xdrcount0)) OCGOTO(shortxdr);
  855. if(!xxdr_uint(xdrs,&xdrcount1)) OCGOTO(shortxdr);
  856. if(xdrcount0 != xdrcount1) return OCTHROW(OC_EXDR);
  857. if(xdrcount0 < start+count) OCGOTO(shortxdr);
  858. }
  859. #endif
  860. /* Handle packed data specially*/
  861. if(packed) {
  862. readsize = count*1; /* |OC_(Char,Byte,UByte)| == 1 */
  863. skipsize = start*1; /* |OC_(Char,Byte,UByte)| == 1 */
  864. /* skip to start of what we want to read */
  865. if(!xxdr_skip(xdrs,skipsize)) OCGOTO(shortxdr);
  866. /* read data, keeping xdrs on XDRUNIT boundary */
  867. if(!xxdr_opaque(xdrs,memory,readsize))
  868. OCGOTO(shortxdr);
  869. return OCTHROW(OC_NOERR);
  870. }
  871. /* Not packed */
  872. #ifdef OCIGNORE
  873. /* If this (primitive) object is cacheable and is valid cache,
  874. then modify start and set the xdr position accordingly
  875. */
  876. if(node->cache.cacheable && node->cache.valid) {
  877. if(node->cache.index <= start) {
  878. localstart -= node->cache.index;
  879. if(!xxdr_setpos(xdrs,node->cache.offset)) return xdrerror();
  880. }
  881. }
  882. #endif
  883. /* Compute how much to skip based on the content's cache index */
  884. localstart = start - content->cache.index;
  885. if(localstart < 0) localstart = 0;
  886. /* extract count items; use xxdr_getbytes to speed up*/
  887. srcmem = memory;
  888. switch (etype) {
  889. case OC_Float64: case OC_Int64: case OC_UInt64:
  890. readsize = count*2*XDRUNIT;
  891. skipsize = localstart*2*XDRUNIT;
  892. /* skip to start of what we want to read */
  893. if(!xxdr_skip(xdrs,skipsize)) OCGOTO(shortxdr);
  894. if(!xxdr_opaque(xdrs,(char*)srcmem,readsize)) OCGOTO(shortxdr);
  895. if(etype == OC_Float64) {
  896. double* dp;
  897. for(dp=(double*)srcmem,i=0;i<count;i++,dp++) {
  898. double swap;
  899. xxdrntohdouble((char*)dp,&swap);
  900. *dp = swap;
  901. }
  902. } else if(!xxdr_network_order) {
  903. unsigned long long* llp;
  904. for(llp=(unsigned long long*)srcmem,i=0;i<count;i++,p++) {
  905. swapinline64(llp);
  906. }
  907. }
  908. break;
  909. case OC_String: case OC_URL: {
  910. /* Read string by string */
  911. char* s = NULL;
  912. char** pmem = (char**)srcmem;
  913. /* First skip to the starting string */
  914. for(i=0;i<localstart;i++) {
  915. unsigned int slen;
  916. if(!xxdr_uint(xdrs,&slen)) OCGOTO(shortxdr);
  917. slen = RNDUP(slen);
  918. if(!xxdr_skip(xdrs,slen)) OCGOTO(shortxdr);
  919. }
  920. /* Read count strings */
  921. for(i=0;i<count;i++) {
  922. off_t slen;
  923. /* xxdr_string will always alloc the space */
  924. if(!xxdr_string(xdrs,&s,&slen))
  925. OCGOTO(shortxdr);
  926. pmem[i] = s;
  927. }
  928. } break;
  929. case OC_Char: case OC_Byte: case OC_UByte:
  930. case OC_Int16: case OC_UInt16:
  931. /* We need to store the xdr data locally until we can convert it out
  932. because elemsize < sizeof(int) */
  933. srcmem = localmem;
  934. if(count*elemsize > sizeof(localmem)) {
  935. srcmem = (char*)ocmalloc(count*sizeof(unsigned int));
  936. if(srcmem == NULL) {stat = OCTHROW(OC_ENOMEM); goto done;}
  937. }
  938. /* fall thru */
  939. case OC_Int32: case OC_UInt32:
  940. case OC_Float32:
  941. readsize = (count)*XDRUNIT;
  942. skipsize = (localstart)*XDRUNIT;
  943. if(!xxdr_skip(xdrs,skipsize)) OCGOTO(shortxdr);
  944. if(!xxdr_opaque(xdrs,(char*)srcmem,readsize)) OCGOTO(shortxdr);
  945. if(!xxdr_network_order) {
  946. for(p=(unsigned int*)srcmem,i=0;i<count;i++,p++) {
  947. swapinline32(p);
  948. }
  949. }
  950. break;
  951. default: OCPANIC("unexpected etype"); break;
  952. }
  953. /* Convert memory to right format */
  954. switch (etype) {
  955. case OC_Char: case OC_Byte: case OC_UByte: {
  956. char* pmem = (char*)memory;
  957. p = (unsigned int*)srcmem;
  958. for(i=0;i<count;i++) {
  959. unsigned int tmp = *p++;
  960. *pmem++ = (unsigned char)tmp;
  961. }
  962. } break;
  963. case OC_Int16: case OC_UInt16: {
  964. unsigned short* pmem = (unsigned short*)memory;
  965. p = (unsigned int*)srcmem;
  966. for(i=0;i<count;i++) {
  967. unsigned int tmp = *p++;
  968. *pmem++ = (unsigned short)tmp;
  969. }
  970. } break;
  971. default:
  972. break; /* already handled above */
  973. }
  974. /* set cache */
  975. content->cache.index = start + count; /* should be our current index */
  976. content->cache.offset = xxdr_getpos(xdrs); /* should be our current position */
  977. done:
  978. return OCTHROW(stat);
  979. shortxdr:
  980. content->cache.valid = 0; /* no longer valid */
  981. if(!ocerrorstring(xdrs))
  982. oc_log(LOGERR,"DAP DATADDS packet is apparently too short");
  983. stat = OCTHROW(OC_EDATADDS);
  984. goto done;
  985. }
  986. int
  987. occountrecords(OCnode* node, XXDR* xdrs, size_t* nrecordsp)
  988. {
  989. int stat = OC_NOERR;
  990. size_t nrecords = 0;
  991. if(node->octype != OC_Sequence) return OCTHROW(OC_EINVAL);
  992. /* checkpoint the xdr position*/
  993. for(nrecords=0;;nrecords++) {
  994. int tag = 0;
  995. stat = ocskipinstance(node,xdrs,SKIPINSTANCE,&tag);
  996. if(stat != OC_NOERR) break;
  997. if(tag == EndOfSequence) break;
  998. if(tag != StartOfSequence) {
  999. oc_log(LOGERR,"missing/invalid begin/end record marker\n");
  1000. stat = OC_EINVALCOORDS;
  1001. break;
  1002. }
  1003. if(stat != OC_NOERR) break;
  1004. }
  1005. if(nrecordsp != NULL) *nrecordsp = nrecords;
  1006. return OCTHROW(stat);
  1007. }
  1008. #define tag "Error {\n"
  1009. static int
  1010. ocerrorstring(XXDR* xdrs)
  1011. {
  1012. /* Check to see if the xdrs contains "Error {\n'; assume it is at the beginning of data */
  1013. off_t avail = xxdr_getavail(xdrs);
  1014. char* data = (char*)malloc(avail);
  1015. if(!xxdr_setpos(xdrs,0)) return 0;
  1016. if(!xxdr_opaque(xdrs,data,avail)) return 0;
  1017. /* check for error tag at front */
  1018. if(ocstrncmp(data,tag,sizeof(tag))==0) {
  1019. char* p;
  1020. if((p=strchr(data,'}')) != NULL) *(++p)='\0';
  1021. oc_log(LOGERR,"Server error: %s",data);
  1022. /* Since important, report to stderr as well */
  1023. fprintf(stderr,"Server error: %s",data);
  1024. return 1;
  1025. }
  1026. return 0;
  1027. }