parser = xml_parser_create(); $this->result = null; $this->inLLSDElement = false; $this->stack = array(); $this->keyStack = array(); $this->depth = 0; $this->skipping = false; $this->skipThrough; $this->currentContent = ''; xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, False); xml_set_object($this->parser, $this); xml_set_element_handler($this->parser, 'tag_open', 'tag_close'); xml_set_character_data_handler($this->parser, 'cdata'); } function GetLLSDObject() { return $this->result; } function parse($data) { $result = xml_parse($this->parser, $data); if( $result == 0 ) { $errno = xml_get_error_code( $this->parser ); $errstr = xml_error_string( $errno ); $line = xml_get_current_line_number( $this->parser ); $col = xml_get_current_column_number( $this->parser ); $msg = "$errstr (line $line, col $col)"; throw new Exception( $msg, $errno ); } } function startSkipping() { $this->skipping = true; $this->skipThrough = $this->depth; } function tag_open($parser, $tag, $attributes) { $this->depth += 1; if ($this->skipping) return; $this->currentContent = ''; switch ($tag) { case 'llsd': if ($this->inLLSDElement) return $this->startSkipping(); $this->inLLSDElement = true; return; case 'key': if (empty($this->keyStack) or end($this->keyStack) === false) return $this->startSkipping(); return; } if (!$this->inLLSDElement) return $this->startSkipping(); switch ($tag) { case 'binary': $this->currentEncoding = $attributes['encoding']; break; case 'map': $this->stack[] = array(); $this->keyStack[] = true; break; case 'array': $this->stack[] = array(); $this->keyStack[] = false; break; } } function tag_close($parser, $tag) { $this->depth -= 1; if ($this->skipping) { if ($this->depth < $this->skipThrough) { $this->skipping = false; } return; } switch ($tag) { case 'llsd': $this->inLLSDElement = false; return; case 'key': array_pop($this->keyStack); $this->keyStack[] = $this->currentContent; return; } if (!$this->inLLSDElement) return; $content = $this->currentContent; $value = null; switch ($tag) { case 'undef': $value = null; break; case 'boolean': $value = $content == 'true' || $content == '1'; break; case 'integer': $value = (int)$content; break; case 'real': $value = (float)$content; break; case 'string': $value = (string)$content; break; case 'uuid': $value = new llsd_UUID; $value->Set($content); break; case 'date': $value = new llsd_Date; $value->Set($content); break; case 'uri': $value = new llsd_URI; $value->Set($content); break; case 'binary': $value = new llsd_Binary; $value->Set($content, $this->currentEncoding); break; case 'array': case 'map': $value = array_pop($this->stack); array_pop($this->keyStack); break; default: $value = null; break; } if (empty($this->stack)) { $this->result = $value; } else { $n = count($this->stack) - 1; $struct = &$this->stack[$n]; $key = $this->keyStack[$n]; if ($key === false) { $struct[] = $value; } else { $struct[$key] = $value; } } } function cdata($parser, $cdata) { if ($this->skipping) return; $this->currentContent .= $cdata; } } function llsd_decode($str) { try { $LLSDParser = new LLSDParser(); $LLSDParser->parse($str); } catch (Exception $e) { return array(); } return $LLSDParser->GetLLSDObject(); } ?>