blob: e5a9dc6cd5cfc6019ec19cea9e8959551560d8cc [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"
13
Michael Clarkf0d08882007-03-13 08:26:18 +000014#include <stdio.h>
15#include <stdlib.h>
Michael Clarkc8f4a6e2007-12-07 02:44:24 +000016#include <stddef.h>
Michael Clark4504df72007-03-13 08:26:20 +000017#include <limits.h>
Michael Clarkf0d08882007-03-13 08:26:18 +000018#include <string.h>
19#include <errno.h>
Michael Clarkc4dceae2010-10-06 16:39:20 +000020#include <ctype.h>
Michael Clark4504df72007-03-13 08:26:20 +000021
22#if HAVE_SYS_TYPES_H
Michael Clarkf0d08882007-03-13 08:26:18 +000023#include <sys/types.h>
Michael Clark4504df72007-03-13 08:26:20 +000024#endif /* HAVE_SYS_TYPES_H */
25
26#if HAVE_SYS_STAT_H
Michael Clarkf0d08882007-03-13 08:26:18 +000027#include <sys/stat.h>
Michael Clark4504df72007-03-13 08:26:20 +000028#endif /* HAVE_SYS_STAT_H */
29
30#if HAVE_FCNTL_H
Michael Clarkf0d08882007-03-13 08:26:18 +000031#include <fcntl.h>
Michael Clark4504df72007-03-13 08:26:20 +000032#endif /* HAVE_FCNTL_H */
33
34#if HAVE_UNISTD_H
35# include <unistd.h>
36#endif /* HAVE_UNISTD_H */
37
38#ifdef WIN32
39# define WIN32_LEAN_AND_MEAN
40# include <windows.h>
41# include <io.h>
42#endif /* defined(WIN32) */
Michael Clarkf0d08882007-03-13 08:26:18 +000043
Michael Clark837240f2007-03-13 08:26:25 +000044#if !HAVE_OPEN && defined(WIN32)
45# define open _open
46#endif
47
48
Michael Clarkf0d08882007-03-13 08:26:18 +000049#include "bits.h"
50#include "debug.h"
51#include "printbuf.h"
Michael Clarkc4dceae2010-10-06 16:39:20 +000052#include "json_inttypes.h"
Michael Clarkf0d08882007-03-13 08:26:18 +000053#include "json_object.h"
54#include "json_tokener.h"
55#include "json_util.h"
56
Michael Clark88ded9c2009-08-27 06:40:59 +000057struct json_object* json_object_from_file(const char *filename)
Michael Clarkf0d08882007-03-13 08:26:18 +000058{
59 struct printbuf *pb;
60 struct json_object *obj;
61 char buf[JSON_FILE_BUF_SIZE];
62 int fd, ret;
63
64 if((fd = open(filename, O_RDONLY)) < 0) {
Michael Clarkdfaf6702007-10-25 02:26:00 +000065 MC_ERROR("json_object_from_file: error reading file %s: %s\n",
Michael Clarkf0d08882007-03-13 08:26:18 +000066 filename, strerror(errno));
Michael Clarkaaec1ef2009-02-25 02:31:32 +000067 return (struct json_object*)error_ptr(-1);
Michael Clarkf0d08882007-03-13 08:26:18 +000068 }
69 if(!(pb = printbuf_new())) {
Michael Clarkdfaf6702007-10-25 02:26:00 +000070 MC_ERROR("json_object_from_file: printbuf_new failed\n");
Michael Clarkaaec1ef2009-02-25 02:31:32 +000071 return (struct json_object*)error_ptr(-1);
Michael Clarkf0d08882007-03-13 08:26:18 +000072 }
73 while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) {
74 printbuf_memappend(pb, buf, ret);
75 }
76 close(fd);
77 if(ret < 0) {
Michael Clarkdfaf6702007-10-25 02:26:00 +000078 MC_ABORT("json_object_from_file: error reading file %s: %s\n",
Michael Clarkf0d08882007-03-13 08:26:18 +000079 filename, strerror(errno));
80 printbuf_free(pb);
Michael Clarkaaec1ef2009-02-25 02:31:32 +000081 return (struct json_object*)error_ptr(-1);
Michael Clarkf0d08882007-03-13 08:26:18 +000082 }
83 obj = json_tokener_parse(pb->buf);
84 printbuf_free(pb);
85 return obj;
86}
87
88int json_object_to_file(char *filename, struct json_object *obj)
89{
Michael Clark68cafad2009-01-06 22:56:57 +000090 const char *json_str;
Michael Clark4504df72007-03-13 08:26:20 +000091 int fd, ret;
92 unsigned int wpos, wsize;
Michael Clarkf0d08882007-03-13 08:26:18 +000093
94 if(!obj) {
Michael Clarkdfaf6702007-10-25 02:26:00 +000095 MC_ERROR("json_object_to_file: object is null\n");
Michael Clarkf0d08882007-03-13 08:26:18 +000096 return -1;
97 }
98
99 if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
Michael Clarkdfaf6702007-10-25 02:26:00 +0000100 MC_ERROR("json_object_to_file: error opening file %s: %s\n",
Michael Clarkf0d08882007-03-13 08:26:18 +0000101 filename, strerror(errno));
102 return -1;
103 }
Michael Clark4504df72007-03-13 08:26:20 +0000104
105 if(!(json_str = json_object_to_json_string(obj))) { return -1; }
106
107
108 wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */
Michael Clarkf0d08882007-03-13 08:26:18 +0000109 wpos = 0;
110 while(wpos < wsize) {
111 if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) {
112 close(fd);
Michael Clarkdfaf6702007-10-25 02:26:00 +0000113 MC_ERROR("json_object_to_file: error writing file %s: %s\n",
Michael Clarkf0d08882007-03-13 08:26:18 +0000114 filename, strerror(errno));
115 return -1;
116 }
Michael Clark4504df72007-03-13 08:26:20 +0000117
118 /* because of the above check for ret < 0, we can safely cast and add */
119 wpos += (unsigned int)ret;
Michael Clarkf0d08882007-03-13 08:26:18 +0000120 }
121
122 close(fd);
123 return 0;
124}
Michael Clarkc4dceae2010-10-06 16:39:20 +0000125
126int json_parse_int64(const char *buf, int64_t *retval)
127{
128 int64_t num64;
129 if (sscanf(buf, "%" SCNd64, &num64) != 1)
130 {
131 printf("Failed to parse, sscanf != 1\n");
132 return 1;
133 }
134 const char *buf_skip_space = buf;
135 int orig_has_neg = 0;
136 // Skip leading spaces
137 while (isspace((int)*buf_skip_space) && *buf_skip_space)
138 buf_skip_space++;
139 if (*buf_skip_space == '-')
140 {
141 buf_skip_space++;
142 orig_has_neg = 1;
143 }
144 // Skip leading zeros
145 while (*buf_skip_space == '0' && *buf_skip_space)
146 buf_skip_space++;
147
148 if (errno != ERANGE)
149 {
150 char buf_cmp[100];
151 char *buf_cmp_start = buf_cmp;
152 int recheck_has_neg = 0;
153 snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64);
154 if (*buf_cmp_start == '-')
155 {
156 recheck_has_neg = 1;
157 buf_cmp_start++;
158 }
159 // No need to skip leading spaces or zeros here.
160
161 int buf_cmp_len = strlen(buf_cmp_start);
162 /**
163 * If the sign is different, or
164 * some of the digits are different, or
165 * there is another digit present in the original string
166 * then we NOT successfully parsed the value.
167 */
168 if (orig_has_neg != recheck_has_neg ||
169 strncmp(buf_skip_space, buf_cmp_start, strlen(buf_cmp_start)) != 0 ||
170 (strlen(buf_skip_space) != buf_cmp_len &&
171 isdigit(buf_skip_space[buf_cmp_len])
172 )
173 )
174 {
175 errno = ERANGE;
176 }
177 }
178 if (errno == ERANGE)
179 {
180 if (orig_has_neg)
181 num64 = INT64_MIN;
182 else
183 num64 = INT64_MAX;
184 }
185 *retval = num64;
186 return 0;
187}