| // 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; |
| } |
| |