
git-svn-id: https://rapidjson.googlecode.com/svn/trunk@2 c5894555-1306-4e8d-425f-1f6f381ee07c
234 lines
6.0 KiB
C++
234 lines
6.0 KiB
C++
#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
|
|
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=%d\n", path.c_str(), value.asInt() );
|
|
break;
|
|
case Json::uintValue:
|
|
fprintf( fout, "%s=%u\n", path.c_str(), value.asUInt() );
|
|
break;
|
|
case Json::realValue:
|
|
fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
|
|
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.getFormatedErrorMessages().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 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 ( 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;
|
|
}
|
|
|
|
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 );
|
|
}
|
|
}
|
|
|
|
return exitCode;
|
|
}
|
|
|