3 require_once 'Services/JSON.php';
6 class Pman_Builder_Generator_JSON extends Services_JSON
13 function __construct($use = 0) {
15 foreach($use as $k=>$v) {
26 function _encode($var)
29 switch (gettype($var)) {
31 return $var ? 'true' : 'false';
44 // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
46 $strlen_var = strlen($var);
49 * Iterate over every character in the string,
50 * escaping with a slash or encoding to UTF-8 where necessary
52 for ($c = 0; $c < $strlen_var; ++$c) {
54 $ord_var_c = ord($var[$c]);
57 case $ord_var_c == 0x08:
60 case $ord_var_c == 0x09:
63 case $ord_var_c == 0x0A:
66 case $ord_var_c == 0x0C:
69 case $ord_var_c == 0x0D:
73 case $ord_var_c == 0x22:
74 case $ord_var_c == 0x2F:
75 case $ord_var_c == 0x5C:
76 // double quote, slash, slosh
77 $ascii .= '\\'.$var[$c];
80 case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
81 // characters U-00000000 - U-0000007F (same as ASCII)
85 case (($ord_var_c & 0xE0) == 0xC0):
86 // characters U-00000080 - U-000007FF, mask 110XXXXX
87 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
88 if ($c+1 >= $strlen_var) {
94 $char = pack('C*', $ord_var_c, ord($var[$c + 1]));
96 $utf16 = $this->utf82utf16($char);
97 $ascii .= sprintf('\u%04s', bin2hex($utf16));
100 case (($ord_var_c & 0xF0) == 0xE0):
101 if ($c+2 >= $strlen_var) {
106 // characters U-00000800 - U-0000FFFF, mask 1110XXXX
107 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
108 $char = pack('C*', $ord_var_c,
112 $utf16 = $this->utf82utf16($char);
113 $ascii .= sprintf('\u%04s', bin2hex($utf16));
116 case (($ord_var_c & 0xF8) == 0xF0):
117 if ($c+3 >= $strlen_var) {
122 // characters U-00010000 - U-001FFFFF, mask 11110XXX
123 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
124 $char = pack('C*', $ord_var_c,
129 $utf16 = $this->utf82utf16($char);
130 $ascii .= sprintf('\u%04s', bin2hex($utf16));
133 case (($ord_var_c & 0xFC) == 0xF8):
134 // characters U-00200000 - U-03FFFFFF, mask 111110XX
135 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
136 if ($c+4 >= $strlen_var) {
141 $char = pack('C*', $ord_var_c,
147 $utf16 = $this->utf82utf16($char);
148 $ascii .= sprintf('\u%04s', bin2hex($utf16));
151 case (($ord_var_c & 0xFE) == 0xFC):
152 if ($c+5 >= $strlen_var) {
157 // characters U-04000000 - U-7FFFFFFF, mask 1111110X
158 // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
159 $char = pack('C*', $ord_var_c,
166 $utf16 = $this->utf82utf16($char);
167 $ascii .= sprintf('\u%04s', bin2hex($utf16));
172 return (strpos($ascii, "'") > -1) ? '"'.$ascii.'"' : "'".$ascii."'";
176 * As per JSON spec if any array key is not an integer
177 * we must treat the the whole array as an object. We
178 * also try to catch a sparsely populated associative
179 * array with numeric keys here because some JS engines
180 * will create an array with empty indexes up to
181 * max_index which can cause memory issues and because
182 * the keys, which may be relevant, will be remapped
185 * As per the ECMA and JSON specification an object may
186 * have any string as a property. Unfortunately due to
187 * a hole in the ECMA specification if the key is a
188 * ECMA reserved word or starts with a digit the
189 * parameter is only accessible using ECMAScript's
193 // treat as a JSON object
194 if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
195 $var = (object) $var;
196 // drop throug to object.!
200 // treat it like a regular array
201 $elements = array_map(array($this, '_encode'), $var);
203 foreach($elements as $element) {
204 if(Services_JSON::isError($element)) {
209 return '[' . join(',', $elements) . ']';
211 // fall through for associative arrays..
214 $vars = get_object_vars($var);
216 $properties = array_map(array($this, 'name_value'),
218 array_values($vars));
220 foreach($properties as $property) {
221 if(Services_JSON::isError($property)) {
226 $ind = str_repeat($this->tab, $this->indent);
227 $indx = $ind. $this->tab;
228 return "{" . $this->crlf . $indx . join(",". $this->crlf . $indx, $properties) . $this->crlf .$ind."}";
231 return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
233 : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
237 function name_value($name, $value)
239 $encoded_value = $this->_encode($value);
241 if(Services_JSON::isError($encoded_value)) {
242 return $encoded_value;
245 // do not escape keyvalues if they are just text, and not keywords...
246 if (preg_match('/^[a-z_]+$/i', $lv)) {
247 if (!in_array($lv, $GLOBALS['Pman_Builder_Generator_JSON']['keywords'])) {
248 return $lv .' : ' . $encoded_value;
253 return $this->_encode(strval($name)) . ' : ' . $encoded_value;
259 $GLOBALS['Pman_Builder_Generator_JSON']['keywords'] = array(