1// 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 6/* This executable is used for testing parser/writer using real JSON files. 7 */ 8 9 10#include <json/json.h> 11#include <algorithm> // sort 12#include <stdio.h> 13 14#if defined(_MSC_VER) && _MSC_VER >= 1310 15# pragma warning( disable: 4996 ) // disable fopen deprecation warning 16#endif 17 18static std::string 19normalizeFloatingPointStr( double value ) 20{ 21 char buffer[32]; 22 sprintf( buffer, "%.16g", value ); 23 buffer[sizeof(buffer)-1] = 0; 24 std::string s( buffer ); 25 std::string::size_type index = s.find_last_of( "eE" ); 26 if ( index != std::string::npos ) 27 { 28 std::string::size_type hasSign = (s[index+1] == '+' || s[index+1] == '-') ? 1 : 0; 29 std::string::size_type exponentStartIndex = index + 1 + hasSign; 30 std::string normalized = s.substr( 0, exponentStartIndex ); 31 std::string::size_type indexDigit = s.find_first_not_of( '0', exponentStartIndex ); 32 std::string exponent = "0"; 33 if ( indexDigit != std::string::npos ) // There is an exponent different from 0 34 { 35 exponent = s.substr( indexDigit ); 36 } 37 return normalized + exponent; 38 } 39 return s; 40} 41 42 43static std::string 44readInputTestFile( const char *path ) 45{ 46 FILE *file = fopen( path, "rb" ); 47 if ( !file ) 48 return std::string(""); 49 fseek( file, 0, SEEK_END ); 50 long size = ftell( file ); 51 fseek( file, 0, SEEK_SET ); 52 std::string text; 53 char *buffer = new char[size+1]; 54 buffer[size] = 0; 55 if ( fread( buffer, 1, size, file ) == (unsigned long)size ) 56 text = buffer; 57 fclose( file ); 58 delete[] buffer; 59 return text; 60} 61 62static void 63printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." ) 64{ 65 switch ( value.type() ) 66 { 67 case Json::nullValue: 68 fprintf( fout, "%s=null\n", path.c_str() ); 69 break; 70 case Json::intValue: 71 fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestInt() ).c_str() ); 72 break; 73 case Json::uintValue: 74 fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestUInt() ).c_str() ); 75 break; 76 case Json::realValue: 77 fprintf( fout, "%s=%s\n", path.c_str(), normalizeFloatingPointStr(value.asDouble()).c_str() ); 78 break; 79 case Json::stringValue: 80 fprintf( fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str() ); 81 break; 82 case Json::booleanValue: 83 fprintf( fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false" ); 84 break; 85 case Json::arrayValue: 86 { 87 fprintf( fout, "%s=[]\n", path.c_str() ); 88 int size = value.size(); 89 for ( int index =0; index < size; ++index ) 90 { 91 static char buffer[16]; 92 sprintf( buffer, "[%d]", index ); 93 printValueTree( fout, value[index], path + buffer ); 94 } 95 } 96 break; 97 case Json::objectValue: 98 { 99 fprintf( fout, "%s={}\n", path.c_str() ); 100 Json::Value::Members members( value.getMemberNames() ); 101 std::sort( members.begin(), members.end() ); 102 std::string suffix = *(path.end()-1) == '.' ? "" : "."; 103 for ( Json::Value::Members::iterator it = members.begin(); 104 it != members.end(); 105 ++it ) 106 { 107 const std::string &name = *it; 108 printValueTree( fout, value[name], path + suffix + name ); 109 } 110 } 111 break; 112 default: 113 break; 114 } 115} 116 117 118static int 119parseAndSaveValueTree( const std::string &input, 120 const std::string &actual, 121 const std::string &kind, 122 Json::Value &root, 123 const Json::Features &features, 124 bool parseOnly ) 125{ 126 Json::Reader reader( features ); 127 bool parsingSuccessful = reader.parse( input, root ); 128 if ( !parsingSuccessful ) 129 { 130 printf( "Failed to parse %s file: \n%s\n", 131 kind.c_str(), 132 reader.getFormattedErrorMessages().c_str() ); 133 return 1; 134 } 135 136 if ( !parseOnly ) 137 { 138 FILE *factual = fopen( actual.c_str(), "wt" ); 139 if ( !factual ) 140 { 141 printf( "Failed to create %s actual file.\n", kind.c_str() ); 142 return 2; 143 } 144 printValueTree( factual, root ); 145 fclose( factual ); 146 } 147 return 0; 148} 149 150 151static int 152rewriteValueTree( const std::string &rewritePath, 153 const Json::Value &root, 154 std::string &rewrite ) 155{ 156 //Json::FastWriter writer; 157 //writer.enableYAMLCompatibility(); 158 Json::StyledWriter writer; 159 rewrite = writer.write( root ); 160 FILE *fout = fopen( rewritePath.c_str(), "wt" ); 161 if ( !fout ) 162 { 163 printf( "Failed to create rewrite file: %s\n", rewritePath.c_str() ); 164 return 2; 165 } 166 fprintf( fout, "%s\n", rewrite.c_str() ); 167 fclose( fout ); 168 return 0; 169} 170 171 172static std::string 173removeSuffix( const std::string &path, 174 const std::string &extension ) 175{ 176 if ( extension.length() >= path.length() ) 177 return std::string(""); 178 std::string suffix = path.substr( path.length() - extension.length() ); 179 if ( suffix != extension ) 180 return std::string(""); 181 return path.substr( 0, path.length() - extension.length() ); 182} 183 184 185static void 186printConfig() 187{ 188 // Print the configuration used to compile JsonCpp 189#if defined(JSON_NO_INT64) 190 printf( "JSON_NO_INT64=1\n" ); 191#else 192 printf( "JSON_NO_INT64=0\n" ); 193#endif 194} 195 196 197static int 198printUsage( const char *argv[] ) 199{ 200 printf( "Usage: %s [--strict] input-json-file", argv[0] ); 201 return 3; 202} 203 204 205int 206parseCommandLine( int argc, const char *argv[], 207 Json::Features &features, std::string &path, 208 bool &parseOnly ) 209{ 210 parseOnly = false; 211 if ( argc < 2 ) 212 { 213 return printUsage( argv ); 214 } 215 216 int index = 1; 217 if ( std::string(argv[1]) == "--json-checker" ) 218 { 219 features = Json::Features::strictMode(); 220 parseOnly = true; 221 ++index; 222 } 223 224 if ( std::string(argv[1]) == "--json-config" ) 225 { 226 printConfig(); 227 return 3; 228 } 229 230 if ( index == argc || index + 1 < argc ) 231 { 232 return printUsage( argv ); 233 } 234 235 path = argv[index]; 236 return 0; 237} 238 239 240int main( int argc, const char *argv[] ) 241{ 242 std::string path; 243 Json::Features features; 244 bool parseOnly; 245 int exitCode = parseCommandLine( argc, argv, features, path, parseOnly ); 246 if ( exitCode != 0 ) 247 { 248 return exitCode; 249 } 250 251 try 252 { 253 std::string input = readInputTestFile( path.c_str() ); 254 if ( input.empty() ) 255 { 256 printf( "Failed to read input or empty input: %s\n", path.c_str() ); 257 return 3; 258 } 259 260 std::string basePath = removeSuffix( argv[1], ".json" ); 261 if ( !parseOnly && basePath.empty() ) 262 { 263 printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() ); 264 return 3; 265 } 266 267 std::string actualPath = basePath + ".actual"; 268 std::string rewritePath = basePath + ".rewrite"; 269 std::string rewriteActualPath = basePath + ".actual-rewrite"; 270 271 Json::Value root; 272 exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly ); 273 if ( exitCode == 0 && !parseOnly ) 274 { 275 std::string rewrite; 276 exitCode = rewriteValueTree( rewritePath, root, rewrite ); 277 if ( exitCode == 0 ) 278 { 279 Json::Value rewriteRoot; 280 exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath, 281 "rewrite", rewriteRoot, features, parseOnly ); 282 } 283 } 284 } 285 catch ( const std::exception &e ) 286 { 287 printf( "Unhandled exception:\n%s\n", e.what() ); 288 exitCode = 1; 289 } 290 291 return exitCode; 292} 293 294