• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/json-c/json_object.c

  1 /*
  2  * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $
  3  *
  4  * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
  5  * Michael Clark <michael@metaparadigm.com>
  6  * Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
  7  *
  8  * This library is free software; you can redistribute it and/or modify
  9  * it under the terms of the MIT license. See COPYING for details.
 10  *
 11  */
 12 
 13 #include "config.h"
 14 
 15 #include <stdio.h>
 16 #include <stdlib.h>
 17 #include <stddef.h>
 18 #include <string.h>
 19 
 20 #include "debug.h"
 21 #include "printbuf.h"
 22 #include "linkhash.h"
 23 #include "arraylist.h"
 24 #include "json_inttypes.h"
 25 #include "json_object.h"
 26 #include "json_object_private.h"
 27 #include "json_util.h"
 28 
 29 #if !defined(HAVE_STRDUP) && defined(_MSC_VER)
 30   /* MSC has the version as _strdup */
 31 # define strdup _strdup
 32 #elif !defined(HAVE_STRDUP)
 33 # error You do not have strdup on your system.
 34 #endif /* HAVE_STRDUP */
 35 
 36 #if !defined(HAVE_STRNDUP)
 37   char* strndup(const char* str, size_t n);
 38 #endif /* !HAVE_STRNDUP */
 39 
 40 // Don't define this.  It's not thread-safe.
 41 /* #define REFCOUNT_DEBUG 1 */
 42 
 43 const char *json_number_chars = "0123456789.+-eE";
 44 const char *json_hex_chars = "0123456789abcdefABCDEF";
 45 
 46 static void json_object_generic_delete(struct json_object* jso);
 47 static struct json_object* json_object_new(enum json_type o_type);
 48 
 49 static json_object_to_json_string_fn json_object_object_to_json_string;
 50 static json_object_to_json_string_fn json_object_boolean_to_json_string;
 51 static json_object_to_json_string_fn json_object_int_to_json_string;
 52 static json_object_to_json_string_fn json_object_double_to_json_string;
 53 static json_object_to_json_string_fn json_object_string_to_json_string;
 54 static json_object_to_json_string_fn json_object_array_to_json_string;
 55 
 56 
 57 /* ref count debugging */
 58 
 59 #ifdef REFCOUNT_DEBUG
 60 
 61 static struct lh_table *json_object_table;
 62 
 63 static void json_object_init(void) __attribute__ ((constructor));
 64 static void json_object_init(void) {
 65   MC_DEBUG("json_object_init: creating object table\n");
 66   json_object_table = lh_kptr_table_new(128, "json_object_table", NULL);
 67 }
 68 
 69 static void json_object_fini(void) __attribute__ ((destructor));
 70 static void json_object_fini(void) {
 71   struct lh_entry *ent;
 72   if(MC_GET_DEBUG()) {
 73     if (json_object_table->count) {
 74       MC_DEBUG("json_object_fini: %d referenced objects at exit\n",
 75                json_object_table->count);
 76       lh_foreach(json_object_table, ent) {
 77         struct json_object* obj = (struct json_object*)ent->v;
 78         MC_DEBUG("\t%s:%p\n", json_type_to_name(obj->o_type), obj);
 79       }
 80     }
 81   }
 82   MC_DEBUG("json_object_fini: freeing object table\n");
 83   lh_table_free(json_object_table);
 84 }
 85 #endif /* REFCOUNT_DEBUG */
 86 
 87 
 88 /* string escaping */
 89 
 90 static int json_escape_str(struct printbuf *pb, char *str, int len)
 91 {
 92   int pos = 0, start_offset = 0;
 93   unsigned char c;
 94   while (len--) {
 95     c = str[pos];
 96     switch(c) {
 97     case '\b':
 98     case '\n':
 99     case '\r':
100     case '\t':
101     case '\f':
102     case '"':
103     case '\\':
104     case '/':
105       if(pos - start_offset > 0)
106         printbuf_memappend(pb, str + start_offset, pos - start_offset);
107       if(c == '\b') printbuf_memappend(pb, "\\b", 2);
108       else if(c == '\n') printbuf_memappend(pb, "\\n", 2);
109       else if(c == '\r') printbuf_memappend(pb, "\\r", 2);
110       else if(c == '\t') printbuf_memappend(pb, "\\t", 2);
111       else if(c == '\f') printbuf_memappend(pb, "\\f", 2);
112       else if(c == '"') printbuf_memappend(pb, "\\\"", 2);
113       else if(c == '\\') printbuf_memappend(pb, "\\\\", 2);
114       else if(c == '/') printbuf_memappend(pb, "\\/", 2);
115       start_offset = ++pos;
116       break;
117     default:
118       if(c < ' ') {
119         if(pos - start_offset > 0)
120           printbuf_memappend(pb, str + start_offset, pos - start_offset);
121         sprintbuf(pb, "\\u00%c%c",
122                   json_hex_chars[c >> 4],
123                   json_hex_chars[c & 0xf]);
124         start_offset = ++pos;
125       } else pos++;
126     }
127   }
128   if(pos - start_offset > 0)
129     printbuf_memappend(pb, str + start_offset, pos - start_offset);
130   return 0;
131 }
132 
133 
134 /* reference counting */
135 
136 extern struct json_object* json_object_get(struct json_object *jso)
137 {
138   if(jso) {
139     jso->_ref_count++;
140   }
141   return jso;
142 }
143 
144 int json_object_put(struct json_object *jso)
145 {
146         if(jso)
147         {
148                 jso->_ref_count--;
149                 if(!jso->_ref_count)
150                 {
151                         if (jso->_user_delete)
152                                 jso->_user_delete(jso, jso->_userdata);
153                         jso->_delete(jso);
154                         return 1;
155                 }
156         }
157         return 0;
158 }
159 
160 
161 /* generic object construction and destruction parts */
162 
163 static void json_object_generic_delete(struct json_object* jso)
164 {
165 #ifdef REFCOUNT_DEBUG
166   MC_DEBUG("json_object_delete_%s: %p\n",
167            json_type_to_name(jso->o_type), jso);
168   lh_table_delete(json_object_table, jso);
169 #endif /* REFCOUNT_DEBUG */
170   printbuf_free(jso->_pb);
171   free(jso);
172 }
173 
174 static struct json_object* json_object_new(enum json_type o_type)
175 {
176   struct json_object *jso;
177 
178   jso = (struct json_object*)calloc(sizeof(struct json_object), 1);
179   if(!jso) return NULL;
180   jso->o_type = o_type;
181   jso->_ref_count = 1;
182   jso->_delete = &json_object_generic_delete;
183 #ifdef REFCOUNT_DEBUG
184   lh_table_insert(json_object_table, jso, jso);
185   MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso);
186 #endif /* REFCOUNT_DEBUG */
187   return jso;
188 }
189 
190 
191 /* type checking functions */
192 
193 int json_object_is_type(struct json_object *jso, enum json_type type)
194 {
195   if (!jso)
196     return (type == json_type_null);
197   return (jso->o_type == type);
198 }
199 
200 enum json_type json_object_get_type(struct json_object *jso)
201 {
202   if (!jso)
203     return json_type_null;
204   return jso->o_type;
205 }
206 
207 /* set a custom conversion to string */
208 
209 void json_object_set_serializer(json_object *jso,
210         json_object_to_json_string_fn to_string_func,
211         void *userdata,
212         json_object_delete_fn *user_delete)
213 {
214         // First, clean up any previously existing user info
215         if (jso->_user_delete)
216         {
217                 jso->_user_delete(jso, jso->_userdata);
218         }
219         jso->_userdata = NULL;
220         jso->_user_delete = NULL;
221 
222         if (to_string_func == NULL)
223         {
224                 // Reset to the standard serialization function
225                 switch(jso->o_type)
226                 {
227                 case json_type_null:
228                         jso->_to_json_string = NULL;
229                         break;
230                 case json_type_boolean:
231                         jso->_to_json_string = &json_object_boolean_to_json_string;
232                         break;
233                 case json_type_double:
234                         jso->_to_json_string = &json_object_double_to_json_string;
235                         break;
236                 case json_type_int:
237                         jso->_to_json_string = &json_object_int_to_json_string;
238                         break;
239                 case json_type_object:
240                         jso->_to_json_string = &json_object_object_to_json_string;
241                         break;
242                 case json_type_array:
243                         jso->_to_json_string = &json_object_array_to_json_string;
244                         break;
245                 case json_type_string:
246                         jso->_to_json_string = &json_object_string_to_json_string;
247                         break;
248                 }
249                 return;
250         }
251 
252         jso->_to_json_string = to_string_func;
253         jso->_userdata = userdata;
254         jso->_user_delete = user_delete;
255 }
256 
257 
258 /* extended conversion to string */
259 
260 const char* json_object_to_json_string_ext(struct json_object *jso, int flags)
261 {
262         if (!jso)
263                 return "null";
264 
265         if ((!jso->_pb) && !(jso->_pb = printbuf_new()))
266                 return NULL;
267 
268         printbuf_reset(jso->_pb);
269 
270         if(jso->_to_json_string(jso, jso->_pb, 0, flags) < 0)
271                 return NULL;
272 
273         return jso->_pb->buf;
274 }
275 
276 /* backwards-compatible conversion to string */
277 
278 const char* json_object_to_json_string(struct json_object *jso)
279 {
280         return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED);
281 }
282 
283 static void indent(struct printbuf *pb, int level, int flags)
284 {
285         if (flags & JSON_C_TO_STRING_PRETTY)
286         {
287                 printbuf_memset(pb, -1, ' ', level * 2);
288         }
289 }
290 
291 /* json_object_object */
292 
293 static int json_object_object_to_json_string(struct json_object* jso,
294                                              struct printbuf *pb,
295                                              int level,
296                                                  int flags)
297 {
298         int had_children = 0;
299         struct json_object_iter iter;
300 
301         sprintbuf(pb, "{" /*}*/);
302         if (flags & JSON_C_TO_STRING_PRETTY)
303                 sprintbuf(pb, "\n");
304         json_object_object_foreachC(jso, iter)
305         {
306                 if (had_children)
307                 {
308                         sprintbuf(pb, ",");
309                         if (flags & JSON_C_TO_STRING_PRETTY)
310                                 sprintbuf(pb, "\n");
311                 }
312                 had_children = 1;
313                 if (flags & JSON_C_TO_STRING_SPACED)
314                         sprintbuf(pb, " ");
315                 indent(pb, level+1, flags);
316                 sprintbuf(pb, "\"");
317                 json_escape_str(pb, iter.key, strlen(iter.key));
318                 if (flags & JSON_C_TO_STRING_SPACED)
319                         sprintbuf(pb, "\": ");
320                 else
321                         sprintbuf(pb, "\":");
322                 if(iter.val == NULL)
323                         sprintbuf(pb, "null");
324                 else
325                         iter.val->_to_json_string(iter.val, pb, level+1,flags);
326         }
327         if (flags & JSON_C_TO_STRING_PRETTY)
328         {
329                 if (had_children)
330                         sprintbuf(pb, "\n");
331                 indent(pb,level,flags);
332         }
333         if (flags & JSON_C_TO_STRING_SPACED)
334                 return sprintbuf(pb, /*{*/ " }");
335         else
336                 return sprintbuf(pb, /*{*/ "}");
337 }
338 
339 
340 static void json_object_lh_entry_free(struct lh_entry *ent)
341 {
342   free(ent->k);
343   json_object_put((struct json_object*)ent->v);
344 }
345 
346 static void json_object_object_delete(struct json_object* jso)
347 {
348   lh_table_free(jso->o.c_object);
349   json_object_generic_delete(jso);
350 }
351 
352 struct json_object* json_object_new_object(void)
353 {
354   struct json_object *jso = json_object_new(json_type_object);
355   if(!jso) return NULL;
356   jso->_delete = &json_object_object_delete;
357   jso->_to_json_string = &json_object_object_to_json_string;
358   jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES,
359                                         NULL, &json_object_lh_entry_free);
360   return jso;
361 }
362 
363 struct lh_table* json_object_get_object(struct json_object *jso)
364 {
365   if(!jso) return NULL;
366   switch(jso->o_type) {
367   case json_type_object:
368     return jso->o.c_object;
369   default:
370     return NULL;
371   }
372 }
373 
374 void json_object_object_add(struct json_object* jso, const char *key,
375                             struct json_object *val)
376 {
377         // We lookup the entry and replace the value, rather than just deleting
378         // and re-adding it, so the existing key remains valid.
379         json_object *existing_value = NULL;
380         struct lh_entry *existing_entry;
381         existing_entry = lh_table_lookup_entry(jso->o.c_object, (void*)key);
382         if (!existing_entry)
383         {
384                 lh_table_insert(jso->o.c_object, strdup(key), val);
385                 return;
386         }
387         existing_value = (void *)existing_entry->v;
388         if (existing_value)
389                 json_object_put(existing_value);
390         existing_entry->v = val;
391 }
392 
393 int json_object_object_length(struct json_object *jso)
394 {
395         return lh_table_length(jso->o.c_object);
396 }
397 
398 struct json_object* json_object_object_get(struct json_object* jso, const char *key)
399 {
400         struct json_object *result = NULL;
401         json_object_object_get_ex(jso, key, &result);
402         return result;
403 }
404 
405 json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value)
406 {
407         if (value != NULL)
408                 *value = NULL;
409 
410         if (NULL == jso)
411                 return FALSE;
412 
413         switch(jso->o_type)
414         {
415         case json_type_object:
416                 return lh_table_lookup_ex(jso->o.c_object, (void*)key, (void**)value);
417         default:
418                 if (value != NULL)
419                         *value = NULL;
420                 return FALSE;
421         }
422 }
423 
424 void json_object_object_del(struct json_object* jso, const char *key)
425 {
426         lh_table_delete(jso->o.c_object, key);
427 }
428 
429 
430 /* json_object_boolean */
431 
432 static int json_object_boolean_to_json_string(struct json_object* jso,
433                                               struct printbuf *pb,
434                                               int level,
435                                                   int flags)
436 {
437   if(jso->o.c_boolean) return sprintbuf(pb, "true");
438   else return sprintbuf(pb, "false");
439 }
440 
441 struct json_object* json_object_new_boolean(json_bool b)
442 {
443   struct json_object *jso = json_object_new(json_type_boolean);
444   if(!jso) return NULL;
445   jso->_to_json_string = &json_object_boolean_to_json_string;
446   jso->o.c_boolean = b;
447   return jso;
448 }
449 
450 json_bool json_object_get_boolean(struct json_object *jso)
451 {
452   if(!jso) return FALSE;
453   switch(jso->o_type) {
454   case json_type_boolean:
455     return jso->o.c_boolean;
456   case json_type_int:
457     return (jso->o.c_int64 != 0);
458   case json_type_double:
459     return (jso->o.c_double != 0);
460   case json_type_string:
461     return (jso->o.c_string.len != 0);
462   default:
463     return FALSE;
464   }
465 }
466 
467 
468 /* json_object_int */
469 
470 static int json_object_int_to_json_string(struct json_object* jso,
471                                           struct printbuf *pb,
472                                           int level,
473                                           int flags)
474 {
475   return sprintbuf(pb, "%"PRId64, jso->o.c_int64);
476 }
477 
478 struct json_object* json_object_new_int(int32_t i)
479 {
480   struct json_object *jso = json_object_new(json_type_int);
481   if(!jso) return NULL;
482   jso->_to_json_string = &json_object_int_to_json_string;
483   jso->o.c_int64 = i;
484   return jso;
485 }
486 
487 int32_t json_object_get_int(struct json_object *jso)
488 {
489   int64_t cint64;
490   enum json_type o_type;
491 
492   if(!jso) return 0;
493 
494   o_type = jso->o_type;
495   cint64 = jso->o.c_int64;
496 
497   if (o_type == json_type_string)
498   {
499         /*
500          * Parse strings into 64-bit numbers, then use the
501          * 64-to-32-bit number handling below.
502          */
503         if (json_parse_int64(jso->o.c_string.str, &cint64) != 0)
504                 return 0; /* whoops, it didn't work. */
505         o_type = json_type_int;
506   }
507 
508   switch(o_type) {
509   case json_type_int:
510         /* Make sure we return the correct values for out of range numbers. */
511         if (cint64 <= INT32_MIN)
512                 return INT32_MIN;
513         else if (cint64 >= INT32_MAX)
514                 return INT32_MAX;
515         else
516                 return (int32_t)cint64;
517   case json_type_double:
518     return (int32_t)jso->o.c_double;
519   case json_type_boolean:
520     return jso->o.c_boolean;
521   default:
522     return 0;
523   }
524 }
525 
526 struct json_object* json_object_new_int64(int64_t i)
527 {
528   struct json_object *jso = json_object_new(json_type_int);
529   if(!jso) return NULL;
530   jso->_to_json_string = &json_object_int_to_json_string;
531   jso->o.c_int64 = i;
532   return jso;
533 }
534 
535 int64_t json_object_get_int64(struct json_object *jso)
536 {
537    int64_t cint;
538 
539   if(!jso) return 0;
540   switch(jso->o_type) {
541   case json_type_int:
542     return jso->o.c_int64;
543   case json_type_double:
544     return (int64_t)jso->o.c_double;
545   case json_type_boolean:
546     return jso->o.c_boolean;
547   case json_type_string:
548         if (json_parse_int64(jso->o.c_string.str, &cint) == 0) return cint;
549   default:
550     return 0;
551   }
552 }
553 
554 
555 /* json_object_double */
556 
557 static int json_object_double_to_json_string(struct json_object* jso,
558                                              struct printbuf *pb,
559                                              int level,
560                                                  int flags)
561 {
562   char buf[128], *p, *q;
563   int size;
564 
565   size = snprintf(buf, 128, "%f", jso->o.c_double);
566   p = strchr(buf, ',');
567   if (p) {
568     *p = '.';
569   } else {
570     p = strchr(buf, '.');
571   }
572   if (p && (flags & JSON_C_TO_STRING_NOZERO)) {
573     /* last useful digit, always keep 1 zero */
574     p++;
575     for (q=p ; *q ; q++) {
576       if (*q!='') p=q;
577     }
578     /* drop trailing zeroes */
579     *(++p) = 0;
580     size = p-buf;
581   }
582   printbuf_memappend(pb, buf, size);
583   return size;
584 }
585 
586 struct json_object* json_object_new_double(double d)
587 {
588   struct json_object *jso = json_object_new(json_type_double);
589   if(!jso) return NULL;
590   jso->_to_json_string = &json_object_double_to_json_string;
591   jso->o.c_double = d;
592   return jso;
593 }
594 
595 double json_object_get_double(struct json_object *jso)
596 {
597   double cdouble;
598 
599   if(!jso) return 0.0;
600   switch(jso->o_type) {
601   case json_type_double:
602     return jso->o.c_double;
603   case json_type_int:
604     return jso->o.c_int64;
605   case json_type_boolean:
606     return jso->o.c_boolean;
607   case json_type_string:
608     if(sscanf(jso->o.c_string.str, "%lf", &cdouble) == 1) return cdouble;
609   default:
610     return 0.0;
611   }
612 }
613 
614 
615 /* json_object_string */
616 
617 static int json_object_string_to_json_string(struct json_object* jso,
618                                              struct printbuf *pb,
619                                              int level,
620                                                  int flags)
621 {
622   sprintbuf(pb, "\"");
623   json_escape_str(pb, jso->o.c_string.str, jso->o.c_string.len);
624   sprintbuf(pb, "\"");
625   return 0;
626 }
627 
628 static void json_object_string_delete(struct json_object* jso)
629 {
630   free(jso->o.c_string.str);
631   json_object_generic_delete(jso);
632 }
633 
634 struct json_object* json_object_new_string(const char *s)
635 {
636   struct json_object *jso = json_object_new(json_type_string);
637   if(!jso) return NULL;
638   jso->_delete = &json_object_string_delete;
639   jso->_to_json_string = &json_object_string_to_json_string;
640   jso->o.c_string.str = strdup(s);
641   jso->o.c_string.len = strlen(s);
642   return jso;
643 }
644 
645 struct json_object* json_object_new_string_len(const char *s, int len)
646 {
647   struct json_object *jso = json_object_new(json_type_string);
648   if(!jso) return NULL;
649   jso->_delete = &json_object_string_delete;
650   jso->_to_json_string = &json_object_string_to_json_string;
651   jso->o.c_string.str = (char*)malloc(len + 1);
652   memcpy(jso->o.c_string.str, (void *)s, len);
653   jso->o.c_string.str[len] = '\0';
654   jso->o.c_string.len = len;
655   return jso;
656 }
657 
658 const char* json_object_get_string(struct json_object *jso)
659 {
660   if(!jso) return NULL;
661   switch(jso->o_type) {
662   case json_type_string:
663     return jso->o.c_string.str;
664   default:
665     return json_object_to_json_string(jso);
666   }
667 }
668 
669 int json_object_get_string_len(struct json_object *jso)  {
670   if(!jso) return 0;
671   switch(jso->o_type) {
672   case json_type_string:
673     return jso->o.c_string.len;
674   default:
675     return 0;
676   }
677 }
678 
679 
680 /* json_object_array */
681 
682 static int json_object_array_to_json_string(struct json_object* jso,
683                                             struct printbuf *pb,
684                                             int level,
685                                             int flags)
686 {
687         int had_children = 0;
688         int ii;
689         sprintbuf(pb, "[");
690         if (flags & JSON_C_TO_STRING_PRETTY)
691                 sprintbuf(pb, "\n");
692         for(ii=0; ii < json_object_array_length(jso); ii++)
693         {
694                 struct json_object *val;
695                 if (had_children)
696                 {
697                         sprintbuf(pb, ",");
698                         if (flags & JSON_C_TO_STRING_PRETTY)
699                                 sprintbuf(pb, "\n");
700                 }
701                 had_children = 1;
702                 if (flags & JSON_C_TO_STRING_SPACED)
703                         sprintbuf(pb, " ");
704                 indent(pb, level + 1, flags);
705                 val = json_object_array_get_idx(jso, ii);
706                 if(val == NULL)
707                         sprintbuf(pb, "null");
708                 else
709                         val->_to_json_string(val, pb, level+1, flags);
710         }
711         if (flags & JSON_C_TO_STRING_PRETTY)
712         {
713                 if (had_children)
714                         sprintbuf(pb, "\n");
715                 indent(pb,level,flags);
716         }
717 
718         if (flags & JSON_C_TO_STRING_SPACED)
719                 return sprintbuf(pb, " ]");
720         else
721                 return sprintbuf(pb, "]");
722 }
723 
724 static void json_object_array_entry_free(void *data)
725 {
726   json_object_put((struct json_object*)data);
727 }
728 
729 static void json_object_array_delete(struct json_object* jso)
730 {
731   array_list_free(jso->o.c_array);
732   json_object_generic_delete(jso);
733 }
734 
735 struct json_object* json_object_new_array(void)
736 {
737   struct json_object *jso = json_object_new(json_type_array);
738   if(!jso) return NULL;
739   jso->_delete = &json_object_array_delete;
740   jso->_to_json_string = &json_object_array_to_json_string;
741   jso->o.c_array = array_list_new(&json_object_array_entry_free);
742   return jso;
743 }
744 
745 struct array_list* json_object_get_array(struct json_object *jso)
746 {
747   if(!jso) return NULL;
748   switch(jso->o_type) {
749   case json_type_array:
750     return jso->o.c_array;
751   default:
752     return NULL;
753   }
754 }
755 
756 void json_object_array_sort(struct json_object *jso, int(*sort_fn)(const void *, const void *))
757 {
758   array_list_sort(jso->o.c_array, sort_fn);
759 }
760 
761 int json_object_array_length(struct json_object *jso)
762 {
763   return array_list_length(jso->o.c_array);
764 }
765 
766 int json_object_array_add(struct json_object *jso,struct json_object *val)
767 {
768   return array_list_add(jso->o.c_array, val);
769 }
770 
771 int json_object_array_put_idx(struct json_object *jso, int idx,
772                               struct json_object *val)
773 {
774   return array_list_put_idx(jso->o.c_array, idx, val);
775 }
776 
777 struct json_object* json_object_array_get_idx(struct json_object *jso,
778                                               int idx)
779 {
780   return (struct json_object*)array_list_get_idx(jso->o.c_array, idx);
781 }
782 
783 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt