1 | <?php |
---|
2 | /*********************************************** |
---|
3 | * File : wbxmldecoder.php |
---|
4 | * Project : Z-Push |
---|
5 | * Descr : WBXMLDecoder decodes from Wap Binary XML |
---|
6 | * |
---|
7 | * Created : 01.10.2007 |
---|
8 | * |
---|
9 | * Copyright 2007 - 2012 Zarafa Deutschland GmbH |
---|
10 | * |
---|
11 | * This program is free software: you can redistribute it and/or modify |
---|
12 | * it under the terms of the GNU Affero General Public License, version 3, |
---|
13 | * as published by the Free Software Foundation with the following additional |
---|
14 | * term according to sec. 7: |
---|
15 | * |
---|
16 | * According to sec. 7 of the GNU Affero General Public License, version 3, |
---|
17 | * the terms of the AGPL are supplemented with the following terms: |
---|
18 | * |
---|
19 | * "Zarafa" is a registered trademark of Zarafa B.V. |
---|
20 | * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH |
---|
21 | * The licensing of the Program under the AGPL does not imply a trademark license. |
---|
22 | * Therefore any rights, title and interest in our trademarks remain entirely with us. |
---|
23 | * |
---|
24 | * However, if you propagate an unmodified version of the Program you are |
---|
25 | * allowed to use the term "Z-Push" to indicate that you distribute the Program. |
---|
26 | * Furthermore you may use our trademarks where it is necessary to indicate |
---|
27 | * the intended purpose of a product or service provided you use it in accordance |
---|
28 | * with honest practices in industrial or commercial matters. |
---|
29 | * If you want to propagate modified versions of the Program under the name "Z-Push", |
---|
30 | * you may only do so if you have a written permission by Zarafa Deutschland GmbH |
---|
31 | * (to acquire a permission please contact Zarafa at trademark@zarafa.com). |
---|
32 | * |
---|
33 | * This program is distributed in the hope that it will be useful, |
---|
34 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
35 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
36 | * GNU Affero General Public License for more details. |
---|
37 | * |
---|
38 | * You should have received a copy of the GNU Affero General Public License |
---|
39 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
40 | * |
---|
41 | * Consult LICENSE file for details |
---|
42 | ************************************************/ |
---|
43 | |
---|
44 | |
---|
45 | class WBXMLDecoder extends WBXMLDefs { |
---|
46 | private $in; |
---|
47 | |
---|
48 | private $version; |
---|
49 | private $publicid; |
---|
50 | private $publicstringid; |
---|
51 | private $charsetid; |
---|
52 | private $stringtable; |
---|
53 | |
---|
54 | private $tagcp = 0; |
---|
55 | private $attrcp = 0; |
---|
56 | |
---|
57 | private $ungetbuffer; |
---|
58 | |
---|
59 | private $logStack = array(); |
---|
60 | |
---|
61 | private $inputBuffer = ""; |
---|
62 | private $isWBXML = true; |
---|
63 | |
---|
64 | const VERSION = 0x03; |
---|
65 | |
---|
66 | /** |
---|
67 | * WBXML Decode Constructor |
---|
68 | * |
---|
69 | * @param stream $input the incoming data stream |
---|
70 | * |
---|
71 | * @access public |
---|
72 | */ |
---|
73 | public function WBXMLDecoder($input) { |
---|
74 | // make sure WBXML_DEBUG is defined. It should be at this point |
---|
75 | if (!defined('WBXML_DEBUG')) define('WBXML_DEBUG', false); |
---|
76 | |
---|
77 | $this->in = $input; |
---|
78 | |
---|
79 | $this->readVersion(); |
---|
80 | if (isset($this->version) && $this->version != self::VERSION) { |
---|
81 | $this->isWBXML = false; |
---|
82 | return; |
---|
83 | } |
---|
84 | |
---|
85 | $this->publicid = $this->getMBUInt(); |
---|
86 | if($this->publicid == 0) { |
---|
87 | $this->publicstringid = $this->getMBUInt(); |
---|
88 | } |
---|
89 | |
---|
90 | $this->charsetid = $this->getMBUInt(); |
---|
91 | $this->stringtable = $this->getStringTable(); |
---|
92 | } |
---|
93 | |
---|
94 | /** |
---|
95 | * Returns either start, content or end, and auto-concatenates successive content |
---|
96 | * |
---|
97 | * @access public |
---|
98 | * @return element/value |
---|
99 | */ |
---|
100 | public function getElement() { |
---|
101 | $element = $this->getToken(); |
---|
102 | |
---|
103 | switch($element[EN_TYPE]) { |
---|
104 | case EN_TYPE_STARTTAG: |
---|
105 | return $element; |
---|
106 | case EN_TYPE_ENDTAG: |
---|
107 | return $element; |
---|
108 | case EN_TYPE_CONTENT: |
---|
109 | while(1) { |
---|
110 | $next = $this->getToken(); |
---|
111 | if($next == false) |
---|
112 | return false; |
---|
113 | else if($next[EN_TYPE] == EN_CONTENT) { |
---|
114 | $element[EN_CONTENT] .= $next[EN_CONTENT]; |
---|
115 | } else { |
---|
116 | $this->ungetElement($next); |
---|
117 | break; |
---|
118 | } |
---|
119 | } |
---|
120 | return $element; |
---|
121 | } |
---|
122 | |
---|
123 | return false; |
---|
124 | } |
---|
125 | |
---|
126 | /** |
---|
127 | * Get a peek at the next element |
---|
128 | * |
---|
129 | * @access public |
---|
130 | * @return element |
---|
131 | */ |
---|
132 | public function peek() { |
---|
133 | $element = $this->getElement(); |
---|
134 | $this->ungetElement($element); |
---|
135 | return $element; |
---|
136 | } |
---|
137 | |
---|
138 | /** |
---|
139 | * Get the element of a StartTag |
---|
140 | * |
---|
141 | * @param $tag |
---|
142 | * |
---|
143 | * @access public |
---|
144 | * @return element/boolean returns false if not available |
---|
145 | */ |
---|
146 | public function getElementStartTag($tag) { |
---|
147 | $element = $this->getToken(); |
---|
148 | |
---|
149 | if($element[EN_TYPE] == EN_TYPE_STARTTAG && $element[EN_TAG] == $tag) |
---|
150 | return $element; |
---|
151 | else { |
---|
152 | ZLog::Write(LOGLEVEL_WBXMLSTACK, sprintf("WBXMLDecoder->getElementStartTag(): unmatched WBXML tag: '%s' matching '%s' type '%s' flags '%s'", $tag, ((isset($element[EN_TAG]))?$element[EN_TAG]:""), ((isset($element[EN_TYPE]))?$element[EN_TYPE]:""), ((isset($element[EN_FLAGS]))?$element[EN_FLAGS]:""))); |
---|
153 | $this->ungetElement($element); |
---|
154 | } |
---|
155 | |
---|
156 | return false; |
---|
157 | } |
---|
158 | |
---|
159 | /** |
---|
160 | * Get the element of a EndTag |
---|
161 | * |
---|
162 | * @access public |
---|
163 | * @return element/boolean returns false if not available |
---|
164 | */ |
---|
165 | public function getElementEndTag() { |
---|
166 | $element = $this->getToken(); |
---|
167 | |
---|
168 | if($element[EN_TYPE] == EN_TYPE_ENDTAG) |
---|
169 | return $element; |
---|
170 | else { |
---|
171 | ZLog::Write(LOGLEVEL_WBXMLSTACK, sprintf("WBXMLDecoder->getElementEndTag(): unmatched WBXML tag: '%s' type '%s' flags '%s'", ((isset($element[EN_TAG]))?$element[EN_TAG]:""), ((isset($element[EN_TYPE]))?$element[EN_TYPE]:""), ((isset($element[EN_FLAGS]))?$element[EN_FLAGS]:""))); |
---|
172 | |
---|
173 | $bt = debug_backtrace(); |
---|
174 | ZLog::Write(LOGLEVEL_ERROR, sprintf("WBXMLDecoder->getElementEndTag(): could not read end tag in '%s'. Please enable the LOGLEVEL_WBXML and send the log to the Z-Push dev team.", $bt[0]["file"] . ":" . $bt[0]["line"])); |
---|
175 | |
---|
176 | // log the remaining wbxml content |
---|
177 | $this->ungetElement($element); |
---|
178 | while($el = $this->getElement()); |
---|
179 | } |
---|
180 | |
---|
181 | return false; |
---|
182 | } |
---|
183 | |
---|
184 | /** |
---|
185 | * Get the content of an element |
---|
186 | * |
---|
187 | * @access public |
---|
188 | * @return string/boolean returns false if not available |
---|
189 | */ |
---|
190 | public function getElementContent() { |
---|
191 | $element = $this->getToken(); |
---|
192 | |
---|
193 | if($element[EN_TYPE] == EN_TYPE_CONTENT) { |
---|
194 | return $element[EN_CONTENT]; |
---|
195 | } |
---|
196 | else { |
---|
197 | ZLog::Write(LOGLEVEL_WBXMLSTACK, sprintf("WBXMLDecoder->getElementContent(): unmatched WBXML content: '%s' type '%s' flags '%s'", ((isset($element[EN_TAG]))?$element[EN_TAG]:""), ((isset($element[EN_TYPE]))?$element[EN_TYPE]:""), ((isset($element[EN_FLAGS]))?$element[EN_FLAGS]:""))); |
---|
198 | $this->ungetElement($element); |
---|
199 | } |
---|
200 | |
---|
201 | return false; |
---|
202 | } |
---|
203 | |
---|
204 | /** |
---|
205 | * 'Ungets' an element writing it into a buffer to be 'get' again |
---|
206 | * |
---|
207 | * @param element $element the element to get ungetten |
---|
208 | * |
---|
209 | * @access public |
---|
210 | * @return |
---|
211 | */ |
---|
212 | public function ungetElement($element) { |
---|
213 | if($this->ungetbuffer) |
---|
214 | ZLog::Write(LOGLEVEL_ERROR,sprintf("WBXMLDecoder->ungetElement(): WBXML double unget on tag: '%s' type '%s' flags '%s'", ((isset($element[EN_TAG]))?$element[EN_TAG]:""), ((isset($element[EN_TYPE]))?$element[EN_TYPE]:""), ((isset($element[EN_FLAGS]))?$element[EN_FLAGS]:""))); |
---|
215 | |
---|
216 | $this->ungetbuffer = $element; |
---|
217 | } |
---|
218 | |
---|
219 | /** |
---|
220 | * Returns the plain input stream |
---|
221 | * |
---|
222 | * @access public |
---|
223 | * @return string |
---|
224 | */ |
---|
225 | public function GetPlainInputStream() { |
---|
226 | $plain = $this->inputBuffer; |
---|
227 | while($data = fread($this->in, 4096)) |
---|
228 | $plain .= $data; |
---|
229 | |
---|
230 | return $plain; |
---|
231 | } |
---|
232 | |
---|
233 | /** |
---|
234 | * Returns if the input is WBXML |
---|
235 | * |
---|
236 | * @access public |
---|
237 | * @return boolean |
---|
238 | */ |
---|
239 | public function IsWBXML() { |
---|
240 | return $this->isWBXML; |
---|
241 | } |
---|
242 | |
---|
243 | |
---|
244 | |
---|
245 | /**---------------------------------------------------------------------------------------------------------- |
---|
246 | * Private WBXMLDecoder stuff |
---|
247 | */ |
---|
248 | |
---|
249 | /** |
---|
250 | * Returns the next token |
---|
251 | * |
---|
252 | * @access private |
---|
253 | * @return token |
---|
254 | */ |
---|
255 | private function getToken() { |
---|
256 | // See if there's something in the ungetBuffer |
---|
257 | if($this->ungetbuffer) { |
---|
258 | $element = $this->ungetbuffer; |
---|
259 | $this->ungetbuffer = false; |
---|
260 | return $element; |
---|
261 | } |
---|
262 | |
---|
263 | $el = $this->_getToken(); |
---|
264 | $this->logToken($el); |
---|
265 | |
---|
266 | return $el; |
---|
267 | } |
---|
268 | |
---|
269 | /** |
---|
270 | * Log the a token to ZLog |
---|
271 | * |
---|
272 | * @param string $el token |
---|
273 | * |
---|
274 | * @access private |
---|
275 | * @return |
---|
276 | */ |
---|
277 | private function logToken($el) { |
---|
278 | if(!WBXML_DEBUG) |
---|
279 | return; |
---|
280 | |
---|
281 | $spaces = str_repeat(" ", count($this->logStack)); |
---|
282 | |
---|
283 | switch($el[EN_TYPE]) { |
---|
284 | case EN_TYPE_STARTTAG: |
---|
285 | if($el[EN_FLAGS] & EN_FLAGS_CONTENT) { |
---|
286 | ZLog::Write(LOGLEVEL_WBXML,"I " . $spaces . " <". $el[EN_TAG] . ">"); |
---|
287 | array_push($this->logStack, $el[EN_TAG]); |
---|
288 | } else |
---|
289 | ZLog::Write(LOGLEVEL_WBXML,"I " . $spaces . " <" . $el[EN_TAG] . "/>"); |
---|
290 | |
---|
291 | break; |
---|
292 | case EN_TYPE_ENDTAG: |
---|
293 | $tag = array_pop($this->logStack); |
---|
294 | ZLog::Write(LOGLEVEL_WBXML,"I " . $spaces . "</" . $tag . ">"); |
---|
295 | break; |
---|
296 | case EN_TYPE_CONTENT: |
---|
297 | ZLog::Write(LOGLEVEL_WBXML,"I " . $spaces . " " . $el[EN_CONTENT]); |
---|
298 | break; |
---|
299 | } |
---|
300 | } |
---|
301 | |
---|
302 | /** |
---|
303 | * Returns either a start tag, content or end tag |
---|
304 | * |
---|
305 | * @access private |
---|
306 | * @return |
---|
307 | */ |
---|
308 | private function _getToken() { |
---|
309 | // Get the data from the input stream |
---|
310 | $element = array(); |
---|
311 | |
---|
312 | while(1) { |
---|
313 | $byte = $this->getByte(); |
---|
314 | |
---|
315 | if(!isset($byte)) |
---|
316 | break; |
---|
317 | |
---|
318 | switch($byte) { |
---|
319 | case WBXML_SWITCH_PAGE: |
---|
320 | $this->tagcp = $this->getByte(); |
---|
321 | continue; |
---|
322 | |
---|
323 | case WBXML_END: |
---|
324 | $element[EN_TYPE] = EN_TYPE_ENDTAG; |
---|
325 | return $element; |
---|
326 | |
---|
327 | case WBXML_ENTITY: |
---|
328 | $entity = $this->getMBUInt(); |
---|
329 | $element[EN_TYPE] = EN_TYPE_CONTENT; |
---|
330 | $element[EN_CONTENT] = $this->entityToCharset($entity); |
---|
331 | return $element; |
---|
332 | |
---|
333 | case WBXML_STR_I: |
---|
334 | $element[EN_TYPE] = EN_TYPE_CONTENT; |
---|
335 | $element[EN_CONTENT] = $this->getTermStr(); |
---|
336 | return $element; |
---|
337 | |
---|
338 | case WBXML_LITERAL: |
---|
339 | $element[EN_TYPE] = EN_TYPE_STARTTAG; |
---|
340 | $element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt()); |
---|
341 | $element[EN_FLAGS] = 0; |
---|
342 | return $element; |
---|
343 | |
---|
344 | case WBXML_EXT_I_0: |
---|
345 | case WBXML_EXT_I_1: |
---|
346 | case WBXML_EXT_I_2: |
---|
347 | $this->getTermStr(); |
---|
348 | // Ignore extensions |
---|
349 | continue; |
---|
350 | |
---|
351 | case WBXML_PI: |
---|
352 | // Ignore PI |
---|
353 | $this->getAttributes(); |
---|
354 | continue; |
---|
355 | |
---|
356 | case WBXML_LITERAL_C: |
---|
357 | $element[EN_TYPE] = EN_TYPE_STARTTAG; |
---|
358 | $element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt()); |
---|
359 | $element[EN_FLAGS] = EN_FLAGS_CONTENT; |
---|
360 | return $element; |
---|
361 | |
---|
362 | case WBXML_EXT_T_0: |
---|
363 | case WBXML_EXT_T_1: |
---|
364 | case WBXML_EXT_T_2: |
---|
365 | $this->getMBUInt(); |
---|
366 | // Ingore extensions; |
---|
367 | continue; |
---|
368 | |
---|
369 | case WBXML_STR_T: |
---|
370 | $element[EN_TYPE] = EN_TYPE_CONTENT; |
---|
371 | $element[EN_CONTENT] = $this->getStringTableEntry($this->getMBUInt()); |
---|
372 | return $element; |
---|
373 | |
---|
374 | case WBXML_LITERAL_A: |
---|
375 | $element[EN_TYPE] = EN_TYPE_STARTTAG; |
---|
376 | $element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt()); |
---|
377 | $element[EN_ATTRIBUTES] = $this->getAttributes(); |
---|
378 | $element[EN_FLAGS] = EN_FLAGS_ATTRIBUTES; |
---|
379 | return $element; |
---|
380 | case WBXML_EXT_0: |
---|
381 | case WBXML_EXT_1: |
---|
382 | case WBXML_EXT_2: |
---|
383 | continue; |
---|
384 | |
---|
385 | case WBXML_OPAQUE: |
---|
386 | $length = $this->getMBUInt(); |
---|
387 | $element[EN_TYPE] = EN_TYPE_CONTENT; |
---|
388 | $element[EN_CONTENT] = $this->getOpaque($length); |
---|
389 | return $element; |
---|
390 | |
---|
391 | case WBXML_LITERAL_AC: |
---|
392 | $element[EN_TYPE] = EN_TYPE_STARTTAG; |
---|
393 | $element[EN_TAG] = $this->getStringTableEntry($this->getMBUInt()); |
---|
394 | $element[EN_ATTRIBUTES] = $this->getAttributes(); |
---|
395 | $element[EN_FLAGS] = EN_FLAGS_ATTRIBUTES | EN_FLAGS_CONTENT; |
---|
396 | return $element; |
---|
397 | |
---|
398 | default: |
---|
399 | $element[EN_TYPE] = EN_TYPE_STARTTAG; |
---|
400 | $element[EN_TAG] = $this->getMapping($this->tagcp, $byte & 0x3f); |
---|
401 | $element[EN_FLAGS] = ($byte & 0x80 ? EN_FLAGS_ATTRIBUTES : 0) | ($byte & 0x40 ? EN_FLAGS_CONTENT : 0); |
---|
402 | if($byte & 0x80) |
---|
403 | $element[EN_ATTRIBUTES] = $this->getAttributes(); |
---|
404 | return $element; |
---|
405 | } |
---|
406 | } |
---|
407 | } |
---|
408 | |
---|
409 | /** |
---|
410 | * Gets attributes |
---|
411 | * |
---|
412 | * @access private |
---|
413 | * @return |
---|
414 | */ |
---|
415 | private function getAttributes() { |
---|
416 | $attributes = array(); |
---|
417 | $attr = ""; |
---|
418 | |
---|
419 | while(1) { |
---|
420 | $byte = $this->getByte(); |
---|
421 | |
---|
422 | if(count($byte) == 0) |
---|
423 | break; |
---|
424 | |
---|
425 | switch($byte) { |
---|
426 | case WBXML_SWITCH_PAGE: |
---|
427 | $this->attrcp = $this->getByte(); |
---|
428 | break; |
---|
429 | |
---|
430 | case WBXML_END: |
---|
431 | if($attr != "") |
---|
432 | $attributes += $this->splitAttribute($attr); |
---|
433 | |
---|
434 | return $attributes; |
---|
435 | |
---|
436 | case WBXML_ENTITY: |
---|
437 | $entity = $this->getMBUInt(); |
---|
438 | $attr .= $this->entityToCharset($entity); |
---|
439 | return $attr; /* fmbiete's contribution r1534, ZP-324 */ |
---|
440 | |
---|
441 | case WBXML_STR_I: |
---|
442 | $attr .= $this->getTermStr(); |
---|
443 | return $attr; /* fmbiete's contribution r1534, ZP-324 */ |
---|
444 | |
---|
445 | case WBXML_LITERAL: |
---|
446 | if($attr != "") |
---|
447 | $attributes += $this->splitAttribute($attr); |
---|
448 | |
---|
449 | $attr = $this->getStringTableEntry($this->getMBUInt()); |
---|
450 | return $attr; /* fmbiete's contribution r1534, ZP-324 */ |
---|
451 | |
---|
452 | case WBXML_EXT_I_0: |
---|
453 | case WBXML_EXT_I_1: |
---|
454 | case WBXML_EXT_I_2: |
---|
455 | $this->getTermStr(); |
---|
456 | continue; |
---|
457 | |
---|
458 | case WBXML_PI: |
---|
459 | case WBXML_LITERAL_C: |
---|
460 | // Invalid |
---|
461 | return false; |
---|
462 | |
---|
463 | case WBXML_EXT_T_0: |
---|
464 | case WBXML_EXT_T_1: |
---|
465 | case WBXML_EXT_T_2: |
---|
466 | $this->getMBUInt(); |
---|
467 | continue; |
---|
468 | |
---|
469 | case WBXML_STR_T: |
---|
470 | $attr .= $this->getStringTableEntry($this->getMBUInt()); |
---|
471 | return $attr; /* fmbiete's contribution r1534, ZP-324 */ |
---|
472 | |
---|
473 | case WBXML_LITERAL_A: |
---|
474 | return false; |
---|
475 | |
---|
476 | case WBXML_EXT_0: |
---|
477 | case WBXML_EXT_1: |
---|
478 | case WBXML_EXT_2: |
---|
479 | continue; |
---|
480 | |
---|
481 | case WBXML_OPAQUE: |
---|
482 | $length = $this->getMBUInt(); |
---|
483 | $attr .= $this->getOpaque($length); |
---|
484 | return $attr; /* fmbiete's contribution r1534, ZP-324 */ |
---|
485 | |
---|
486 | case WBXML_LITERAL_AC: |
---|
487 | return false; |
---|
488 | |
---|
489 | default: |
---|
490 | if($byte < 128) { |
---|
491 | if($attr != "") { |
---|
492 | $attributes += $this->splitAttribute($attr); |
---|
493 | $attr = ""; |
---|
494 | } |
---|
495 | } |
---|
496 | $attr .= $this->getMapping($this->attrcp, $byte); |
---|
497 | break; |
---|
498 | } |
---|
499 | } |
---|
500 | } |
---|
501 | |
---|
502 | /** |
---|
503 | * Splits an attribute |
---|
504 | * |
---|
505 | * @param string $attr attribute to be splitted |
---|
506 | * |
---|
507 | * @access private |
---|
508 | * @return array |
---|
509 | */ |
---|
510 | private function splitAttribute($attr) { |
---|
511 | $attributes = array(); |
---|
512 | |
---|
513 | $pos = strpos($attr,chr(61)); // equals sign |
---|
514 | |
---|
515 | if($pos) |
---|
516 | $attributes[substr($attr, 0, $pos)] = substr($attr, $pos+1); |
---|
517 | else |
---|
518 | $attributes[$attr] = null; |
---|
519 | |
---|
520 | return $attributes; |
---|
521 | } |
---|
522 | |
---|
523 | /** |
---|
524 | * Reads from the stream until getting a string terminator |
---|
525 | * |
---|
526 | * @access private |
---|
527 | * @return string |
---|
528 | */ |
---|
529 | private function getTermStr() { |
---|
530 | $str = ""; |
---|
531 | while(1) { |
---|
532 | $in = $this->getByte(); |
---|
533 | |
---|
534 | if($in == 0) |
---|
535 | break; |
---|
536 | else |
---|
537 | $str .= chr($in); |
---|
538 | } |
---|
539 | |
---|
540 | return $str; |
---|
541 | } |
---|
542 | |
---|
543 | /** |
---|
544 | * Reads $len from the input stream |
---|
545 | * |
---|
546 | * @param int $len |
---|
547 | * |
---|
548 | * @access private |
---|
549 | * @return string |
---|
550 | */ |
---|
551 | private function getOpaque($len) { |
---|
552 | // TODO check if it's possible to do it other way |
---|
553 | // fread stops reading because the following condition is true (from php.net): |
---|
554 | // if the stream is read buffered and it does not represent a plain file, |
---|
555 | // at most one read of up to a number of bytes equal to the chunk size |
---|
556 | // (usually 8192) is made; depending on the previously buffered data, |
---|
557 | // the size of the returned data may be larger than the chunk size. |
---|
558 | |
---|
559 | // using only return fread it will return only a part of stream if chunk is smaller |
---|
560 | // than $len. Read from stream in a loop until the $len is reached. |
---|
561 | $d = ""; |
---|
562 | $l = 0; |
---|
563 | while (1) { |
---|
564 | $l = (($len - strlen($d)) > 8192) ? 8192 : ($len - strlen($d)); |
---|
565 | if ($l > 0) { |
---|
566 | $data = fread($this->in, $l); |
---|
567 | |
---|
568 | // Stream ends prematurely on instable connections and big mails |
---|
569 | if ($data === false || feof($this->in)) |
---|
570 | throw new HTTPReturnCodeException(sprintf("WBXMLDecoder->getOpaque() connection unavailable while trying to read %d bytes from stream. Aborting after %d bytes read.", $len, strlen($d)), HTTP_CODE_500, null, LOGLEVEL_WARN); |
---|
571 | else |
---|
572 | $d .= $data; |
---|
573 | } |
---|
574 | if (strlen($d) >= $len) break; |
---|
575 | } |
---|
576 | return $d; |
---|
577 | } |
---|
578 | |
---|
579 | /** |
---|
580 | * Reads one byte from the input stream |
---|
581 | * |
---|
582 | * @access private |
---|
583 | * @return int |
---|
584 | */ |
---|
585 | private function getByte() { |
---|
586 | $ch = fread($this->in, 1); |
---|
587 | if(strlen($ch) > 0) |
---|
588 | return ord($ch); |
---|
589 | else |
---|
590 | return; |
---|
591 | } |
---|
592 | |
---|
593 | /** |
---|
594 | * Reads string length from the input stream |
---|
595 | * |
---|
596 | * @access private |
---|
597 | * @return |
---|
598 | */ |
---|
599 | private function getMBUInt() { |
---|
600 | $uint = 0; |
---|
601 | |
---|
602 | while(1) { |
---|
603 | $byte = $this->getByte(); |
---|
604 | |
---|
605 | $uint |= $byte & 0x7f; |
---|
606 | |
---|
607 | if($byte & 0x80) |
---|
608 | $uint = $uint << 7; |
---|
609 | else |
---|
610 | break; |
---|
611 | } |
---|
612 | |
---|
613 | return $uint; |
---|
614 | } |
---|
615 | |
---|
616 | /** |
---|
617 | * Reads string table from the input stream |
---|
618 | * |
---|
619 | * @access private |
---|
620 | * @return int |
---|
621 | */ |
---|
622 | private function getStringTable() { |
---|
623 | $stringtable = ""; |
---|
624 | |
---|
625 | $length = $this->getMBUInt(); |
---|
626 | if($length > 0) |
---|
627 | $stringtable = fread($this->in, $length); |
---|
628 | |
---|
629 | return $stringtable; |
---|
630 | } |
---|
631 | |
---|
632 | /** |
---|
633 | * Returns the mapping for a specified codepage and id |
---|
634 | * |
---|
635 | * @param $cp codepage |
---|
636 | * @param $id |
---|
637 | * |
---|
638 | * @access public |
---|
639 | * @return string |
---|
640 | */ |
---|
641 | private function getMapping($cp, $id) { |
---|
642 | if(!isset($this->dtd["codes"][$cp]) || !isset($this->dtd["codes"][$cp][$id])) |
---|
643 | return false; |
---|
644 | else { |
---|
645 | if(isset($this->dtd["namespaces"][$cp])) { |
---|
646 | return $this->dtd["namespaces"][$cp] . ":" . $this->dtd["codes"][$cp][$id]; |
---|
647 | } else |
---|
648 | return $this->dtd["codes"][$cp][$id]; |
---|
649 | } |
---|
650 | } |
---|
651 | |
---|
652 | /** |
---|
653 | * Reads one byte from the input stream |
---|
654 | * |
---|
655 | * @access private |
---|
656 | * @return void |
---|
657 | */ |
---|
658 | private function readVersion() { |
---|
659 | $ch = $this->getByte(); |
---|
660 | |
---|
661 | if($ch != NULL) { |
---|
662 | $this->inputBuffer .= chr($ch); |
---|
663 | $this->version = $ch; |
---|
664 | } |
---|
665 | } |
---|
666 | } |
---|
667 | |
---|
668 | ?> |
---|