new qt gui

pull/40/head
Nestal Wan 2013-04-28 18:40:21 +08:00
parent 113b1107d8
commit 755ee1c9ad
32 changed files with 778 additions and 177 deletions

View File

@ -6,6 +6,8 @@ set( GRIVE_VERSION "0.3.0-pre" )
# common compile options
add_definitions( -DVERSION="${GRIVE_VERSION}" )
add_definitions( -D_FILE_OFFSET_BITS=64 )
add_definitions( -DPROJ_NS=gr )
add_subdirectory( libgrive )
add_subdirectory( grive )
add_subdirectory( bgrive )

43
bgrive/CMakeLists.txt Normal file
View File

@ -0,0 +1,43 @@
project( bgrive )
find_package(Qt4 REQUIRED)
find_package(Boost REQUIRED)
INCLUDE(${QT_USE_FILE})
include_directories(
${bgrive_SOURCE_DIR}/../libgrive/src
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
file (GLOB BGRIVE_EXE_SRC
${bgrive_SOURCE_DIR}/src/*.cc
)
file (GLOB BGRIVE_UI
${bgrive_SOURCE_DIR}/ui/*.ui
)
QT4_WRAP_UI(BGRIVE_UI_SRCS ${BGRIVE_UI})
QT4_WRAP_CPP(BGRIVE_MOC_SRCS
src/MainWnd.hh )
add_executable( bgrive_executable
${BGRIVE_EXE_SRC}
${BGRIVE_UI_SRCS}
${BGRIVE_MOC_SRCS}
)
target_link_libraries( bgrive_executable
${Boost_LIBRARIES}
${QT_QTMAIN_LIBRARY}
${QT_LIBRARIES}
grive
)
set_target_properties( bgrive_executable
PROPERTIES OUTPUT_NAME bgrive
)
install(TARGETS bgrive_executable RUNTIME DESTINATION bin)
install(FILES doc/grive.1 DESTINATION share/man/man1 )

30
bgrive/src/MainWnd.cc Normal file
View File

@ -0,0 +1,30 @@
/*
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 "MainWnd.hh"
namespace gr {
MainWnd::MainWnd( )
{
m_ui.setupUi(this) ;
}
} // end of namespace

40
bgrive/src/MainWnd.hh Normal file
View File

@ -0,0 +1,40 @@
/*
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 <QtGui/QMainWindow>
#include "ui_MainWindow.h"
namespace gr {
class MainWnd : public QMainWindow
{
Q_OBJECT
public :
MainWnd( ) ;
private :
Ui::MainWindow m_ui ;
} ;
} // end of namespace

78
bgrive/src/main.cc Normal file
View File

@ -0,0 +1,78 @@
/*
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 "MainWnd.hh"
#include <QtGui/QApplication>
#include <QtCore/QDebug>
#include "drive/CommonUri.hh"
#include "drive/Entry.hh"
#include "drive/Feed.hh"
#include "http/CurlAgent.hh"
#include "http/Header.hh"
#include "http/XmlResponse.hh"
#include "protocol/Json.hh"
#include "protocol/OAuth2.hh"
#include "protocol/AuthAgent.hh"
#include "util/File.hh"
#include <string>
const std::string client_id = "22314510474.apps.googleusercontent.com" ;
const std::string client_secret = "bl4ufi89h-9MkFlypcI7R785" ;
using namespace gr ;
int main( int argc, char **argv )
{
File file( ".grive" ) ;
Json cfg = Json::Parse( &file ) ;
std::string refresh_token = cfg["refresh_token"].Str() ;
qDebug() << refresh_token.c_str() ;
OAuth2 token( refresh_token, client_id, client_secret ) ;
AuthAgent agent( token, std::auto_ptr<http::Agent>( new http::CurlAgent ) ) ;
http::XmlResponse xml ;
agent.Get( feed_base + "/-/folder?max-results=50&showroot=true", &xml, http::Header() ) ;
Feed feed( xml.Response() ) ;
do
{
// first, get all collections from the query result
for ( Feed::iterator i = feed.begin() ; i != feed.end() ; ++i )
{
Entry e( *i ) ;
qDebug() << e.Name().c_str() ;
}
} while ( feed.GetNext( &agent, http::Header() ) ) ;
QApplication app( argc, argv ) ;
MainWnd wnd ;
wnd.show();
return app.exec() ;
}

86
bgrive/ui/MainWindow.ui Normal file
View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Grive</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="m_dir">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="QListView" name="m_files">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="m_menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="m_menu_file">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="m_action_exit"/>
</widget>
<addaction name="m_menu_file"/>
</widget>
<widget class="QStatusBar" name="m_statusbar"/>
<action name="m_action_exit">
<property name="text">
<string>E&amp;xit</string>
</property>
</action>
</widget>
<resources/>
<connections>
<connection>
<sender>m_action_exit</sender>
<signal>activated()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -67,7 +67,7 @@ private :
std::auto_ptr<LogInfo> m_log ;
xml::Node m_root ;
xml::NodeSet m_entries ;
xml::NodeSet m_entries ;
} ;
class Feed::iterator : public boost::iterator_adaptor<

View File

@ -32,7 +32,7 @@
#include "util/Crypt.hh"
#include "util/log/Log.hh"
#include "util/OS.hh"
#include "util/StdioFile.hh"
#include "util/File.hh"
#include "xml/Node.hh"
#include "xml/NodeSet.hh"
#include "xml/String.hh"
@ -269,7 +269,7 @@ void Resource::FromLocal( const DateTime& last_sync )
else
m_state = ( m_mtime > last_sync ? local_new : remote_deleted ) ;
m_name = Path2Str( path.filename() ) ;
m_name = path.filename().string() ;
m_kind = fs::is_directory(path) ? "folder" : "file" ;
m_md5 = fs::is_directory(path) ? "" : crypt::MD5::Get( path ) ;
}
@ -583,7 +583,7 @@ bool Resource::Upload(
{
assert( http != 0 ) ;
StdioFile file( Path() ) ;
File file( Path() ) ;
std::ostringstream xcontent_len ;
xcontent_len << "X-Upload-Content-Length: " << file.Size() ;

View File

@ -25,6 +25,7 @@
#include "http/Agent.hh"
#include "util/Crypt.hh"
#include "util/File.hh"
#include "util/log/Log.hh"
#include "protocol/Json.hh"
@ -72,7 +73,7 @@ void State::FromLocal( const fs::path& p, gr::Resource* folder )
for ( fs::directory_iterator i( p ) ; i != fs::directory_iterator() ; ++i )
{
std::string fname = Path2Str(i->path().filename()) ;
std::string fname = i->path().filename().string() ;
if ( IsIgnore(fname) )
Log( "file %1% is ignored by grive", fname, log::verbose ) ;
@ -228,7 +229,8 @@ void State::Read( const fs::path& filename )
{
try
{
Json json = Json::ParseFile( filename.string() ) ;
File file( filename ) ;
Json json = Json::Parse( &file ) ;
Json last_sync = json["last_sync"] ;
m_last_sync.Assign(

View File

@ -23,7 +23,7 @@
namespace gr {
class StdioFile ;
class File ;
namespace http {
@ -33,6 +33,8 @@ class Receivable ;
class Agent
{
public :
virtual ~Agent() {}
virtual long Put(
const std::string& url,
const std::string& data,
@ -41,7 +43,7 @@ public :
virtual long Put(
const std::string& url,
StdioFile& file,
File& file,
Receivable *dest,
const Header& hdr ) = 0 ;

View File

@ -25,7 +25,7 @@
#include "Receivable.hh"
#include "util/log/Log.hh"
#include "util/StdioFile.hh"
#include "util/File.hh"
#include <boost/throw_exception.hpp>
@ -62,7 +62,7 @@ size_t ReadStringCallback( void *ptr, std::size_t size, std::size_t nmemb, std::
return count ;
}
size_t ReadFileCallback( void *ptr, std::size_t size, std::size_t nmemb, StdioFile *file )
size_t ReadFileCallback( void *ptr, std::size_t size, std::size_t nmemb, File *file )
{
assert( ptr != 0 ) ;
assert( file != 0 ) ;
@ -73,7 +73,7 @@ size_t ReadFileCallback( void *ptr, std::size_t size, std::size_t nmemb, StdioFi
assert( count <= std::numeric_limits<std::size_t>::max() ) ;
if ( count > 0 )
file->Read( ptr, static_cast<std::size_t>(count) ) ;
file->Read( static_cast<char*>(ptr), static_cast<std::size_t>(count) ) ;
return count ;
}
@ -197,7 +197,7 @@ long CurlAgent::Put(
long CurlAgent::Put(
const std::string& url,
StdioFile& file,
File& file,
Receivable *dest,
const Header& hdr )
{

View File

@ -47,7 +47,7 @@ public :
long Put(
const std::string& url,
StdioFile& file,
File& file,
Receivable *dest,
const Header& hdr ) ;

View File

@ -72,7 +72,7 @@ std::size_t Download::OnData( void *data, std::size_t count )
if ( m_crypt.get() != 0 )
m_crypt->Write( data, count ) ;
return m_file.Write( data, count ) ;
return m_file.Write( static_cast<char*>(data), count ) ;
}
} } // end of namespace

View File

@ -20,7 +20,7 @@
#pragma once
#include "Receivable.hh"
#include "util/StdioFile.hh"
#include "util/File.hh"
#include <string>
@ -47,7 +47,7 @@ public :
std::size_t OnData( void *data, std::size_t count ) ;
private :
StdioFile m_file ;
File m_file ;
std::auto_ptr<crypt::MD5> m_crypt ;
} ;

View File

@ -0,0 +1,39 @@
/*
grive: an GPL program to sync a local directory with Google Drive
Copyright (C) 2012 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 "http/Agent.hh"
namespace gr { namespace http {
class HttpRequest ;
/*! \brief An marshaller for HTTP agent
This agent will marshal the HTTP requests to a request objects containing the arguments
of the request and the response.
*/
class MarshalAgent : public Agent
{
public :
MarshalAgent( std::auto_ptr<Agent> real_agent ) ;
} ;
}} // end of namespace

