Fix empty array dumping
[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_INTEGER:
110         {
111             char *buffer;
112             int size, ret;
113
114             size = asprintf(&buffer, "%d", json_integer_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_REAL:
124         {
125             char *buffer;
126             int size, ret;
127
128             size = asprintf(&buffer, "%.17f", json_real_value(json));
129             if(size == -1)
130                 return -1;
131
132             ret = dump(buffer, size, data);
133             free(buffer);
134             return ret;
135         }
136
137         case JSON_STRING:
138             return dump_string(json_string_value(json), dump, data);
139
140         case JSON_ARRAY:
141         {
142             int i;
143             int n = json_array_size(json);
144
145             if(dump("[", 1, data))
146                 return -1;
147             if(n == 0)
148                 return dump("]", 1, data);
149             if(dump_indent(flags, depth + 1, dump, data))
150                 return -1;
151
152             for(i = 0; i < n; ++i) {
153                 if(do_dump(json_array_get(json, i), flags, depth + 1,
154                            dump, data))
155                     return -1;
156
157                 if(i < n - 1)
158                 {
159                     if(dump(",", 1, data) ||
160                        dump_indent(flags, depth + 1, dump, data))
161                         return -1;
162                 }
163                 else
164                 {
165                     if(dump_indent(flags, depth, dump, data))
166                         return -1;
167                 }
168             }
169             return dump("]", 1, data);
170         }
171
172         case JSON_OBJECT:
173         {
174             void *iter = json_object_iter((json_t *)json);
175
176             if(dump("{", 1, data))
177                 return -1;
178             if(!iter)
179                 return dump("}", 1, data);
180             if(dump_indent(flags, depth + 1, dump, data))
181                 return -1;
182
183             while(iter)
184             {
185                 void *next = json_object_iter_next((json_t *)json, iter);
186
187                 dump_string(json_object_iter_key(iter), dump, data);
188                 if(dump(": ", 2, data) ||
189                    do_dump(json_object_iter_value(iter), flags, depth + 1,
190                            dump, data))
191                     return -1;
192
193                 if(next)
194                 {
195                     if(dump(",", 1, data) ||
196                        dump_indent(flags, depth + 1, dump, data))
197                         return -1;
198                 }
199                 else
200                 {
201                     if(dump_indent(flags, depth, dump, data))
202                         return -1;
203                 }
204
205                 iter = next;
206             }
207             return dump("}", 1, data);
208         }
209
210         default:
211             /* not reached */
212             return -1;
213     }
214 }
215
216
217 int json_dump(const json_t *json, const char *path, uint32_t flags)
218 {
219     FILE *output = fopen(path, "w");
220     if(!output)
221         return -1;
222
223     return json_dumpf(json, output, flags);
224 }
225
226 char *json_dumps(const json_t *json, uint32_t flags)
227 {
228     strbuffer_t strbuff;
229     char *result;
230
231     if(strbuffer_init(&strbuff))
232       return NULL;
233
234     if(do_dump(json, flags, 0, dump_to_strbuffer, (void *)&strbuff))
235         return NULL;
236
237     if(dump_to_strbuffer("\n", 1, (void *)&strbuff))
238         return NULL;
239
240     result = strdup(strbuffer_value(&strbuff));
241     strbuffer_close(&strbuff);
242
243     return result;
244 }
245
246 int json_dumpf(const json_t *json, FILE *output, uint32_t flags)
247 {
248     if(do_dump(json, flags, 0, dump_to_file, (void *)output))
249         return -1;
250     return dump_to_file("\n", 1, (void *)output);
251 }
252
253 int json_dumpfd(const json_t *json, int fd, uint32_t flags)
254 {
255     if(do_dump(json, flags, 0, dump_to_fd, (void *)&fd))
256         return -1;
257     return dump_to_fd("\n", 1, (void *)&fd);
258 }