blob: 4e4e00cee1fff969e683a62c86fbcc31b65c5a4d [file] [log] [blame]
Michael Clark4504df72007-03-13 08:26:20 +00001/*
Michael Clark837240f2007-03-13 08:26:25 +00002 * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $
Michael Clark4504df72007-03-13 08:26:20 +00003 *
Michael Clarkf6a6e482007-03-13 08:26:23 +00004 * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
Michael Clark4504df72007-03-13 08:26:20 +00005 * Michael Clark <michael@metaparadigm.com>
6 *
Michael Clarkf6a6e482007-03-13 08:26:23 +00007 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the MIT license. See COPYING for details.
Michael Clark4504df72007-03-13 08:26:20 +00009 *
10 */
11
12#include "config.h"
ehaszla252669c2010-12-07 18:15:35 +000013#undef realloc
Michael Clark4504df72007-03-13 08:26:20 +000014
Michael Clarkf0d08882007-03-13 08:26:18 +000015#include <stdio.h>
16#include <stdlib.h>
Michael Clarkc8f4a6e2007-12-07 02:44:24 +000017#include <stddef.h>
Michael Clark4504df72007-03-13 08:26:20 +000018#include <limits.h>
Michael Clarkf0d08882007-03-13 08:26:18 +000019#include <string.h>
20#include <errno.h>
Michael Clarkc4dceae2010-10-06 16:39:20 +000021#include <ctype.h>
Michael Clark4504df72007-03-13 08:26:20 +000022
Mateusz Loskota6f39a32012-05-21 23:22:36 +010023#ifdef HAVE_SYS_TYPES_H
Michael Clarkf0d08882007-03-13 08:26:18 +000024#include <sys/types.h>
Michael Clark4504df72007-03-13 08:26:20 +000025#endif /* HAVE_SYS_TYPES_H */
26
Mateusz Loskota6f39a32012-05-21 23:22:36 +010027#ifdef HAVE_SYS_STAT_H
Michael Clarkf0d08882007-03-13 08:26:18 +000028#include <sys/stat.h>
Michael Clark4504df72007-03-13 08:26:20 +000029#endif /* HAVE_SYS_STAT_H */
30
Mateusz Loskota6f39a32012-05-21 23:22:36 +010031#ifdef HAVE_FCNTL_H
Michael Clarkf0d08882007-03-13 08:26:18 +000032#include <fcntl.h>
Michael Clark4504df72007-03-13 08:26:20 +000033#endif /* HAVE_FCNTL_H */
34
Mateusz Loskota6f39a32012-05-21 23:22:36 +010035#ifdef HAVE_UNISTD_H
Michael Clark4504df72007-03-13 08:26:20 +000036# include <unistd.h>
37#endif /* HAVE_UNISTD_H */
38
39#ifdef WIN32
40# define WIN32_LEAN_AND_MEAN
41# include <windows.h>
42# include <io.h>
43#endif /* defined(WIN32) */
Michael Clarkf0d08882007-03-13 08:26:18 +000044
Mateusz Loskota6f39a32012-05-21 23:22:36 +010045#if !defined(HAVE_OPEN) && defined(WIN32)
Michael Clark837240f2007-03-13 08:26:25 +000046# define open _open
47#endif
48
Mateusz Loskota6f39a32012-05-21 23:22:36 +010049#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER)
50 /* MSC has the version as _snprintf */
51# define snprintf _snprintf
52#elif !defined(HAVE_SNPRINTF)
53# error You do not have snprintf on your system.
54#endif /* HAVE_SNPRINTF */
Michael Clark837240f2007-03-13 08:26:25 +000055
Michael Clarkf0d08882007-03-13 08:26:18 +000056#include "bits.h"
57#include "debug.h"
58#include "printbuf.h"
Michael Clarkc4dceae2010-10-06 16:39:20 +000059#include "json_inttypes.h"
Michael Clarkf0d08882007-03-13 08:26:18 +000060#include "json_object.h"
61#include "json_tokener.h"
62#include "json_util.h"
63
Michael Clark88ded9c2009-08-27 06:40:59 +000064struct json_object* json_object_from_file(const char *filename)
Michael Clarkf0d08882007-03-13 08:26:18 +000065{
66 struct printbuf *pb;
67 struct json_object *obj;
68 char buf[JSON_FILE_BUF_SIZE];
69 int fd, ret;
70
71 if((fd = open(filename, O_RDONLY)) < 0) {
Michael Clarkdfaf6702007-10-25 02:26:00 +000072 MC_ERROR("json_object_from_file: error reading file %s: %s\n",
Michael Clarkf0d08882007-03-13 08:26:18 +000073 filename, strerror(errno));
Eric Haszlakiewiczeead1a72012-07-08 20:32:12 -050074 return NULL;
Michael Clarkf0d08882007-03-13 08:26:18 +000075 }
76 if(!(pb = printbuf_new())) {
Michael Clarkbd0a5672010-10-13 14:09:41 +000077 close(fd);
Michael Clarkdfaf6702007-10-25 02:26:00 +000078 MC_ERROR("json_object_from_file: printbuf_new failed\n");
Eric Haszlakiewicz3fcffe12012-04-28 13:26:09 -050079 return NULL;
Michael Clarkf0d08882007-03-13 08:26:18 +000080 }
81 while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
82 printbuf_memappend(pb, buf, ret);
83 }
84 close(fd);
85 if(ret < 0) {
Michael Clarkdfaf6702007-10-25 02:26:00 +000086 MC_ABORT("json_object_from_file: error reading file %s: %s\n",
Michael Clarkf0d08882007-03-13 08:26:18 +000087 filename, strerror(errno));
88 printbuf_free(pb);
Eric Haszlakiewicz3fcffe12012-04-28 13:26:09 -050089 return NULL;
Michael Clarkf0d08882007-03-13 08:26:18 +000090 }
91 obj = json_tokener_parse(pb->buf);
92 printbuf_free(pb);
93 return obj;
94}
95
Eric Haszlakiewicz3fcffe12012-04-28 13:26:09 -050096/* extended "format and write to file" function */
97
98int json_object_to_file_ext(char *filename, struct json_object *obj, int flags)
Michael Clarkf0d08882007-03-13 08:26:18 +000099{
Michael Clark68cafad2009-01-06 22:56:57 +0000100 const char *json_str;
Michael Clark4504df72007-03-13 08:26:20 +0000101 int fd, ret;
102 unsigned int wpos, wsize;
Michael Clarkf0d08882007-03-13 08:26:18 +0000103
104 if(!obj) {
Michael Clarkdfaf6702007-10-25 02:26:00 +0000105 MC_ERROR("json_object_to_file: object is null\n");
Michael Clarkf0d08882007-03-13 08:26:18 +0000106 return -1;
107 }
108
109 if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
Michael Clarkdfaf6702007-10-25 02:26:00 +0000110 MC_ERROR("json_object_to_file: error opening file %s: %s\n",
Michael Clarkf0d08882007-03-13 08:26:18 +0000111 filename, strerror(errno));
112 return -1;
113 }
Michael Clark4504df72007-03-13 08:26:20 +0000114
Eric Haszlakiewicz3fcffe12012-04-28 13:26:09 -0500115 if(!(json_str = json_object_to_json_string_ext(obj,flags))) {
Michael Clarkf1ae67d2010-10-13 14:10:51 +0000116 close(fd);
117 return -1;
118 }
Michael Clark4504df72007-03-13 08:26:20 +0000119
120 wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */
Michael Clarkf0d08882007-03-13 08:26:18 +0000121 wpos = 0;
122 while(wpos < wsize) {
123 if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) {
124 close(fd);
Michael Clarkdfaf6702007-10-25 02:26:00 +0000125 MC_ERROR("json_object_to_file: error writing file %s: %s\n",
Michael Clarkf0d08882007-03-13 08:26:18 +0000126 filename, strerror(errno));
127 return -1;
128 }
Michael Clark4504df72007-03-13 08:26:20 +0000129
130 /* because of the above check for ret < 0, we can safely cast and add */
131 wpos += (unsigned int)ret;
Michael Clarkf0d08882007-03-13 08:26:18 +0000132 }
133
134 close(fd);
135 return 0;
136}
Michael Clarkc4dceae2010-10-06 16:39:20 +0000137
Eric Haszlakiewicz3fcffe12012-04-28 13:26:09 -0500138// backwards compatible "format and write to file" function
139
140int json_object_to_file(char *filename, struct json_object *obj)
141{
142 return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN);
143}
144
Michael Clarkc4dceae2010-10-06 16:39:20 +0000145int json_parse_int64(const char *buf, int64_t *retval)
146{
147 int64_t num64;
John Arbash Meinel6a231e42012-02-01 09:27:49 +0100148 const char *buf_skip_space;
149 int orig_has_neg;
Greg Hazel77d04932013-01-03 16:54:04 -0800150 int saved_errno;
Eric Haszlakiewicz77c62392012-07-29 12:13:54 -0500151 errno = 0; // sscanf won't always set errno, so initialize
Michael Clarkc4dceae2010-10-06 16:39:20 +0000152 if (sscanf(buf, "%" SCNd64, &num64) != 1)
153 {
ehaszla252669c2010-12-07 18:15:35 +0000154 MC_DEBUG("Failed to parse, sscanf != 1\n");
Michael Clarkc4dceae2010-10-06 16:39:20 +0000155 return 1;
156 }
Greg Hazel77d04932013-01-03 16:54:04 -0800157 saved_errno = errno;
John Arbash Meinel6a231e42012-02-01 09:27:49 +0100158 buf_skip_space = buf;
159 orig_has_neg = 0;
Michael Clarkc4dceae2010-10-06 16:39:20 +0000160 // Skip leading spaces
161 while (isspace((int)*buf_skip_space) && *buf_skip_space)
162 buf_skip_space++;
163 if (*buf_skip_space == '-')
164 {
165 buf_skip_space++;
166 orig_has_neg = 1;
167 }
ehaszla252669c2010-12-07 18:15:35 +0000168 // Skip leading zeros, but keep at least one digit
169 while (buf_skip_space[0] == '0' && buf_skip_space[1] != '\0')
Michael Clarkc4dceae2010-10-06 16:39:20 +0000170 buf_skip_space++;
ehaszla252669c2010-12-07 18:15:35 +0000171 if (buf_skip_space[0] == '0' && buf_skip_space[1] == '\0')
172 orig_has_neg = 0; // "-0" is the same as just plain "0"
Michael Clarkc4dceae2010-10-06 16:39:20 +0000173
Greg Hazel77d04932013-01-03 16:54:04 -0800174 if (saved_errno != ERANGE)
Michael Clarkc4dceae2010-10-06 16:39:20 +0000175 {
176 char buf_cmp[100];
177 char *buf_cmp_start = buf_cmp;
178 int recheck_has_neg = 0;
John Arbash Meinel6a231e42012-02-01 09:27:49 +0100179 int buf_cmp_len;
Michael Clarkc4dceae2010-10-06 16:39:20 +0000180 snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64);
181 if (*buf_cmp_start == '-')
182 {
183 recheck_has_neg = 1;
184 buf_cmp_start++;
185 }
186 // No need to skip leading spaces or zeros here.
187
John Arbash Meinel6a231e42012-02-01 09:27:49 +0100188 buf_cmp_len = strlen(buf_cmp_start);
Michael Clarkc4dceae2010-10-06 16:39:20 +0000189 /**
190 * If the sign is different, or
191 * some of the digits are different, or
192 * there is another digit present in the original string
193 * then we NOT successfully parsed the value.
194 */
195 if (orig_has_neg != recheck_has_neg ||
196 strncmp(buf_skip_space, buf_cmp_start, strlen(buf_cmp_start)) != 0 ||
Eric Haszlakiewiczca8b27d2013-02-09 16:35:24 -0600197 ((int)strlen(buf_skip_space) != buf_cmp_len &&
ehaszla252669c2010-12-07 18:15:35 +0000198 isdigit((int)buf_skip_space[buf_cmp_len])
Michael Clarkc4dceae2010-10-06 16:39:20 +0000199 )
200 )
201 {
Greg Hazel77d04932013-01-03 16:54:04 -0800202 saved_errno = ERANGE;
Michael Clarkc4dceae2010-10-06 16:39:20 +0000203 }
204 }
Greg Hazel77d04932013-01-03 16:54:04 -0800205 if (saved_errno == ERANGE)
Michael Clarkc4dceae2010-10-06 16:39:20 +0000206 {
207 if (orig_has_neg)
208 num64 = INT64_MIN;
209 else
210 num64 = INT64_MAX;
211 }
212 *retval = num64;
213 return 0;
214}
ehaszla252669c2010-12-07 18:15:35 +0000215
Mateusz Loskota6f39a32012-05-21 23:22:36 +0100216#ifndef HAVE_REALLOC
ehaszla252669c2010-12-07 18:15:35 +0000217void* rpl_realloc(void* p, size_t n)
218{
219 if (n == 0)
220 n = 1;
221 if (p == 0)
222 return malloc(n);
223 return realloc(p, n);
224}
225#endif
Eric Haszlakiewicz886c4fb2011-05-03 20:40:49 +0000226
227#define NELEM(a) (sizeof(a) / sizeof(a[0]))
228static const char* json_type_name[] = {
229 /* If you change this, be sure to update the enum json_type definition too */
230 "null",
231 "boolean",
232 "double",
233 "int",
234 "object",
235 "array",
236 "string",
237};
238
239const char *json_type_to_name(enum json_type o_type)
240{
Eric Haszlakiewiczca8b27d2013-02-09 16:35:24 -0600241 int o_type_int = (int)o_type;
242 if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name))
Eric Haszlakiewicz886c4fb2011-05-03 20:40:49 +0000243 {
244 MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name));
245 return NULL;
246 }
247 return json_type_name[o_type];
248}
249