View File

@ -26,6 +26,7 @@ namespace gr { namespace http {
class Receivable
{
public :
virtual ~Receivable() {}
virtual std::size_t OnData( void *data, std::size_t count ) = 0 ;
virtual void Clear() = 0 ;
} ;

View File

@ -62,7 +62,7 @@ long AuthAgent::Put(
long AuthAgent::Put(
const std::string& url,
StdioFile& file,
File& file,
Receivable *dest,
const Header& hdr )
{

View File

@ -44,7 +44,7 @@ public :
long Put(
const std::string& url,
StdioFile& file,
File& file,
http::Receivable *dest,
const http::Header& hdr ) ;

View File

@ -19,10 +19,21 @@
#include "Json.hh"
#include "util/StdioFile.hh"
#include "util/DataStream.hh"
// needs to include stdint.h before json-c to avoid macro re-def warning
#include <boost/cstdint.hpp>
// disable macro re-def warning for json-c headers
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4005)
#endif
#include <json/json_tokener.h>
#include <json/linkhash.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include <cassert>
#include <cstring>
@ -35,51 +46,99 @@ Json::Json( ) :
m_json( ::json_object_new_object() )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json object" ) ) ;
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_object_new_object" )
) ;
}
Json::Json( const char *str ) :
m_json( ::json_object_new_string( str ) )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION(
Error() << expt::ErrMsg( "cannot create json string \"" + std::string(str) + "\"" ) ) ;
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_object_new_string" )
<< ValueErr( str )
) ;
}
struct json_object* Json::InitStr( const char *str, std::size_t n )
{
struct json_object *j = ::json_object_new_string_len( str, n ) ;
if ( j == 0 )
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_object_new_string_len" )
<< ValueErr( std::string(str, n) )
) ;
return j ;
}
template <>
Json::Json( const std::string& str ) :
m_json( ::json_object_new_string( str.c_str() ) )
m_json( InitStr( str.c_str(), str.size() ) )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION(
Error() << expt::ErrMsg( "cannot create json string \"" + str + "\"" ) ) ;
// paranoid check
assert( ::json_object_get_string( m_json ) == str ) ;
}
template <>
Json::Json( const int& l ) :
Json::Json( const double& val ) :
m_json( ::json_object_new_double( val ) )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_object_new_double" )
<< ValueErr( val )
) ;
}
template <>
Json::Json( const boost::int32_t& l ) :
m_json( ::json_object_new_int( l ) )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json int" ) ) ;
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_object_new_int" )
<< ValueErr( l )
) ;
}
template <>
Json::Json( const long& l ) :
m_json( ::json_object_new_int( static_cast<int>(l) ) )
Json::Json( const boost::int64_t& l ) :
m_json( ::json_object_new_int64( l ) )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json int" ) ) ;
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_object_new_int64" )
<< ValueErr( l )
) ;
}
template <>
Json::Json( const unsigned long& l ) :
Json::Json( const boost::uint32_t& l ) :
m_json( ::json_object_new_int( static_cast<int>(l) ) )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json int" ) ) ;
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_object_new_int" )
<< ValueErr( l )
) ;
}
template <>
Json::Json( const boost::uint64_t& l ) :
m_json( ::json_object_new_int64( l ) )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_object_new_int64" )
<< ValueErr( l )
) ;
}
template <>
@ -87,7 +146,7 @@ Json::Json( const std::vector<Json>& arr ) :
m_json( ::json_object_new_array( ) )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json int" ) ) ;
BOOST_THROW_EXCEPTION( Error() << JsonCApi_( "json_object_new_array" ) ) ;
for ( std::vector<Json>::const_iterator i = arr.begin() ; i != arr.end() ; ++i )
Add( *i ) ;
@ -98,7 +157,11 @@ Json::Json( const bool& b ) :
m_json( ::json_object_new_boolean( b ) )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json bool" ) ) ;
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_object_new_boolean" )
<< ValueErr( b )
) ;
}
template <>
@ -106,7 +169,7 @@ Json::Json( const Object& obj ) :
m_json( ::json_object_new_object() )
{
if ( m_json == 0 )
BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "cannot create json object" ) ) ;
BOOST_THROW_EXCEPTION( Error() << JsonCApi_( "json_object_new_object" ) ) ;
for ( Object::const_iterator i = obj.begin() ; i != obj.end() ; ++i )
Add( i->first, i->second ) ;
@ -157,13 +220,15 @@ Json Json::operator[]( const std::string& key ) const
{
assert( m_json != 0 ) ;
struct json_object *j = ::json_object_object_get( m_json, key.c_str() ) ;
if ( j == 0 )
struct json_object *j = 0 ;
if ( !::json_object_object_get_ex( m_json, key.c_str(), &j ) )
BOOST_THROW_EXCEPTION(
Error()
<< expt::ErrMsg( "key: " + key + " is not found in object" )
<< JsonInfo( *this ) ) ;
<< JsonCApi_( "json_object_object_get" )
<< KeyNotFound_( key )
<< Json_( ::json_object_to_json_string(m_json) ) ) ;
assert( j != 0 ) ;
return Json( j ) ;
}
@ -174,12 +239,11 @@ Json Json::operator[]( const std::size_t& idx ) const
struct json_object *j = ::json_object_array_get_idx( m_json, idx ) ;
if ( j == 0 )
{
std::ostringstream ss ;
ss << "index " << idx << " is not found in array" ;
BOOST_THROW_EXCEPTION(
Error()
<< expt::ErrMsg( ss.str() )
<< JsonInfo( *this ) ) ;
<< JsonCApi_( "json_object_array_get_idx" )
<< OutOfRange_( idx )
<< Json_( ::json_object_to_json_string(m_json) ) ) ;
}
return Json( j ) ;
@ -188,15 +252,17 @@ Json Json::operator[]( const std::size_t& idx ) const
bool Json::Has( const std::string& key ) const
{
assert( m_json != 0 ) ;
return ::json_object_object_get( m_json, key.c_str() ) != 0 ;
return ::json_object_object_get_ex( m_json, key.c_str(), 0 ) == TRUE ;
}
bool Json::Get( const std::string& key, Json& json ) const
{
assert( m_json != 0 ) ;
struct json_object *j = ::json_object_object_get( m_json, key.c_str() ) ;
if ( j != 0 )
struct json_object *j = 0 ;
if ( ::json_object_object_get_ex( m_json, key.c_str(), &j ) )
{
assert( j != 0 ) ;
Json tmp( j ) ;
json.Swap( tmp ) ;
return true ;
@ -226,14 +292,20 @@ void Json::Add( const Json& json )
bool Json::Bool() const
{
assert( m_json != 0 ) ;
return ::json_object_get_boolean( m_json ) ;
return ::json_object_get_boolean( m_json ) == TRUE ;
}
template <>
bool Json::Is<bool>() const
{
assert( m_json != 0 ) ;
return ::json_object_is_type( m_json, json_type_boolean ) ;
return ::json_object_is_type( m_json, json_type_boolean ) == TRUE ;
}
template <>
bool Json::As<bool>() const
{
return Bool() ;
}
std::string Json::Str() const
@ -246,7 +318,13 @@ template <>
bool Json::Is<std::string>() const
{
assert( m_json != 0 ) ;
return ::json_object_is_type( m_json, json_type_string ) ;
return ::json_object_is_type( m_json, json_type_string ) == TRUE ;
}
template <>
std::string Json::As<std::string>() const
{
return Str() ;
}
int Json::Int() const
@ -259,7 +337,31 @@ template <>
bool Json::Is<int>() const
{
assert( m_json != 0 ) ;
return ::json_object_is_type( m_json, json_type_int ) ;
return ::json_object_is_type( m_json, json_type_int ) == TRUE ;
}
template <>
boost::int32_t Json::As<boost::int32_t>() const
{
return Int() ;
}
template <>
boost::uint32_t Json::As<boost::uint32_t>() const
{
return static_cast<boost::uint32_t>(Int()) ;
}
template <>
boost::int64_t Json::As<boost::int64_t>() const
{
return ::json_object_get_int64( m_json ) ;
}
template <>
boost::uint64_t Json::As<boost::uint64_t>() const
{
return ::json_object_get_int64( m_json ) ;
}
std::ostream& operator<<( std::ostream& os, const Json& json )
@ -268,10 +370,12 @@ std::ostream& operator<<( std::ostream& os, const Json& json )
return os << ::json_object_to_json_string( json.m_json ) ;
}
void Json::Write( StdioFile& file ) const
void Json::Write( DataStream *out ) const
{
assert( out != 0 ) ;
const char *str = ::json_object_to_json_string( m_json ) ;
file.Write( str, std::strlen(str) ) ;
out->Write( str, std::strlen(str) ) ;
}
Json::Type Json::DataType() const
@ -296,7 +400,13 @@ template <>
bool Json::Is<Json::Object>() const
{
assert( m_json != 0 ) ;
return ::json_object_is_type( m_json, json_type_object ) ;
return ::json_object_is_type( m_json, json_type_object ) == TRUE ;
}
template <>
Json::Object Json::As<Json::Object>() const
{
return AsObject() ;
}
Json::Array Json::AsArray() const
@ -314,9 +424,18 @@ template <>
bool Json::Is<Json::Array>() const
{
assert( m_json != 0 ) ;
return ::json_object_is_type( m_json, json_type_array ) ;
return ::json_object_is_type( m_json, json_type_array ) == TRUE ;
}
template <>
Json::Array Json::As<Json::Array>() const
{
return AsArray() ;
}
/// Finds an element in the array.
/// \pre "this" is an array
/// \return *this[i] if *this[i][key] == value
Json Json::FindInArray( const std::string& key, const std::string& value ) const
{
std::size_t count = ::json_object_array_length( m_json ) ;
@ -327,8 +446,16 @@ Json Json::FindInArray( const std::string& key, const std::string& value ) const
if ( item.Has(key) && item[key].Str() == value )
return item ;
}
BOOST_THROW_EXCEPTION(
Error() << expt::ErrMsg( "cannot find " + key + " = " + value + " in array" ) ) ;
Error()
<< JsonCApi_( "Json::FindInArray" )
<< KeyNotFound_( key )
<< Value_(value)
) ;
// shut off compiler warnings
return Json() ;
}
bool Json::FindInArray( const std::string& key, const std::string& value, Json& result ) const
@ -340,37 +467,58 @@ bool Json::FindInArray( const std::string& key, const std::string& value, Json&
}
catch ( Error& )
{
return false ;
}
return false ;
}
Json Json::Parse( const std::string& str )
{
struct json_object *json = ::json_tokener_parse( str.c_str() ) ;
if ( json == 0 )
BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( "json parse error" ) ) ;
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_tokener_parse" )
<< ValueErr( str )
) ;
return Json( json, NotOwned() ) ;
}
Json Json::ParseFile( const std::string& filename )
/// Parse a file. The file is loaded from file system.
/// \throw Error expt::ErrMsg contains a human-readable message describing the
/// error.
Json Json::Parse( DataStream *in )
{
StdioFile file( filename ) ;
assert( in != 0 ) ;
struct json_tokener *tok = ::json_tokener_new() ;
struct json_object *json = 0 ;
char buf[1024] ;
std::size_t count = 0 ;
while ( (count = file.Read( buf, sizeof(buf) ) ) > 0 )
while ( (count = in->Read( buf, sizeof(buf) ) ) > 0 )
{
json = ::json_tokener_parse_ex( tok, buf, count ) ;
// check for parse error
if ( ::json_tokener_get_error(tok) == ::json_tokener_continue )
break ;
}
if ( json == 0 )
BOOST_THROW_EXCEPTION( Error() << expt::ErrMsg( ::json_tokener_errors[tok->err] ) ) ;
::json_tokener_free( tok ) ;
// save the error code and free the tokener before throwing exceptions
::json_tokener_error err = ::json_tokener_get_error(tok) ;
::json_tokener_free( tok ) ; tok = 0 ;
if ( err != json_tokener_success || json == 0 )
{
BOOST_THROW_EXCEPTION(
Error()
<< JsonCApi_( "json_tokener_parse" )
<< expt::ErrMsg( ::json_tokener_error_desc(err) )
) ;
}
return Json( json, NotOwned() ) ;
}

