added ValResponse class to parse JSON from http

pull/40/head
Nestal Wan 2013-05-02 00:04:42 +08:00
parent 2d29692601
commit abfa9ce765
13 changed files with 463 additions and 181 deletions

View File

@ -65,6 +65,7 @@ file (GLOB LIBGRIVE_SRC
src/drive2/*.cc
src/http/*.cc
src/protocol/*.cc
src/json/*.cc
src/util/*.cc
src/util/log/*.cc
src/xml/*.cc

View File

@ -1,135 +0,0 @@
/*
grive: an GPL program to sync a local directory with Google Drive
Copyright (C) 2013 Wan Wai Ho
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#include "JsonVal.hh"
#include "Val.hh"
#include "ValBuilder.hh"
#include <yajl/yajl_parse.h>
namespace gr { namespace json {
namespace
{
int OnNull( void *ctx )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->BuildNull() ;
return true ;
}
int OnBool( void *ctx, int value )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->Build( static_cast<long long>(value) ) ;
return true ;
}
int OnInt( void *ctx, long long value )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->Build(value) ;
return true ;
}
int OnDouble( void *ctx, double value )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->Build(value) ;
return true ;
}
int OnStr( void *ctx, const unsigned char *str, std::size_t len )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->Build( std::string(reinterpret_cast<const char*>(str), len) ) ;
return true ;
}
int StartMap( void *ctx )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->StartObject() ;
return true ;
}
int OnMapKey( void *ctx, const unsigned char *str, std::size_t len )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->BuildKey( std::string(reinterpret_cast<const char*>(str), len) ) ;
return true ;
}
int EndMap( void *ctx )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->EndObject() ;
return true ;
}
int StartArray( void *ctx )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->StartArray() ;
return true ;
}
int EndArray( void *ctx )
{
ValBuilder *b = reinterpret_cast<ValBuilder*>(ctx) ;
b->EndArray() ;
return true ;
}
const yajl_callbacks callbacks = {
OnNull,
OnBool,
OnInt,
OnDouble,
0,
OnStr,
StartMap,
OnMapKey,
EndMap,
StartArray,
EndArray,
};
}
Val Parse( const std::string& json )
{
ValBuilder b ;
yajl_handle hand = yajl_alloc( &callbacks, 0, &b ) ;
yajl_parse( hand, reinterpret_cast<unsigned const char*>(json.c_str()), json.size() ) ;
if ( yajl_complete_parse(hand) != yajl_status_ok )
{
unsigned char *msg = yajl_get_error( hand, true, reinterpret_cast<unsigned const char*>(json.c_str()), json.size() ) ;
std::string msg_str(reinterpret_cast<char*>(msg)) ;
yajl_free_error(hand, msg) ;
BOOST_THROW_EXCEPTION( Error() << ParseErr_(msg_str) << JsonText_(json) ) ;
}
return b.Result() ;
}
} } // end of namespace gr::json

View File

@ -0,0 +1,174 @@
/*
grive: an GPL program to sync a local directory with Google Drive
Copyright (C) 2013 Wan Wai Ho
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#include "JsonParser.hh"
#include "Val.hh"
#include "ValBuilder.hh"
#include <yajl/yajl_parse.h>
namespace gr {
namespace
{
int OnNull( void *ctx )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->VisitNull() ;
return true ;
}
int OnBool( void *ctx, int value )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->Visit( static_cast<long long>(value) ) ;
return true ;
}
int OnInt( void *ctx, long long value )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->Visit(value) ;
return true ;
}
int OnDouble( void *ctx, double value )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->Visit(value) ;
return true ;
}
int OnStr( void *ctx, const unsigned char *str, std::size_t len )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->Visit( std::string(reinterpret_cast<const char*>(str), len) ) ;
return true ;
}
int StartMap( void *ctx )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->StartObject() ;
return true ;
}
int OnMapKey( void *ctx, const unsigned char *str, std::size_t len )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->VisitKey( std::string(reinterpret_cast<const char*>(str), len) ) ;
return true ;
}
int EndMap( void *ctx )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->EndObject() ;
return true ;
}
int StartArray( void *ctx )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->StartArray() ;
return true ;
}
int EndArray( void *ctx )
{
ValVisitor *b = reinterpret_cast<ValVisitor*>(ctx) ;
b->EndArray() ;
return true ;
}
const yajl_callbacks callbacks = {
OnNull,
OnBool,
OnInt,
OnDouble,
0,
OnStr,
StartMap,
OnMapKey,
EndMap,
StartArray,
EndArray,
};
}
void JsonParser::Parse( const std::string& json, ValVisitor *callback )
{
JsonParser parser( callback ) ;
parser.Parse( json.c_str(), json.size() ) ;
parser.Finish() ;
}
struct JsonParser::Impl
{
ValVisitor *callback ;
yajl_handle hand ;
} ;
JsonParser::JsonParser( ValVisitor *callback ) :
m_impl( new Impl )
{
m_impl->callback = callback ;
m_impl->hand = yajl_alloc( &callbacks, 0, m_impl->callback ) ;
}
JsonParser::~JsonParser()
{
yajl_free( m_impl->hand ) ;
}
void JsonParser::Parse( const char *str, std::size_t size )
{
const unsigned char *ustr = reinterpret_cast<unsigned const char*>(str) ;
yajl_status r = yajl_parse( m_impl->hand, ustr, size ) ;
if ( r != yajl_status_ok )
{
unsigned char *msg = yajl_get_error( m_impl->hand, true, ustr, size ) ;
std::string msg_str(reinterpret_cast<char*>(msg)) ;
yajl_free_error(m_impl->hand, msg) ;
BOOST_THROW_EXCEPTION(
Error()
<< ParseErr_(msg_str)
<< JsonText_(std::string(str,size))
);
}
}
void JsonParser::Finish()
{
if ( yajl_complete_parse(m_impl->hand) != yajl_status_ok )
{
unsigned char *msg = yajl_get_error( m_impl->hand, false, 0, 0 ) ;
std::string msg_str(reinterpret_cast<char*>(msg)) ;
yajl_free_error(m_impl->hand, msg) ;
BOOST_THROW_EXCEPTION( Error() << ParseErr_(msg_str) ) ;
}
}
} // end of namespace gr::json

View File

@ -0,0 +1,53 @@
/*
grive: an GPL program to sync a local directory with Google Drive
Copyright (C) 2013 Wan Wai Ho
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#pragma once
#include "util/Exception.hh"
#include <string>
#include <memory>
namespace gr {
class ValVisitor ;
class JsonParser
{
public :
struct Error : virtual Exception {} ;
typedef boost::error_info<struct ParseErr, std::string> ParseErr_ ;
typedef boost::error_info<struct JsonText, std::string> JsonText_ ;
static void Parse( const std::string& json, ValVisitor *callback ) ;
explicit JsonParser( ValVisitor *callback ) ;
~JsonParser() ;
void Parse( const char *str, std::size_t size ) ;
void Finish() ;
private :
struct Impl ;
std::auto_ptr<Impl> m_impl ;
} ;
} // end of namespace

View File

@ -38,6 +38,18 @@ Val::~Val()
{
}
void Val::Swap( Val& val )
{
std::swap( m_base, val.m_base ) ;
}
Val& Val::operator=( const Val& val )
{
Val tmp(val) ;
Swap(tmp) ;
return *this ;
}
Val::TypeEnum Val::Type() const
{
return m_base->Type() ;
@ -66,16 +78,60 @@ const Val& Val::operator[]( std::size_t index ) const
throw ;
}
std::string Val::Str() const
{
return As<std::string>() ;
}
int Val::Int() const
{
return static_cast<int>(As<long long>()) ;
}
double Val::Double() const
{
return As<double>() ;
}
bool Val::Bool() const
{
return As<bool>() ;
}
const Val::Array& Val::AsArray() const
{
return As<Array>() ;
}
const Val::Object& Val::AsObject() const
{
return As<Object>() ;
}
bool Val::Has( const std::string& key ) const
{
const Object& obj = As<Object>() ;
return obj.find(key) != obj.end() ;
}
bool Val::Get( const std::string& key, Val& val ) const
{
const Object& obj = As<Object>() ;
Object::const_iterator i = obj.find(key) ;
if ( i != obj.end() )
{
val = i->second ;
return true ;
}
else
return false ;
}
void Val::Add( const std::string& key, const Val& value )
{
As<Object>().insert( std::make_pair(key, value) ) ;
}
void Val::Swap( Val& val )
{
std::swap( m_base, val.m_base ) ;
}
} // end of namespace
namespace std

View File

@ -23,14 +23,16 @@
#include "util/Exception.hh"
#include <cstddef>
#include <memory>
#include <vector>
#include <map>
#include <string>
#include <iosfwd>
#include <map>
#include <memory>
#include <string>
#include <vector>
namespace gr {
class ValVisitor ;
class Val
{
public :
@ -66,14 +68,9 @@ public :
template <typename T>
Val& Assign( const T& t ) ;
void Swap( Val& val ) ;
Val& operator=( const Val& val )
{
Val tmp(val) ;
Swap(tmp) ;
return *this ;
}
void Swap( Val& val ) ;
Val& operator=( const Val& val ) ;
template <typename T>
Val& operator=( const T& t )
@ -95,7 +92,27 @@ public :
const Val& operator[]( const std::string& key ) const ;
const Val& operator[]( std::size_t index ) const ;
void Add( const std::string& key, const Val& value ) ;
// shortcuts for As<>()
std::string Str() const ;
int Int() const ;
long Long() const ;
double Double() const ;
bool Bool() const ;
const Array& AsArray() const ;
const Object& AsObject() const ;
// shortcuts for objects
bool Has( const std::string& key ) const ;
bool Get( const std::string& key, Val& val ) const ;
void Add( const std::string& key, const Val& val ) ;
// shortcuts for array (and array of objects)
void Add( const Val& json ) ;
Val FindInArray( const std::string& key, const std::string& value ) const ;
bool FindInArray( const std::string& key, const std::string& value, Val& result ) const ;
// friend std::ostream& operator<<( std::ostream& os, const Val& json ) ;
// void Visit( DataStream *out ) const ;
private :
struct Base ;

View File

@ -32,27 +32,27 @@ ValBuilder::~ValBuilder()
{
}
void ValBuilder::Build( long long t )
void ValBuilder::Visit( long long t )
{
Build(Val(t)) ;
}
void ValBuilder::Build( double t )
void ValBuilder::Visit( double t )
{
Build(Val(t)) ;
}
void ValBuilder::Build( const std::string& t )
void ValBuilder::Visit( const std::string& t )
{
Build(Val(t)) ;
}
void ValBuilder::Build( bool t )
void ValBuilder::Visit( bool t )
{
Build(Val(t)) ;
}
void ValBuilder::BuildNull()
void ValBuilder::VisitNull()
{
Build(Val()) ;
}
@ -83,7 +83,7 @@ void ValBuilder::Build( const Val& t )
BOOST_THROW_EXCEPTION( Error() << Unexpected_(m_ctx.top()) ) ;
}
void ValBuilder::BuildKey( const std::string& t )
void ValBuilder::VisitKey( const std::string& t )
{
m_key.reset( new Val(t) ) ;
}

View File

@ -20,6 +20,8 @@
#pragma once
#include "ValVisitor.hh"
#include "Val.hh"
#include "util/Exception.hh"
@ -28,7 +30,7 @@
namespace gr {
class ValBuilder
class ValBuilder : public ValVisitor
{
public :
struct Error : virtual Exception {} ;
@ -40,17 +42,17 @@ public :
ValBuilder( ) ;
~ValBuilder() ;
void Build( long long t ) ;
void Build( double t ) ;
void Build( const std::string& t ) ;
void Build( bool t ) ;
void BuildNull() ;
void Visit( long long t ) ;
void Visit( double t ) ;
void Visit( const std::string& t ) ;
void Visit( bool t ) ;
void VisitNull() ;
void Build( const Val& t ) ;
void StartArray() ;
void EndArray() ;
void StartObject() ;
void BuildKey( const std::string& t ) ;
void VisitKey( const std::string& t ) ;
void EndObject() ;
Val Result() const ;

View File

@ -0,0 +1,53 @@
/*
grive: an GPL program to sync a local directory with Google Drive
Copyright (C) 2013 Wan Wai Ho
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#include "ValResponse.hh"
#include "Val.hh"
namespace gr { namespace http {
ValResponse::ValResponse( ) :
m_parser( &m_val )
{
}
std::size_t ValResponse::Write( const char *data, std::size_t count )
{
m_parser.Parse( data, count ) ;
return count ;
}
std::size_t ValResponse::Read( char *data, std::size_t count )
{
return count ;
}
Val ValResponse::Response() const
{
return m_val.Result() ;
}
void ValResponse::Finish()
{
m_parser.Finish() ;
}
} } // end of namespace gr::http

View File

@ -20,22 +20,33 @@
#pragma once
#include "util/Exception.hh"
#include "util/DataStream.hh"
#include <string>
#include "JsonParser.hh"
#include "ValBuilder.hh"
namespace gr
{
class Val ;
}
namespace json
{
struct Error : virtual Exception {} ;
typedef boost::error_info<struct ParseErr, std::string> ParseErr_ ;
typedef boost::error_info<struct JsonText, std::string> JsonText_ ;
Val Parse( const std::string& json ) ;
}
} // end of namespace
namespace gr { namespace http {
class ValResponse : public DataStream
{
public :
ValResponse() ;
std::size_t Write( const char *data, std::size_t count ) ;
std::size_t Read( char *data, std::size_t count ) ;
void Finish() ;
Val Response() const ;
private :
ValBuilder m_val ;
JsonParser m_parser ;
} ;
} } // end of namespace gr::http

View File

@ -0,0 +1,46 @@
/*
grive: an GPL program to sync a local directory with Google Drive
Copyright (C) 2013 Wan Wai Ho
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#pragma once
#include <string>
namespace gr {
class ValVisitor
{
public :
virtual ~ValVisitor() {}
virtual void Visit( long long t ) = 0 ;
virtual void Visit( double t ) = 0 ;
virtual void Visit( const std::string& t ) = 0 ;
virtual void Visit( bool t ) = 0 ;
virtual void VisitNull() = 0 ;
virtual void StartArray() = 0 ;
virtual void EndArray() = 0 ;
virtual void StartObject() = 0 ;
virtual void VisitKey( const std::string& t ) = 0 ;
virtual void EndObject() = 0 ;
} ;
} // end of namespace

View File

@ -17,8 +17,9 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "drive2/JsonVal.hh"
#include "drive2/Val.hh"
#include "json/JsonParser.hh"
#include "json/Val.hh"
#include "json/ValBuilder.hh"
#include <boost/test/unit_test.hpp>
@ -35,7 +36,10 @@ BOOST_FIXTURE_TEST_SUITE( JsonValTest, F )
BOOST_AUTO_TEST_CASE( Test )
{
Val json = json::Parse( "{\"key\": 100 }" ) ;
ValBuilder b ;
JsonParser::Parse( "{\"key\": 100 }", &b ) ;
Val json = b.Result() ;
BOOST_CHECK( json.Is<Val::Object>() ) ;
BOOST_CHECK_EQUAL( json["key"].As<long long>(), 100 ) ;
}

View File

@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "drive2/Val.hh"
#include "json/Val.hh"
#include <boost/test/unit_test.hpp>
using namespace gr ;