From 208b983734d7431699f4bd3534e08321e42ada86 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 6 Oct 2011 03:25:22 +0000 Subject: Renamed most of the core threading system, some ancillary systems need some kind of prefix or something, we could stick with Ito, I will until I think of something else. --- src/condition.cpp | 49 +++++++++++++++++++++++ src/condition.h | 90 +++++++++++++++++++++++++++++++++++++++++++ src/ito.cpp | 55 -------------------------- src/ito.h | 107 --------------------------------------------------- src/itocondition.cpp | 49 ----------------------- src/itocondition.h | 90 ------------------------------------------- src/itocounter.h | 4 +- src/itolocker.cpp | 13 ------- src/itolocker.h | 18 --------- src/itomutex.cpp | 34 ---------------- src/itomutex.h | 68 -------------------------------- src/itoqueue.h | 8 ++-- src/itoserver.h | 12 +++--- src/mutex.cpp | 34 ++++++++++++++++ src/mutex.h | 68 ++++++++++++++++++++++++++++++++ src/mutexlocker.cpp | 24 ++++++++++++ src/mutexlocker.h | 21 ++++++++++ src/thread.cpp | 55 ++++++++++++++++++++++++++ src/thread.h | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ 19 files changed, 460 insertions(+), 446 deletions(-) create mode 100644 src/condition.cpp create mode 100644 src/condition.h delete mode 100644 src/ito.cpp delete mode 100644 src/ito.h delete mode 100644 src/itocondition.cpp delete mode 100644 src/itocondition.h delete mode 100644 src/itolocker.cpp delete mode 100644 src/itolocker.h delete mode 100644 src/itomutex.cpp delete mode 100644 src/itomutex.h create mode 100644 src/mutex.cpp create mode 100644 src/mutex.h create mode 100644 src/mutexlocker.cpp create mode 100644 src/mutexlocker.h create mode 100644 src/thread.cpp create mode 100644 src/thread.h (limited to 'src') diff --git a/src/condition.cpp b/src/condition.cpp new file mode 100644 index 0000000..2f55ce2 --- /dev/null +++ b/src/condition.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include + +#include "bu/condition.h" + +Bu::Condition::Condition() +{ + pthread_cond_init( &cond, NULL ); +} + +Bu::Condition::~Condition() +{ + pthread_cond_destroy( &cond ); +} + +int Bu::Condition::wait() +{ + return pthread_cond_wait( &cond, &mutex ); +} + +int Bu::Condition::wait( int nSec, int nUSec ) +{ + struct timeval now; + struct timespec timeout; + struct timezone tz; + + gettimeofday( &now, &tz ); + timeout.tv_sec = now.tv_sec + nSec + ((now.tv_usec + nUSec)/1000000); + timeout.tv_nsec = ((now.tv_usec + nUSec)%1000000)*1000; + + return pthread_cond_timedwait( &cond, &mutex, &timeout ); +} + +int Bu::Condition::signal() +{ + return pthread_cond_signal( &cond ); +} + +int Bu::Condition::broadcast() +{ + return pthread_cond_broadcast( &cond ); +} + diff --git a/src/condition.h b/src/condition.h new file mode 100644 index 0000000..71634f5 --- /dev/null +++ b/src/condition.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_CONDITION_H +#define BU_CONDITION_H + +#include + +#include "bu/mutex.h" + +namespace Bu +{ + /** + * Ito condition. This is a fairly simple condition mechanism. As you may + * notice this class inherits from the Mutex class, this is because all + * conditions must be within a locked block. The standard usage of a + * condition is to pause one thread, perhaps indefinately, until another + * thread signals that it is alright to procede. + *
+ * Standard usage for the thread that wants to wait is as follows: + *
+	 * Condition cond;
+	 * ... // Perform setup and enter your run loop
+	 * cond.lock();
+	 * while( !isFinished() ) // Could be anything you're waiting for
+	 *     cond.wait();
+	 * ...  // Take care of what you have to.
+	 * cond.unlock();
+	 * 
+ * The usage for the triggering thread is much simpler, when it needs to + * tell the others that it's time to grab some data it calls either signal + * or broadcast. See both of those functions for the difference. + *@ingroup Threading + */ + class Condition : public Mutex + { + public: + /** + * Create a condition. + */ + Condition(); + + /** + * Destroy a condition. + */ + ~Condition(); + + /** + * Wait forever, or until signalled. This has to be called from within + * a locked section, i.e. before calling this this object's lock + * function should be called. + */ + int wait(); + + /** + * Wait for a maximum of nSec seconds and nUSec micro-seconds or until + * signalled. This is a little more friendly function if you want to + * perform other operations in the thrad loop that calls this function. + * Like the other wait function, this must be inside a locked section. + *@param nSec The seconds to wait. + *@param nUSec the micro-seconds to wait. + */ + int wait( int nSec, int nUSec ); + + /** + * Notify the next thread waiting on this condition that they can go + * ahead. This only signals one thread, the next one in the condition + * queue, that it is safe to procede with whatever operation was being + * waited on. + */ + int signal(); + + /** + * Notify all threads waiting on this condition that they can go ahead + * now. This function is slower than signal, but more effective in + * certain situations where you may not know how many threads should be + * activated. + */ + int broadcast(); + + private: + pthread_cond_t cond; /**< Internal condition reference. */ + }; +} + +#endif diff --git a/src/ito.cpp b/src/ito.cpp deleted file mode 100644 index aa9a597..0000000 --- a/src/ito.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include "bu/ito.h" - -#include "bu/config.h" - -Bu::Ito::Ito() -{ -} - -Bu::Ito::~Ito() -{ -} - -bool Bu::Ito::start() -{ - nHandle = pthread_create( &ptHandle, NULL, threadRunner, this ); - - return true; -} - -bool Bu::Ito::stop() -{ - pthread_cancel( ptHandle ); - - return true; -} - -void *Bu::Ito::threadRunner( void *pThread ) -{ - ((Ito *)pThread)->run(); - pthread_exit( NULL ); - return NULL; -} - -bool Bu::Ito::join() -{ - pthread_join( ptHandle, NULL ); - return true; -} - -void Bu::Ito::yield() -{ -#ifndef WIN32 - pthread_yield(); -#else - #warning Bu::Ito::yield IS A STUB for WIN32!!!! -#endif -} - diff --git a/src/ito.h b/src/ito.h deleted file mode 100644 index 9f50b2a..0000000 --- a/src/ito.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_ITO_H -#define BU_ITO_H - -#include - -namespace Bu -{ - /** - * Simple thread class. This wraps the basic pthread (posix threads) - * system in an object oriented sort of way. It allows you to create a - * class with standard member variables and callable functions that can be - * run in it's own thread, one per class instance. - *@ingroup Threading - */ - class Ito - { - public: - /** - * Construct an Ito thread. - */ - Ito(); - - /** - * Destroy an Ito thread. - */ - virtual ~Ito(); - - /** - * Begin thread execution. This will call the overridden run function, - * which will simply execute in it's own thread until the function - * exits, the thread is killed, or the thread is cancelled (optionally). - * The thread started in this manner has access to all of it's class - * variables, but be sure to protect possible multiple-access with - * ItoMutex objects. - * @returns True if starting the thread was successful. False if - * something went wrong and the thread has not started. - */ - bool start(); - - /** - * Forcibly kill a thread. This is not generally considered a good - * thing to do, but in those rare cases you need it, it's invaluable. - * The problem with stopping (or killing) a thread is that it stops it - * the moment you call stop, no matter what it's doing. The object - * oriented approach to this will help clean up any class variables - * that were used, but anything not managed as a member variable will - * probably create a memory leak type of situation. Instead of stop, - * consider using cancel, which can be handled by the running thread in - * a graceful manner. - *@returns True if the thread was stopped, false otherwise. When this - * function returns the thread may not have stopped, to ensure that the - * thread has really stopped, call join. - */ - bool stop(); - - /** - * Join the thread in action. This function performs what is commonly - * called a thread join. That is that it effectively makes the calling - * thread an the Ito thread contained in the called object one in the - * same, and pauses the calling thread until the called thread exits. - * That is, when called from, say, your main(), mythread.join() will - * not return until the thread mythread has exited. This is very handy - * at the end of programs to ensure all of your data was cleaned up. - *@returns True if the thread was joined, false if the thread couldn't - * be joined, usually because it isn't running to begin with. - */ - bool join(); - - private: - pthread_t ptHandle; /**< Internal handle to the posix thread. */ - int nHandle; /**< Numeric handle to the posix thread. */ - - protected: - /** - * The workhorse of the Ito class. This is the function that will run - * in the thread, when this function exits the thread dies and is - * cleaned up by the system. Make sure to read up on ItoMutex, - * ItoCondition, and cancel to see how to control and protect - * everything you do in a safe way within this function. - *@returns I'm not sure right now, but this is the posix standard form. - */ - virtual void run()=0; - - /** - * This is the hidden-heard of the thread system. While run is what the - * user gets to override, and everything said about it is true, this is - * the function that actually makes up the thread, it simply calls the - * run member function in an OO-friendly way. This is what allows us to - * use member variables from within the thread itself. - *@param pThread Should always be this. - *@returns This is specified by posix, I'm not sure yet. - */ - static void *threadRunner( void *pThread ); - - void yield(); - - }; -} - -#endif diff --git a/src/itocondition.cpp b/src/itocondition.cpp deleted file mode 100644 index 3d8db60..0000000 --- a/src/itocondition.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include - -#include "bu/itocondition.h" - -Bu::ItoCondition::ItoCondition() -{ - pthread_cond_init( &cond, NULL ); -} - -Bu::ItoCondition::~ItoCondition() -{ - pthread_cond_destroy( &cond ); -} - -int Bu::ItoCondition::wait() -{ - return pthread_cond_wait( &cond, &mutex ); -} - -int Bu::ItoCondition::wait( int nSec, int nUSec ) -{ - struct timeval now; - struct timespec timeout; - struct timezone tz; - - gettimeofday( &now, &tz ); - timeout.tv_sec = now.tv_sec + nSec + ((now.tv_usec + nUSec)/1000000); - timeout.tv_nsec = ((now.tv_usec + nUSec)%1000000)*1000; - - return pthread_cond_timedwait( &cond, &mutex, &timeout ); -} - -int Bu::ItoCondition::signal() -{ - return pthread_cond_signal( &cond ); -} - -int Bu::ItoCondition::broadcast() -{ - return pthread_cond_broadcast( &cond ); -} - diff --git a/src/itocondition.h b/src/itocondition.h deleted file mode 100644 index 88e8d6c..0000000 --- a/src/itocondition.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_ITO_CONDITION_H -#define BU_ITO_CONDITION_H - -#include - -#include "itomutex.h" - -namespace Bu -{ - /** - * Ito condition. This is a fairly simple condition mechanism. As you may - * notice this class inherits from the ItoMutex class, this is because all - * conditions must be within a locked block. The standard usage of a - * condition is to pause one thread, perhaps indefinately, until another - * thread signals that it is alright to procede. - *
- * Standard usage for the thread that wants to wait is as follows: - *
-	 * ItoCondition cond;
-	 * ... // Perform setup and enter your run loop
-	 * cond.lock();
-	 * while( !isFinished() ) // Could be anything you're waiting for
-	 *     cond.wait();
-	 * ...  // Take care of what you have to.
-	 * cond.unlock();
-	 * 
- * The usage for the triggering thread is much simpler, when it needs to - * tell the others that it's time to grab some data it calls either signal - * or broadcast. See both of those functions for the difference. - *@ingroup Threading - */ - class ItoCondition : public ItoMutex - { - public: - /** - * Create a condition. - */ - ItoCondition(); - - /** - * Destroy a condition. - */ - ~ItoCondition(); - - /** - * Wait forever, or until signalled. This has to be called from within - * a locked section, i.e. before calling this this object's lock - * function should be called. - */ - int wait(); - - /** - * Wait for a maximum of nSec seconds and nUSec micro-seconds or until - * signalled. This is a little more friendly function if you want to - * perform other operations in the thrad loop that calls this function. - * Like the other wait function, this must be inside a locked section. - *@param nSec The seconds to wait. - *@param nUSec the micro-seconds to wait. - */ - int wait( int nSec, int nUSec ); - - /** - * Notify the next thread waiting on this condition that they can go - * ahead. This only signals one thread, the next one in the condition - * queue, that it is safe to procede with whatever operation was being - * waited on. - */ - int signal(); - - /** - * Notify all threads waiting on this condition that they can go ahead - * now. This function is slower than signal, but more effective in - * certain situations where you may not know how many threads should be - * activated. - */ - int broadcast(); - - private: - pthread_cond_t cond; /**< Internal condition reference. */ - }; -} - -#endif diff --git a/src/itocounter.h b/src/itocounter.h index 10df467..10126a5 100644 --- a/src/itocounter.h +++ b/src/itocounter.h @@ -8,7 +8,7 @@ #ifndef BU_ITO_COUNTER_H #define BU_ITO_COUNTER_H -#include "itomutex.h" +#include "mutex.h" namespace Bu { @@ -42,7 +42,7 @@ namespace Bu private: T tCounter; /**< The counter itself. */ - ItoMutex mOperate; /**< The master mutex, used on all operations. */ + Mutex mOperate; /**< The master mutex, used on all operations. */ }; } diff --git a/src/itolocker.cpp b/src/itolocker.cpp deleted file mode 100644 index 17e97fd..0000000 --- a/src/itolocker.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "bu/itolocker.h" -#include "bu/itomutex.h" - -Bu::ItoLocker::ItoLocker( Bu::ItoMutex &mu ) : - mu( mu ) -{ - mu.lock(); -} - -Bu::ItoLocker::~ItoLocker() -{ - mu.unlock(); -} diff --git a/src/itolocker.h b/src/itolocker.h deleted file mode 100644 index 76e5198..0000000 --- a/src/itolocker.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef BU_ITO_LOCKER_H -#define BU_ITO_LOCKER_H - -namespace Bu -{ - class ItoMutex; - class ItoLocker - { - public: - ItoLocker( ItoMutex &mu ); - virtual ~ItoLocker(); - - private: - ItoMutex & mu; - }; -}; - -#endif diff --git a/src/itomutex.cpp b/src/itomutex.cpp deleted file mode 100644 index 8de6336..0000000 --- a/src/itomutex.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include "bu/itomutex.h" - -Bu::ItoMutex::ItoMutex() -{ - pthread_mutex_init( &mutex, NULL ); -} - -Bu::ItoMutex::~ItoMutex() -{ - pthread_mutex_destroy( &mutex ); -} - -int Bu::ItoMutex::lock() -{ - return pthread_mutex_lock( &mutex ); -} - -int Bu::ItoMutex::unlock() -{ - return pthread_mutex_unlock( &mutex ); -} - -int Bu::ItoMutex::trylock() -{ - return pthread_mutex_trylock( &mutex ); -} - diff --git a/src/itomutex.h b/src/itomutex.h deleted file mode 100644 index 68a0c1d..0000000 --- a/src/itomutex.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_ITO_MUTEX_H -#define BU_ITO_MUTEX_H - -#include - -namespace Bu -{ - /** - * Simple mutex wrapper. Currently this doesn't do anything extra for you - * except keep all of the functionality together in an OO sorta' way and - * keep you from having to worry about cleaning up your mutexes properly, - * or initing them. - *@ingroup Threading - */ - class ItoMutex - { - public: - /** - * Create an unlocked mutex. - */ - ItoMutex(); - - /** - * Destroy a mutex. This can only be done when a mutex is unlocked. - * Failure to unlock before destroying a mutex object could cause it to - * wait for the mutex to unlock, the odds of which are usually farily - * low at deconstruction time. - */ - ~ItoMutex(); - - /** - * Lock the mutex. This causes all future calls to lock on this - * instance of mutex to block until the first thread that called mutex - * unlocks it. At that point the next thread that called lock will get - * a chance to go to work. Because of the nature of a mutex lock it is - * a very bad idea to do any kind of serious or rather time consuming - * computation within a locked section. This can cause thread-deadlock - * and your program may hang. - */ - int lock(); - - /** - * Unlock the mutex. This allows the next thread that asked for a lock - * to lock the mutex and continue with execution. - */ - int unlock(); - - /** - * Try to lock the mutex. This is the option to go with if you cannot - * avoid putting lengthy operations within a locked section. trylock - * will attempt to lock the mutex, if the mutex is already locked this - * function returns immediately with an error code. - */ - int trylock(); - - protected: - pthread_mutex_t mutex; /**< The internal mutex reference. */ - }; -} - -#endif diff --git a/src/itoqueue.h b/src/itoqueue.h index dc3cadb..039e09c 100644 --- a/src/itoqueue.h +++ b/src/itoqueue.h @@ -10,8 +10,8 @@ #include -#include "itomutex.h" -#include "itocondition.h" +#include "mutex.h" +#include "condition.h" namespace Bu { @@ -232,8 +232,8 @@ namespace Bu Item *pEnd; /**< The end of the queue, the last element to dequeue. */ long nSize; /**< The number of items in the queue. */ - ItoMutex mOperate; /**< The master mutex, used on all operations. */ - ItoCondition cBlock; /**< The condition for blocking dequeues. */ + Mutex mOperate; /**< The master mutex, used on all operations. */ + Condition cBlock; /**< The condition for blocking dequeues. */ }; } diff --git a/src/itoserver.h b/src/itoserver.h index 902c684..75b3349 100644 --- a/src/itoserver.h +++ b/src/itoserver.h @@ -16,8 +16,8 @@ #include "bu/string.h" #include "bu/list.h" -#include "bu/ito.h" -#include "bu/itomutex.h" +#include "bu/thread.h" +#include "bu/mutex.h" #include "bu/itoqueue.h" #include "bu/set.h" @@ -50,7 +50,7 @@ namespace Bu * happening within the server itself, and actually makes it useful. *@ingroup Threading Serving */ - class ItoServer : public Ito + class ItoServer : public Thread { friend class ItoClient; friend class SrvClientLinkFactory; @@ -74,7 +74,7 @@ namespace Bu private: class SrvClientLink; - class ItoClient : public Ito + class ItoClient : public Thread { friend class Bu::ItoServer::SrvClientLink; public: @@ -96,7 +96,7 @@ namespace Bu int iPort; int nTimeoutSec; int nTimeoutUSec; - ItoMutex imProto; + Mutex imProto; }; class SrvClientLink : public Bu::ClientLink @@ -132,7 +132,7 @@ namespace Bu typedef ItoQueue ClientQueue; ClientHash hClients; ClientQueue qClientCleanup; - ItoMutex imClients; + Mutex imClients; void clientCleanup( int iSocket ); }; diff --git a/src/mutex.cpp b/src/mutex.cpp new file mode 100644 index 0000000..dbaaece --- /dev/null +++ b/src/mutex.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/mutex.h" + +Bu::Mutex::Mutex() +{ + pthread_mutex_init( &mutex, NULL ); +} + +Bu::Mutex::~Mutex() +{ + pthread_mutex_destroy( &mutex ); +} + +int Bu::Mutex::lock() +{ + return pthread_mutex_lock( &mutex ); +} + +int Bu::Mutex::unlock() +{ + return pthread_mutex_unlock( &mutex ); +} + +int Bu::Mutex::trylock() +{ + return pthread_mutex_trylock( &mutex ); +} + diff --git a/src/mutex.h b/src/mutex.h new file mode 100644 index 0000000..b5c8b7a --- /dev/null +++ b/src/mutex.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_MUTEX_H +#define BU_MUTEX_H + +#include + +namespace Bu +{ + /** + * Simple mutex wrapper. Currently this doesn't do anything extra for you + * except keep all of the functionality together in an OO sorta' way and + * keep you from having to worry about cleaning up your mutexes properly, + * or initing them. + *@ingroup Threading + */ + class Mutex + { + public: + /** + * Create an unlocked mutex. + */ + Mutex(); + + /** + * Destroy a mutex. This can only be done when a mutex is unlocked. + * Failure to unlock before destroying a mutex object could cause it to + * wait for the mutex to unlock, the odds of which are usually farily + * low at deconstruction time. + */ + ~Mutex(); + + /** + * Lock the mutex. This causes all future calls to lock on this + * instance of mutex to block until the first thread that called mutex + * unlocks it. At that point the next thread that called lock will get + * a chance to go to work. Because of the nature of a mutex lock it is + * a very bad idea to do any kind of serious or rather time consuming + * computation within a locked section. This can cause thread-deadlock + * and your program may hang. + */ + int lock(); + + /** + * Unlock the mutex. This allows the next thread that asked for a lock + * to lock the mutex and continue with execution. + */ + int unlock(); + + /** + * Try to lock the mutex. This is the option to go with if you cannot + * avoid putting lengthy operations within a locked section. trylock + * will attempt to lock the mutex, if the mutex is already locked this + * function returns immediately with an error code. + */ + int trylock(); + + protected: + pthread_mutex_t mutex; /**< The internal mutex reference. */ + }; +} + +#endif diff --git a/src/mutexlocker.cpp b/src/mutexlocker.cpp new file mode 100644 index 0000000..90b730e --- /dev/null +++ b/src/mutexlocker.cpp @@ -0,0 +1,24 @@ +#include "bu/mutexlocker.h" +#include "bu/mutex.h" + +Bu::MutexLocker::MutexLocker( Bu::Mutex &mu ) : + mu( mu ) +{ + mu.lock(); +} + +Bu::MutexLocker::~MutexLocker() +{ + mu.unlock(); +} + +void Bu::MutexLocker::unlock() +{ + mu.unlock(); +} + +void Bu::MutexLocker::relock() +{ + mu.lock(); +} + diff --git a/src/mutexlocker.h b/src/mutexlocker.h new file mode 100644 index 0000000..7c3c97e --- /dev/null +++ b/src/mutexlocker.h @@ -0,0 +1,21 @@ +#ifndef BU_MUTEX_LOCKER_H +#define BU_MUTEX_LOCKER_H + +namespace Bu +{ + class Mutex; + class MutexLocker + { + public: + MutexLocker( Mutex &mu ); + virtual ~MutexLocker(); + + void unlock(); + void relock(); + + private: + Mutex μ + }; +}; + +#endif diff --git a/src/thread.cpp b/src/thread.cpp new file mode 100644 index 0000000..e4563a2 --- /dev/null +++ b/src/thread.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/thread.h" + +#include "bu/config.h" + +Bu::Thread::Thread() +{ +} + +Bu::Thread::~Thread() +{ +} + +bool Bu::Thread::start() +{ + nHandle = pthread_create( &ptHandle, NULL, threadRunner, this ); + + return true; +} + +bool Bu::Thread::stop() +{ + pthread_cancel( ptHandle ); + + return true; +} + +void *Bu::Thread::threadRunner( void *pThread ) +{ + ((Thread *)pThread)->run(); + pthread_exit( NULL ); + return NULL; +} + +bool Bu::Thread::join() +{ + pthread_join( ptHandle, NULL ); + return true; +} + +void Bu::Thread::yield() +{ +#ifndef WIN32 + pthread_yield(); +#else + #warning Bu::Thread::yield IS A STUB for WIN32!!!! +#endif +} + diff --git a/src/thread.h b/src/thread.h new file mode 100644 index 0000000..70e6f5f --- /dev/null +++ b/src/thread.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_THREAD_H +#define BU_THREAD_H + +#include + +namespace Bu +{ + /** + * Simple thread class. This wraps the basic pthread (posix threads) + * system in an object oriented sort of way. It allows you to create a + * class with standard member variables and callable functions that can be + * run in it's own thread, one per class instance. + *@ingroup Threading + */ + class Thread + { + public: + /** + * Construct an Thread thread. + */ + Thread(); + + /** + * Destroy an Thread thread. + */ + virtual ~Thread(); + + /** + * Begin thread execution. This will call the overridden run function, + * which will simply execute in it's own thread until the function + * exits, the thread is killed, or the thread is cancelled (optionally). + * The thread started in this manner has access to all of it's class + * variables, but be sure to protect possible multiple-access with + * ThreadMutex objects. + * @returns True if starting the thread was successful. False if + * something went wrong and the thread has not started. + */ + bool start(); + + /** + * Forcibly kill a thread. This is not generally considered a good + * thing to do, but in those rare cases you need it, it's invaluable. + * The problem with stopping (or killing) a thread is that it stops it + * the moment you call stop, no matter what it's doing. The object + * oriented approach to this will help clean up any class variables + * that were used, but anything not managed as a member variable will + * probably create a memory leak type of situation. Instead of stop, + * consider using cancel, which can be handled by the running thread in + * a graceful manner. + *@returns True if the thread was stopped, false otherwise. When this + * function returns the thread may not have stopped, to ensure that the + * thread has really stopped, call join. + */ + bool stop(); + + /** + * Join the thread in action. This function performs what is commonly + * called a thread join. That is that it effectively makes the calling + * thread an the Thread thread contained in the called object one in the + * same, and pauses the calling thread until the called thread exits. + * That is, when called from, say, your main(), mythread.join() will + * not return until the thread mythread has exited. This is very handy + * at the end of programs to ensure all of your data was cleaned up. + *@returns True if the thread was joined, false if the thread couldn't + * be joined, usually because it isn't running to begin with. + */ + bool join(); + + private: + pthread_t ptHandle; /**< Internal handle to the posix thread. */ + int nHandle; /**< Numeric handle to the posix thread. */ + + protected: + /** + * The workhorse of the Thread class. This is the function that will run + * in the thread, when this function exits the thread dies and is + * cleaned up by the system. Make sure to read up on ThreadMutex, + * ThreadCondition, and cancel to see how to control and protect + * everything you do in a safe way within this function. + *@returns I'm not sure right now, but this is the posix standard form. + */ + virtual void run()=0; + + /** + * This is the hidden-heard of the thread system. While run is what the + * user gets to override, and everything said about it is true, this is + * the function that actually makes up the thread, it simply calls the + * run member function in an OO-friendly way. This is what allows us to + * use member variables from within the thread itself. + *@param pThread Should always be this. + *@returns This is specified by posix, I'm not sure yet. + */ + static void *threadRunner( void *pThread ); + + void yield(); + + }; +} + +#endif -- cgit v1.2.3 From da1e0ef0772b078bd295301bd675afdee00d40e9 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 23 Oct 2011 07:43:50 +0000 Subject: Switched ito* to synchro*, except the server, I'm thinking of takeing the core in a different direction anyway. Added the Deflate class, it uses zlib, and can do raw (headerless) deflate streams, zlib format, or gzip format. It's easy to use and quite versitile. --- default.bld | 5 + src/bzip2.cpp | 2 +- src/conduit.h | 8 +- src/deflate.cpp | 242 +++++++++++++++++++++++++++++++++++++++++++++++++ src/deflate.h | 63 +++++++++++++ src/itoatom.h | 64 ------------- src/itocounter.cpp | 8 -- src/itocounter.h | 49 ---------- src/itoheap.cpp | 9 -- src/itoheap.h | 154 ------------------------------- src/itoqueue.h | 240 ------------------------------------------------ src/itoserver.h | 6 +- src/synchroatom.h | 63 +++++++++++++ src/synchrocounter.cpp | 8 ++ src/synchrocounter.h | 49 ++++++++++ src/synchroheap.cpp | 9 ++ src/synchroheap.h | 151 ++++++++++++++++++++++++++++++ src/synchroqueue.h | 240 ++++++++++++++++++++++++++++++++++++++++++++++++ src/tests/deflate.cpp | 53 +++++++++++ 19 files changed, 891 insertions(+), 532 deletions(-) create mode 100644 src/deflate.cpp create mode 100644 src/deflate.h delete mode 100644 src/itoatom.h delete mode 100644 src/itocounter.cpp delete mode 100644 src/itocounter.h delete mode 100644 src/itoheap.cpp delete mode 100644 src/itoheap.h delete mode 100644 src/itoqueue.h create mode 100644 src/synchroatom.h create mode 100644 src/synchrocounter.cpp create mode 100644 src/synchrocounter.h create mode 100644 src/synchroheap.cpp create mode 100644 src/synchroheap.h create mode 100644 src/synchroqueue.h create mode 100644 src/tests/deflate.cpp (limited to 'src') diff --git a/default.bld b/default.bld index 8f98db0..6666fe2 100644 --- a/default.bld +++ b/default.bld @@ -167,6 +167,11 @@ target ["tests/bzip2", "tests/streamstack"] LDFLAGS += "-lbz2"; } +target ["tests/deflate"] +{ + LDFLAGS += "-lz"; +} + target ["tests/itoserver", "tests/socketblock", "tests/itoheap", "tests/itoqueue1", "tests/itoqueue2", "tests/conduit"] { diff --git a/src/bzip2.cpp b/src/bzip2.cpp index 5c35a26..0ff5444 100644 --- a/src/bzip2.cpp +++ b/src/bzip2.cpp @@ -33,7 +33,7 @@ void Bu::BZip2::start() bzState.bzfree = NULL; bzState.opaque = NULL; - nBufSize = 50000; + nBufSize = 64*1024; pBuf = new char[nBufSize]; } diff --git a/src/conduit.h b/src/conduit.h index 72b8d52..9babaaf 100644 --- a/src/conduit.h +++ b/src/conduit.h @@ -11,8 +11,8 @@ #include "bu/stream.h" #include "bu/string.h" #include "bu/queuebuf.h" -#include "bu/itomutex.h" -#include "bu/itocondition.h" +#include "bu/mutex.h" +#include "bu/condition.h" namespace Bu { @@ -54,8 +54,8 @@ namespace Bu private: QueueBuf qb; - mutable ItoMutex im; - ItoCondition cBlock; + mutable Mutex im; + Condition cBlock; bool bBlocking; bool bOpen; }; diff --git a/src/deflate.cpp b/src/deflate.cpp new file mode 100644 index 0000000..aec2a18 --- /dev/null +++ b/src/deflate.cpp @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/deflate.h" +#include "bu/trace.h" + +using namespace Bu; + +Bu::Deflate::Deflate( Bu::Stream &rNext, int nCompression, Format eFmt ) : + Bu::Filter( rNext ), + nCompression( nCompression ), + sTotalOut( 0 ), + eFmt( eFmt ), + bEos( false ) +{ + TRACE( nCompression ); + start(); +} + +Bu::Deflate::~Deflate() +{ + TRACE(); + stop(); +} + +void Bu::Deflate::start() +{ + TRACE(); + zState.zalloc = NULL; + zState.zfree = NULL; + zState.opaque = NULL; + zState.state = NULL; + + nBufSize = 64*1024; + pBuf = new char[nBufSize]; +} + +Bu::size Bu::Deflate::stop() +{ + TRACE(); + if( zState.state ) + { + if( bReading ) + { + inflateEnd( &zState ); + delete[] pBuf; + pBuf = NULL; + return 0; + } + else + { + for(;;) + { + zState.next_in = NULL; + zState.avail_in = 0; + zState.avail_out = nBufSize; + zState.next_out = (Bytef *)pBuf; + int res = deflate( &zState, Z_FINISH ); + if( zState.avail_out < nBufSize ) + { + sTotalOut += rNext.write( pBuf, nBufSize-zState.avail_out ); + } + if( res == Z_STREAM_END ) + break; + } + deflateEnd( &zState ); + delete[] pBuf; + pBuf = NULL; + return sTotalOut; + } + } + return 0; +} + +void Bu::Deflate::zError( int code ) +{ + TRACE( code ); + switch( code ) + { + case Z_OK: + case Z_STREAM_END: + case Z_NEED_DICT: + return; + + case Z_ERRNO: + throw ExceptionBase("Deflate: Errno - %s", zState.msg ); + + case Z_STREAM_ERROR: + throw ExceptionBase("Deflate: Stream Error - %s", zState.msg ); + + case Z_DATA_ERROR: + throw ExceptionBase("Deflate: Data Error - %s", zState.msg ); + + case Z_MEM_ERROR: + throw ExceptionBase("Deflate: Mem Error - %s", zState.msg ); + + case Z_BUF_ERROR: + throw ExceptionBase("Deflate: Buf Error - %s", zState.msg ); + + case Z_VERSION_ERROR: + throw ExceptionBase("Deflate: Version Error - %s", zState.msg ); + + default: + throw ExceptionBase("Deflate: Unknown error encountered - %s.", zState.msg ); + + } +} + +Bu::size Bu::Deflate::read( void *pData, Bu::size nBytes ) +{ + TRACE( pData, nBytes ); + if( !zState.state ) + { + bReading = true; + if( eFmt&AutoDetect ) + inflateInit2( &zState, 32+15 ); // Auto-detect, large window + else if( eFmt == Raw ) + inflateInit2( &zState, -15 ); // Raw + else if( eFmt == Zlib ) + inflateInit2( &zState, 15 ); // Zlib + else if( eFmt == Gzip ) + inflateInit2( &zState, 16+15 ); // GZip + else + throw Bu::ExceptionBase("Format mode for deflate read."); + zState.next_in = (Bytef *)pBuf; + zState.avail_in = 0; + } + if( bReading == false ) + throw ExceptionBase("This deflate filter is in writing mode, you can't read."); + + int nRead = 0; + int nReadTotal = zState.total_out; + zState.next_out = (Bytef *)pData; + zState.avail_out = nBytes; + for(;;) + { + int ret = inflate( &zState, Z_NO_FLUSH ); + printf("inflate returned %d; avail in=%d, out=%d\n", ret, + zState.avail_in, zState.avail_out ); + + nReadTotal += nRead-zState.avail_out; + + if( ret == Z_STREAM_END ) + { + bEos = true; + if( zState.avail_in > 0 ) + { + if( rNext.isSeekable() ) + { + rNext.seek( -zState.avail_in ); + } + } + return nBytes-zState.avail_out; + } + if( ret != Z_BUF_ERROR ) + zError( ret ); + + if( zState.avail_out ) + { + if( zState.avail_in == 0 ) + { + nRead = rNext.read( pBuf, nBufSize ); + if( nRead == 0 && rNext.isEos() ) + { + throw Bu::ExceptionBase("Premature end of underlying " + "stream found reading deflate stream."); + } + zState.next_in = (Bytef *)pBuf; + zState.avail_in = nRead; + } + } + else + { + return nBytes-zState.avail_out; + } + } + return 0; +} + +Bu::size Bu::Deflate::write( const void *pData, Bu::size nBytes ) +{ + TRACE( pData, nBytes ); + if( !zState.state ) + { + bReading = false; + int iFmt = eFmt&Gzip; + if( iFmt == Raw ) + deflateInit2( &zState, nCompression, Z_DEFLATED, -15, 9, + Z_DEFAULT_STRATEGY ); + else if( iFmt == Zlib ) + deflateInit2( &zState, nCompression, Z_DEFLATED, 15, 9, + Z_DEFAULT_STRATEGY ); + else if( iFmt == Gzip ) + deflateInit2( &zState, nCompression, Z_DEFLATED, 16+15, 9, + Z_DEFAULT_STRATEGY ); + else + throw Bu::ExceptionBase("Invalid format for deflate."); + } + if( bReading == true ) + throw ExceptionBase("This deflate filter is in reading mode, you can't write."); + + zState.next_in = (Bytef *)pData; + zState.avail_in = nBytes; + for(;;) + { + zState.avail_out = nBufSize; + zState.next_out = (Bytef *)pBuf; + + zError( deflate( &zState, Z_NO_FLUSH ) ); + + if( zState.avail_out < nBufSize ) + { + sTotalOut += rNext.write( pBuf, nBufSize-zState.avail_out ); + } + if( zState.avail_in == 0 ) + break; + } + + return nBytes; +} + +bool Bu::Deflate::isOpen() +{ + TRACE(); + return (zState.state != NULL); +} + +bool Bu::Deflate::isEos() +{ + TRACE(); + return bEos; +} + +Bu::size Bu::Deflate::getCompressedSize() +{ + return sTotalOut; +} + diff --git a/src/deflate.h b/src/deflate.h new file mode 100644 index 0000000..cab9b51 --- /dev/null +++ b/src/deflate.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_DEFLATE_H +#define BU_DEFLATE_H + +#include +#include + +#include "bu/filter.h" + +namespace Bu +{ + /** + * + *@ingroup Streams + */ + class Deflate : public Bu::Filter + { + public: + enum Format + { + Raw = 0x01, + Zlib = 0x02, + Gzip = 0x03, + AutoDetect = 0x04, + + AutoRaw = 0x04|0x01, + AutoZlib = 0x04|0x02, + AutoGzip = 0x04|0x03 + }; + + Deflate( Bu::Stream &rNext, int nCompression=9, Format eFmt=AutoRaw ); + virtual ~Deflate(); + + virtual void start(); + virtual Bu::size stop(); + virtual Bu::size read( void *pBuf, Bu::size nBytes ); + virtual Bu::size write( const void *pBuf, Bu::size nBytes ); + + virtual bool isOpen(); + virtual bool isEos(); + + Bu::size getCompressedSize(); + + private: + void zError( int code ); + z_stream zState; + bool bReading; + int nCompression; + char *pBuf; + uint32_t nBufSize; + Bu::size sTotalOut; + Format eFmt; + bool bEos; + }; +} + +#endif diff --git a/src/itoatom.h b/src/itoatom.h deleted file mode 100644 index 3659f4e..0000000 --- a/src/itoatom.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_ITO_ATOM_H -#define BU_ITO_ATOM_H - -#include - -#include "itomutex.h" -#include "itocondition.h" - -namespace Bu -{ - /** - * A thread-safe wrapper class. - *@ingroup Threading - */ - template - class ItoAtom - { - public: - /** - * Construct an empty queue. - */ - ItoAtom() - { - } - - ItoAtom( const T &src ) : - data( src ) - { - } - - ~ItoAtom() - { - } - - T get() - { - mOperate.lock(); - T ret = data; - mOperate.unlock(); - return ret; - } - - void set( const T &val ) - { - mOperate.lock(); - data = val; - mOperate.unlock(); - } - - private: - T data; - - ItoMutex mOperate; /**< The master mutex, used on all operations. */ - }; -}; - -#endif diff --git a/src/itocounter.cpp b/src/itocounter.cpp deleted file mode 100644 index 0c6e06c..0000000 --- a/src/itocounter.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include "bu/itocounter.h" diff --git a/src/itocounter.h b/src/itocounter.h deleted file mode 100644 index 10126a5..0000000 --- a/src/itocounter.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_ITO_COUNTER_H -#define BU_ITO_COUNTER_H - -#include "mutex.h" - -namespace Bu -{ - /** - * A simple thread-safe counter class. This is handy for assigning unique - * IDs to objects that are being created in different threads. - *@ingroup Threading Containers - */ - template - class ItoCounter - { - public: - ItoCounter() : - tCounter( 0 ) - { - } - - virtual ~ItoCounter() - { - } - - T next() - { - mOperate.lock(); - T tRet = tCounter; - tCounter++; - mOperate.unlock(); - - return tRet; - } - - private: - T tCounter; /**< The counter itself. */ - Mutex mOperate; /**< The master mutex, used on all operations. */ - }; -} - -#endif diff --git a/src/itoheap.cpp b/src/itoheap.cpp deleted file mode 100644 index 21ccef8..0000000 --- a/src/itoheap.cpp +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include "bu/itoheap.h" - diff --git a/src/itoheap.h b/src/itoheap.h deleted file mode 100644 index a5aad05..0000000 --- a/src/itoheap.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_ITO_HEAP_H -#define BU_ITO_HEAP_H - -#include "bu/heap.h" -#include "bu/itomutex.h" -#include "bu/itocondition.h" - -namespace Bu -{ - class ItoMutex; - class ItoCondition; - - template, - typename itemalloc=std::allocator > - class ItoHeap - { - public: - ItoHeap() - { - } - - virtual ~ItoHeap() - { - } - - void enqueue( item i ) - { - imData.lock(); - hData.enqueue( i ); - icBlock.signal(); - imData.unlock(); - } - - item dequeue( bool bBlock=false ) - { - imData.lock(); - if( hData.isEmpty() ) - { - imData.unlock(); - - if( bBlock ) - { - icBlock.lock(); - - while( hData.isEmpty() ) - icBlock.wait(); - - imData.lock(); - try - { - item iRet = hData.dequeue(); - imData.unlock(); - icBlock.unlock(); - return iRet; - } - catch(...) - { - imData.unlock(); - icBlock.unlock(); - throw; - } - } - throw HeapException("Heap empty."); - } - else - { - try - { - item iRet = hData.dequeue(); - imData.unlock(); - return iRet; - } - catch(...) - { - imData.unlock(); - throw; - } - } - } - - item dequeue( int iSec, int iUSec ) - { - imData.lock(); - if( hData.isEmpty() ) - { - imData.unlock(); - - icBlock.lock(); - - icBlock.wait( iSec, iUSec ); - - imData.lock(); - try - { - item iRet = hData.dequeue(); - imData.unlock(); - icBlock.unlock(); - return iRet; - } - catch(...) - { - imData.unlock(); - icBlock.unlock(); - throw; - } - } - else - { - try - { - item iRet = hData.dequeue(); - imData.unlock(); - return iRet; - } - catch(...) - { - imData.unlock(); - throw; - } - } - } - - bool isEmpty() - { - imData.lock(); - bool bRet = hData.isEmpty(); - imData.unlock(); - return bRet; - } - - int getSize() - { - imData.lock(); - int iRet = hData.getSize(); - imData.unlock(); - return iRet; - } - - private: - Heap< item, cmpfunc, itemalloc > hData; - ItoMutex imData; - ItoCondition icBlock; - }; -}; - -#endif - diff --git a/src/itoqueue.h b/src/itoqueue.h deleted file mode 100644 index 039e09c..0000000 --- a/src/itoqueue.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2007-2011 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_ITO_QUEUE_H -#define BU_ITO_QUEUE_H - -#include - -#include "mutex.h" -#include "condition.h" - -namespace Bu -{ - /** - * A thread-safe queue class. This class is a very simple queue with some - * cool extra functionality for use with the Ito system. The main extra - * that it provides is the option to either dequeue without blocking, with - * infinite blocking, or with timed blocking, which will return a value if - * something is enqueued within the specified time limit, or NULL if the - * time limit is exceded. - *@ingroup Threading Containers - */ - template - class ItoQueue - { - private: - /** - * Helper struct. Keeps track of linked-list items for the queue data. - */ - typedef struct Item - { - T pData; - Item *pNext; - } Item; - - public: - /** - * Construct an empty queue. - */ - ItoQueue() : - pStart( NULL ), - pEnd( NULL ), - nSize( 0 ) - { - } - - /** - * Destroy the queue. This function will simply free all contained - * structures. If you stored pointers in the queue, this will lose the - * pointers without cleaning up the memory they pointed to. Make sure - * you're queue is empty before allowing it to be destroyed! - */ - ~ItoQueue() - { - Item *pCur = pStart; - while( pCur ) - { - Item *pTmp = pCur->pNext; - delete pCur; - pCur = pTmp; - } - } - - /** - * Enqueue a pieces of data. The new data will go at the end of the - * queue, and unless another piece of data is enqueued, will be the - * last piece of data to be dequeued. - *@param pData The data to enqueue. If this is not a primitive data - * type it's probably best to use a pointer type. - */ - void enqueue( T pData ) - { - mOperate.lock(); - - if( pStart == NULL ) - { - pStart = pEnd = new Item; - pStart->pData = pData; - pStart->pNext = NULL; - nSize++; - } - else - { - pEnd->pNext = new Item; - pEnd = pEnd->pNext; - pEnd->pData = pData; - pEnd->pNext = NULL; - nSize++; - } - - cBlock.signal(); - - mOperate.unlock(); - } - - /** - * Dequeue the first item from the queue. This function can operate in - * two different modes, blocking and non-blocking. In non-blocking - * mode it will return immediately weather there was data in the queue - * or not. If there was data it will remove it from the queue and - * return it to the caller. - * - * In blocking mode it will block forever wating for data to be - * enqueued. When data finally is enqueued this function will return - * immediately with the new data. The only way this function should - * ever return a null in blocking mode is if the calling thread was - * cancelled. It's probably a good idea to check for NULL return - * values even if you use blocking, just to be on the safe side. - *@param bBlock Set to true to enable blocking, leave as false to work - * in non-blocking mode. - *@returns The next piece of data in the queue, or NULL if no data was - * in the queue. - */ - T dequeue( bool bBlock=false ) - { - mOperate.lock(); - if( pStart == NULL ) - { - mOperate.unlock(); - - if( bBlock ) - { - cBlock.lock(); - - while( pStart == NULL ) - cBlock.wait(); - - T tmp = dequeue( false ); - - cBlock.unlock(); - return tmp; - - } - - return NULL; - } - else - { - T pTmp = pStart->pData; - Item *pDel = pStart; - pStart = pStart->pNext; - delete pDel; - nSize--; - - mOperate.unlock(); - return pTmp; - } - } - - /** - * Operates just like the other dequeue function in blocking mode with - * one twist. This function will block for at most nSec seconds and - * nUSec micro-seconds. If the timer is up and no data is available, - * this will just return NULL. If data is enqueued before the timeout - * expires, it will dequeue and exit immediately. - *@param nSec The number of seconds to wait, max. - *@param nUSec The number of micro-seconds to wait, max. - *@returns The next piece of data in the queue, or NULL if the timeout - * was exceeded. - */ - T dequeue( int nSec, int nUSec ) - { - mOperate.lock(); - if( pStart == NULL ) - { - mOperate.unlock(); - - cBlock.lock(); - - cBlock.wait( nSec, nUSec ); - - if( pStart == NULL ) - { - cBlock.unlock(); - return NULL; - } - - mOperate.lock(); - T pTmp = pStart->pData; - Item *pDel = pStart; - pStart = pStart->pNext; - delete pDel; - nSize--; - mOperate.unlock(); - - cBlock.unlock(); - return pTmp; - } - else - { - T pTmp = pStart->pData; - Item *pDel = pStart; - pStart = pStart->pNext; - delete pDel; - nSize--; - - mOperate.unlock(); - return pTmp; - } - } - - /** - * Checks to see if the queue has data in it or not. Note that there - * is no function to determine the length of the queue. This data - * isn't kept track of. If you really need to know, fix this. - *@returns True if the queue is empty, false if it has data in it. - */ - bool isEmpty() - { - mOperate.lock(); - bool bEmpty = (pStart == NULL ); - mOperate.unlock(); - - return bEmpty; - } - - long getSize() - { - mOperate.lock(); - long nRet = nSize; - mOperate.unlock(); - - return nRet; - } - - private: - Item *pStart; /**< The start of the queue, the next element to dequeue. */ - Item *pEnd; /**< The end of the queue, the last element to dequeue. */ - long nSize; /**< The number of items in the queue. */ - - Mutex mOperate; /**< The master mutex, used on all operations. */ - Condition cBlock; /**< The condition for blocking dequeues. */ - }; -} - -#endif diff --git a/src/itoserver.h b/src/itoserver.h index 75b3349..b1f5479 100644 --- a/src/itoserver.h +++ b/src/itoserver.h @@ -18,7 +18,7 @@ #include "bu/list.h" #include "bu/thread.h" #include "bu/mutex.h" -#include "bu/itoqueue.h" +#include "bu/synchroqueue.h" #include "bu/set.h" #include "bu/clientlink.h" @@ -82,7 +82,7 @@ namespace Bu int nTimeoutSec, int nTimeoutUSec ); virtual ~ItoClient(); - typedef ItoQueue StringQueue; + typedef SynchroQueue StringQueue; StringQueue qMsg; protected: @@ -129,7 +129,7 @@ namespace Bu typedef Hash ServerHash; ServerHash hServers; typedef Hash ClientHash; - typedef ItoQueue ClientQueue; + typedef SynchroQueue ClientQueue; ClientHash hClients; ClientQueue qClientCleanup; Mutex imClients; diff --git a/src/synchroatom.h b/src/synchroatom.h new file mode 100644 index 0000000..fb02054 --- /dev/null +++ b/src/synchroatom.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_SYNCHRO_ATOM_H +#define BU_SYNCHRO_ATOM_H + +#include + +#include "bu/mutex.h" + +namespace Bu +{ + /** + * A thread-safe wrapper class. + *@ingroup Threading + */ + template + class SynchroAtom + { + public: + /** + * Construct an empty queue. + */ + SynchroAtom() + { + } + + SynchroAtom( const T &src ) : + data( src ) + { + } + + ~SynchroAtom() + { + } + + T get() + { + mOperate.lock(); + T ret = data; + mOperate.unlock(); + return ret; + } + + void set( const T &val ) + { + mOperate.lock(); + data = val; + mOperate.unlock(); + } + + private: + T data; + + Mutex mOperate; /**< The master mutex, used on all operations. */ + }; +}; + +#endif diff --git a/src/synchrocounter.cpp b/src/synchrocounter.cpp new file mode 100644 index 0000000..48bbe21 --- /dev/null +++ b/src/synchrocounter.cpp @@ -0,0 +1,8 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/synchrocounter.h" diff --git a/src/synchrocounter.h b/src/synchrocounter.h new file mode 100644 index 0000000..d201bee --- /dev/null +++ b/src/synchrocounter.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_SYNCHRO_COUNTER_H +#define BU_SYNCHRO_COUNTER_H + +#include "bu/mutex.h" + +namespace Bu +{ + /** + * A simple thread-safe counter class. This is handy for assigning unique + * IDs to objects that are being created in different threads. + *@ingroup Threading Containers + */ + template + class SynchroCounter + { + public: + SynchroCounter() : + tCounter( 0 ) + { + } + + virtual ~SynchroCounter() + { + } + + T next() + { + mOperate.lock(); + T tRet = tCounter; + tCounter++; + mOperate.unlock(); + + return tRet; + } + + private: + T tCounter; /**< The counter itself. */ + Mutex mOperate; /**< The master mutex, used on all operations. */ + }; +} + +#endif diff --git a/src/synchroheap.cpp b/src/synchroheap.cpp new file mode 100644 index 0000000..5dcce33 --- /dev/null +++ b/src/synchroheap.cpp @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/synchroheap.h" + diff --git a/src/synchroheap.h b/src/synchroheap.h new file mode 100644 index 0000000..4dd898d --- /dev/null +++ b/src/synchroheap.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_SYNCHRO_HEAP_H +#define BU_SYNCHRO_HEAP_H + +#include "bu/heap.h" +#include "bu/mutex.h" +#include "bu/condition.h" + +namespace Bu +{ + template, + typename itemalloc=std::allocator > + class SynchroHeap + { + public: + SynchroHeap() + { + } + + virtual ~SynchroHeap() + { + } + + void enqueue( item i ) + { + imData.lock(); + hData.enqueue( i ); + icBlock.signal(); + imData.unlock(); + } + + item dequeue( bool bBlock=false ) + { + imData.lock(); + if( hData.isEmpty() ) + { + imData.unlock(); + + if( bBlock ) + { + icBlock.lock(); + + while( hData.isEmpty() ) + icBlock.wait(); + + imData.lock(); + try + { + item iRet = hData.dequeue(); + imData.unlock(); + icBlock.unlock(); + return iRet; + } + catch(...) + { + imData.unlock(); + icBlock.unlock(); + throw; + } + } + throw HeapException("Heap empty."); + } + else + { + try + { + item iRet = hData.dequeue(); + imData.unlock(); + return iRet; + } + catch(...) + { + imData.unlock(); + throw; + } + } + } + + item dequeue( int iSec, int iUSec ) + { + imData.lock(); + if( hData.isEmpty() ) + { + imData.unlock(); + + icBlock.lock(); + + icBlock.wait( iSec, iUSec ); + + imData.lock(); + try + { + item iRet = hData.dequeue(); + imData.unlock(); + icBlock.unlock(); + return iRet; + } + catch(...) + { + imData.unlock(); + icBlock.unlock(); + throw; + } + } + else + { + try + { + item iRet = hData.dequeue(); + imData.unlock(); + return iRet; + } + catch(...) + { + imData.unlock(); + throw; + } + } + } + + bool isEmpty() + { + imData.lock(); + bool bRet = hData.isEmpty(); + imData.unlock(); + return bRet; + } + + int getSize() + { + imData.lock(); + int iRet = hData.getSize(); + imData.unlock(); + return iRet; + } + + private: + Heap< item, cmpfunc, itemalloc > hData; + Mutex imData; + Condition icBlock; + }; +}; + +#endif + diff --git a/src/synchroqueue.h b/src/synchroqueue.h new file mode 100644 index 0000000..79d5e49 --- /dev/null +++ b/src/synchroqueue.h @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_SYNCHRO_QUEUE_H +#define BU_SYNCHRO_QUEUE_H + +#include + +#include "bu/mutex.h" +#include "bu/condition.h" + +namespace Bu +{ + /** + * A thread-safe queue class. This class is a very simple queue with some + * cool extra functionality for use with the Synchro system. The main extra + * that it provides is the option to either dequeue without blocking, with + * infinite blocking, or with timed blocking, which will return a value if + * something is enqueued within the specified time limit, or NULL if the + * time limit is exceded. + *@ingroup Threading Containers + */ + template + class SynchroQueue + { + private: + /** + * Helper struct. Keeps track of linked-list items for the queue data. + */ + typedef struct Item + { + T pData; + Item *pNext; + } Item; + + public: + /** + * Construct an empty queue. + */ + SynchroQueue() : + pStart( NULL ), + pEnd( NULL ), + nSize( 0 ) + { + } + + /** + * Destroy the queue. This function will simply free all contained + * structures. If you stored pointers in the queue, this will lose the + * pointers without cleaning up the memory they pointed to. Make sure + * you're queue is empty before allowing it to be destroyed! + */ + ~SynchroQueue() + { + Item *pCur = pStart; + while( pCur ) + { + Item *pTmp = pCur->pNext; + delete pCur; + pCur = pTmp; + } + } + + /** + * Enqueue a pieces of data. The new data will go at the end of the + * queue, and unless another piece of data is enqueued, will be the + * last piece of data to be dequeued. + *@param pData The data to enqueue. If this is not a primitive data + * type it's probably best to use a pointer type. + */ + void enqueue( T pData ) + { + mOperate.lock(); + + if( pStart == NULL ) + { + pStart = pEnd = new Item; + pStart->pData = pData; + pStart->pNext = NULL; + nSize++; + } + else + { + pEnd->pNext = new Item; + pEnd = pEnd->pNext; + pEnd->pData = pData; + pEnd->pNext = NULL; + nSize++; + } + + cBlock.signal(); + + mOperate.unlock(); + } + + /** + * Dequeue the first item from the queue. This function can operate in + * two different modes, blocking and non-blocking. In non-blocking + * mode it will return immediately weather there was data in the queue + * or not. If there was data it will remove it from the queue and + * return it to the caller. + * + * In blocking mode it will block forever wating for data to be + * enqueued. When data finally is enqueued this function will return + * immediately with the new data. The only way this function should + * ever return a null in blocking mode is if the calling thread was + * cancelled. It's probably a good idea to check for NULL return + * values even if you use blocking, just to be on the safe side. + *@param bBlock Set to true to enable blocking, leave as false to work + * in non-blocking mode. + *@returns The next piece of data in the queue, or NULL if no data was + * in the queue. + */ + T dequeue( bool bBlock=false ) + { + mOperate.lock(); + if( pStart == NULL ) + { + mOperate.unlock(); + + if( bBlock ) + { + cBlock.lock(); + + while( pStart == NULL ) + cBlock.wait(); + + T tmp = dequeue( false ); + + cBlock.unlock(); + return tmp; + + } + + return NULL; + } + else + { + T pTmp = pStart->pData; + Item *pDel = pStart; + pStart = pStart->pNext; + delete pDel; + nSize--; + + mOperate.unlock(); + return pTmp; + } + } + + /** + * Operates just like the other dequeue function in blocking mode with + * one twist. This function will block for at most nSec seconds and + * nUSec micro-seconds. If the timer is up and no data is available, + * this will just return NULL. If data is enqueued before the timeout + * expires, it will dequeue and exit immediately. + *@param nSec The number of seconds to wait, max. + *@param nUSec The number of micro-seconds to wait, max. + *@returns The next piece of data in the queue, or NULL if the timeout + * was exceeded. + */ + T dequeue( int nSec, int nUSec ) + { + mOperate.lock(); + if( pStart == NULL ) + { + mOperate.unlock(); + + cBlock.lock(); + + cBlock.wait( nSec, nUSec ); + + if( pStart == NULL ) + { + cBlock.unlock(); + return NULL; + } + + mOperate.lock(); + T pTmp = pStart->pData; + Item *pDel = pStart; + pStart = pStart->pNext; + delete pDel; + nSize--; + mOperate.unlock(); + + cBlock.unlock(); + return pTmp; + } + else + { + T pTmp = pStart->pData; + Item *pDel = pStart; + pStart = pStart->pNext; + delete pDel; + nSize--; + + mOperate.unlock(); + return pTmp; + } + } + + /** + * Checks to see if the queue has data in it or not. Note that there + * is no function to determine the length of the queue. This data + * isn't kept track of. If you really need to know, fix this. + *@returns True if the queue is empty, false if it has data in it. + */ + bool isEmpty() + { + mOperate.lock(); + bool bEmpty = (pStart == NULL ); + mOperate.unlock(); + + return bEmpty; + } + + long getSize() + { + mOperate.lock(); + long nRet = nSize; + mOperate.unlock(); + + return nRet; + } + + private: + Item *pStart; /**< The start of the queue, the next element to dequeue. */ + Item *pEnd; /**< The end of the queue, the last element to dequeue. */ + long nSize; /**< The number of items in the queue. */ + + Mutex mOperate; /**< The master mutex, used on all operations. */ + Condition cBlock; /**< The condition for blocking dequeues. */ + }; +} + +#endif diff --git a/src/tests/deflate.cpp b/src/tests/deflate.cpp new file mode 100644 index 0000000..9796408 --- /dev/null +++ b/src/tests/deflate.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/deflate.h" +#include "bu/file.h" + +int main( int argc, char *argv[] ) +{ + if( argc < 3 ) + { + printf("usage: %s \n", argv[0] ); + return -1; + } + + char buf[1024]; + size_t nRead; + + /* + Bu::File fin( argv[1], Bu::File::Read ); + fin.seek( 4 ); + Bu::Deflate def( fin ); + + Bu::File f( argv[2], Bu::File::WriteNew ); + + for(;;) + { + nRead = def.read( buf, 1024 ); + if( nRead > 0 ) + f.write( buf, nRead ); + if( def.isEos() ) + break; + } + */ + + Bu::File fin( argv[1], Bu::File::Read ); + + Bu::File f( argv[2], Bu::File::WriteNew ); + Bu::Deflate def( f, 9, Bu::Deflate::Gzip ); + + for(;;) + { + nRead = fin.read( buf, 1024 ); + if( nRead > 0 ) + def.write( buf, nRead ); + if( fin.isEos() ) + break; + } +} + -- cgit v1.2.3 From 27c2cbbbc0ed1e1b38274261c33b0427f976f22c Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 23 Oct 2011 17:08:48 +0000 Subject: The strfilter.h header has been added, it gives you one call filter access on strings. encodeStr( str ) and decodeStr( str ). It's pretty cool, try it out :) --- default.bld | 2 +- src/strfilter.h | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/string.h | 2 +- 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 src/strfilter.h (limited to 'src') diff --git a/default.bld b/default.bld index 6666fe2..1b6eb4d 100644 --- a/default.bld +++ b/default.bld @@ -162,7 +162,7 @@ target files("src/tests/*.cpp").replace("src/","").replace(".cpp","") // Some tests need extra libs and whatnot, that goes here. -target ["tests/bzip2", "tests/streamstack"] +target ["tests/bzip2", "tests/streamstack", "tests/enc"] { LDFLAGS += "-lbz2"; } diff --git a/src/strfilter.h b/src/strfilter.h new file mode 100644 index 0000000..8da0a3f --- /dev/null +++ b/src/strfilter.h @@ -0,0 +1,124 @@ +#ifndef STR_FILTER_H +#define STR_FILTER_H + +#include "bu/string.h" +#include "bu/membuf.h" + +namespace Bu +{ + // + // Encoders + // + template + Bu::String encodeStr( const Bu::String &sIn ) + { + Bu::MemBuf mb; + { + tFilter fEnc( mb ); + fEnc.write( sIn.getStr(), sIn.getSize() ); + } + return mb.getString(); + } + + template + Bu::String encodeStr( const Bu::String &sIn, p1t p1 ) + { + Bu::MemBuf mb; + { + tFilter fEnc( mb, p1 ); + fEnc.write( sIn.getStr(), sIn.getSize() ); + } + return mb.getString(); + } + + template + Bu::String encodeStr( const Bu::String &sIn, p1t p1, p2t p2 ) + { + Bu::MemBuf mb; + { + tFilter fEnc( mb, p1, p2 ); + fEnc.write( sIn.getStr(), sIn.getSize() ); + } + return mb.getString(); + } + + template + Bu::String encodeStr( const Bu::String &sIn, p1t p1, p2t p2, p3t p3 ) + { + Bu::MemBuf mb; + { + tFilter fEnc( mb, p1, p2 ); + fEnc.write( sIn.getStr(), sIn.getSize() ); + } + return mb.getString(); + } + + // + // Decoders + // + template + Bu::String decodeStr( const Bu::String &sIn ) + { + Bu::MemBuf mb( sIn ); + tFilter fDec( mb ); + char buf[1024]; + String sRet; + for(;;) + { + int iRead = fDec.read( buf, 1024 ); + if( iRead == 0 ) + return sRet; + sRet.append( buf, iRead ); + } + } + + template + Bu::String decodeStr( const Bu::String &sIn, p1t p1 ) + { + Bu::MemBuf mb( sIn ); + tFilter fDec( mb, p1 ); + char buf[1024]; + String sRet; + for(;;) + { + int iRead = fDec.read( buf, 1024 ); + if( iRead == 0 ) + return sRet; + sRet.append( buf, iRead ); + } + } + + template + Bu::String decodeStr( const Bu::String &sIn, p1t p1, p2t p2 ) + { + Bu::MemBuf mb( sIn ); + tFilter fDec( mb, p1, p2 ); + char buf[1024]; + String sRet; + for(;;) + { + int iRead = fDec.read( buf, 1024 ); + if( iRead == 0 ) + return sRet; + sRet.append( buf, iRead ); + } + } + + template + Bu::String decodeStr( const Bu::String &sIn, p1t p1, p2t p2, p3t p3 ) + { + Bu::MemBuf mb( sIn ); + tFilter fDec( mb, p1, p2, p3 ); + char buf[1024]; + String sRet; + for(;;) + { + int iRead = fDec.read( buf, 1024 ); + if( iRead == 0 ) + return sRet; + sRet.append( buf, iRead ); + } + } +}; + +#endif diff --git a/src/string.h b/src/string.h index 2874e37..a9006d1 100644 --- a/src/string.h +++ b/src/string.h @@ -18,12 +18,12 @@ #include "bu/list.h" #include "bu/fmt.h" #include "bu/variant.h" - #include namespace Bu { class String; + class MemBuf; /** @cond DEVEL */ class StringCore -- cgit v1.2.3 From e2fbc414b932ae9fd305c8e9fc315a306a876a09 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 24 Oct 2011 16:19:09 +0000 Subject: Lzma filter added. Now we're really getting somewhere. Libbu++ now supports all major, common compression algorithms. --- default.bld | 5 ++ src/deflate.h | 2 +- src/lzma.cpp | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lzma.h | 56 ++++++++++++ src/tests/lzma.cpp | 53 ++++++++++++ 5 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 src/lzma.cpp create mode 100644 src/lzma.h create mode 100644 src/tests/lzma.cpp (limited to 'src') diff --git a/default.bld b/default.bld index 1b6eb4d..18a2d72 100644 --- a/default.bld +++ b/default.bld @@ -172,6 +172,11 @@ target ["tests/deflate"] LDFLAGS += "-lz"; } +target ["tests/lzma"] +{ + LDFLAGS += "-llzma"; +} + target ["tests/itoserver", "tests/socketblock", "tests/itoheap", "tests/itoqueue1", "tests/itoqueue2", "tests/conduit"] { diff --git a/src/deflate.h b/src/deflate.h index cab9b51..8ce283b 100644 --- a/src/deflate.h +++ b/src/deflate.h @@ -34,7 +34,7 @@ namespace Bu AutoGzip = 0x04|0x03 }; - Deflate( Bu::Stream &rNext, int nCompression=9, Format eFmt=AutoRaw ); + Deflate( Bu::Stream &rNext, int nCompression=-1, Format eFmt=AutoRaw ); virtual ~Deflate(); virtual void start(); diff --git a/src/lzma.cpp b/src/lzma.cpp new file mode 100644 index 0000000..6ed0806 --- /dev/null +++ b/src/lzma.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/lzma.h" +#include "bu/trace.h" + +#include + +#define pState ((lzma_stream *)prState) + +using namespace Bu; + +Bu::Lzma::Lzma( Bu::Stream &rNext, int nCompression, Format eFmt ) : + Bu::Filter( rNext ), + prState( NULL ), + nCompression( nCompression ), + sTotalOut( 0 ), + eFmt( eFmt ), + bEos( false ) +{ + TRACE( nCompression ); + start(); +} + +Bu::Lzma::~Lzma() +{ + TRACE(); + stop(); +} + +void Bu::Lzma::start() +{ + TRACE(); + nBufSize = 64*1024; + pBuf = new char[nBufSize]; +} + +Bu::size Bu::Lzma::stop() +{ + TRACE(); + if( pState ) + { + if( bReading ) + { + lzma_end( pState ); + delete[] pBuf; + pBuf = NULL; + delete pState; + prState = NULL; + return 0; + } + else + { + for(;;) + { + pState->next_in = NULL; + pState->avail_in = 0; + pState->avail_out = nBufSize; + pState->next_out = (uint8_t *)pBuf; + int res = lzma_code( pState, LZMA_FINISH ); + if( pState->avail_out < nBufSize ) + { + sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); + } + if( res == LZMA_STREAM_END ) + break; + } + lzma_end( pState ); + delete[] pBuf; + pBuf = NULL; + delete pState; + prState = NULL; + return sTotalOut; + } + } + return 0; +} + +void Bu::Lzma::lzmaError( int code ) +{ + TRACE( code ); + switch( code ) + { + case LZMA_OK: + case LZMA_STREAM_END: + case LZMA_NO_CHECK: + case LZMA_UNSUPPORTED_CHECK: + break; + + case LZMA_MEM_ERROR: + throw ExceptionBase("Lzma: Memory allocation error."); + + case LZMA_MEMLIMIT_ERROR: + throw ExceptionBase("Lzma: Memory usage limit was reached."); + + case LZMA_FORMAT_ERROR: + throw ExceptionBase("Lzma: File format not recognized."); + + case LZMA_OPTIONS_ERROR: + throw ExceptionBase("Lzma: Invalid or unsupported options."); + + case LZMA_DATA_ERROR: + throw ExceptionBase("Lzma: Data is corrupt."); + + case LZMA_BUF_ERROR: + throw ExceptionBase("Lzma: No progress is possible."); + + case LZMA_PROG_ERROR: + throw ExceptionBase("Lzma: Programming error."); + + default: + throw ExceptionBase("Lzma: Unknown error encountered." ); + } +} + +Bu::size Bu::Lzma::read( void *pData, Bu::size nBytes ) +{ + TRACE( pData, nBytes ); + if( !pState ) + { + prState = new ::lzma_stream; + lzma_stream zEmpty = LZMA_STREAM_INIT; + Bu::memcpy( prState, &zEmpty, sizeof(lzma_stream) ); + + bReading = true; + lzmaError( lzma_auto_decoder( pState, UINT64_MAX, 0 ) ); + pState->next_in = (uint8_t *)pBuf; + pState->avail_in = 0; + } + if( bReading == false ) + throw ExceptionBase("This lzma filter is in writing mode, you can't read."); + + int nRead = 0; + int nReadTotal = pState->total_out; + pState->next_out = (uint8_t *)pData; + pState->avail_out = nBytes; + for(;;) + { + int ret = lzma_code( pState, LZMA_RUN ); + printf("inflate returned %d; avail in=%d, out=%d\n", ret, + pState->avail_in, pState->avail_out ); + + nReadTotal += nRead-pState->avail_out; + + if( ret == LZMA_STREAM_END ) + { + bEos = true; + if( pState->avail_in > 0 ) + { + if( rNext.isSeekable() ) + { + rNext.seek( -pState->avail_in ); + } + } + return nBytes-pState->avail_out; + } +// if( ret != LZMA_BUF_ERROR ) + lzmaError( ret ); + + if( pState->avail_out ) + { + if( pState->avail_in == 0 ) + { + nRead = rNext.read( pBuf, nBufSize ); + if( nRead == 0 && rNext.isEos() ) + { + throw Bu::ExceptionBase("Premature end of underlying " + "stream found reading deflate stream."); + } + pState->next_in = (uint8_t *)pBuf; + pState->avail_in = nRead; + } + } + else + { + return nBytes-pState->avail_out; + } + } + return 0; +} + +Bu::size Bu::Lzma::write( const void *pData, Bu::size nBytes ) +{ + TRACE( pData, nBytes ); + if( !pState ) + { + prState = new ::lzma_stream; + lzma_stream zEmpty = LZMA_STREAM_INIT; + Bu::memcpy( prState, &zEmpty, sizeof(lzma_stream) ); + + bReading = false; + if( eFmt == Xz ) + lzmaError( + lzma_easy_encoder( pState, nCompression, LZMA_CHECK_CRC64 ) + ); + else if( eFmt == LzmaAlone ) + { + lzma_options_lzma opt; + lzma_lzma_preset( &opt, nCompression ); + lzmaError( lzma_alone_encoder( pState, &opt ) ); + } + else + throw Bu::ExceptionBase("Invalid format for lzma."); + } + if( bReading == true ) + throw ExceptionBase("This lzma filter is in reading mode, you can't write."); + + pState->next_in = (uint8_t *)pData; + pState->avail_in = nBytes; + for(;;) + { + pState->avail_out = nBufSize; + pState->next_out = (uint8_t *)pBuf; + + lzmaError( lzma_code( pState, LZMA_RUN ) ); + + if( pState->avail_out < nBufSize ) + { + sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); + } + if( pState->avail_in == 0 ) + break; + } + + return nBytes; +} + +bool Bu::Lzma::isOpen() +{ + TRACE(); + return (pState != NULL); +} + +bool Bu::Lzma::isEos() +{ + TRACE(); + return bEos; +} + +Bu::size Bu::Lzma::getCompressedSize() +{ + return sTotalOut; +} + diff --git a/src/lzma.h b/src/lzma.h new file mode 100644 index 0000000..21da6e8 --- /dev/null +++ b/src/lzma.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_LZMA_H +#define BU_LZMA_H + +#include + +#include "bu/filter.h" + +namespace Bu +{ + /** + * + *@ingroup Streams + */ + class Lzma : public Bu::Filter + { + public: + enum Format + { + Xz = 0x01, + LzmaAlone = 0x02, + }; + + Lzma( Bu::Stream &rNext, int nCompression=6, Format eFmt=Xz ); + virtual ~Lzma(); + + virtual void start(); + virtual Bu::size stop(); + virtual Bu::size read( void *pBuf, Bu::size nBytes ); + virtual Bu::size write( const void *pBuf, Bu::size nBytes ); + + virtual bool isOpen(); + virtual bool isEos(); + + Bu::size getCompressedSize(); + + private: + void lzmaError( int code ); + void *prState; + bool bReading; + int nCompression; + char *pBuf; + uint32_t nBufSize; + Bu::size sTotalOut; + Format eFmt; + bool bEos; + }; +} + +#endif diff --git a/src/tests/lzma.cpp b/src/tests/lzma.cpp new file mode 100644 index 0000000..752357a --- /dev/null +++ b/src/tests/lzma.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/lzma.h" +#include "bu/file.h" + +int main( int argc, char *argv[] ) +{ + if( argc < 3 ) + { + printf("usage: %s \n", argv[0] ); + return -1; + } + + char buf[1024]; + size_t nRead; + + /* + Bu::File fin( argv[1], Bu::File::Read ); + fin.seek( 4 ); + Bu::Deflate def( fin ); + + Bu::File f( argv[2], Bu::File::WriteNew ); + + for(;;) + { + nRead = def.read( buf, 1024 ); + if( nRead > 0 ) + f.write( buf, nRead ); + if( def.isEos() ) + break; + } + */ + + Bu::File fin( argv[1], Bu::File::Read ); + + Bu::File f( argv[2], Bu::File::WriteNew ); + Bu::Lzma def( f, 9 ); + + for(;;) + { + nRead = fin.read( buf, 1024 ); + if( nRead > 0 ) + def.write( buf, nRead ); + if( fin.isEos() ) + break; + } +} + -- cgit v1.2.3 From 9cb2695ad318dcda83a353b03c21b4fd71d0f9d6 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 24 Oct 2011 16:30:39 +0000 Subject: Made the encoder state opaque to the caller in Deflate and BZip2 to match Lzma. That means that when you use Bu::Deflate, Bu::Bzip2, or Bu::Lzma you don't get any of the respective libraries' header files. --- src/bzip2.cpp | 95 ++++++++++++++++++++++++-------------------- src/bzip2.h | 3 +- src/deflate.cpp | 120 ++++++++++++++++++++++++++++++-------------------------- src/deflate.h | 3 +- 4 files changed, 120 insertions(+), 101 deletions(-) (limited to 'src') diff --git a/src/bzip2.cpp b/src/bzip2.cpp index 0ff5444..ca007b0 100644 --- a/src/bzip2.cpp +++ b/src/bzip2.cpp @@ -8,10 +8,15 @@ #include "bu/bzip2.h" #include "bu/trace.h" +#include + +#define pState ((bz_stream *)prState) + using namespace Bu; Bu::BZip2::BZip2( Bu::Stream &rNext, int nCompression ) : Bu::Filter( rNext ), + prState( NULL ), nCompression( nCompression ), sTotalOut( 0 ) { @@ -28,10 +33,12 @@ Bu::BZip2::~BZip2() void Bu::BZip2::start() { TRACE(); - bzState.state = NULL; - bzState.bzalloc = NULL; - bzState.bzfree = NULL; - bzState.opaque = NULL; + + prState = new bz_stream; + pState->state = NULL; + pState->bzalloc = NULL; + pState->bzfree = NULL; + pState->opaque = NULL; nBufSize = 64*1024; pBuf = new char[nBufSize]; @@ -40,13 +47,15 @@ void Bu::BZip2::start() Bu::size Bu::BZip2::stop() { TRACE(); - if( bzState.state ) + if( pState->state ) { if( bReading ) { - BZ2_bzDecompressEnd( &bzState ); + BZ2_bzDecompressEnd( pState ); delete[] pBuf; pBuf = NULL; + delete pState; + prState = NULL; return 0; } else @@ -54,21 +63,23 @@ Bu::size Bu::BZip2::stop() // Bu::size sTotal = 0; for(;;) { - bzState.next_in = NULL; - bzState.avail_in = 0; - bzState.avail_out = nBufSize; - bzState.next_out = pBuf; - int res = BZ2_bzCompress( &bzState, BZ_FINISH ); - if( bzState.avail_out < nBufSize ) + pState->next_in = NULL; + pState->avail_in = 0; + pState->avail_out = nBufSize; + pState->next_out = pBuf; + int res = BZ2_bzCompress( pState, BZ_FINISH ); + if( pState->avail_out < nBufSize ) { - sTotalOut += rNext.write( pBuf, nBufSize-bzState.avail_out ); + sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); } if( res == BZ_STREAM_END ) break; } - BZ2_bzCompressEnd( &bzState ); + BZ2_bzCompressEnd( pState ); delete[] pBuf; pBuf = NULL; + delete pState; + prState = NULL; return sTotalOut; } } @@ -122,42 +133,42 @@ void Bu::BZip2::bzError( int code ) Bu::size Bu::BZip2::read( void *pData, Bu::size nBytes ) { TRACE( pData, nBytes ); - if( !bzState.state ) + if( !pState->state ) { bReading = true; - BZ2_bzDecompressInit( &bzState, 0, 0 ); - bzState.next_in = pBuf; - bzState.avail_in = 0; + BZ2_bzDecompressInit( pState, 0, 0 ); + pState->next_in = pBuf; + pState->avail_in = 0; } if( bReading == false ) throw ExceptionBase("This bzip2 filter is in writing mode, you can't read."); int nRead = 0; - int nReadTotal = bzState.total_out_lo32; - bzState.next_out = (char *)pData; - bzState.avail_out = nBytes; + int nReadTotal = pState->total_out_lo32; + pState->next_out = (char *)pData; + pState->avail_out = nBytes; for(;;) { - int ret = BZ2_bzDecompress( &bzState ); + int ret = BZ2_bzDecompress( pState ); - nReadTotal += nRead-bzState.avail_out; + nReadTotal += nRead-pState->avail_out; if( ret == BZ_STREAM_END ) { - if( bzState.avail_in > 0 ) + if( pState->avail_in > 0 ) { if( rNext.isSeekable() ) { - rNext.seek( -bzState.avail_in ); + rNext.seek( -pState->avail_in ); } } - return nBytes-bzState.avail_out; + return nBytes-pState->avail_out; } bzError( ret ); - if( bzState.avail_out ) + if( pState->avail_out ) { - if( bzState.avail_in == 0 ) + if( pState->avail_in == 0 ) { nRead = rNext.read( pBuf, nBufSize ); if( nRead == 0 && rNext.isEos() ) @@ -165,13 +176,13 @@ Bu::size Bu::BZip2::read( void *pData, Bu::size nBytes ) throw Bu::ExceptionBase("Premature end of underlying " "stream found reading bzip2 stream."); } - bzState.next_in = pBuf; - bzState.avail_in = nRead; + pState->next_in = pBuf; + pState->avail_in = nRead; } } else { - return nBytes-bzState.avail_out; + return nBytes-pState->avail_out; } } return 0; @@ -180,29 +191,29 @@ Bu::size Bu::BZip2::read( void *pData, Bu::size nBytes ) Bu::size Bu::BZip2::write( const void *pData, Bu::size nBytes ) { TRACE( pData, nBytes ); - if( !bzState.state ) + if( !pState->state ) { bReading = false; - BZ2_bzCompressInit( &bzState, nCompression, 0, 30 ); + BZ2_bzCompressInit( pState, nCompression, 0, 30 ); } if( bReading == true ) throw ExceptionBase("This bzip2 filter is in reading mode, you can't write."); // Bu::size sTotalOut = 0; - bzState.next_in = (char *)pData; - bzState.avail_in = nBytes; + pState->next_in = (char *)pData; + pState->avail_in = nBytes; for(;;) { - bzState.avail_out = nBufSize; - bzState.next_out = pBuf; + pState->avail_out = nBufSize; + pState->next_out = pBuf; - bzError( BZ2_bzCompress( &bzState, BZ_RUN ) ); + bzError( BZ2_bzCompress( pState, BZ_RUN ) ); - if( bzState.avail_out < nBufSize ) + if( pState->avail_out < nBufSize ) { - sTotalOut += rNext.write( pBuf, nBufSize-bzState.avail_out ); + sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); } - if( bzState.avail_in == 0 ) + if( pState->avail_in == 0 ) break; } @@ -212,7 +223,7 @@ Bu::size Bu::BZip2::write( const void *pData, Bu::size nBytes ) bool Bu::BZip2::isOpen() { TRACE(); - return (bzState.state != NULL); + return (pState->state != NULL); } Bu::size Bu::BZip2::getCompressedSize() diff --git a/src/bzip2.h b/src/bzip2.h index 6da3dff..0b5140d 100644 --- a/src/bzip2.h +++ b/src/bzip2.h @@ -9,7 +9,6 @@ #define BU_BZIP2_H #include -#include #include "bu/filter.h" @@ -36,7 +35,7 @@ namespace Bu private: void bzError( int code ); - bz_stream bzState; + void *prState; bool bReading; int nCompression; char *pBuf; diff --git a/src/deflate.cpp b/src/deflate.cpp index aec2a18..10a9c5f 100644 --- a/src/deflate.cpp +++ b/src/deflate.cpp @@ -8,10 +8,15 @@ #include "bu/deflate.h" #include "bu/trace.h" +#include + +#define pState ((z_stream *)prState) + using namespace Bu; Bu::Deflate::Deflate( Bu::Stream &rNext, int nCompression, Format eFmt ) : Bu::Filter( rNext ), + prState( NULL ), nCompression( nCompression ), sTotalOut( 0 ), eFmt( eFmt ), @@ -30,10 +35,11 @@ Bu::Deflate::~Deflate() void Bu::Deflate::start() { TRACE(); - zState.zalloc = NULL; - zState.zfree = NULL; - zState.opaque = NULL; - zState.state = NULL; + prState = new z_stream; + pState->zalloc = NULL; + pState->zfree = NULL; + pState->opaque = NULL; + pState->state = NULL; nBufSize = 64*1024; pBuf = new char[nBufSize]; @@ -42,34 +48,38 @@ void Bu::Deflate::start() Bu::size Bu::Deflate::stop() { TRACE(); - if( zState.state ) + if( pState && pState->state ) { if( bReading ) { - inflateEnd( &zState ); + inflateEnd( pState ); delete[] pBuf; pBuf = NULL; + delete pState; + prState = NULL; return 0; } else { for(;;) { - zState.next_in = NULL; - zState.avail_in = 0; - zState.avail_out = nBufSize; - zState.next_out = (Bytef *)pBuf; - int res = deflate( &zState, Z_FINISH ); - if( zState.avail_out < nBufSize ) + pState->next_in = NULL; + pState->avail_in = 0; + pState->avail_out = nBufSize; + pState->next_out = (Bytef *)pBuf; + int res = deflate( pState, Z_FINISH ); + if( pState->avail_out < nBufSize ) { - sTotalOut += rNext.write( pBuf, nBufSize-zState.avail_out ); + sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); } if( res == Z_STREAM_END ) break; } - deflateEnd( &zState ); + deflateEnd( pState ); delete[] pBuf; pBuf = NULL; + delete pState; + prState = NULL; return sTotalOut; } } @@ -87,25 +97,25 @@ void Bu::Deflate::zError( int code ) return; case Z_ERRNO: - throw ExceptionBase("Deflate: Errno - %s", zState.msg ); + throw ExceptionBase("Deflate: Errno - %s", pState->msg ); case Z_STREAM_ERROR: - throw ExceptionBase("Deflate: Stream Error - %s", zState.msg ); + throw ExceptionBase("Deflate: Stream Error - %s", pState->msg ); case Z_DATA_ERROR: - throw ExceptionBase("Deflate: Data Error - %s", zState.msg ); + throw ExceptionBase("Deflate: Data Error - %s", pState->msg ); case Z_MEM_ERROR: - throw ExceptionBase("Deflate: Mem Error - %s", zState.msg ); + throw ExceptionBase("Deflate: Mem Error - %s", pState->msg ); case Z_BUF_ERROR: - throw ExceptionBase("Deflate: Buf Error - %s", zState.msg ); + throw ExceptionBase("Deflate: Buf Error - %s", pState->msg ); case Z_VERSION_ERROR: - throw ExceptionBase("Deflate: Version Error - %s", zState.msg ); + throw ExceptionBase("Deflate: Version Error - %s", pState->msg ); default: - throw ExceptionBase("Deflate: Unknown error encountered - %s.", zState.msg ); + throw ExceptionBase("Deflate: Unknown error encountered - %s.", pState->msg ); } } @@ -113,55 +123,55 @@ void Bu::Deflate::zError( int code ) Bu::size Bu::Deflate::read( void *pData, Bu::size nBytes ) { TRACE( pData, nBytes ); - if( !zState.state ) + if( !pState->state ) { bReading = true; if( eFmt&AutoDetect ) - inflateInit2( &zState, 32+15 ); // Auto-detect, large window + inflateInit2( pState, 32+15 ); // Auto-detect, large window else if( eFmt == Raw ) - inflateInit2( &zState, -15 ); // Raw + inflateInit2( pState, -15 ); // Raw else if( eFmt == Zlib ) - inflateInit2( &zState, 15 ); // Zlib + inflateInit2( pState, 15 ); // Zlib else if( eFmt == Gzip ) - inflateInit2( &zState, 16+15 ); // GZip + inflateInit2( pState, 16+15 ); // GZip else throw Bu::ExceptionBase("Format mode for deflate read."); - zState.next_in = (Bytef *)pBuf; - zState.avail_in = 0; + pState->next_in = (Bytef *)pBuf; + pState->avail_in = 0; } if( bReading == false ) throw ExceptionBase("This deflate filter is in writing mode, you can't read."); int nRead = 0; - int nReadTotal = zState.total_out; - zState.next_out = (Bytef *)pData; - zState.avail_out = nBytes; + int nReadTotal = pState->total_out; + pState->next_out = (Bytef *)pData; + pState->avail_out = nBytes; for(;;) { - int ret = inflate( &zState, Z_NO_FLUSH ); + int ret = inflate( pState, Z_NO_FLUSH ); printf("inflate returned %d; avail in=%d, out=%d\n", ret, - zState.avail_in, zState.avail_out ); + pState->avail_in, pState->avail_out ); - nReadTotal += nRead-zState.avail_out; + nReadTotal += nRead-pState->avail_out; if( ret == Z_STREAM_END ) { bEos = true; - if( zState.avail_in > 0 ) + if( pState->avail_in > 0 ) { if( rNext.isSeekable() ) { - rNext.seek( -zState.avail_in ); + rNext.seek( -pState->avail_in ); } } - return nBytes-zState.avail_out; + return nBytes-pState->avail_out; } if( ret != Z_BUF_ERROR ) zError( ret ); - if( zState.avail_out ) + if( pState->avail_out ) { - if( zState.avail_in == 0 ) + if( pState->avail_in == 0 ) { nRead = rNext.read( pBuf, nBufSize ); if( nRead == 0 && rNext.isEos() ) @@ -169,13 +179,13 @@ Bu::size Bu::Deflate::read( void *pData, Bu::size nBytes ) throw Bu::ExceptionBase("Premature end of underlying " "stream found reading deflate stream."); } - zState.next_in = (Bytef *)pBuf; - zState.avail_in = nRead; + pState->next_in = (Bytef *)pBuf; + pState->avail_in = nRead; } } else { - return nBytes-zState.avail_out; + return nBytes-pState->avail_out; } } return 0; @@ -184,18 +194,18 @@ Bu::size Bu::Deflate::read( void *pData, Bu::size nBytes ) Bu::size Bu::Deflate::write( const void *pData, Bu::size nBytes ) { TRACE( pData, nBytes ); - if( !zState.state ) + if( !pState->state ) { bReading = false; int iFmt = eFmt&Gzip; if( iFmt == Raw ) - deflateInit2( &zState, nCompression, Z_DEFLATED, -15, 9, + deflateInit2( pState, nCompression, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY ); else if( iFmt == Zlib ) - deflateInit2( &zState, nCompression, Z_DEFLATED, 15, 9, + deflateInit2( pState, nCompression, Z_DEFLATED, 15, 9, Z_DEFAULT_STRATEGY ); else if( iFmt == Gzip ) - deflateInit2( &zState, nCompression, Z_DEFLATED, 16+15, 9, + deflateInit2( pState, nCompression, Z_DEFLATED, 16+15, 9, Z_DEFAULT_STRATEGY ); else throw Bu::ExceptionBase("Invalid format for deflate."); @@ -203,20 +213,20 @@ Bu::size Bu::Deflate::write( const void *pData, Bu::size nBytes ) if( bReading == true ) throw ExceptionBase("This deflate filter is in reading mode, you can't write."); - zState.next_in = (Bytef *)pData; - zState.avail_in = nBytes; + pState->next_in = (Bytef *)pData; + pState->avail_in = nBytes; for(;;) { - zState.avail_out = nBufSize; - zState.next_out = (Bytef *)pBuf; + pState->avail_out = nBufSize; + pState->next_out = (Bytef *)pBuf; - zError( deflate( &zState, Z_NO_FLUSH ) ); + zError( deflate( pState, Z_NO_FLUSH ) ); - if( zState.avail_out < nBufSize ) + if( pState->avail_out < nBufSize ) { - sTotalOut += rNext.write( pBuf, nBufSize-zState.avail_out ); + sTotalOut += rNext.write( pBuf, nBufSize-pState->avail_out ); } - if( zState.avail_in == 0 ) + if( pState->avail_in == 0 ) break; } @@ -226,7 +236,7 @@ Bu::size Bu::Deflate::write( const void *pData, Bu::size nBytes ) bool Bu::Deflate::isOpen() { TRACE(); - return (zState.state != NULL); + return (pState != NULL && pState->state != NULL); } bool Bu::Deflate::isEos() diff --git a/src/deflate.h b/src/deflate.h index 8ce283b..20d609a 100644 --- a/src/deflate.h +++ b/src/deflate.h @@ -9,7 +9,6 @@ #define BU_DEFLATE_H #include -#include #include "bu/filter.h" @@ -49,7 +48,7 @@ namespace Bu private: void zError( int code ); - z_stream zState; + void *prState; bool bReading; int nCompression; char *pBuf; -- cgit v1.2.3 From 2f163b90c745491a995dfdbe78464c64a536ec54 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Mon, 24 Oct 2011 16:42:22 +0000 Subject: Added some more docs. --- src/bzip2.h | 2 ++ src/deflate.h | 4 ++++ src/doxy/groups.dox | 5 +++++ src/lzma.h | 3 +++ 4 files changed, 14 insertions(+) (limited to 'src') diff --git a/src/bzip2.h b/src/bzip2.h index 0b5140d..9a8d172 100644 --- a/src/bzip2.h +++ b/src/bzip2.h @@ -15,8 +15,10 @@ namespace Bu { /** + * Provides BZip2 type compression and decompression. * *@ingroup Streams + *@ingroup Compression */ class BZip2 : public Bu::Filter { diff --git a/src/deflate.h b/src/deflate.h index 20d609a..34e8657 100644 --- a/src/deflate.h +++ b/src/deflate.h @@ -15,8 +15,12 @@ namespace Bu { /** + * Provides Deflate (LZ77) support via zlib. This provides zlib, raw, and + * gzip stream types. By default it will autodetect the input type and + * encode into a raw deflate stream. * *@ingroup Streams + *@ingroup Compression */ class Deflate : public Bu::Filter { diff --git a/src/doxy/groups.dox b/src/doxy/groups.dox index 479186a..6b7cd57 100644 --- a/src/doxy/groups.dox +++ b/src/doxy/groups.dox @@ -29,3 +29,8 @@ *@defgroup Streams Streams * Streams are for data. */ + +/** + *@defgroup Compression Compression + * Filters that give access to common compression libraries. + */ diff --git a/src/lzma.h b/src/lzma.h index 21da6e8..090da8d 100644 --- a/src/lzma.h +++ b/src/lzma.h @@ -15,8 +15,11 @@ namespace Bu { /** + * Provides XZ compression and decompression, both LZMA1 (LzmaAlone) as + * well as the newer LZMA2 (xz) format. This uses .xz by default. * *@ingroup Streams + *@ingroup Compression */ class Lzma : public Bu::Filter { -- cgit v1.2.3 From b3adc199b6fbf3460d709934de5d92668d75a6cf Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 25 Oct 2011 05:40:33 +0000 Subject: Bu::print and Bu::println are added, they just take a string, but you can use string formatting no problem. I'll add some that can take unicode strings too. --- src/sio.cpp | 23 +++++++++++++++++++++++ src/sio.h | 6 ++++++ 2 files changed, 29 insertions(+) (limited to 'src') diff --git a/src/sio.cpp b/src/sio.cpp index 0fe60d9..5f8e234 100644 --- a/src/sio.cpp +++ b/src/sio.cpp @@ -10,3 +10,26 @@ Bu::StdStream Bu::sioRaw; Bu::Formatter Bu::sio( Bu::sioRaw ); +Bu::size Bu::print( Bu::Stream &s, const Bu::String &str ) +{ + return s.write( str.getStr(), str.getSize() ); +} + +Bu::size Bu::print( const Bu::String &str ) +{ + return print( sioRaw, str ); +} + +Bu::size Bu::println( Bu::Stream &s, const Bu::String &str ) +{ + Bu::size sRet = s.write( str.getStr(), str.getSize() ); + sRet += s.write("\n", 1 ); + s.flush(); + return sRet; +} + +Bu::size Bu::println( const Bu::String &str ) +{ + return println( sioRaw, str ); +} + diff --git a/src/sio.h b/src/sio.h index ad3000a..9f2cd05 100644 --- a/src/sio.h +++ b/src/sio.h @@ -15,6 +15,12 @@ namespace Bu { extern Bu::StdStream sioRaw; extern Bu::Formatter sio; + + Bu::size print( Bu::Stream &s, const Bu::String &str ); + Bu::size print( const Bu::String &str ); + + Bu::size println( Bu::Stream &s, const Bu::String &str ); + Bu::size println( const Bu::String &str ); }; #endif -- cgit v1.2.3 From 7c9cf28012f65ce6a67651030b817d7d45eda62b Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 25 Oct 2011 15:11:32 +0000 Subject: Fixed bug in base64 decoding. If an attempt is made to read data after the end of the stream has been reached, and the input didn't end with '=' chars then it would return the final buffer an extra time before ending. Now it ends when it should, no matter how many extra times you try to read. --- src/base64.cpp | 2 ++ src/unit/base64.unit | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/unit/base64.unit (limited to 'src') diff --git a/src/base64.cpp b/src/base64.cpp index 18a18e5..04ca009 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -118,6 +118,8 @@ Bu::size Bu::Base64::read( void *pBuf, Bu::size nBytes ) { if( rNext.isEos() ) { + if( iRPos == 0 ) + iRPos = iChars; bEosIn = true; if( j != 0 ) { diff --git a/src/unit/base64.unit b/src/unit/base64.unit new file mode 100644 index 0000000..e4630c5 --- /dev/null +++ b/src/unit/base64.unit @@ -0,0 +1,28 @@ +// vim: syntax=cpp +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/strfilter.h" +#include "bu/base64.h" + +suite MemBuf +{ + test decode01 + { + unitTest( Bu::decodeStr("RnVu") == "Fun" ); + unitTest( Bu::decodeStr("V2hhdA==") == "What" ); + unitTest( Bu::decodeStr("SGVsbG8=") == "Hello" ); + } + + test encode01 + { + unitTest( Bu::decodeStr("R n V u") == "Fun" ); + unitTest( Bu::decodeStr("V2\n\n\thh dA==") == "What" ); + unitTest( Bu::decodeStr("\n\n\t\t SGV\r\ns\tbG8\n=") == "Hello" ); + } +} + -- cgit v1.2.3 From 052da60c2c5c4ce80ec0986ea07482348e7aa30a Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 25 Oct 2011 16:04:43 +0000 Subject: Base64 does line wrapping correctly on write, and also doesn't try to flush the write buffer when reading is done. It's...strange, but yeah, it was doing that. Deflate also defaults to zlib compression now, which means you can compress & decompress without using any extra params. Turns out zlib auto-detect won't decompress raw streams, so this is the safest overall option, and the easiest to work with. zlib headers are small, and includes a crc at the end so you can be sure your data is accurate, raw does not. --- default.bld | 4 ++-- src/base64.cpp | 45 +++++++++++++++++++++++++++++++++++++-------- src/base64.h | 4 +++- src/deflate.cpp | 3 --- src/deflate.h | 2 +- 5 files changed, 43 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/default.bld b/default.bld index 18a2d72..130c1a2 100644 --- a/default.bld +++ b/default.bld @@ -162,12 +162,12 @@ target files("src/tests/*.cpp").replace("src/","").replace(".cpp","") // Some tests need extra libs and whatnot, that goes here. -target ["tests/bzip2", "tests/streamstack", "tests/enc"] +target ["tests/bzip2", "tests/streamstack"] { LDFLAGS += "-lbz2"; } -target ["tests/deflate"] +target ["tests/deflate", "tests/enc"] { LDFLAGS += "-lz"; } diff --git a/src/base64.cpp b/src/base64.cpp index 04ca009..4d659f0 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -13,7 +13,7 @@ const char Bu::Base64::tblEnc[65] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" }; -Bu::Base64::Base64( Bu::Stream &rNext ) : +Bu::Base64::Base64( Bu::Stream &rNext, int iChunkSize ) : Bu::Filter( rNext ), iBPos( 0 ), iBuf( 0 ), @@ -22,7 +22,9 @@ Bu::Base64::Base64( Bu::Stream &rNext ) : bEosIn( false ), iTotalIn( 0 ), iTotalOut( 0 ), - eMode( Nothing ) + eMode( Nothing ), + iChunkSize( iChunkSize ), + iCurChunk( 0 ) { start(); @@ -62,11 +64,12 @@ Bu::Base64::~Base64() void Bu::Base64::start() { + iCurChunk = 0; } Bu::size Bu::Base64::stop() { -// if( eMode |= Encode ) + if( eMode == Encode ) { char outBuf[4]; int iBUsed = 4-(3-iBPos); @@ -80,17 +83,30 @@ Bu::size Bu::Base64::stop() { outBuf[k] = '='; } - iTotalOut += rNext.write( outBuf, 4 ); + iCurChunk += 4; + if( iChunkSize && iCurChunk >= iChunkSize ) + { + iCurChunk = iCurChunk-iChunkSize; + iTotalOut += rNext.write( outBuf, 4-iCurChunk ); + iTotalOut += rNext.write("\r\n", 2 ); + iTotalOut += rNext.write( outBuf+(4-iCurChunk), iCurChunk ); + } + else + iTotalOut += rNext.write( outBuf, 4 ); return iTotalOut; } -// else -// { + else + { return iTotalIn; -// } + } } Bu::size Bu::Base64::read( void *pBuf, Bu::size nBytes ) { + if( eMode == Encode ) + throw Bu::Base64Exception("Cannot read from an output stream."); + eMode = Decode; + if( bEosIn == true && iRPos == iChars ) return 0; Bu::size sIn = 0; @@ -157,6 +173,10 @@ Bu::size Bu::Base64::read( void *pBuf, Bu::size nBytes ) Bu::size Bu::Base64::write( const void *pBuf, Bu::size nBytes ) { + if( eMode == Decode ) + throw Bu::Base64Exception("Cannot write to an input stream."); + eMode = Encode; + Bu::size sOut = 0; char outBuf[4]; for( Bu::size j = 0; j < nBytes; j++ ) @@ -168,7 +188,16 @@ Bu::size Bu::Base64::write( const void *pBuf, Bu::size nBytes ) { outBuf[3-k] = tblEnc[(iBuf>>(6*k))&0x3f]; } - sOut += rNext.write( outBuf, 4 ); + iCurChunk += 4; + if( iChunkSize && iCurChunk >= iChunkSize ) + { + iCurChunk = iCurChunk-iChunkSize; + sOut += rNext.write( outBuf, 4-iCurChunk ); + sOut += rNext.write("\r\n", 2 ); + sOut += rNext.write( outBuf+(4-iCurChunk), iCurChunk ); + } + else + sOut += rNext.write( outBuf, 4 ); iBPos = iBuf = 0; } } diff --git a/src/base64.h b/src/base64.h index 53d7860..c081ac1 100644 --- a/src/base64.h +++ b/src/base64.h @@ -22,7 +22,7 @@ namespace Bu class Base64 : public Bu::Filter { public: - Base64( Bu::Stream &rNext ); + Base64( Bu::Stream &rNext, int iChunkSize=0 ); virtual ~Base64(); virtual void start(); @@ -51,6 +51,8 @@ namespace Bu Decode = 0x02, }; Mode eMode; + int iChunkSize; + int iCurChunk; }; }; diff --git a/src/deflate.cpp b/src/deflate.cpp index 10a9c5f..2d925a7 100644 --- a/src/deflate.cpp +++ b/src/deflate.cpp @@ -149,9 +149,6 @@ Bu::size Bu::Deflate::read( void *pData, Bu::size nBytes ) for(;;) { int ret = inflate( pState, Z_NO_FLUSH ); - printf("inflate returned %d; avail in=%d, out=%d\n", ret, - pState->avail_in, pState->avail_out ); - nReadTotal += nRead-pState->avail_out; if( ret == Z_STREAM_END ) diff --git a/src/deflate.h b/src/deflate.h index 34e8657..f835cfc 100644 --- a/src/deflate.h +++ b/src/deflate.h @@ -37,7 +37,7 @@ namespace Bu AutoGzip = 0x04|0x03 }; - Deflate( Bu::Stream &rNext, int nCompression=-1, Format eFmt=AutoRaw ); + Deflate( Bu::Stream &rNext, int nCompression=-1, Format eFmt=AutoZlib ); virtual ~Deflate(); virtual void start(); -- cgit v1.2.3 From b57332230fb39c38ae1806348dbc4cd6c725d5db Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 26 Oct 2011 15:57:52 +0000 Subject: Virtual deconstructor! --- src/sha1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/sha1.h b/src/sha1.h index 579d990..1b7f6df 100644 --- a/src/sha1.h +++ b/src/sha1.h @@ -23,7 +23,7 @@ namespace Bu { public: Sha1(); - ~Sha1(); + virtual ~Sha1(); virtual void reset(); virtual void setSalt( const Bu::String &sSalt ); -- cgit v1.2.3 From 029b5d159023f4dad607359dbfaa2479e21fe9e5 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 27 Oct 2011 04:01:46 +0000 Subject: Added simple hex encoder/decoder filter. --- src/hex.cpp | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/hex.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 src/hex.cpp create mode 100644 src/hex.h (limited to 'src') diff --git a/src/hex.cpp b/src/hex.cpp new file mode 100644 index 0000000..2a04c6f --- /dev/null +++ b/src/hex.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include "bu/hex.h" + +Bu::Hex::Hex( Bu::Stream &rNext, bool bUpperCase, int iChunk ) : + Bu::Filter( rNext ), + iChunk( iChunk ), + iPos( 0 ), + iIn( 0 ), + sChrs(bUpperCase?"0123456789ABCDEF":"0123456789abcdef") +{ +} + +Bu::Hex::~Hex() +{ +} + +void Bu::Hex::start() +{ + iPos = iIn = 0; +} + +Bu::size Bu::Hex::stop() +{ + return iPos; +} + +Bu::size Bu::Hex::read( void *pBuf, Bu::size iBytes ) +{ + Bu::size j; + uint8_t *puBuf = (uint8_t *)pBuf; + for( j = 0; j < iBytes; j++ ) + { + for(; iIn < 2; iIn++ ) + { + if( rNext.read( &cIn[iIn], 1 ) == 0 ) + return j; + if( cIn[iIn] == ' ' || cIn[iIn] == '\t' || + cIn[iIn] == '\n' || cIn[iIn] == '\r' ) + iIn--; + } +#define chr2nibble( c ) ((c>='0'&&c<='9')?(c-'0'):((c|0x60)-'a'+10)) + puBuf[j] = ((chr2nibble(cIn[0])<<4)|chr2nibble(cIn[1])); + iIn = 0; + } + return j; +} + +Bu::size Bu::Hex::write( const void *pBuf, Bu::size iBytes ) +{ + char cOut[2]; + uint8_t *puBuf = (uint8_t *)pBuf; + for( Bu::size j = 0; j < iBytes; j++ ) + { + cOut[0] = sChrs[(puBuf[j]&0xf0)>>4]; + cOut[1] = sChrs[(puBuf[j]&0x0f)]; + if( iChunk > 0 && iPos%iChunk == 0 && iPos>0 ) + rNext.write(" ", 1 ); + rNext.write( cOut, 2 ); + iPos++; + } + return iBytes; +} + diff --git a/src/hex.h b/src/hex.h new file mode 100644 index 0000000..3595fae --- /dev/null +++ b/src/hex.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2007-2011 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_HEX_H +#define BU_HEX_H + +#include "bu/filter.h" + +namespace Bu +{ + /** + * This very simple filter encodes to/decodes from hex encoded string data. + * The primary use of this filter is in debugging, use it with + * Bu::encodeStr to easily create hex dumps of string data, even other raw + * structures. + * + *@code + Bu::println("Hexdump: " + Bu::encodeStr("Test data ;)") ); + @endcode + * Or... + *@code + complex_struct data; + ... + Bu::println("Hexdump: " + + Bu::encodeStr( + Bu::String( &data, sizeof(data) ) + ) + ); + @endcode + **/ + class Hex : public Bu::Filter + { + public: + Hex( Bu::Stream &rNext, bool bUpperCase=false, int iChunk=-1 ); + virtual ~Hex(); + + virtual void start(); + virtual Bu::size stop(); + + virtual Bu::size read( void *pBuf, Bu::size iBytes ); + virtual Bu::size write( const void *pBuf, Bu::size iBytes ); + using Bu::Stream::write; + + private: + int iChunk; + Bu::size iPos; + char cIn[2]; + int iIn; + const char *sChrs; + }; +}; + +#endif -- cgit v1.2.3