diff --git a/libgrive/src/drive2/Drive.cc b/libgrive/src/drive2/Drive.cc index cb3fad6..feaa84b 100644 --- a/libgrive/src/drive2/Drive.cc +++ b/libgrive/src/drive2/Drive.cc @@ -22,9 +22,12 @@ #include "CommonUri.hh" #include "Feed.hh" -#include "protocol/Json.hh" +#include "json/Val.hh" #include "util/Exception.hh" +#include + +#include #include #include @@ -74,8 +77,8 @@ void Drive::NewResource( http::Agent *agent, Feed& items ) while ( items.Next( agent ) ) { - std::vector item_json = items.Content()["items"].AsArray() ; - for ( std::vector::iterator i = item_json.begin() ; i != item_json.end() ; ++i ) + std::vector item_json = items.Content()["items"].AsArray() ; + for ( std::vector::iterator i = item_json.begin() ; i != item_json.end() ; ++i ) NewResource( *i ) ; } } @@ -89,16 +92,19 @@ Resource* Drive::NewResource( http::Agent *agent, const std::string& id ) return NewResource( feed.Content() ) ; } -Resource* Drive::NewResource( const Json& item ) +Resource* Drive::NewResource( const Val& item ) { // assume resource is directly under root std::string parent_id = m_root != 0 ? m_root->ID() : "" ; - Json parents ; + Val parents ; if ( item.Get( "parents", parents ) ) { + std::vector pids_val = parents.Select( "id" ) ; std::vector pids ; - parents.Select( "id", std::back_inserter(pids) ) ; + std::transform( pids_val.begin(), pids_val.end(), + std::back_inserter( pids ), + boost::bind( &Val::Str, _1 ) ) ; // only the first parent counts if ( !pids.empty() ) diff --git a/libgrive/src/drive2/Drive.hh b/libgrive/src/drive2/Drive.hh index 392fb62..33014b0 100644 --- a/libgrive/src/drive2/Drive.hh +++ b/libgrive/src/drive2/Drive.hh @@ -34,7 +34,7 @@ namespace http class Agent ; } -class Json ; +class Val ; namespace v2 { @@ -76,7 +76,7 @@ public : const Resource* Parent( const Resource *child ) const ; private : - Resource* NewResource( const Json& item ) ; + Resource* NewResource( const Val& item ) ; Resource* NewResource( http::Agent *agent, const std::string& id ) ; void NewResource( http::Agent *agent, Feed& items ) ; diff --git a/libgrive/src/drive2/Feed.cc b/libgrive/src/drive2/Feed.cc index 952d3a7..78f67f0 100644 --- a/libgrive/src/drive2/Feed.cc +++ b/libgrive/src/drive2/Feed.cc @@ -21,7 +21,7 @@ #include "http/Agent.hh" #include "http/Header.hh" -#include "protocol/JsonResponse.hh" +#include "json/ValResponse.hh" #include @@ -31,22 +31,22 @@ Feed::Feed( const std::string& base ) : m_base( base ) { // Next() will grab this link - m_content.Add( "nextLink", Json(base) ) ; + m_content.Add( "nextLink", Val(base) ) ; } void Feed::Query( const std::string& field, const std::string& value ) { std::string url = m_content["nextLink"].Str() ; - m_content.Add( "nextLink", Json( url + "?q=" + field + "+%3d+%27" + value + "%27" ) ) ; + m_content.Add( "nextLink", Val( url + "?q=" + field + "+%3d+%27" + value + "%27" ) ) ; } bool Feed::Next( http::Agent *agent ) { - Json url ; + Val url ; if ( !m_content.Get("nextLink", url) ) return false ; - http::JsonResponse out ; + http::ValResponse out ; try { agent->Get( url.Str(), &out, http::Header() ) ; @@ -61,7 +61,7 @@ bool Feed::Next( http::Agent *agent ) return true ; } -Json Feed::Content() const +Val Feed::Content() const { return m_content ; } diff --git a/libgrive/src/drive2/Feed.hh b/libgrive/src/drive2/Feed.hh index bbdd92b..ad1f294 100644 --- a/libgrive/src/drive2/Feed.hh +++ b/libgrive/src/drive2/Feed.hh @@ -19,7 +19,7 @@ #pragma once -#include "protocol/Json.hh" +#include "json/Val.hh" #include "util/Exception.hh" #include @@ -32,7 +32,7 @@ namespace http class Header ; } -class Json ; +class Val ; namespace v2 { @@ -40,7 +40,7 @@ class Feed { public : // exception info - typedef boost::error_info DriveFeed_ ; + typedef boost::error_info DriveFeed_ ; public : Feed( const std::string& base ) ; @@ -49,11 +49,11 @@ public : bool Next( http::Agent *agent ) ; - Json Content() const ; + Val Content() const ; private : std::string m_base ; - Json m_content ; + Val m_content ; } ; } } // end of namespace gr::v2 diff --git a/libgrive/src/json/Val.cc b/libgrive/src/json/Val.cc index 02f7dff..79c0b5e 100644 --- a/libgrive/src/json/Val.cc +++ b/libgrive/src/json/Val.cc @@ -27,9 +27,30 @@ namespace gr { -Val::Val( ) : - m_base( new Impl ) +const Val& Val::Null() { + static const Val null( null_type ) ; + return null ; +} + +Val::Val( ) : + m_base( new Impl ) +{ +} + +Val::Val( TypeEnum type ) +{ + switch ( type ) + { + case int_type: m_base.reset( new Impl ) ; break ; + case bool_type: m_base.reset( new Impl ) ; break ; + case double_type: m_base.reset( new Impl ) ; break ; + case string_type: m_base.reset( new Impl ) ; break ; + case array_type: m_base.reset( new Impl ) ; break ; + case object_type: m_base.reset( new Impl ) ; break ; + case null_type: + default: m_base.reset( new Impl ) ; break ; + } } Val::Val( const Val& v ) : @@ -174,6 +195,35 @@ void Val::Visit( ValVisitor *visitor ) const } } +void Val::Select( const Object& obj, const std::string& key, std::vector& result ) const +{ + Object::const_iterator i = obj.find(key) ; + if ( i != obj.end() ) + result.push_back(i->second) ; +} + +/** If \a this is an array of objects, this function returns all values of + the objects in the array with the key \a key. If \a this is an object, + just return the value with the key \a key. +*/ +std::vector Val::Select( const std::string& key ) const +{ + std::vector result ; + if ( Is() ) + Select( As(), key, result ) ; + + else if ( Is() ) + { + const Array& array = As() ; + for ( Array::const_iterator i = array.begin() ; i != array.end() ; ++i ) + { + if ( i->Is() ) + Select( i->As(), key, result ) ; + } + } + return result ; +} + std::ostream& operator<<( std::ostream& os, const Val& val ) { StdStream ss( os.rdbuf() ) ; diff --git a/libgrive/src/json/Val.hh b/libgrive/src/json/Val.hh index 56e43bc..2547886 100644 --- a/libgrive/src/json/Val.hh +++ b/libgrive/src/json/Val.hh @@ -58,8 +58,11 @@ public : public : Val() ; Val( const Val& v ) ; + explicit Val( TypeEnum type ) ; ~Val() ; + static const Val& Null() ; + template explicit Val( const T& t ) { @@ -110,19 +113,22 @@ public : 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 ; - + + std::vector Select( const std::string& key ) const ; + friend std::ostream& operator<<( std::ostream& os, const Val& val ) ; void Visit( ValVisitor *visitor ) const ; private : struct Base ; - + template struct Impl ; std::auto_ptr m_base ; private : + void Select( const Object& obj, const std::string& key, std::vector& result ) const ; } ; template <> struct Val::Type2Enum { static const TypeEnum type = null_type ; } ; @@ -160,6 +166,7 @@ template struct Val::Impl : public Base { T val ; + Impl( ) : val() {} Impl( const T& t ) : val(t) {} Impl* Clone() const { return new Impl(val); } TypeEnum Type() const { return Type2Enum::type ; } diff --git a/libgrive/src/json/ValBuilder.cc b/libgrive/src/json/ValBuilder.cc index a80be2d..c5658ff 100644 --- a/libgrive/src/json/ValBuilder.cc +++ b/libgrive/src/json/ValBuilder.cc @@ -60,37 +60,41 @@ void ValBuilder::VisitNull() void ValBuilder::Build( const Val& t ) { if ( m_ctx.empty() ) - m_ctx.push( t ) ; - - else if ( m_ctx.top().Is() ) { - Val::Array& ar = m_ctx.top().As() ; + Level l = { Val::Null(), t } ; + m_ctx.push( l ) ; + } + + else if ( m_ctx.top().val.Is() ) + { + Val::Array& ar = m_ctx.top().val.As() ; ar.push_back( t ) ; } - else if ( m_ctx.top().Is() ) + else if ( m_ctx.top().val.Is() ) { - if ( m_key.get() == 0 ) + if ( !m_ctx.top().key.Is() ) BOOST_THROW_EXCEPTION( Error() << NoKey_(t) ) ; else { - Val::Object& obj = m_ctx.top().As() ; - obj.insert( std::make_pair( m_key->As(), t ) ) ; - m_key.reset() ; + Val::Object& obj = m_ctx.top().val.As() ; + obj.insert( std::make_pair( m_ctx.top().key.Str(), t ) ) ; + m_ctx.top().key = Val::Null() ; } } else - BOOST_THROW_EXCEPTION( Error() << Unexpected_(m_ctx.top()) ) ; + BOOST_THROW_EXCEPTION( Error() << Unexpected_(m_ctx.top().val) ) ; } void ValBuilder::VisitKey( const std::string& t ) { - m_key.reset( new Val(t) ) ; + m_ctx.top().key = t ; } void ValBuilder::StartArray() { - m_ctx.push( Val( Val::Array() ) ) ; + Level l = { Val::Null(), Val(Val::Array()) } ; + m_ctx.push(l) ; } void ValBuilder::EndArray() @@ -100,11 +104,13 @@ void ValBuilder::EndArray() void ValBuilder::End( Val::TypeEnum type ) { - if ( m_ctx.top().Type() == type ) + if ( m_ctx.top().val.Type() == type ) { + assert( m_ctx.top().key.Is() ) ; + // get top Val from stack Val current ; - current.Swap( m_ctx.top() ) ; + current.Swap( m_ctx.top().val ) ; m_ctx.pop() ; Build(current) ; @@ -113,7 +119,8 @@ void ValBuilder::End( Val::TypeEnum type ) void ValBuilder::StartObject() { - m_ctx.push( Val( Val::Object() ) ) ; + Level l = { Val::Null(), Val( Val::Object() ) } ; + m_ctx.push(l) ; } void ValBuilder::EndObject() @@ -124,7 +131,7 @@ void ValBuilder::EndObject() Val ValBuilder::Result() const { assert( m_ctx.size() == 1U ) ; - return m_ctx.top() ; + return m_ctx.top().val ; } } // end of namespace diff --git a/libgrive/src/json/ValBuilder.hh b/libgrive/src/json/ValBuilder.hh index f5c2ab3..efbe5b2 100644 --- a/libgrive/src/json/ValBuilder.hh +++ b/libgrive/src/json/ValBuilder.hh @@ -61,8 +61,13 @@ private : void End( Val::TypeEnum type ) ; private : - std::stack m_ctx ; - std::auto_ptr m_key ; + struct Level + { + Val key ; + Val val ; + } ; + + std::stack m_ctx ; } ; } // end of namespace