// Copyright 2007-2010 Baptiste Lepilleur // Distributed under MIT license, or public domain if desired and // recognized in your jurisdiction. // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE /* This executable is used for testing parser/writer using real JSON files. */ #include <json/json.h> #include <algorithm> // sort #include <stdio.h> #if defined(_MSC_VER) && _MSC_VER >= 1310 # pragma warning( disable: 4996 ) // disable fopen deprecation warning #endif static std::string normalizeFloatingPointStr( double value ) { char buffer[32]; sprintf( buffer, "%.16g", value ); buffer[sizeof(buffer)-1] = 0; std::string s( buffer ); std::string::size_type index = s.find_last_of( "eE" ); if ( index != std::string::npos ) { std::string::size_type hasSign = (s[index+1] == '+' || s[index+1] == '-') ? 1 : 0; std::string::size_type exponentStartIndex = index + 1 + hasSign; std::string normalized = s.substr( 0, exponentStartIndex ); std::string::size_type indexDigit = s.find_first_not_of( '0', exponentStartIndex ); std::string exponent = "0"; if ( indexDigit != std::string::npos ) // There is an exponent different from 0 { exponent = s.substr( indexDigit ); } return normalized + exponent; } return s; } static std::string readInputTestFile( const char *path ) { FILE *file = fopen( path, "rb" ); if ( !file ) return std::string(""); fseek( file, 0, SEEK_END ); long size = ftell( file ); fseek( file, 0, SEEK_SET ); std::string text; char *buffer = new char[size+1]; buffer[size] = 0; if ( fread( buffer, 1, size, file ) == (unsigned long)size ) text = buffer; fclose( file ); delete[] buffer; return text; } static void printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." ) { switch ( value.type() ) { case Json::nullValue: fprintf( fout, "%s=null\n", path.c_str() ); break; case Json::intValue: fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestInt() ).c_str() ); break; case Json::uintValue: fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestUInt() ).c_str() ); break; case Json::realValue: fprintf( fout, "%s=%s\n", path.c_str(), normalizeFloatingPointStr(value.asDouble()).c_str() ); break; case Json::stringValue: fprintf( fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str() ); break; case Json::booleanValue: fprintf( fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false" ); break; case Json::arrayValue: { fprintf( fout, "%s=[]\n", path.c_str() ); int size = value.size(); for ( int index =0; index < size; ++index ) { static char buffer[16]; sprintf( buffer, "[%d]", index ); printValueTree( fout, value[index], path + buffer ); } } break; case Json::objectValue: { fprintf( fout, "%s={}\n", path.c_str() ); Json::Value::Members members( value.getMemberNames() ); std::sort( members.begin(), members.end() ); std::string suffix = *(path.end()-1) == '.' ? "" : "."; for ( Json::Value::Members::iterator it = members.begin(); it != members.end(); ++it ) { const std::string &name = *it; printValueTree( fout, value[name], path + suffix + name ); } } break; default: break; } } static int parseAndSaveValueTree( const std::string &input, const std::string &actual, const std::string &kind, Json::Value &root, const Json::Features &features, bool parseOnly ) { Json::Reader reader( features ); bool parsingSuccessful = reader.parse( input, root ); if ( !parsingSuccessful ) { printf( "Failed to parse %s file: \n%s\n", kind.c_str(), reader.getFormattedErrorMessages().c_str() ); return 1; } if ( !parseOnly ) { FILE *factual = fopen( actual.c_str(), "wt" ); if ( !factual ) { printf( "Failed to create %s actual file.\n", kind.c_str() ); return 2; } printValueTree( factual, root ); fclose( factual ); } return 0; } static int rewriteValueTree( const std::string &rewritePath, const Json::Value &root, std::string &rewrite ) { //Json::FastWriter writer; //writer.enableYAMLCompatibility(); Json::StyledWriter writer; rewrite = writer.write( root ); FILE *fout = fopen( rewritePath.c_str(), "wt" ); if ( !fout ) { printf( "Failed to create rewrite file: %s\n", rewritePath.c_str() ); return 2; } fprintf( fout, "%s\n", rewrite.c_str() ); fclose( fout ); return 0; } static std::string removeSuffix( const std::string &path, const std::string &extension ) { if ( extension.length() >= path.length() ) return std::string(""); std::string suffix = path.substr( path.length() - extension.length() ); if ( suffix != extension ) return std::string(""); return path.substr( 0, path.length() - extension.length() ); } static void printConfig() { // Print the configuration used to compile JsonCpp #if defined(JSON_NO_INT64) printf( "JSON_NO_INT64=1\n" ); #else printf( "JSON_NO_INT64=0\n" ); #endif } static int printUsage( const char *argv[] ) { printf( "Usage: %s [--strict] input-json-file", argv[0] ); return 3; } int parseCommandLine( int argc, const char *argv[], Json::Features &features, std::string &path, bool &parseOnly ) { parseOnly = false; if ( argc < 2 ) { return printUsage( argv ); } int index = 1; if ( std::string(argv[1]) == "--json-checker" ) { features = Json::Features::strictMode(); parseOnly = true; ++index; } if ( std::string(argv[1]) == "--json-config" ) { printConfig(); return 3; } if ( index == argc || index + 1 < argc ) { return printUsage( argv ); } path = argv[index]; return 0; } int main( int argc, const char *argv[] ) { std::string path; Json::Features features; bool parseOnly; int exitCode = parseCommandLine( argc, argv, features, path, parseOnly ); if ( exitCode != 0 ) { return exitCode; } try { std::string input = readInputTestFile( path.c_str() ); if ( input.empty() ) { printf( "Failed to read input or empty input: %s\n", path.c_str() ); return 3; } std::string basePath = removeSuffix( argv[1], ".json" ); if ( !parseOnly && basePath.empty() ) { printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() ); return 3; } std::string actualPath = basePath + ".actual"; std::string rewritePath = basePath + ".rewrite"; std::string rewriteActualPath = basePath + ".actual-rewrite"; Json::Value root; exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly ); if ( exitCode == 0 && !parseOnly ) { std::string rewrite; exitCode = rewriteValueTree( rewritePath, root, rewrite ); if ( exitCode == 0 ) { Json::Value rewriteRoot; exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath, "rewrite", rewriteRoot, features, parseOnly ); } } } catch ( const std::exception &e ) { printf( "Unhandled exception:\n%s\n", e.what() ); exitCode = 1; } return exitCode; }