ce77b950ccbc9cefdb5979ef29bbc54027a89e58
[jansson.git] / src / dump.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6
7 #include <jansson.h>
8 #include "strbuffer.h"
9
10 typedef int (*dump_func)(const char *buffer, int size, void *data);
11
12 struct string
13 {
14     char *buffer;
15     int length;
16     int size;
17 };
18
19 static int dump_to_strbuffer(const char *buffer, int size, void *data)
20 {
21     return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
22 }
23
24 static int dump_to_file(const char *buffer, int size, void *data)
25 {
26     FILE *dest = (FILE *)data;
27     if(fwrite(buffer, size, 1, dest) != 1)
28         return -1;
29     return 0;
30 }
31
32 static int dump_to_fd(const char *buffer, int size, void *data)
33 {
34     int *fd = (int *)data;
35     if(write(*fd, buffer, size) != size)
36         return -1;
37     return 0;
38 }
39
40 static int dump_indent(uint32_t flags, int depth, dump_func dump, void *data)
41 {
42     if(JSON_INDENT(flags) > 0)
43     {
44         char *ws_buffer;
45         int ws_count = JSON_INDENT(flags) * depth;
46
47         if(dump("\n", 1, data))
48             return -1;
49
50         if(ws_count == 0)
51             return 0;
52
53         ws_buffer = alloca(ws_count);
54         memset(ws_buffer, ' ', ws_count);
55         return dump(ws_buffer, ws_count, data);
56     }
57     else
58         return dump(" ", 1, data);
59 }
60
61 static int dump_string(const char *str, dump_func dump, void *data)
62 {
63     const char *end;
64
65     if(dump("\"", 1, data))
66         return -1;
67
68     end = str;
69     while(*end)
70     {
71         while(*end && *end != '\\' && *end != '"')
72             end++;
73
74         if(end != str)
75             if(dump(str, end - str, data))
76                 return -1;
77
78         if(*end == '\\')
79         {
80             if(dump("\\\\", 2, data))
81                 return -1;
82             end++;
83         }
84         else if(*end == '"')
85         {
86             if(dump("\\\"", 2, data))
87                 return -1;
88             end++;
89         }
90         str = end;
91     }
92
93     return dump("\"", 1, data);
94 }
95
96 static int do_dump(const json_t *json, uint32_t flags, int depth,
97                    dump_func dump, void *data)
98 {
99     switch(json_typeof(json)) {
100         case JSON_NULL:
101             return dump("null", 4, data);
102
103         case JSON_TRUE:
104             return dump("true", 4, data);
105
106         case JSON_FALSE:
107             return dump("false", 5, data);
108
109         case JSON_NUMBER:
110         {
111             char *buffer;
112             int size, ret;
113
114             size = asprintf(&buffer, "%.17f", json_number_value(json));
115             if(size == -1)
116                 return -1;
117
118             ret = dump(buffer, size, data);
119             free(buffer);
120             return ret;
121         }
122
123         case JSON_STRING:
124             return dump_string(json_string_value(json), dump, data);
125
126         case JSON_ARRAY:
127         {
128             int i;
129             int n = json_array_size(json);
130
131             if(dump("[", 1, data))
132                 return -1;
133             if(n == 0)
134                 dump("]", 1, data);
135             if(dump_indent(flags, depth + 1, dump, data))
136                 return -1;
137
138             for(i = 0; i < n; ++i) {
139                 if(do_dump(json_array_get(json, i), flags, depth + 1,
140                            dump, data))
141                     return -1;
142
143                 if(i < n - 1)
144                 {
145                     if(dump(",", 1, data) ||
146                        dump_indent(flags, depth + 1, dump, data))
147                         return -1;
148                 }
149                 else
150                 {
151                     if(dump_indent(flags, depth, dump, data))
152                         return -1;
153                 }
154             }
155             return dump("]", 1, data);
156         }
157
158         case JSON_OBJECT:
159         {
160             void *iter = json_object_iter((json_t *)json);
161
162             if(dump("{", 1, data))
163                 return -1;
164             if(!iter)
165                 return dump("}", 1, data);
166             if(dump_indent(flags, depth + 1, dump, data))
167                 return -1;
168
169             while(iter)
170             {
171                 void *next = json_object_iter_next((json_t *)json, iter);
172
173                 dump_string(json_object_iter_key(iter), dump, data);
174                 if(dump(": ", 2, data) ||
175                    do_dump(json_object_iter_value(iter), flags, depth + 1,
176                            dump, data))
177                     return -1;
178
179                 if(next)
180                 {
181                     if(dump(",", 1, data) ||
182                        dump_indent(flags, depth + 1, dump, data))
183                         return -1;
184                 }
185                 else
186                 {
187                     if(dump_indent(flags, depth, dump, data))
188                         return -1;
189                 }
190
191                 iter = next;
192             }
193             return dump("}", 1, data);
194         }
195
196         default:
197             /* not reached */
198             return -1;
199     }
200 }
201
202
203 int json_dump(const json_t *json, const char *path, uint32_t flags)
204 {
205     FILE *output = fopen(path, "w");
206     if(!output)
207         return -1;
208
209     return json_dumpf(json, output, flags);
210 }
211
212 char *json_dumps(const json_t *json, uint32_t flags)
213 {
214     strbuffer_t strbuff;
215     char *result;
216
217     strbuffer_init(&strbuff);
218
219     if(do_dump(json, flags, 0, dump_to_strbuffer, (void *)&strbuff))
220         return NULL;
221
222     if(dump_to_strbuffer("\n", 1, (void *)&strbuff))
223         return NULL;
224
225     result = strdup(strbuffer_value(&strbuff));
226     strbuffer_close(&strbuff);
227
228     return result;
229 }
230
231 int json_dumpf(const json_t *json, FILE *output, uint32_t flags)
232 {
233     if(do_dump(json, flags, 0, dump_to_file, (void *)output))
234         return -1;
235     return dump_to_file("\n", 1, (void *)output);
236 }
237
238 int json_dumpfd(const json_t *json, int fd, uint32_t flags)
239 {
240     if(do_dump(json, flags, 0, dump_to_fd, (void *)&fd))
241         return -1;
242     return dump_to_fd("\n", 1, (void *)&fd);
243 }