View File

@ -29,8 +29,13 @@ struct json_object ;
namespace gr {
class StdioFile ;
class DataStream ;
/*! \brief Simple wrapper around JSON-C objects.
This class represents JSON-C objects, which can be integers, booleans, strings
double, arrays and object.
*/
class Json
{
public :
@ -38,19 +43,35 @@ public :
typedef std::vector<Json> Array ;
struct Error : virtual Exception {} ;
typedef boost::error_info<struct JsonTag, Json> JsonInfo ;
typedef boost::error_info<struct JsonTag, std::string> Json_ ;
typedef boost::error_info<struct OutOfRange, std::size_t> OutOfRange_ ;
typedef boost::error_info<struct KeyNotFound, std::string> KeyNotFound_ ;
typedef boost::error_info<struct JsonCApi, std::string> JsonCApi_ ;
typedef boost::error_info<struct Value, std::string> Value_ ;
template <typename T>
struct Val_
{
typedef boost::error_info<struct Value, T> Err ;
} ;
public :
template <typename T>
explicit Json( const T& val ) ;
template <std::size_t n>
explicit Json( const char (&str)[n] ) :
m_json( InitStr( str, n ) )
{
}
Json() ;
Json( const Json& rhs ) ;
Json( const char *str ) ;
~Json( ) ;
~Json() ;
static Json Parse( const std::string& str ) ;
static Json ParseFile( const std::string& filename ) ;
static Json Parse( DataStream *in ) ;
Json operator[]( const std::string& key ) const ;
Json operator[]( const std::size_t& idx ) const ;
@ -68,6 +89,9 @@ public :
template <typename T>
bool Is() const ;
template <typename T>
T As() const ;
bool Has( const std::string& key ) const ;
bool Get( const std::string& key, Json& json ) const ;
void Add( const std::string& key, const Json& json ) ;
@ -76,7 +100,7 @@ public :
bool FindInArray( const std::string& key, const std::string& value, Json& result ) const ;
friend std::ostream& operator<<( std::ostream& os, const Json& json ) ;
void Write( StdioFile& file ) const ;
void Write( DataStream *out ) const ;
enum Type { null_type, bool_type, double_type, int_type, object_type, array_type, string_type } ;
@ -87,10 +111,17 @@ private :
struct NotOwned {} ;
Json( struct json_object *json, NotOwned ) ;
static struct json_object* InitStr( const char *str, std::size_t n ) ;
// helper for throwing exception
template <typename T> static typename Val_<T>::Err ValueErr( const T& t )
{
return typename Val_<T>::Err(t);
}
private :
public :
struct json_object *m_json ;
} ;
}
}

