1 // XMIInspect container methods
2
3 #include "stdafx.h"
4
processContainerData(int block,int container,int size,int type,int subnum,int eindex,int * count)5 int XMIInspect::processContainerData(int block, int container, int size, int type, int subnum, int eindex, int *count)
6 {
7 int stat = 0, i = 0, curvalue = 0;
8 unsigned char *endptr = curptr + size, *startptr = curptr;
9 char isneg, *str = NULL, hexflag = 0;
10 unsigned char c;
11 unsigned int u = 0, restdigits = 0, numdigits = 0;
12 bool base64 = false;
13
14 if (level >= XMIINS_REPORT_ALL) {
15 printf(" processing data for container block %ld/%ld, container %ld/%ld (size: %ld Bytes) of type %s\n",
16 block+1, numblocks, container+1, numcontainers[container], size, ExprInfo::type2text(type));
17 }
18
19 /* check eindex value */
20 if (type == XMIINS_SC_E && (eindex < 0 || eindex >= numglobals)) {
21 if (level >= XMIINS_REPORT_ERRORS) {
22 printf("eindex value out of range: %ld\n", eindex);
23 }
24 stat = XMIINS_ERR_INTERNAL;
25 goto cleanup;
26 }
27
28 switch (type) {
29 case XMIINS_SC_T:
30 while (curptr < endptr) {
31 if (level >= XMIINS_REPORT_ALL) {
32 printf (" text value: '");
33 }
34 delete[] printlstring(curptr, false, XMIINS_REPORT_ALL);
35 if (level >= XMIINS_REPORT_ALL) {
36 printf ("'\n");
37 }
38 (*count)++;
39 }
40 break;
41
42 case XMIINS_SC_U: // report the number
43 case XMIINS_SC_OR: // check & report the current choice
44 case XMIINS_SC_REP: // report the repeat count
45 case XMIINS_SC_E: // check & report the index to the current enum table
46 while (curptr < endptr) {
47 u = Load::UInt32(curptr);
48 switch (type) {
49 case XMIINS_SC_OR:
50 /* check choice no. */
51 if (u >= subnum) {
52 if (level >= XMIINS_REPORT_ERRORS) {
53 printf ("'or' choice value too large: %ld >= %ld\n", u, subnum);
54 }
55 stat = XMIINS_ERR_OR;
56 goto cleanup;
57 }
58 break;
59 case XMIINS_SC_REP:
60 if (level >= XMIINS_REPORT_ALL) {
61 printf (" repeat count: %ld\n", u);
62 }
63 break;
64 case XMIINS_SC_U:
65 if (level >= XMIINS_REPORT_ALL) {
66 printf (" uint32 value: %ld\n", u);
67 }
68 break;
69 case XMIINS_SC_E:
70 /* check index no. */
71 if (u >= index[eindex]) {
72 /* e container -> global data mapping is bogus, just print a warning
73 if (level >= XMIINS_REPORT_ERRORS) {
74 printf ("'e' dictionary index too large: %ld >= %ld\n", u, index[eindex]);
75 }
76 stat = XMIINS_ERR_E;
77 goto cleanup;*/
78 if (level >= XMIINS_REPORT_WARNINGS) {
79 printf ("'e' dictionary index %ld too large: %ld >= %ld. "
80 "Probably an internal mapping error\n",
81 eindex, u, index[eindex]);
82 }
83 }
84 break;
85 default:
86 break;
87 }
88 /* increase the data counter */
89 (*count)++;
90 }
91 break;
92
93 case XMIINS_SC_I:
94 case XMIINS_SC_DI:
95 while (curptr < endptr) {
96 i = Load::SInt32(curptr, &isneg);
97 if (isneg) {
98 i = -i;
99 }
100 if (type == XMIINS_SC_DI) {
101 curvalue += i;
102 } else {
103 curvalue = i;
104 }
105 if (level >= XMIINS_REPORT_ALL) {
106 printf (" sint32/di value: %ld\n", i);
107 }
108 (*count)++;
109 }
110 break;
111
112 case XMIINS_SC_RL: // report run length and text
113 while (curptr < endptr) {
114 /* repeat count */
115 u = Load::UInt32(curptr);
116 /* text to repeat */
117 str = printlstring(curptr, false, XMIINS_REPORT_VERYMUCH);
118 /* report */
119 if (level >= XMIINS_REPORT_ALL) {
120 printf (" rl value: %ld times '%s'\n", u, str);
121 }
122 trydela (str);
123 (*count)++;
124 }
125 break;
126
127 case XMIINS_SC_U8: // report 8-bit number
128 while (curptr < endptr) {
129 /* note, this char is used as an 8-bits number, not an ASCII char! */
130 c = Load::Char(curptr);
131 /* report */
132 if (level >= XMIINS_REPORT_ALL) {
133 printf (" u8 value: %ld\n", c);
134 }
135 (*count)++;
136 }
137 break;
138
139 case XMIINS_SC_BASE64:
140 base64 = true;
141 // no break!
142 case XMIINS_SC_BASEX:
143 case XMIINS_SC_BASE2:
144 case XMIINS_SC_BASE16:
145 case XMIINS_SC_BASE22:
146 while (curptr < endptr) {
147 /* flag */
148 c = Load::Char(curptr);
149 hexflag = c & 0x03;
150 restdigits = (c & 0x7C) >> 2;
151 /* digit count */
152 u = Load::UInt32(curptr);
153 /* skip digit data */
154 if (base64) {
155 curptr += u * 3;
156 /* skip rest digits (possible values: 1-3) */
157 if (restdigits > 0)
158 curptr++;
159 if (restdigits > 1)
160 curptr++;
161 if (restdigits > 2)
162 curptr++;
163 } else {
164 numdigits = u + (restdigits > 0 ? 1 : 0);
165 for (i=0; i<numdigits; i++) {
166 Load::UInt32(curptr);
167 }
168 }
169 (*count)++;
170 }
171 break;
172
173 case XMIINS_SC_SEQCOMB:
174 case XMIINS_SC_SEQ:
175 case XMIINS_SC_C:
176 case XMIINS_SC_P:
177 /* these types should not be hit at all, but check size just to be sure */
178 if (size != 0) {
179 if (level >= XMIINS_REPORT_ERRORS) {
180 printf ("container block %ld/%ld, container %ld/%ld of type %s hase size %ld, should be 0!\n",
181 block+1, numblocks, container+1, numcontainers[container], ExprInfo::type2text(type), size);
182 }
183 stat = XMIINS_ERR_DATASIZE;
184 goto cleanup;
185 }
186 break;
187
188 case XMIINS_SC_UNKNOWN:
189 /* unknown & default should not be hit at all, but skip size just to be sure */
190 case XMIINS_SC_MIXED:
191 default:
192 /* skip the data, don't check or increase data count */
193 curptr += size;
194 break;
195 }
196
197 /* was too little or too much data processed? */
198 if (endptr != curptr) {
199 if (level >= XMIINS_REPORT_ERRORS) {
200 printf ("container block %ld/%ld, container %ld/%ld of type %s hase size %ld, but %ld Bytes were processed!\n",
201 block+1, numblocks, container+1, numcontainers[block], ExprInfo::type2text(type), size,
202 curptr - startptr);
203 }
204 stat = XMIINS_ERR_DATASIZE;
205 goto cleanup;
206 }
207
208 cleanup:
209 return stat;
210 }
211
inspectContainerBlock(int block,int container,bool issmall)212 int XMIInspect::inspectContainerBlock(int block, int container, bool issmall)
213 {
214 int stat = 0, exprnum = 0, type = 0;
215 long size = containersize[block+numblocks*container], macro, labelid;
216 unsigned char *endptr;
217 char isneg;
218 int numprec = 0;
219
220 if (size == 0) {
221 /* empty block, skip it */
222 goto cleanup;
223 }
224
225 if (issmall) {
226 /* small container */
227 if (level >= XMIINS_REPORT_MOREINFO) {
228 printf("block %ld/%ld, container %ld/%ld has size %ld and is contained in this header\n",
229 block+1, numblocks,
230 container+1, numcontainers[block],
231 containersize[block+numblocks*container]);
232 }
233 } else {
234 /* large container */
235 if (level >= XMIINS_REPORT_INFO) {
236 printf("large block %ld/%ld, container %ld/%ld has size %ld\n",
237 curcontainer+1, numblocks,
238 curblock+1, numcontainers[curcontainer],
239 containersize[curcontainer+numblocks*curblock]);
240 }
241 if (len != containersize[curcontainer+numblocks*curblock]) {
242 if (level >= XMIINS_REPORT_ERRORS) {
243 printf("size of uncompressed buffer (%ld Bytes) is not equal to container block %ld/%ld (%ld Bytes)!\n",
244 len, curcontainer+1, numblocks, containersize[curcontainer+numblocks*curblock]);
245 }
246 stat = XMIINS_ERR_CONTAINERSIZE;
247 goto cleanup;
248 }
249 }
250 /* increase run size */
251 runsize += size;
252 /* For block 0, container 0-2 we can check and/or print the data:
253 C0 = structure container (a stream of sint32's)
254 C1 = global whitespace container (a stream of lstring's)
255 C2 = special container for CDATA, PI, CDATA and comments (a stream of lstring's)
256 */
257 if (block == 0) {
258 endptr = curptr + size;
259 switch (container) {
260 case 0:
261 if (level >= XMIINS_REPORT_MOREINFO) {
262 printf(" this is the structure container\n");
263 }
264 do {
265 /* read macro & data flag */
266 macro = Load::SInt32(curptr, &isneg);
267 if (isneg) {
268 /* data, we've just read a container index */
269 if (macro >= numblocks || macro == 0) {
270 if (level >= XMIINS_REPORT_ERRORS) {
271 printf(" container index %ld is out of range (min = %ld, max = %ld)!\n",
272 macro, 1, numblocks-1);
273 }
274 stat = XMIINS_ERR_DATA_INDEX_UNKNOWN;
275 goto cleanup;
276 }
277 /* increase data counts */
278 numcontdata[macro]++;
279 numdata++;
280 /* print info */
281 if (level >= XMIINS_REPORT_ALL) {
282 /* note: macro 0 would refer to the structure container. negative flag is on, so the stored
283 number cannot be 0. pathindex[0] will always be 0, since the structure container has no
284 associated path expression */
285 printf(" container index %ld, associated path expression index: %ld\n", macro, pathindex[macro]);
286 }
287 } else {
288 /* element label or special data */
289 switch (macro) {
290 case TREETOKEN_ENDLABEL:
291 numclose++;
292 if (level >= XMIINS_REPORT_ALL) {
293 printf(" end label\n");
294 }
295 break;
296 case TREETOKEN_EMPTYENDLABEL:
297 numclose++;
298 if (level >= XMIINS_REPORT_ALL) {
299 printf(" empty end label\n");
300 }
301 break;
302 case TREETOKEN_WHITESPACE:
303 numwhite++;
304 if (level >= XMIINS_REPORT_ALL) {
305 printf(" white space\n");
306 }
307 break;
308 case TREETOKEN_ATTRIBWHITESPACE:
309 numwhite++;
310 if (level >= XMIINS_REPORT_ALL) {
311 printf(" attribute white space\n");
312 }
313 break;
314 case TREETOKEN_SPECIAL:
315 numspecial++;
316 if (level >= XMIINS_REPORT_ALL) {
317 printf(" special data\n");
318 }
319 break;
320 default:
321 numopen++;
322 /* label */
323 if ((labelid = macro-LABELIDX_TOKENOFFS) >= numlabels) {
324 stat = XMIINS_ERR_UNKNOWNLABEL;
325 if (level >= XMIINS_REPORT_ERRORS) {
326 printf("label %ld unknown (max = %ld)!\n", labelid, numlabels-1);
327 }
328 goto cleanup;
329 }
330 if (level >= XMIINS_REPORT_ALL) {
331 printf(" label %ld: '%s'\n", labelid, labels[labelid]);
332 }
333 break;
334 }
335 }
336 } while (curptr < endptr);
337 break;
338
339 case 1:
340 if (level >= XMIINS_REPORT_MOREINFO) {
341 printf(" this is the global whitespace container\n");
342 }
343 do {
344 if (level >= XMIINS_REPORT_DEBUG) {
345 printf(" whitespace: ");
346 }
347 delete[] printlstring(curptr, false, XMIINS_REPORT_DEBUG);
348 if (level >= XMIINS_REPORT_DEBUG) {
349 printf("\n");
350 }
351 } while (curptr < endptr);
352 break;
353
354 case 2:
355 if (level >= XMIINS_REPORT_MOREINFO) {
356 printf(" this is the special container\n");
357 }
358 do {
359 if (level >= XMIINS_REPORT_DEBUG) {
360 printf(" special data: ");
361 }
362 delete[] printlstring(curptr, false, XMIINS_REPORT_DEBUG);
363 if (level >= XMIINS_REPORT_DEBUG) {
364 printf("\n");
365 }
366 } while (curptr < endptr);
367 break;
368
369 default:
370 if (level >= XMIINS_REPORT_ERRORS) {
371 printf("Block %ld/%ld, container %ld/%ld is unknown!\n",
372 block+1, numblocks,
373 container+1, numcontainers[block]);
374 }
375 stat = XMIINS_ERR_GLOBALCONTAINER;
376 goto cleanup;
377 }
378 } else {
379 /* normal container block, inspect & report on the container data */
380 exprnum = pathindex[block];
381 type = exprinfo[exprnum]->getTranslatedContainerType(container+1);
382 if (level >= XMIINS_REPORT_MOREINFO) {
383 printf(" the container refers to pathexpr %ld, type: %s\n", exprnum, ExprInfo::type2text(type));
384 }
385 /* type check */
386 if (type == XMIINS_SC_UNKNOWN || (type != XMIINS_SC_MIXED && ExprInfo::numContainers(type) != 1)) {
387 if (level >= XMIINS_REPORT_ERRORS) {
388 printf ("internal error; the type %ld is not correct\n", type);
389 }
390 stat = XMIINS_ERR_INTERNAL;
391 goto cleanup;
392 }
393
394 numprec = numPrecedingBlocks(block, exprnum);
395 /* we should now decode the data and increase the numrealcontdata[block+numblocks*container] count */
396 if ((stat = processContainerData(block, container, size, type,
397 exprinfo[exprnum]->getTranslatedUsedSubs(container),
398 exprinfo[exprnum]->getEnumIndex(block, container, numprec),
399 &numrealcontdata[block+numblocks*container])) != 0) {
400 goto cleanup;
401 }
402 }
403
404 cleanup:
405 return stat;
406 }
407
408 /* read container info from the run header
409 */
readContainerInfo()410 int XMIInspect::readContainerInfo()
411 {
412 int stat = 0, exprcontainernum = 0;
413
414 numblocks = Load::UInt32(curptr);
415 if (level >= XMIINS_REPORT_SOMEINFO) {
416 printf("datasize: %ld Bytes\n# container blocks: %ld\n", datasize, numblocks);
417 }
418 trydela(numcontainers);
419 trydela(containersize);
420 numcontainers = new long[numblocks];
421 pathindex = new long[numblocks];
422 numcontdata = new int[numblocks];
423 numrealcontdata = new int[numblocks*MAXCONTAINERS];
424 containersize = new long[numblocks*MAXCONTAINERS];
425 for (int j = 0; j < numblocks; j++) {
426 numcontdata[j] = 0;
427 /* load & check path index */
428 if ((pathindex[j] = Load::UInt32(curptr)) > numexprs) {
429 if (level >= XMIINS_REPORT_ERRORS) {
430 printf("path index %ld for container %ld out of range (max. %ld)!\n",
431 pathindex[j], j, numexprs);
432 }
433 stat = XMIINS_ERR_CONTAINER_INDEX_UNKNOWN;
434 goto cleanup;
435 }
436 /* load & check # containers in this block */
437 if ((numcontainers[j] = Load::UInt32(curptr)) > MAXCONTAINERS) {
438 if (level >= XMIINS_REPORT_ERRORS) {
439 printf("too many containers: %ld > %ld!\n", numcontainers[j], MAXCONTAINERS);
440 }
441 stat = XMIINS_ERR_TOOMANYCONTAINERS;
442 goto cleanup;
443 }
444 /* check the number against the number of container that the path expression defines */
445 exprcontainernum = exprinfo[pathindex[j]]->getNumContainers();
446 if (numcontainers[j] != exprcontainernum
447 && exprcontainernum != -1) {
448 if (level >= XMIINS_REPORT_ERRORS) {
449 printf("# containers (%ld) in block %ld/%ld mismatches the # containers that pathexpr %ld expects: %ld!\n",
450 numcontainers[j], j+1, numblocks, pathindex[j], exprcontainernum );
451 }
452 stat = XMIINS_ERR_NUM_CONTAINERS_MISMATCH;
453 goto cleanup;
454 }
455
456 /* report some info */
457 if (level >= XMIINS_REPORT_MOREINFO) {
458 printf(" block %ld/%ld path expr index: %ld, # containers: %ld\n",
459 j+1, numblocks,
460 pathindex[j], numcontainers[j]);
461 }
462 /* read container sizes */
463 for (int k = 0; k < numcontainers[j]; k++) {
464 containersize[j+numblocks*k] = Load::UInt32(curptr);
465 numrealcontdata[j+numblocks*k] = 0;
466 if (level >= XMIINS_REPORT_MOREINFO) {
467 printf(" containersize: %ld Bytes\n", containersize[j+numblocks*k]);
468 }
469 }
470 }
471
472 cleanup:
473 return stat;
474 }
475
476 /* read a small container block's container
477 *
478 * structure:
479 * none, as this is dependent on the semantic compressor.
480 */
readSmallContainerBlock()481 int XMIInspect::readSmallContainerBlock()
482 {
483 int stat = 0;
484
485 for (int j = 0; j < numblocks; j++) {
486 for (int k = 0; k < numcontainers[j]; k++) {
487 if (containersize[j+numblocks*k] < SMALLCONT_THRESHOLD) {
488 /* small container, inspect it */
489 if ((stat = inspectContainerBlock(j, k, true)) != 0) {
490 goto cleanup;
491 }
492 } else {
493 /* large container, defer processing */
494 expectedcontainers++;
495 }
496 }
497 }
498
499 cleanup:
500 return stat;
501 }
502
503 /* read a large container block's container
504 *
505 * structure:
506 * none, as this is dependent on the semantic compressor.
507 */
readLargeContainerBlock()508 int XMIInspect::readLargeContainerBlock()
509 {
510 int stat = 0;
511
512 /* find next block & container */
513 while (curcontainer < numblocks && containersize[curcontainer+numblocks*curblock] < SMALLCONT_THRESHOLD) {
514 /* next block */
515 if (++curblock >= numcontainers[curcontainer]) {
516 curblock = 0;
517 /* next container */
518 curcontainer++;
519 }
520 }
521
522 /* found it, now report size & check buffer length */
523 foundcontainers++;
524 if ((stat = inspectContainerBlock(curcontainer, curblock)) != 0) {
525 goto cleanup;
526 }
527
528 /* check if all data was consumed */
529 bytesleft = len - (long)curptr + (long)buffer;
530 if (bytesleft != 0) {
531 if (level >= XMIINS_REPORT_WARNINGS) {
532 printf("container block %ld/%ld now contains %ld Bytes, should be 0!\n",
533 curcontainer+1, expectedcontainers,
534 bytesleft);
535 }
536 } else if (level >= XMIINS_REPORT_MOREINFO) {
537 printf ("large container block %ld/%ld is OK\n", foundcontainers, expectedcontainers);
538 }
539
540 /* find next block & container */
541 do {
542 /* next block */
543 if (++curblock >= numcontainers[curcontainer]) {
544 curblock = 0;
545 /* next container */
546 curcontainer++;
547 }
548 } while (curcontainer < numblocks && containersize[curcontainer+numblocks*curblock] < SMALLCONT_THRESHOLD);
549
550 /* all containers found? */
551 if (foundcontainers == expectedcontainers) {
552 /* all found, this is the end of the run */
553 if ((stat = endThisRun()) != 0) {
554 goto cleanup;
555 }
556 }
557
558 cleanup:
559 return stat;
560 }
561
562