blob: be3f44cb4e8998e46fe52d0d38dc930032b61026 [file] [log] [blame]
Baptiste Lepilleur7469f1d2010-04-20 21:35:19 +00001// Copyright 2007-2010 Baptiste Lepilleur
2// Distributed under MIT license, or public domain if desired and
3// recognized in your jurisdiction.
4// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5
Christopher Dunnf9864232007-06-14 21:01:26 +00006#include <json/json.h>
7#include <algorithm> // sort
8#include <stdio.h>
9
10#if defined(_MSC_VER) && _MSC_VER >= 1310
11# pragma warning( disable: 4996 ) // disable fopen deprecation warning
12#endif
13
14static std::string
15readInputTestFile( const char *path )
16{
17 FILE *file = fopen( path, "rb" );
18 if ( !file )
19 return std::string("");
20 fseek( file, 0, SEEK_END );
21 long size = ftell( file );
22 fseek( file, 0, SEEK_SET );
23 std::string text;
24 char *buffer = new char[size+1];
25 buffer[size] = 0;
26 if ( fread( buffer, 1, size, file ) == (unsigned long)size )
27 text = buffer;
28 fclose( file );
29 delete[] buffer;
30 return text;
31}
32
33
34static void
35printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
36{
37 switch ( value.type() )
38 {
39 case Json::nullValue:
40 fprintf( fout, "%s=null\n", path.c_str() );
41 break;
42 case Json::intValue:
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +000043 fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asInt() ).c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +000044 break;
45 case Json::uintValue:
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +000046 fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asUInt() ).c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +000047 break;
48 case Json::realValue:
49 fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
50 break;
51 case Json::stringValue:
52 fprintf( fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str() );
53 break;
54 case Json::booleanValue:
55 fprintf( fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false" );
56 break;
57 case Json::arrayValue:
58 {
59 fprintf( fout, "%s=[]\n", path.c_str() );
60 int size = value.size();
61 for ( int index =0; index < size; ++index )
62 {
63 static char buffer[16];
64 sprintf( buffer, "[%d]", index );
65 printValueTree( fout, value[index], path + buffer );
66 }
67 }
68 break;
69 case Json::objectValue:
70 {
71 fprintf( fout, "%s={}\n", path.c_str() );
72 Json::Value::Members members( value.getMemberNames() );
73 std::sort( members.begin(), members.end() );
74 std::string suffix = *(path.end()-1) == '.' ? "" : ".";
75 for ( Json::Value::Members::iterator it = members.begin();
76 it != members.end();
77 ++it )
78 {
79 const std::string &name = *it;
80 printValueTree( fout, value[name], path + suffix + name );
81 }
82 }
83 break;
84 default:
85 break;
86 }
87}
88
89
90static int
91parseAndSaveValueTree( const std::string &input,
92 const std::string &actual,
93 const std::string &kind,
Baptiste Lepilleur88681472009-11-18 21:38:54 +000094 Json::Value &root,
95 const Json::Features &features,
96 bool parseOnly )
Christopher Dunnf9864232007-06-14 21:01:26 +000097{
Baptiste Lepilleur88681472009-11-18 21:38:54 +000098 Json::Reader reader( features );
Christopher Dunnf9864232007-06-14 21:01:26 +000099 bool parsingSuccessful = reader.parse( input, root );
100 if ( !parsingSuccessful )
101 {
102 printf( "Failed to parse %s file: \n%s\n",
103 kind.c_str(),
104 reader.getFormatedErrorMessages().c_str() );
105 return 1;
106 }
107
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000108 if ( !parseOnly )
Christopher Dunnf9864232007-06-14 21:01:26 +0000109 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000110 FILE *factual = fopen( actual.c_str(), "wt" );
111 if ( !factual )
112 {
113 printf( "Failed to create %s actual file.\n", kind.c_str() );
114 return 2;
115 }
116 printValueTree( factual, root );
117 fclose( factual );
Christopher Dunnf9864232007-06-14 21:01:26 +0000118 }
Christopher Dunnf9864232007-06-14 21:01:26 +0000119 return 0;
120}
121
122
123static int
124rewriteValueTree( const std::string &rewritePath,
125 const Json::Value &root,
126 std::string &rewrite )
127{
128 //Json::FastWriter writer;
129 //writer.enableYAMLCompatibility();
130 Json::StyledWriter writer;
131 rewrite = writer.write( root );
132 FILE *fout = fopen( rewritePath.c_str(), "wt" );
133 if ( !fout )
134 {
135 printf( "Failed to create rewrite file: %s\n", rewritePath.c_str() );
136 return 2;
137 }
138 fprintf( fout, "%s\n", rewrite.c_str() );
139 fclose( fout );
140 return 0;
141}
142
143
144static std::string
145removeSuffix( const std::string &path,
146 const std::string &extension )
147{
148 if ( extension.length() >= path.length() )
149 return std::string("");
150 std::string suffix = path.substr( path.length() - extension.length() );
151 if ( suffix != extension )
152 return std::string("");
153 return path.substr( 0, path.length() - extension.length() );
154}
155
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +0000156
157static void
158printConfig()
159{
160 // Print the configuration used to compile JsonCpp
161#if defined(JSON_NO_INT64)
162 printf( "JSON_NO_INT64=1\n" );
163#else
164 printf( "JSON_NO_INT64=0\n" );
165#endif
166}
167
168
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000169static int
170printUsage( const char *argv[] )
Christopher Dunnf9864232007-06-14 21:01:26 +0000171{
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000172 printf( "Usage: %s [--strict] input-json-file", argv[0] );
173 return 3;
174}
175
176
177int
178parseCommandLine( int argc, const char *argv[],
179 Json::Features &features, std::string &path,
180 bool &parseOnly )
181{
182 parseOnly = false;
183 if ( argc < 2 )
Christopher Dunnf9864232007-06-14 21:01:26 +0000184 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000185 return printUsage( argv );
Christopher Dunnf9864232007-06-14 21:01:26 +0000186 }
187
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000188 int index = 1;
189 if ( std::string(argv[1]) == "--json-checker" )
190 {
191 features = Json::Features::strictMode();
192 parseOnly = true;
193 ++index;
194 }
195
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +0000196 if ( std::string(argv[1]) == "--json-config" )
197 {
198 printConfig();
199 return 3;
200 }
201
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000202 if ( index == argc || index + 1 < argc )
203 {
204 return printUsage( argv );
205 }
206
207 path = argv[index];
208 return 0;
209}
210
211
212int main( int argc, const char *argv[] )
213{
214 std::string path;
215 Json::Features features;
216 bool parseOnly;
217 int exitCode = parseCommandLine( argc, argv, features, path, parseOnly );
218 if ( exitCode != 0 )
219 {
220 return exitCode;
221 }
222
223 std::string input = readInputTestFile( path.c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +0000224 if ( input.empty() )
225 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000226 printf( "Failed to read input or empty input: %s\n", path.c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +0000227 return 3;
228 }
229
230 std::string basePath = removeSuffix( argv[1], ".json" );
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000231 if ( !parseOnly && basePath.empty() )
Christopher Dunnf9864232007-06-14 21:01:26 +0000232 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000233 printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +0000234 return 3;
235 }
236
237 std::string actualPath = basePath + ".actual";
238 std::string rewritePath = basePath + ".rewrite";
239 std::string rewriteActualPath = basePath + ".actual-rewrite";
240
241 Json::Value root;
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000242 exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
243 if ( exitCode == 0 && !parseOnly )
Christopher Dunnf9864232007-06-14 21:01:26 +0000244 {
245 std::string rewrite;
246 exitCode = rewriteValueTree( rewritePath, root, rewrite );
247 if ( exitCode == 0 )
248 {
249 Json::Value rewriteRoot;
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000250 exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
251 "rewrite", rewriteRoot, features, parseOnly );
Christopher Dunnf9864232007-06-14 21:01:26 +0000252 }
253 }
254
255 return exitCode;
256}
257