View File

@ -19,7 +19,7 @@
#include "Config.hh"
#include "util/StdioFile.hh"
#include "util/File.hh"
#include <boost/program_options.hpp>
@ -28,7 +28,7 @@
namespace po = boost::program_options;
namespace gr {
namespace PROJ_NS {
const std::string default_filename = ".grive";
const char *env_name = "GR_CONFIG";
@ -64,8 +64,8 @@ const fs::path Config::Filename() const
void Config::Save( )
{
StdioFile file( m_path.string(), 0600 ) ;
m_file.Write( file ) ;
gr::File file( m_path.string(), 0600 ) ;
m_file.Write( &file ) ;
}
void Config::Set( const std::string& key, const Json& value )
@ -93,7 +93,8 @@ Json Config::Read()
{
try
{
return Json::ParseFile( m_path.string() ) ;
gr::File file(m_path) ;
return Json::Parse( &file ) ;
}
catch ( Exception& e )
{

View File

@ -31,7 +31,7 @@ namespace boost
}
}
namespace gr {
namespace PROJ_NS {
class Config
{

View File

@ -19,7 +19,7 @@
#include "Crypt.hh"
#include "StdioFile.hh"
#include "File.hh"
#include "Exception.hh"
#include "MemMap.hh"
@ -76,16 +76,16 @@ std::string MD5::Get( const fs::path& file )
{
try
{
StdioFile sfile( file ) ;
File sfile( file ) ;
return Get( sfile ) ;
}
catch ( StdioFile::Error& )
catch ( File::Error& )
{
return "" ;
}
}
std::string MD5::Get( StdioFile& file )
std::string MD5::Get( File& file )
{
MD5 crypt ;

View File

@ -26,7 +26,7 @@
namespace gr {
class StdioFile ;
class File ;
namespace crypt {
@ -36,7 +36,7 @@ public :
MD5() ;
~MD5() ;
static std::string Get( StdioFile& file ) ;
static std::string Get( File& file ) ;
static std::string Get( const boost::filesystem::path& file ) ;
void Write( const void *data, std::size_t size ) ;

View File

@ -0,0 +1,55 @@
/*
webwrite: an GPL program to sync a local directory with Google Drive
Copyright (C) 2012 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 <cstddef>
namespace gr {
/** \brief Encapsulation of data streams. Useful for unit tests.
This class provides two functions: Read() and Write().
*/
class DataStream
{
protected :
virtual ~DataStream() {}
public :
/** Reading from the stream. The caller indicates that it wants
to read `size` bytes and must provide enough space pointed
by `data`.
\param data Buffer to hold the data read from the stream
Must have at least `size` bytes.
\param size Number of bytes the caller wants to read.
\throw wb::Exception In case of any error.
\return The number of byte actually read from the stream.
0 indicates the end of stream, i.e. you will
still get 0 if you call again.
*/
virtual std::size_t Read( char *data, std::size_t size ) = 0 ;
virtual std::size_t Write( const char *data, std::size_t size ) = 0 ;
} ;
/// Stream for /dev/null, i.e. read and writing nothing
DataStream* DevNull() ;
} // end of namespace

View File

@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "util/Exception.hh"
#include "Exception.hh"
#include "bfd/Backtrace.hh"
#include "bfd/Debug.hh"
@ -28,15 +28,20 @@
#include <iterator>
#include <sstream>
namespace gr {
namespace PROJ_NS {
class Backtrace ;
Exception::Exception( )
{
#ifdef HAVE_BFD
*this << expt::BacktraceInfo( Backtrace() ) ;
*this << expt::Backtrace_( Backtrace() ) ;
#endif
}
const char* Exception::what() const throw()
{
return boost::diagnostic_information_what( *this ) ;
}
} // end of namespace

View File

@ -1,5 +1,5 @@
/*
grive: an GPL program to sync a local directory with Google Drive
webwrite: an GPL program to sync a local directory with Google Drive
Copyright (C) 2012 Wan Wai Ho
This program is free software; you can redistribute it and/or
@ -25,54 +25,35 @@
#include <exception>
#include <string>
namespace gr {
namespace PROJ_NS {
class Backtrace ;
/** \defgroup exception Exception Classes
*/
/// base class for exception in libpdfdoc
/** \ingroup exception
This class is the base class for all exception class in libpdfdoc.
/** \brief base class for exception in WebWrite
\ingroup exception
This class is the base class for all exception class in WebWrite.
It allows us to catch all WebWrite exception with one catch clause.
*/
struct Exception :
virtual public std::exception,
virtual public boost::exception
{
Exception( ) ;
virtual const char* what() const throw() ;
} ;
struct FileError : virtual Exception {} ;
/// Parse error exception.
/** \ingroup exception
This exception will be thrown when there is a parse error when reading
a PDF file.
*/
struct ParseError : virtual Exception {} ;
/// Invalid type exception.
/** \ingroup exception
This exception will be thrown when the Object cannot convert its
underlying data to a specific type. The what() member function will
describe the expected and actual type of the data.
*/
struct BadType : virtual Exception {} ;
struct Unsupported : virtual Exception {} ;
// Exception informations
/// Exception informations
namespace expt
{
// back-trace information. should be present for all exceptions
typedef boost::error_info<struct BacktraceTag, Backtrace> BacktraceInfo ;
typedef boost::error_info<struct BacktraceTag, Backtrace> Backtrace_ ;
// generic error message
typedef boost::error_info<struct MsgTag, std::string> ErrMsg ;
// nested exception
typedef boost::error_info<struct ExceptionTag, Exception> Nested ;
/// generic error message
typedef boost::error_info<struct MsgTag, std::string> ErrMsg ;
}
} // end of namespace

View File

@ -17,27 +17,34 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "StdioFile.hh"
#include "File.hh"
#include <cassert>
// boost headers
#include <boost/throw_exception.hpp>
#include <boost/exception/errinfo_api_function.hpp>
#include <boost/exception/errinfo_at_line.hpp>
#include <boost/exception/errinfo_errno.hpp>
#include <boost/exception/errinfo_file_name.hpp>
#include <boost/exception/errinfo_file_open_mode.hpp>
#include <boost/exception/info.hpp>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#ifdef WIN32
#include <io.h>
typedef int ssize_t ;
#else
#include <sys/mman.h>
#endif
// local functions
namespace {
using namespace gr ;
off_t LSeek( int fd, off_t offset, int whence )
{
assert( fd >= 0 ) ;
@ -46,7 +53,7 @@ off_t LSeek( int fd, off_t offset, int whence )
if ( r == static_cast<off_t>(-1) )
{
BOOST_THROW_EXCEPTION(
gr::StdioFile::Error()
File::Error()
<< boost::errinfo_api_function("lseek")
<< boost::errinfo_errno(errno)
) ;
@ -61,7 +68,7 @@ struct stat FStat( int fd )
if ( ::fstat( fd, &s ) != 0 )
{
BOOST_THROW_EXCEPTION(
gr::StdioFile::Error()
File::Error()
<< boost::errinfo_api_function("fstat")
<< boost::errinfo_errno(errno)
) ;
@ -71,28 +78,40 @@ struct stat FStat( int fd )
} // end of local functions
namespace gr {
namespace PROJ_NS {
StdioFile::StdioFile( ) : m_fd( -1 )
File::File( ) : m_fd( -1 )
{
}
StdioFile::StdioFile( const fs::path& path ) : m_fd( -1 )
/** Opens the file for reading.
\param path Path to the file to be opened.
\throw Error When the file cannot be openned.
*/
File::File( const fs::path& path ) : m_fd( -1 )
{
OpenForRead( path ) ;
}
StdioFile::StdioFile( const fs::path& path, int mode ) : m_fd( -1 )
/** Opens the file for writing.
\param path Path to the file to be opened.
\param mode Mode of the file to be created, e.g. 0600 for user
readable/writable.
\throw Error When the file cannot be opened.
*/
File::File( const fs::path& path, int mode ) : m_fd( -1 )
{
OpenForWrite( path, mode ) ;
}
StdioFile::~StdioFile( )
/** The destructor will close the file.
*/
File::~File( )
{
Close() ;
}
void StdioFile::Open( const fs::path& path, int flags, int mode )
void File::Open( const fs::path& path, int flags, int mode )
{
if ( IsOpened() )
Close() ;
@ -110,17 +129,25 @@ void StdioFile::Open( const fs::path& path, int flags, int mode )
}
}
void StdioFile::OpenForRead( const fs::path& path )
void File::OpenForRead( const fs::path& path )
{
Open( path, O_RDONLY, 0 ) ;
int flags = O_RDONLY ;
#ifdef WIN32
flags |= O_BINARY ;
#endif
Open( path, flags, 0 ) ;
}
void StdioFile::OpenForWrite( const fs::path& path, int mode )
void File::OpenForWrite( const fs::path& path, int mode )
{
Open( path, O_CREAT|O_RDWR|O_TRUNC, mode ) ;
int flags = O_CREAT|O_RDWR|O_TRUNC ;
#ifdef WIN32
flags |= O_BINARY ;
#endif
Open( path, flags, mode ) ;
}
void StdioFile::Close()
void File::Close()
{
if ( IsOpened() )
{
@ -129,12 +156,15 @@ void StdioFile::Close()
}
}
bool StdioFile::IsOpened() const
bool File::IsOpened() const
{
return m_fd != -1 ;
}
std::size_t StdioFile::Read( void *ptr, std::size_t size )
/** Read bytes from file. See DataStream::Read() for details.
\throw Error In case of any error.
*/
std::size_t File::Read( char *ptr, std::size_t size )
{
assert( IsOpened() ) ;
ssize_t count = ::read( m_fd, ptr, size ) ;
@ -149,7 +179,7 @@ std::size_t StdioFile::Read( void *ptr, std::size_t size )
return count ;
}
std::size_t StdioFile::Write( const void *ptr, std::size_t size )
std::size_t File::Write( const char *ptr, std::size_t size )
{
assert( IsOpened() ) ;
ssize_t count = ::write( m_fd, ptr, size ) ;
@ -157,26 +187,26 @@ std::size_t StdioFile::Write( const void *ptr, std::size_t size )
{
BOOST_THROW_EXCEPTION(
Error()
<< boost::errinfo_api_function("read")
<< boost::errinfo_api_function("write")
<< boost::errinfo_errno(errno)
) ;
}
return count ;
}
off_t StdioFile::Seek( off_t offset, int whence )
off_t File::Seek( off_t offset, int whence )
{
assert( IsOpened() ) ;
return LSeek( m_fd, offset, whence ) ;
}
off_t StdioFile::Tell() const
off_t File::Tell() const
{
assert( IsOpened() ) ;
return LSeek( m_fd, 0, SEEK_CUR ) ;
}
u64_t StdioFile::Size() const
u64_t File::Size() const
{
assert( IsOpened() ) ;
@ -186,10 +216,10 @@ u64_t StdioFile::Size() const
return static_cast<uint64_t>( s.st_size ) ;
}
void StdioFile::Chmod( int mode )
void File::Chmod( int mode )
{
assert( IsOpened() ) ;
#ifndef WIN32
if ( ::fchmod( m_fd, mode ) != 0 )
{
BOOST_THROW_EXCEPTION(
@ -198,12 +228,18 @@ void StdioFile::Chmod( int mode )
<< boost::errinfo_errno(errno)
) ;
}
#endif
}
void* StdioFile::Map( off_t offset, std::size_t length )
/// This function is not implemented in win32 yet.
void* File::Map( off_t offset, std::size_t length )
{
assert( IsOpened() ) ;
#ifdef WIN32
assert( false ) ;
return 0 ;
#else
void *addr = ::mmap( 0, length, PROT_READ, MAP_PRIVATE, m_fd, offset ) ;
if ( addr == reinterpret_cast<void*>( -1 ) )
{
@ -214,10 +250,12 @@ void* StdioFile::Map( off_t offset, std::size_t length )
) ;
}
return addr ;
#endif
}
void StdioFile::UnMap( void *addr, std::size_t length )
void File::UnMap( void *addr, std::size_t length )
{
#ifndef WIN32
if ( ::munmap( addr, length ) != 0 )
{
BOOST_THROW_EXCEPTION(
@ -226,6 +264,21 @@ void StdioFile::UnMap( void *addr, std::size_t length )
<< boost::errinfo_errno(errno)
) ;
}
#endif
}
struct stat File::Stat() const
{
struct stat result = {} ;
if ( ::fstat( m_fd, &result ) != 0 )
{
BOOST_THROW_EXCEPTION(
Error()
<< boost::errinfo_api_function("fstat")
<< boost::errinfo_errno(errno)
) ;
}
return result ;
}
} // end of namespace

View File

@ -19,32 +19,47 @@
#pragma once
#include "DataStream.hh"
#include "Exception.hh"
#include "FileSystem.hh"
#include "Types.hh"
#include <string>
struct stat ;
namespace gr {
class StdioFile
/** \brief A wrapper class for file read/write.
It is a simple wrapper around the UNIX file descriptor. It will
throw exceptions (i.e. Error) when it encounters errors.
*/
class File : public DataStream
{
public :
/// File specific errors. It often includes
/// boost::errinfo_api_function and boost::errinfo_errno for the
/// detail information.
struct Error : virtual Exception {} ;
public :
StdioFile() ;
StdioFile( const fs::path& path ) ;
StdioFile( const fs::path& path, int mode ) ;
~StdioFile( ) ;
File() ;
File( const fs::path& path ) ;
File( const fs::path& path, int mode ) ;
~File( ) ;
File( const File& rhs ) ;
File& operator=( const File& rhs ) ;
void Swap( File& other ) ;
void OpenForRead( const fs::path& path ) ;
void OpenForWrite( const fs::path& path, int mode = 0600 ) ;
void Close() ;
bool IsOpened() const ;
std::size_t Read( void *ptr, std::size_t size ) ;
std::size_t Write( const void *ptr, std::size_t size ) ;
std::size_t Read( char *ptr, std::size_t size ) ;
std::size_t Write( const char *ptr, std::size_t size ) ;
off_t Seek( off_t offset, int whence ) ;
off_t Tell() const ;
@ -54,7 +69,9 @@ public :
void* Map( off_t offset, std::size_t length ) ;
static void UnMap( void *addr, std::size_t length ) ;
struct stat Stat() const ;
private :
void Open( const fs::path& path, int flags, int mode ) ;

View File

@ -25,17 +25,4 @@
namespace gr
{
namespace fs = boost::filesystem ;
// these two functions are for ancient distro which does not have boost v1.44 or later
// will be removed once people upgrade
inline std::string Path2Str( const fs::path& p )
{
return p.string() ;
}
inline std::string Path2Str( const std::string& s )
{
return s ;
}
}

View File

@ -18,11 +18,11 @@
*/
#include "MemMap.hh"
#include "StdioFile.hh"
#include "File.hh"
namespace gr {
MemMap::MemMap( StdioFile& file, off_t offset, std::size_t length ) :
MemMap::MemMap( File& file, off_t offset, std::size_t length ) :
m_addr ( file.Map( offset, length ) ),
m_length( length )
{
@ -30,7 +30,7 @@ MemMap::MemMap( StdioFile& file, off_t offset, std::size_t length ) :
MemMap::~MemMap()
{
StdioFile::UnMap( m_addr, m_length ) ;
File::UnMap( m_addr, m_length ) ;
}
void* MemMap::Addr() const

View File

@ -25,7 +25,7 @@
namespace gr {
class StdioFile ;
class File ;
class MemMap
{
@ -33,7 +33,7 @@ public :
struct Error : virtual Exception {} ;
public :
MemMap( StdioFile& file, off_t offset, std::size_t length ) ;
MemMap( File& file, off_t offset, std::size_t length ) ;
~MemMap() ;
void* Addr() const ;