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