summaryrefslogtreecommitdiff
path: root/lib/common
diff options
context:
space:
mode:
Diffstat (limited to 'lib/common')
-rwxr-xr-xlib/common/BannerText.h17
-rw-r--r--lib/common/BeginStructPackForWire.h23
-rwxr-xr-xlib/common/Box.h180
-rwxr-xr-xlib/common/BoxException.cpp21
-rwxr-xr-xlib/common/BoxException.h37
-rwxr-xr-xlib/common/BoxPlatform.h236
-rwxr-xr-xlib/common/BoxPortsAndFiles.h31
-rwxr-xr-xlib/common/BoxTime.cpp32
-rwxr-xr-xlib/common/BoxTime.h44
-rwxr-xr-xlib/common/BoxTimeToText.cpp41
-rwxr-xr-xlib/common/BoxTimeToText.h19
-rwxr-xr-xlib/common/BoxTimeToUnix.h30
-rwxr-xr-xlib/common/CollectInBufferStream.cpp274
-rwxr-xr-xlib/common/CollectInBufferStream.h60
-rwxr-xr-xlib/common/CommonException.h17
-rw-r--r--lib/common/CommonException.txt44
-rwxr-xr-xlib/common/Configuration.cpp741
-rwxr-xr-xlib/common/Configuration.h98
-rw-r--r--lib/common/Conversion.h98
-rw-r--r--lib/common/ConversionException.txt8
-rw-r--r--lib/common/ConversionString.cpp123
-rwxr-xr-xlib/common/DebugAssertFailed.cpp32
-rwxr-xr-xlib/common/DebugMemLeakFinder.cpp377
-rwxr-xr-xlib/common/DebugPrintf.cpp72
-rw-r--r--lib/common/EndStructPackForWire.h23
-rw-r--r--lib/common/EventWatchFilesystemObject.cpp99
-rw-r--r--lib/common/EventWatchFilesystemObject.h48
-rwxr-xr-xlib/common/ExcludeList.cpp219
-rwxr-xr-xlib/common/ExcludeList.h65
-rwxr-xr-xlib/common/FdGetLine.cpp211
-rwxr-xr-xlib/common/FdGetLine.h61
-rwxr-xr-xlib/common/FileModificationTime.h57
-rwxr-xr-xlib/common/FileStream.cpp245
-rwxr-xr-xlib/common/FileStream.h46
-rwxr-xr-xlib/common/Guards.h112
-rwxr-xr-xlib/common/IOStream.cpp229
-rwxr-xr-xlib/common/IOStream.h67
-rwxr-xr-xlib/common/IOStreamGetLine.cpp227
-rwxr-xr-xlib/common/IOStreamGetLine.h71
-rwxr-xr-xlib/common/LinuxWorkaround.cpp73
-rwxr-xr-xlib/common/LinuxWorkaround.h20
-rwxr-xr-xlib/common/MainHelper.h42
-rwxr-xr-xlib/common/Makefile.extra11
-rwxr-xr-xlib/common/MemBlockStream.cpp235
-rwxr-xr-xlib/common/MemBlockStream.h52
-rwxr-xr-xlib/common/MemLeakFindOff.h27
-rwxr-xr-xlib/common/MemLeakFindOn.h25
-rwxr-xr-xlib/common/MemLeakFinder.h60
-rwxr-xr-xlib/common/NamedLock.cpp144
-rwxr-xr-xlib/common/NamedLock.h41
-rwxr-xr-xlib/common/PartialReadStream.cpp135
-rwxr-xr-xlib/common/PartialReadStream.h46
-rwxr-xr-xlib/common/ReadGatherStream.cpp262
-rwxr-xr-xlib/common/ReadGatherStream.h67
-rwxr-xr-xlib/common/StreamableMemBlock.cpp365
-rwxr-xr-xlib/common/StreamableMemBlock.h71
-rwxr-xr-xlib/common/TemporaryDirectory.h26
-rwxr-xr-xlib/common/Test.h165
-rwxr-xr-xlib/common/UnixUser.cpp121
-rwxr-xr-xlib/common/UnixUser.h37
-rwxr-xr-xlib/common/Utils.cpp159
-rwxr-xr-xlib/common/Utils.h36
-rw-r--r--lib/common/WaitForEvent.cpp194
-rw-r--r--lib/common/WaitForEvent.h146
-rwxr-xr-xlib/common/makeexception.pl277
65 files changed, 7272 insertions, 0 deletions
diff --git a/lib/common/BannerText.h b/lib/common/BannerText.h
new file mode 100755
index 00000000..8c471171
--- /dev/null
+++ b/lib/common/BannerText.h
@@ -0,0 +1,17 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BannerText.h
+// Purpose: Banner text for daemons and utilities
+// Created: 1/1/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef BANNERTEXT__H
+#define BANNERTEXT__H
+
+#define BANNER_TEXT(UtilityName) \
+ "Box " UtilityName " v" BOX_VERSION ", (c) Ben Summers 2003, 2004\n"
+
+#endif // BANNERTEXT__H
+
diff --git a/lib/common/BeginStructPackForWire.h b/lib/common/BeginStructPackForWire.h
new file mode 100644
index 00000000..f9f8f616
--- /dev/null
+++ b/lib/common/BeginStructPackForWire.h
@@ -0,0 +1,23 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BeginStructPackForWire.h
+// Purpose: Begin structure packing for wire
+// Created: 25/11/03
+//
+// --------------------------------------------------------------------------
+
+// No header guard -- this is intentional
+
+#ifdef STRUCTURE_PATCKING_FOR_WIRE_USE_HEADERS
+
+#pragma pack(1)
+
+#else
+
+ logical error -- check BoxPlatform.h and including file
+
+#endif
+
+
+
diff --git a/lib/common/Box.h b/lib/common/Box.h
new file mode 100755
index 00000000..19e78ada
--- /dev/null
+++ b/lib/common/Box.h
@@ -0,0 +1,180 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Box.h
+// Purpose: Main header file for the Box project
+// Created: 2003/07/08
+//
+// --------------------------------------------------------------------------
+
+#ifndef BOX__H
+#define BOX__H
+
+// Use the same changes as gcc3 for gcc4
+#ifdef PLATFORM_GCC4
+ #define PLATFORM_GCC3
+#endif
+
+#include "BoxPlatform.h"
+
+// uncomment this line to enable full memory leak finding on all malloc-ed blocks (at least, ones used by the STL)
+//#define MEMLEAKFINDER_FULL_MALLOC_MONITORING
+
+#ifndef NDEBUG
+ // not available on OpenBSD... oh well.
+ //#define SHOW_BACKTRACE_ON_EXCEPTION
+#endif
+
+#ifdef SHOW_BACKTRACE_ON_EXCEPTION
+ // include "Utils.h"
+ #define OPTIONAL_DO_BACKTRACE DumpStackBacktrace();
+#else
+ #define OPTIONAL_DO_BACKTRACE
+#endif
+
+#include "CommonException.h"
+
+#ifndef NDEBUG
+
+ extern bool AssertFailuresToSyslog;
+ #define ASSERT_FAILS_TO_SYSLOG_ON {AssertFailuresToSyslog = true;}
+ void BoxDebugAssertFailed(char *cond, char *file, int line);
+ #define ASSERT(cond) {if(!(cond)) {BoxDebugAssertFailed(#cond, __FILE__, __LINE__); THROW_EXCEPTION(CommonException, AssertFailed)}}
+
+ // Note that syslog tracing is independent of BoxDebugTraceOn, but stdout tracing is not
+ extern bool BoxDebugTraceToSyslog;
+ #define TRACE_TO_SYSLOG(x) {BoxDebugTraceToSyslog = x;}
+ extern bool BoxDebugTraceToStdout;
+ #define TRACE_TO_STDOUT(x) {BoxDebugTraceToStdout = x;}
+
+ extern bool BoxDebugTraceOn;
+ int BoxDebug_printf(const char *format, ...);
+ int BoxDebugTrace(const char *format, ...);
+ #define TRACE0(msg) {BoxDebugTrace("%s", msg);}
+ #define TRACE1(msg, a0) {BoxDebugTrace(msg, a0);}
+ #define TRACE2(msg, a0, a1) {BoxDebugTrace(msg, a0, a1);}
+ #define TRACE3(msg, a0, a1, a2) {BoxDebugTrace(msg, a0, a1, a2);}
+ #define TRACE4(msg, a0, a1, a2, a3) {BoxDebugTrace(msg, a0, a1, a2, a3);}
+ #define TRACE5(msg, a0, a1, a2, a3, a4) {BoxDebugTrace(msg, a0, a1, a2, a3, a4);}
+ #define TRACE6(msg, a0, a1, a2, a3, a4, a5) {BoxDebugTrace(msg, a0, a1, a2, a3, a4, a5);}
+ #define TRACE7(msg, a0, a1, a2, a3, a4, a5, a6) {BoxDebugTrace(msg, a0, a1, a2, a3, a4, a5, a6);}
+ #define TRACE8(msg, a0, a1, a2, a3, a4, a5, a6, a7) {BoxDebugTrace(msg, a0, a1, a2, a3, a4, a5, a6, a7);}
+
+ #ifndef PLATFORM_DISABLE_MEM_LEAK_TESTING
+ #define BOX_MEMORY_LEAK_TESTING
+ #endif
+
+ // Exception names
+ #define EXCEPTION_CODENAMES_EXTENDED
+
+#else
+ #define ASSERT_FAILS_TO_SYSLOG_ON
+ #define ASSERT(cond)
+
+ #define TRACE_TO_SYSLOG(x) {}
+ #define TRACE_TO_STDOUT(x) {}
+
+ #define TRACE0(msg)
+ #define TRACE1(msg, a0)
+ #define TRACE2(msg, a0, a1)
+ #define TRACE3(msg, a0, a1, a2)
+ #define TRACE4(msg, a0, a1, a2, a3)
+ #define TRACE5(msg, a0, a1, a2, a3, a4)
+ #define TRACE6(msg, a0, a1, a2, a3, a4, a5)
+ #define TRACE7(msg, a0, a1, a2, a3, a4, a5, a6)
+ #define TRACE8(msg, a0, a1, a2, a3, a4, a5, a6, a7)
+
+ // Box Backup builds release get extra information for exception logging
+ #define EXCEPTION_CODENAMES_EXTENDED
+ #define EXCEPTION_CODENAMES_EXTENDED_WITH_DESCRIPTION
+
+#endif
+
+#ifdef BOX_MEMORY_LEAK_TESTING
+ // Memory leak testing
+ #include "MemLeakFinder.h"
+ #define MEMLEAKFINDER_NOT_A_LEAK(x) memleakfinder_notaleak(x);
+ #define MEMLEAKFINDER_START {memleakfinder_global_enable = true;}
+ #define MEMLEAKFINDER_STOP {memleakfinder_global_enable = false;}
+#else
+ #define DEBUG_NEW new
+ #define MEMLEAKFINDER_NOT_A_LEAK(x)
+ #define MEMLEAKFINDER_START
+ #define MEMLEAKFINDER_STOP
+#endif
+
+
+#define THROW_EXCEPTION(type, subtype) \
+ { \
+ OPTIONAL_DO_BACKTRACE \
+ TRACE1("Exception thrown: " #type "(" #subtype ") at " __FILE__ "(%d)\n", __LINE__) \
+ throw type(type::subtype); \
+ }
+
+// extra macros for converting to network byte order
+
+// Always define a swap64 function, as it's useful.
+inline uint64_t box_swap64(uint64_t x)
+{
+ return ((x & 0xff) << 56 |
+ (x & 0xff00LL) << 40 |
+ (x & 0xff0000LL) << 24 |
+ (x & 0xff000000LL) << 8 |
+ (x & 0xff00000000LL) >> 8 |
+ (x & 0xff0000000000LL) >> 24 |
+ (x & 0xff000000000000LL) >> 40 |
+ (x & 0xff00000000000000LL) >> 56);
+}
+
+// Does the platform provide a built in SWAP64 we can use?
+#ifdef PLATFORM_NO_BUILT_IN_SWAP64
+
+ #define hton64(x) box_swap64(x)
+ #define ntoh64(x) box_swap64(x)
+
+#else
+
+ #if BYTE_ORDER == BIG_ENDIAN
+
+ // Less hassle than trying to find some working things
+ // on Darwin PPC
+ #define hton64(x) (x)
+ #define ntoh64(x) (x)
+
+ #else
+
+ #ifdef PLATFORM_LINUX
+ // On Linux, use some internal kernal stuff to do this
+ #include <asm/byteorder.h>
+ #define hton64 __cpu_to_be64
+ #define ntoh64 __be64_to_cpu
+ #else
+ #define hton64 htobe64
+ #define ntoh64 betoh64
+ #endif
+
+ // hack to make some of these work
+ // version in /usr/include/sys/endian.h doesn't include the 'LL' at the end of the constants
+ // provoking complaints from the compiler
+ #ifdef __GNUC__
+ #undef __swap64gen
+ #define __swap64gen(x) __extension__({ \
+ u_int64_t __swap64gen_x = (x); \
+ \
+ (u_int64_t)((__swap64gen_x & 0xff) << 56 | \
+ (__swap64gen_x & 0xff00LL) << 40 | \
+ (__swap64gen_x & 0xff0000LL) << 24 | \
+ (__swap64gen_x & 0xff000000LL) << 8 | \
+ (__swap64gen_x & 0xff00000000LL) >> 8 | \
+ (__swap64gen_x & 0xff0000000000LL) >> 24 | \
+ (__swap64gen_x & 0xff000000000000LL) >> 40 | \
+ (__swap64gen_x & 0xff00000000000000LL) >> 56); \
+ })
+ #endif // __GNUC__
+
+ #endif // n BYTE_ORDER == BIG_ENDIAN
+
+#endif // PLATFORM_NO_BUILT_IN_SWAP64
+
+#endif // BOX__H
+
diff --git a/lib/common/BoxException.cpp b/lib/common/BoxException.cpp
new file mode 100755
index 00000000..2503ca63
--- /dev/null
+++ b/lib/common/BoxException.cpp
@@ -0,0 +1,21 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BoxException.cpp
+// Purpose: Exception
+// Created: 2003/07/10
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "BoxException.h"
+
+#include "MemLeakFindOn.h"
+
+BoxException::BoxException()
+{
+}
+
+BoxException::~BoxException() throw ()
+{
+}
diff --git a/lib/common/BoxException.h b/lib/common/BoxException.h
new file mode 100755
index 00000000..eb992f57
--- /dev/null
+++ b/lib/common/BoxException.h
@@ -0,0 +1,37 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BoxException.h
+// Purpose: Exception
+// Created: 2003/07/10
+//
+// --------------------------------------------------------------------------
+
+#ifndef BOXEXCEPTION__H
+#define BOXEXCEPTION__H
+
+#include <exception>
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: BoxException
+// Purpose: Exception
+// Created: 2003/07/10
+//
+// --------------------------------------------------------------------------
+class BoxException : public std::exception
+{
+public:
+ BoxException();
+ ~BoxException() throw ();
+
+ virtual unsigned int GetType() const throw() = 0;
+ virtual unsigned int GetSubType() const throw() = 0;
+
+private:
+};
+
+
+#endif // BOXEXCEPTION__H
+
diff --git a/lib/common/BoxPlatform.h b/lib/common/BoxPlatform.h
new file mode 100755
index 00000000..716366d2
--- /dev/null
+++ b/lib/common/BoxPlatform.h
@@ -0,0 +1,236 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BoxPlatform.h
+// Purpose: Specifies what each platform supports in more detail, and includes
+// extra files to get basic support for types.
+// Created: 2003/09/06
+//
+// --------------------------------------------------------------------------
+
+#ifndef BOXPLATFORM__H
+#define BOXPLATFORM__H
+
+#define DIRECTORY_SEPARATOR "/"
+#define DIRECTORY_SEPARATOR_ASCHAR '/'
+
+#define PLATFORM_DEV_NULL "/dev/null"
+
+
+// Other flags which might be useful...
+//
+// #define PLATFORM_BERKELEY_DB_NOT_SUPPORTED
+// -- dbopen etc not on this platform
+//
+// #define PLATFORM_REGEX_NOT_SUPPORTED
+// -- regex support not available on this platform
+
+
+#ifdef PLATFORM_OPENBSD
+
+ #include <sys/types.h>
+
+ #define PLATFORM_HAVE_setproctitle
+
+ #define PLATFORM_STATIC_TEMP_DIRECTORY_NAME "/tmp"
+
+ #define PLATFORM_HAVE_getpeereid
+
+ #define PLATFORM_RANDOM_DEVICE "/dev/arandom"
+
+#endif // PLATFORM_OPENBSD
+
+#ifdef PLATFORM_NETBSD
+
+ #include <sys/types.h>
+
+ #define PLATFORM_HAVE_setproctitle
+
+ #define PLATFORM_NO_BUILT_IN_SWAP64
+
+ #define PLATFORM_STATIC_TEMP_DIRECTORY_NAME "/tmp"
+
+ #define PLATFORM_KQUEUE_NOT_SUPPORTED
+
+ #define PLATFORM_RANDOM_DEVICE "/dev/urandom"
+
+#endif
+
+#ifdef PLATFORM_FREEBSD
+
+ #include <sys/types.h>
+ #include <netinet/in.h>
+
+ #define PLATFORM_HAVE_setproctitle
+
+ #define PLATFORM_NO_BUILT_IN_SWAP64
+
+ #define PLATFORM_STATIC_TEMP_DIRECTORY_NAME "/tmp"
+
+ #define PLATFORM_HAVE_getpeereid
+
+ #define PLATFORM_RANDOM_DEVICE "/dev/urandom"
+
+#endif // PLATFORM_FREEBSD
+
+#ifdef PLATFORM_DARWIN
+
+ #include <sys/types.h>
+ #include <netdb.h>
+
+ // types 'missing'
+ #ifndef _SOCKLEN_T
+ typedef int socklen_t;
+ #endif
+ typedef u_int8_t uint8_t;
+ typedef signed char int8_t;
+ typedef u_int64_t uint64_t;
+ typedef u_int32_t uint32_t;
+ typedef u_int16_t uint16_t;
+
+ // poll() emulator on Darwin misses this declaration
+ #define INFTIM -1
+
+ #define PLATFORM_STATIC_TEMP_DIRECTORY_NAME "/tmp"
+
+ #define PLATFORM_LCHOWN_NOT_SUPPORTED
+
+ #define PLATFORM_READLINE_NOT_SUPPORTED
+
+ #define PLATFORM_RANDOM_DEVICE "/dev/random"
+
+#endif // PLATFORM_DARWIN
+
+#ifdef PLATFORM_LINUX
+
+ #include <sys/types.h>
+
+ // for ntohl etc...
+ #include <netinet/in.h>
+
+ // types 'missing'
+ typedef u_int8_t uint8_t;
+ typedef signed char int8_t;
+ typedef u_int32_t uint32_t;
+ typedef u_int16_t uint16_t;
+ typedef u_int64_t uint64_t;
+
+ // not defined in Linux, a BSD thing
+ #define INFTIM -1
+
+ #define LLONG_MAX 9223372036854775807LL
+ #define LLONG_MIN (-LLONG_MAX - 1LL)
+
+ #define PLATFORM_STATIC_TEMP_DIRECTORY_NAME "/tmp"
+
+ #define PLATFORM_HAVE_getsockopt_SO_PEERCRED
+
+ // load in installation specific linux configuration
+ #include "../../local/_linux_platform.h"
+
+ #define PLATFORM_KQUEUE_NOT_SUPPORTED
+ #define PLATFORM_dirent_BROKEN_d_type
+ #define PLATFORM_stat_SHORT_mtime
+ #define PLATFORM_stat_NO_st_flags
+ #define PLATFORM_USES_MTAB_FILE_FOR_MOUNTS
+ #define PLATFORM_open_NO_O_EXLOCK
+ #define PLATFORM_sockaddr_NO_len
+
+ #define PLATFORM_RANDOM_DEVICE "/dev/urandom"
+
+ // If large file support is on, can't do the intercepts in the test/raidfile
+ #if _FILE_OFFSET_BITS == 64
+ #define PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
+ #endif
+
+#endif // PLATFORM_LINUX
+
+#ifdef PLATFORM_CYGWIN
+
+ #define PLATFORM_BERKELEY_DB_NOT_SUPPORTED
+
+ #define PLATFORM_KQUEUE_NOT_SUPPORTED
+ #define PLATFORM_dirent_BROKEN_d_type
+ #define PLATFORM_stat_SHORT_mtime
+ #define PLATFORM_stat_NO_st_flags
+ #define PLATFORM_USES_MTAB_FILE_FOR_MOUNTS
+ #define PLATFORM_open_NO_O_EXLOCK
+ #define PLATFORM_sockaddr_NO_len
+ #define PLATFORM_NO_BUILT_IN_SWAP64
+
+ #define PLATFORM_STATIC_TEMP_DIRECTORY_NAME "/tmp"
+
+ #define PLATFORM_READLINE_NOT_SUPPORTED
+
+ #define LLONG_MAX 9223372036854775807LL
+ #define LLONG_MIN (-LLONG_MAX - 1LL)
+
+ #define INFTIM -1
+
+ // File listing canonical interesting mount points.
+ #define MNTTAB _PATH_MNTTAB
+
+ // File listing currently active mount points.
+ #define MOUNTED _PATH_MOUNTED
+
+ #define __need_FILE
+
+ // Extra includes
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <netinet/in.h>
+ #include <sys/socket.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <dirent.h>
+ #include <stdio.h>
+ #include <paths.h>
+
+ // No easy random entropy source
+ #define PLATFORM_RANDOM_DEVICE_NONE
+
+#endif // PLATFORM_CYGWIN
+
+
+// Find out if credentials on UNIX sockets can be obtained
+#ifndef PLATFORM_HAVE_getpeereid
+ #ifndef PLATFORM_HAVE_getsockopt_SO_PEERCRED
+ #define PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
+ #endif
+#endif
+
+
+// Compiler issues
+#ifdef __GNUC__
+
+ #ifdef PLATFORM_GCC3
+
+ // GCC v3 doesn't like pragmas in #defines
+ #define STRUCTURE_PATCKING_FOR_WIRE_USE_HEADERS
+
+ // But fortunately, the STL allocations are much better behaved.
+
+ #else
+
+ // Force STL to use malloc() for memory allocation
+ // -- slower, but doesn't gradually use more and more memory
+ // HOWEVER -- this 'fix' is broken on some platforms. Lots of fun!
+ #ifndef PLATFORM_STL_USE_MALLOC_BROKEN
+ #define __USE_MALLOC
+ #endif
+
+ // set packing to one bytes (can't use push/pop on gcc)
+ #define BEGIN_STRUCTURE_PACKING_FOR_WIRE #pragma pack(1)
+
+ // Use default packing
+ #define END_STRUCTURE_PACKING_FOR_WIRE #pragma pack()
+
+ #endif
+
+#else
+ compiler not supported!
+#endif
+
+
+#endif // BOXPLATFORM__H
+
diff --git a/lib/common/BoxPortsAndFiles.h b/lib/common/BoxPortsAndFiles.h
new file mode 100755
index 00000000..7788537e
--- /dev/null
+++ b/lib/common/BoxPortsAndFiles.h
@@ -0,0 +1,31 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BoxPortsAndFiles.h
+// Purpose: Central list of which tcp/ip ports and hardcoded file locations
+// Created: 2003/08/20
+//
+// --------------------------------------------------------------------------
+
+#ifndef BOXPORTSANDFILES__H
+#define BOXPORTSANDFILES__H
+
+#define BOX_PORT_BASE 2200
+
+
+// Backup store daemon
+#define BOX_PORT_BBSTORED (BOX_PORT_BASE+1)
+#define BOX_FILE_BBSTORED_DEFAULT_CONFIG "/etc/box/bbstored.conf"
+// directory within the RAIDFILE root for the backup store daemon
+#define BOX_RAIDFILE_ROOT_BBSTORED "backup"
+
+// Backup client daemon
+#define BOX_FILE_BBACKUPD_DEFAULT_CONFIG "/etc/box/bbackupd.conf"
+
+
+// RaidFile conf location efault
+#define BOX_FILE_RAIDFILE_DEFAULT_CONFIG "/etc/box/raidfile.conf"
+
+
+#endif // BOXPORTSANDFILES__H
+
diff --git a/lib/common/BoxTime.cpp b/lib/common/BoxTime.cpp
new file mode 100755
index 00000000..feada309
--- /dev/null
+++ b/lib/common/BoxTime.cpp
@@ -0,0 +1,32 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BoxTime.cpp
+// Purpose: Time for the box
+// Created: 2003/10/08
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <time.h>
+
+#include "BoxTime.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: GetCurrentBoxTime()
+// Purpose: Returns the current time as a box time. (1 sec precision)
+// Created: 2003/10/08
+//
+// --------------------------------------------------------------------------
+box_time_t GetCurrentBoxTime()
+{
+ ASSERT(sizeof(uint32_t) == sizeof(time_t));
+ return SecondsToBoxTime((uint32_t)time(0));
+}
+
+
diff --git a/lib/common/BoxTime.h b/lib/common/BoxTime.h
new file mode 100755
index 00000000..a7a25ac6
--- /dev/null
+++ b/lib/common/BoxTime.h
@@ -0,0 +1,44 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BoxTime.h
+// Purpose: How time is represented
+// Created: 2003/10/08
+//
+// --------------------------------------------------------------------------
+
+#ifndef BOXTIME__H
+#define BOXTIME__H
+
+// Time is presented as an unsigned 64 bit integer, in microseconds
+typedef uint64_t box_time_t;
+
+#define NANO_SEC_IN_SEC (1000000000LL)
+#define NANO_SEC_IN_USEC (1000)
+#define NANO_SEC_IN_USEC_LL (1000LL)
+#define MICRO_SEC_IN_SEC (1000000)
+#define MICRO_SEC_IN_SEC_LL (1000000LL)
+#define MILLI_SEC_IN_NANO_SEC (1000)
+#define MILLI_SEC_IN_NANO_SEC_LL (1000LL)
+
+box_time_t GetCurrentBoxTime();
+
+inline box_time_t SecondsToBoxTime(uint32_t Seconds)
+{
+ return ((box_time_t)Seconds * MICRO_SEC_IN_SEC_LL);
+}
+inline box_time_t SecondsToBoxTime(uint64_t Seconds)
+{
+ return ((box_time_t)Seconds * MICRO_SEC_IN_SEC_LL);
+}
+inline int64_t BoxTimeToSeconds(box_time_t Time)
+{
+ return Time / MICRO_SEC_IN_SEC_LL;
+}
+inline int64_t BoxTimeToMilliSeconds(box_time_t Time)
+{
+ return Time / MILLI_SEC_IN_NANO_SEC_LL;
+}
+
+#endif // BOXTIME__H
+
diff --git a/lib/common/BoxTimeToText.cpp b/lib/common/BoxTimeToText.cpp
new file mode 100755
index 00000000..94b0d152
--- /dev/null
+++ b/lib/common/BoxTimeToText.cpp
@@ -0,0 +1,41 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BoxTimeToText.cpp
+// Purpose: Convert box time to text
+// Created: 2003/10/10
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <sys/types.h>
+#include <time.h>
+#include <stdio.h>
+
+#include "BoxTimeToText.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BoxTimeToISO8601String(box_time_t)
+// Purpose: Convert a 64 bit box time to a ISO 8601 complient string
+// Created: 2003/10/10
+//
+// --------------------------------------------------------------------------
+std::string BoxTimeToISO8601String(box_time_t Time)
+{
+ time_t timeInSecs = (time_t)BoxTimeToSeconds(Time);
+ struct tm time;
+ gmtime_r(&timeInSecs, &time);
+
+ char str[128]; // more than enough space
+ sprintf(str, "%04d-%02d-%02dT%02d:%02d:%02d", time.tm_year + 1900,
+ time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec);
+
+ return std::string(str);
+}
+
+
diff --git a/lib/common/BoxTimeToText.h b/lib/common/BoxTimeToText.h
new file mode 100755
index 00000000..a25c70b6
--- /dev/null
+++ b/lib/common/BoxTimeToText.h
@@ -0,0 +1,19 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BoxTimeToText.h
+// Purpose: Convert box time to text
+// Created: 2003/10/10
+//
+// --------------------------------------------------------------------------
+
+#ifndef BOXTIMETOTEXT__H
+#define BOXTIMETOTEXT__H
+
+#include <string>
+#include "BoxTime.h"
+
+std::string BoxTimeToISO8601String(box_time_t Time);
+
+#endif // BOXTIMETOTEXT__H
+
diff --git a/lib/common/BoxTimeToUnix.h b/lib/common/BoxTimeToUnix.h
new file mode 100755
index 00000000..17e57e27
--- /dev/null
+++ b/lib/common/BoxTimeToUnix.h
@@ -0,0 +1,30 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: BoxTimeToUnix.h
+// Purpose: Convert times in 64 bit values to UNIX structures
+// Created: 2003/10/07
+//
+// --------------------------------------------------------------------------
+
+#ifndef FILEMODIFICATIONTIMETOTIMEVAL__H
+#define FILEMODIFICATIONTIMETOTIMEVAL__H
+
+#include <sys/time.h>
+
+#include "BoxTime.h"
+
+inline void BoxTimeToTimeval(box_time_t Time, struct timeval &tv)
+{
+ tv.tv_sec = (long)(Time / MICRO_SEC_IN_SEC_LL);
+ tv.tv_usec = (long)(Time % MICRO_SEC_IN_SEC_LL);
+}
+
+inline void BoxTimeToTimespec(box_time_t Time, struct timespec &tv)
+{
+ tv.tv_sec = (time_t)(Time / MICRO_SEC_IN_SEC_LL);
+ tv.tv_nsec = ((long)(Time % MICRO_SEC_IN_SEC_LL)) * NANO_SEC_IN_USEC;
+}
+
+#endif // FILEMODIFICATIONTIMETOTIMEVAL__H
+
diff --git a/lib/common/CollectInBufferStream.cpp b/lib/common/CollectInBufferStream.cpp
new file mode 100755
index 00000000..90e2e7bc
--- /dev/null
+++ b/lib/common/CollectInBufferStream.cpp
@@ -0,0 +1,274 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CollectInBufferStream.cpp
+// Purpose: Collect data in a buffer, and then read it out.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <string.h>
+
+#include "CollectInBufferStream.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+#define INITIAL_BUFFER_SIZE 1024
+#define MAX_BUFFER_ADDITION (1024*64)
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::CollectInBufferStream()
+// Purpose: Constructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+CollectInBufferStream::CollectInBufferStream()
+ : mBuffer(INITIAL_BUFFER_SIZE),
+ mBufferSize(INITIAL_BUFFER_SIZE),
+ mBytesInBuffer(0),
+ mReadPosition(0),
+ mInWritePhase(true)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::~CollectInBufferStream()
+// Purpose: Destructor
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+CollectInBufferStream::~CollectInBufferStream()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::Read(void *, int, int)
+// Purpose: As interface. But only works in read phase
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+int CollectInBufferStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ if(mInWritePhase != false) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
+
+ // Adjust to number of bytes left
+ if(NBytes > (mBytesInBuffer - mReadPosition))
+ {
+ NBytes = (mBytesInBuffer - mReadPosition);
+ }
+ ASSERT(NBytes >= 0);
+ if(NBytes <= 0) return 0; // careful now
+
+ // Copy in the requested number of bytes and adjust the read pointer
+ ::memcpy(pBuffer, ((char*)mBuffer) + mReadPosition, NBytes);
+ mReadPosition += NBytes;
+
+ return NBytes;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::BytesLeftToRead()
+// Purpose: As interface. But only works in read phase
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type CollectInBufferStream::BytesLeftToRead()
+{
+ if(mInWritePhase != false) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
+
+ return (mBytesInBuffer - mReadPosition);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::Write(void *, int)
+// Purpose: As interface. But only works in write phase
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void CollectInBufferStream::Write(const void *pBuffer, int NBytes)
+{
+ if(mInWritePhase != true) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
+
+ // Enough space in the buffer
+ if((mBytesInBuffer + NBytes) > mBufferSize)
+ {
+ // Need to reallocate... what's the block size we'll use?
+ int allocateBlockSize = mBufferSize;
+ if(allocateBlockSize > MAX_BUFFER_ADDITION)
+ {
+ allocateBlockSize = MAX_BUFFER_ADDITION;
+ }
+
+ // Write it the easy way. Although it's not the most efficient...
+ int newSize = mBufferSize;
+ while(newSize < (mBytesInBuffer + NBytes))
+ {
+ newSize += allocateBlockSize;
+ }
+
+ // Reallocate buffer
+ mBuffer.Resize(newSize);
+
+ // Store new size
+ mBufferSize = newSize;
+ }
+
+ // Copy in data and adjust counter
+ ::memcpy(((char*)mBuffer) + mBytesInBuffer, pBuffer, NBytes);
+ mBytesInBuffer += NBytes;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::GetPosition()
+// Purpose: In write phase, returns the number of bytes written, in read
+// phase, the number of bytes to go
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type CollectInBufferStream::GetPosition() const
+{
+ return mInWritePhase?mBytesInBuffer:mReadPosition;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::Seek(pos_type, int)
+// Purpose: As interface. But read phase only.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void CollectInBufferStream::Seek(pos_type Offset, int SeekType)
+{
+ if(mInWritePhase != false) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
+
+ int newPos = 0;
+ switch(SeekType)
+ {
+ case IOStream::SeekType_Absolute:
+ newPos = Offset;
+ break;
+ case IOStream::SeekType_Relative:
+ newPos = mReadPosition + Offset;
+ break;
+ case IOStream::SeekType_End:
+ newPos = mBytesInBuffer + Offset;
+ break;
+ default:
+ THROW_EXCEPTION(CommonException, IOStreamBadSeekType)
+ break;
+ }
+
+ // Make sure it doesn't go over
+ if(newPos > mBytesInBuffer)
+ {
+ newPos = mBytesInBuffer;
+ }
+ // or under
+ if(newPos < 0)
+ {
+ newPos = 0;
+ }
+
+ // Set the new read position
+ mReadPosition = newPos;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::StreamDataLeft()
+// Purpose: As interface
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+bool CollectInBufferStream::StreamDataLeft()
+{
+ return mInWritePhase?(false):(mReadPosition < mBytesInBuffer);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::StreamClosed()
+// Purpose: As interface
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+bool CollectInBufferStream::StreamClosed()
+{
+ return !mInWritePhase;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::SetForReading()
+// Purpose: Switch to read phase, after all data written
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void CollectInBufferStream::SetForReading()
+{
+ if(mInWritePhase != true) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
+
+ // Move to read phase
+ mInWritePhase = false;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::GetBuffer()
+// Purpose: Returns the buffer
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void *CollectInBufferStream::GetBuffer() const
+{
+ return mBuffer.GetPtr();
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::GetSize()
+// Purpose: Returns the buffer size
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+int CollectInBufferStream::GetSize() const
+{
+ return mBytesInBuffer;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: CollectInBufferStream::Reset()
+// Purpose: Reset the stream, so it is empty and ready to be written to.
+// Created: 8/12/03
+//
+// --------------------------------------------------------------------------
+void CollectInBufferStream::Reset()
+{
+ mInWritePhase = true;
+ mBytesInBuffer = 0;
+ mReadPosition = 0;
+}
+
diff --git a/lib/common/CollectInBufferStream.h b/lib/common/CollectInBufferStream.h
new file mode 100755
index 00000000..d73af8db
--- /dev/null
+++ b/lib/common/CollectInBufferStream.h
@@ -0,0 +1,60 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CollectInBufferStream.h
+// Purpose: Collect data in a buffer, and then read it out.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#ifndef COLLECTINBUFFERSTREAM__H
+#define COLLECTINBUFFERSTREAM__H
+
+#include "IOStream.h"
+#include "Guards.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: CollectInBufferStream
+// Purpose: Collect data in a buffer, and then read it out.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+class CollectInBufferStream : public IOStream
+{
+public:
+ CollectInBufferStream();
+ ~CollectInBufferStream();
+private:
+ // No copying
+ CollectInBufferStream(const CollectInBufferStream &);
+ CollectInBufferStream(const IOStream &);
+public:
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual pos_type BytesLeftToRead();
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual pos_type GetPosition() const;
+ virtual void Seek(pos_type Offset, int SeekType);
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+ void SetForReading();
+
+ void Reset();
+
+ void *GetBuffer() const;
+ int GetSize() const;
+ bool IsSetForReading() const {return !mInWritePhase;}
+
+private:
+ MemoryBlockGuard<char*> mBuffer;
+ int mBufferSize;
+ int mBytesInBuffer;
+ int mReadPosition;
+ bool mInWritePhase;
+};
+
+#endif // COLLECTINBUFFERSTREAM__H
+
diff --git a/lib/common/CommonException.h b/lib/common/CommonException.h
new file mode 100755
index 00000000..a0eb3bf5
--- /dev/null
+++ b/lib/common/CommonException.h
@@ -0,0 +1,17 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: CommonException.h
+// Purpose: Exception
+// Created: 2003/07/08
+//
+// --------------------------------------------------------------------------
+
+#ifndef COMMONEXCEPTION__H
+#define COMMONEXCEPTION__H
+
+// Compatibility header with old non-autogen exception scheme
+#include "autogen_CommonException.h"
+
+#endif // COMMONEXCEPTION__H
+
diff --git a/lib/common/CommonException.txt b/lib/common/CommonException.txt
new file mode 100644
index 00000000..3875ed71
--- /dev/null
+++ b/lib/common/CommonException.txt
@@ -0,0 +1,44 @@
+
+# NOTE: Exception descriptions are for public distributions of Box Backup only -- do not rely for other applications.
+
+
+EXCEPTION Common 1
+
+Internal 0
+AssertFailed 1
+OSFileOpenError 2 Can't open a file -- attempted to load a non-existant config file or bad file referenced within?
+OSFileCloseError 3
+FileAlreadyClosed 4
+BadArguments 5
+ConfigNoKey 6
+ConfigNoSubConfig 7
+GetLineNoHandle 8
+OSFileError 9 Error accessing a file. Check permissions.
+GetLineEOF 10
+ConfigBadIntValue 11
+GetLineTooLarge 12 Protects against very large lines using up lots of memory.
+NotSupported 13
+OSFileReadError 14
+OSFileWriteError 15
+FileClosed 16
+IOStreamBadSeekType 17
+CantWriteToPartialReadStream 18
+CollectInBufferStreamNotInCorrectPhase 19
+NamedLockAlreadyLockingSomething 20
+NamedLockNotHeld 21
+StreamableMemBlockIncompleteRead 22
+MemBlockStreamNotSupported 23
+StreamDoesntHaveRequiredProperty 24
+CannotWriteToReadGatherStream 25
+ReadGatherStreamAddingBadBlock 26
+CouldNotLookUpUsername 27
+CouldNotRestoreProcessUser 28
+CouldNotChangeProcessUser 29
+RegexNotSupportedOnThisPlatform 30 Your platform does not have built in regular expression libraries.
+BadRegularExpression 31
+CouldNotCreateKQueue 32
+KEventErrorAdd 33
+KEventErrorWait 34
+KEventErrorRemove 35
+KQueueNotSupportedOnThisPlatform 36
+IOStreamGetLineNotEnoughDataToIgnore 37 Bad value passed to IOStreamGetLine::IgnoreBufferedData()
diff --git a/lib/common/Configuration.cpp b/lib/common/Configuration.cpp
new file mode 100755
index 00000000..def93571
--- /dev/null
+++ b/lib/common/Configuration.cpp
@@ -0,0 +1,741 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Configuration.cpp
+// Purpose: Reading configuration files
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include "Configuration.h"
+#include "CommonException.h"
+#include "Guards.h"
+#include "FdGetLine.h"
+
+#include "MemLeakFindOn.h"
+
+// utility whitespace function
+inline bool iw(int c)
+{
+ return (c == ' ' || c == '\t' || c == '\v' || c == '\f'); // \r, \n are already excluded
+}
+
+// boolean values
+static const char *sValueBooleanStrings[] = {"yes", "true", "no", "false", 0};
+static const bool sValueBooleanValue[] = {true, true, false, false};
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::Configuration(const std::string &)
+// Purpose: Constructor
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+Configuration::Configuration(const std::string &rName)
+ : mName(rName)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::Configuration(const Configuration &)
+// Purpose: Copy constructor
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+Configuration::Configuration(const Configuration &rToCopy)
+ : mName(rToCopy.mName),
+ mSubConfigurations(rToCopy.mSubConfigurations),
+ mKeys(rToCopy.mKeys)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::~Configuration()
+// Purpose: Destructor
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+Configuration::~Configuration()
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::LoadAndVerify(const std::string &, const ConfigurationVerify *, std::string &)
+// Purpose: Loads a configuration file from disc, checks it. Returns NULL if it was faulting, in which
+// case they'll be an error message.
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<Configuration> Configuration::LoadAndVerify(const char *Filename, const ConfigurationVerify *pVerify, std::string &rErrorMsg)
+{
+ // Check arguments
+ if(Filename == 0)
+ {
+ THROW_EXCEPTION(CommonException, BadArguments)
+ }
+
+ // Just to make sure
+ rErrorMsg.erase();
+
+ // Open the file
+ FileHandleGuard<O_RDONLY> file(Filename);
+
+ // GetLine object
+ FdGetLine getline(file);
+
+ // Object to create
+ Configuration *pconfig = new Configuration(std::string("<root>"));
+
+ try
+ {
+ // Load
+ LoadInto(*pconfig, getline, rErrorMsg, true);
+
+ if(!rErrorMsg.empty())
+ {
+ // An error occured, return now
+ //TRACE1("Error message from LoadInto: %s", rErrorMsg.c_str());
+ TRACE0("Error at Configuration::LoadInfo\n");
+ delete pconfig;
+ pconfig = 0;
+ return std::auto_ptr<Configuration>(0);
+ }
+
+ // Verify?
+ if(pVerify)
+ {
+ if(!Verify(*pconfig, *pVerify, std::string(), rErrorMsg))
+ {
+ //TRACE1("Error message from Verify: %s", rErrorMsg.c_str());
+ TRACE0("Error at Configuration::Verify\n");
+ delete pconfig;
+ pconfig = 0;
+ return std::auto_ptr<Configuration>(0);
+ }
+ }
+ }
+ catch(...)
+ {
+ // Clean up
+ delete pconfig;
+ pconfig = 0;
+ throw;
+ }
+
+ // Success. Return result.
+ return std::auto_ptr<Configuration>(pconfig);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: LoadInto(Configuration &, FdGetLine &, std::string &, bool)
+// Purpose: Private. Load configuration information from the file into the config object.
+// Returns 'abort' flag, if error, will be appended to rErrorMsg.
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+bool Configuration::LoadInto(Configuration &rConfig, FdGetLine &rGetLine, std::string &rErrorMsg, bool RootLevel)
+{
+ bool startBlockExpected = false;
+ std::string blockName;
+
+ //TRACE1("BLOCK: |%s|\n", rConfig.mName.c_str());
+
+ while(!rGetLine.IsEOF())
+ {
+ std::string line(rGetLine.GetLine(true)); /* preprocess out whitespace and comments */
+
+ if(line.empty())
+ {
+ // Ignore blank lines
+ continue;
+ }
+
+ // Line an open block string?
+ if(line == "{")
+ {
+ if(startBlockExpected)
+ {
+ // New config object
+ Configuration config(blockName);
+
+ // Continue processing into this block
+ if(!LoadInto(config, rGetLine, rErrorMsg, false))
+ {
+ // Abort error
+ return false;
+ }
+
+ startBlockExpected = false;
+
+ // Store...
+ rConfig.mSubConfigurations.push_back(std::pair<std::string, Configuration>(blockName, config));
+ }
+ else
+ {
+ rErrorMsg += "Unexpected start block in " + rConfig.mName + "\n";
+ }
+ }
+ else
+ {
+ // Close block?
+ if(line == "}")
+ {
+ if(RootLevel)
+ {
+ // error -- root level doesn't have a close
+ rErrorMsg += "Root level has close block -- forget to terminate subblock?\n";
+ // but otherwise ignore
+ }
+ else
+ {
+ //TRACE0("ENDBLOCK\n");
+ return true; // All very good and nice
+ }
+ }
+ // Either a key, or a sub block beginning
+ else
+ {
+ // Can't be a start block
+ if(startBlockExpected)
+ {
+ rErrorMsg += "Block " + blockName + " wasn't started correctly (no '{' on line of it's own)\n";
+ startBlockExpected = false;
+ }
+
+ // Has the line got an = in it?
+ unsigned int equals = 0;
+ for(; equals < line.size(); ++equals)
+ {
+ if(line[equals] == '=')
+ {
+ // found!
+ break;
+ }
+ }
+ if(equals < line.size())
+ {
+ // Make key value pair
+ unsigned int keyend = equals;
+ while(keyend > 0 && iw(line[keyend-1]))
+ {
+ keyend--;
+ }
+ unsigned int valuestart = equals+1;
+ while(valuestart < line.size() && iw(line[valuestart]))
+ {
+ valuestart++;
+ }
+ if(keyend > 0 && valuestart <= line.size())
+ {
+ std::string key(line.substr(0, keyend));
+ std::string value(line.substr(valuestart));
+ //TRACE2("KEY: |%s|=|%s|\n", key.c_str(), value.c_str());
+
+ // Check for duplicate values
+ if(rConfig.mKeys.find(key) != rConfig.mKeys.end())
+ {
+ // Multi-values allowed here, but checked later on
+ rConfig.mKeys[key] += MultiValueSeparator;
+ rConfig.mKeys[key] += value;
+ }
+ else
+ {
+ // Store
+ rConfig.mKeys[key] = value;
+ }
+ }
+ else
+ {
+ rErrorMsg += "Invalid key in block "+rConfig.mName+"\n";
+ }
+ }
+ else
+ {
+ // Start of sub block
+ blockName = line;
+ startBlockExpected = true;
+ }
+ }
+ }
+ }
+
+ // End of file?
+ if(!RootLevel && rGetLine.IsEOF())
+ {
+ // Error if EOF and this isn't the root level
+ rErrorMsg += "File ended without terminating all subblocks\n";
+ }
+
+ return true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::KeyExists(const char *)
+// Purpose: Checks to see if a key exists
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+bool Configuration::KeyExists(const char *pKeyName) const
+{
+ if(pKeyName == 0) {THROW_EXCEPTION(CommonException, BadArguments)}
+
+ return mKeys.find(pKeyName) != mKeys.end();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::GetKeyValue(const char *)
+// Purpose: Returns the value of a configuration variable
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+const std::string &Configuration::GetKeyValue(const char *pKeyName) const
+{
+ if(pKeyName == 0) {THROW_EXCEPTION(CommonException, BadArguments)}
+
+ std::map<std::string, std::string>::const_iterator i(mKeys.find(pKeyName));
+
+ if(i == mKeys.end())
+ {
+ THROW_EXCEPTION(CommonException, ConfigNoKey)
+ }
+ else
+ {
+ return i->second;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::GetKeyValueInt(const char *)
+// Purpose: Gets a key value as an integer
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+int Configuration::GetKeyValueInt(const char *pKeyName) const
+{
+ if(pKeyName == 0) {THROW_EXCEPTION(CommonException, BadArguments)}
+
+ std::map<std::string, std::string>::const_iterator i(mKeys.find(pKeyName));
+
+ if(i == mKeys.end())
+ {
+ THROW_EXCEPTION(CommonException, ConfigNoKey)
+ }
+ else
+ {
+ long value = ::strtol((i->second).c_str(), NULL, 0 /* C style handling */);
+ if(value == LONG_MAX || value == LONG_MIN)
+ {
+ THROW_EXCEPTION(CommonException, ConfigBadIntValue)
+ }
+ return (int)value;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::GetKeyValueBool(const char *) const
+// Purpose: Gets a key value as a boolean
+// Created: 17/2/04
+//
+// --------------------------------------------------------------------------
+bool Configuration::GetKeyValueBool(const char *pKeyName) const
+{
+ if(pKeyName == 0) {THROW_EXCEPTION(CommonException, BadArguments)}
+
+ std::map<std::string, std::string>::const_iterator i(mKeys.find(pKeyName));
+
+ if(i == mKeys.end())
+ {
+ THROW_EXCEPTION(CommonException, ConfigNoKey)
+ }
+ else
+ {
+ bool value = false;
+
+ // Anything this is called for should have been verified as having a correct
+ // string in the verification section. However, this does default to false
+ // if it isn't in the string table.
+
+ for(int l = 0; sValueBooleanStrings[l] != 0; ++l)
+ {
+ if(::strcasecmp((i->second).c_str(), sValueBooleanStrings[l]) == 0)
+ {
+ // Found.
+ value = sValueBooleanValue[l];
+ break;
+ }
+ }
+
+ return value;
+ }
+
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::GetKeyNames()
+// Purpose: Returns list of key names
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+std::vector<std::string> Configuration::GetKeyNames() const
+{
+ std::map<std::string, std::string>::const_iterator i(mKeys.begin());
+
+ std::vector<std::string> r;
+
+ for(; i != mKeys.end(); ++i)
+ {
+ r.push_back(i->first);
+ }
+
+ return r;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::SubConfigurationExists(const char *)
+// Purpose: Checks to see if a sub configuration exists
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+bool Configuration::SubConfigurationExists(const char *pSubName) const
+{
+ if(pSubName == 0) {THROW_EXCEPTION(CommonException, BadArguments)}
+
+ // Attempt to find it...
+ std::list<std::pair<std::string, Configuration> >::const_iterator i(mSubConfigurations.begin());
+
+ for(; i != mSubConfigurations.end(); ++i)
+ {
+ // This the one?
+ if(i->first == pSubName)
+ {
+ // Yes.
+ return true;
+ }
+ }
+
+ // didn't find it.
+ return false;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::GetSubConfiguration(const char *)
+// Purpose: Gets a sub configuration
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+const Configuration &Configuration::GetSubConfiguration(const char *pSubName) const
+{
+ if(pSubName == 0) {THROW_EXCEPTION(CommonException, BadArguments)}
+
+ // Attempt to find it...
+ std::list<std::pair<std::string, Configuration> >::const_iterator i(mSubConfigurations.begin());
+
+ for(; i != mSubConfigurations.end(); ++i)
+ {
+ // This the one?
+ if(i->first == pSubName)
+ {
+ // Yes.
+ return i->second;
+ }
+ }
+
+ THROW_EXCEPTION(CommonException, ConfigNoSubConfig)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::GetSubConfigurationNames()
+// Purpose: Return list of sub configuration names
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+std::vector<std::string> Configuration::GetSubConfigurationNames() const
+{
+ std::list<std::pair<std::string, Configuration> >::const_iterator i(mSubConfigurations.begin());
+
+ std::vector<std::string> r;
+
+ for(; i != mSubConfigurations.end(); ++i)
+ {
+ r.push_back(i->first);
+ }
+
+ return r;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Configuration::Verify(const Configuration &, const ConfigurationVerify &, const std::string &, std::string &)
+// Purpose: Return list of sub configuration names
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+bool Configuration::Verify(Configuration &rConfig, const ConfigurationVerify &rVerify, const std::string &rLevel, std::string &rErrorMsg)
+{
+ bool ok = true;
+
+ // First... check the keys
+ if(rVerify.mpKeys != 0)
+ {
+ const ConfigurationVerifyKey *pvkey = rVerify.mpKeys;
+
+ bool todo = true;
+ do
+ {
+ // Can the key be found?
+ ASSERT(pvkey->mpName);
+ if(rConfig.KeyExists(pvkey->mpName))
+ {
+ // Get value
+ const std::string &rval = rConfig.GetKeyValue(pvkey->mpName);
+ const char *val = rval.c_str();
+
+ // Check it's a number?
+ if((pvkey->Tests & ConfigTest_IsInt) == ConfigTest_IsInt)
+ {
+ // Test it...
+ char *end;
+ long r = ::strtol(val, &end, 0);
+ if(r == LONG_MIN || r == LONG_MAX || end != (val + rval.size()))
+ {
+ // not a good value
+ ok = false;
+ rErrorMsg += rLevel + rConfig.mName +"." + pvkey->mpName + " (key) is not a valid integer.\n";
+ }
+ }
+
+ // Check it's a bool?
+ if((pvkey->Tests & ConfigTest_IsBool) == ConfigTest_IsBool)
+ {
+ // See if it's one of the allowed strings.
+ bool found = false;
+ for(int l = 0; sValueBooleanStrings[l] != 0; ++l)
+ {
+ if(::strcasecmp(val, sValueBooleanStrings[l]) == 0)
+ {
+ // Found.
+ found = true;
+ break;
+ }
+ }
+
+ // Error if it's not one of them.
+ if(!found)
+ {
+ ok = false;
+ rErrorMsg += rLevel + rConfig.mName +"." + pvkey->mpName + " (key) is not a valid boolean value.\n";
+ }
+ }
+
+ // Check for multi valued statments where they're not allowed
+ if((pvkey->Tests & ConfigTest_MultiValueAllowed) == 0)
+ {
+ // Check to see if this key is a multi-value -- it shouldn't be
+ if(rval.find(MultiValueSeparator) != rval.npos)
+ {
+ ok = false;
+ rErrorMsg += rLevel + rConfig.mName +"." + pvkey->mpName + " (key) multi value not allowed (duplicated key?).\n";
+ }
+ }
+ }
+ else
+ {
+ // Is it required to exist?
+ if((pvkey->Tests & ConfigTest_Exists) == ConfigTest_Exists)
+ {
+ // Should exist, but doesn't.
+ ok = false;
+ rErrorMsg += rLevel + rConfig.mName + "." + pvkey->mpName + " (key) is missing.\n";
+ }
+ else if(pvkey->mpDefaultValue)
+ {
+ rConfig.mKeys[std::string(pvkey->mpName)] = std::string(pvkey->mpDefaultValue);
+ }
+ }
+
+ if((pvkey->Tests & ConfigTest_LastEntry) == ConfigTest_LastEntry)
+ {
+ // No more!
+ todo = false;
+ }
+
+ // next
+ pvkey++;
+
+ } while(todo);
+
+ // Check for additional keys
+ for(std::map<std::string, std::string>::const_iterator i = rConfig.mKeys.begin();
+ i != rConfig.mKeys.end(); ++i)
+ {
+ // Is the name in the list?
+ const ConfigurationVerifyKey *scan = rVerify.mpKeys;
+ bool found = false;
+ while(scan)
+ {
+ if(scan->mpName == i->first)
+ {
+ found = true;
+ break;
+ }
+
+ // Next?
+ if((scan->Tests & ConfigTest_LastEntry) == ConfigTest_LastEntry)
+ {
+ break;
+ }
+ scan++;
+ }
+
+ if(!found)
+ {
+ // Shouldn't exist, but does.
+ ok = false;
+ rErrorMsg += rLevel + rConfig.mName + "." + i->first + " (key) is not a known key. Check spelling and placement.\n";
+ }
+ }
+ }
+
+ // Then the sub configurations
+ if(rVerify.mpSubConfigurations)
+ {
+ // Find the wildcard entry, if it exists, and check that required subconfigs are there
+ const ConfigurationVerify *wildcardverify = 0;
+
+ const ConfigurationVerify *scan = rVerify.mpSubConfigurations;
+ while(scan)
+ {
+ ASSERT(scan->mpName);
+ if(scan->mpName[0] == '*')
+ {
+ wildcardverify = scan;
+ }
+
+ // Required?
+ if((scan->Tests & ConfigTest_Exists) == ConfigTest_Exists)
+ {
+ if(scan->mpName[0] == '*')
+ {
+ // Check something exists
+ if(rConfig.mSubConfigurations.size() < 1)
+ {
+ // A sub config should exist, but doesn't.
+ ok = false;
+ rErrorMsg += rLevel + rConfig.mName + ".* (block) is missing (a block must be present).\n";
+ }
+ }
+ else
+ {
+ // Check real thing exists
+ if(!rConfig.SubConfigurationExists(scan->mpName))
+ {
+ // Should exist, but doesn't.
+ ok = false;
+ rErrorMsg += rLevel + rConfig.mName + "." + scan->mpName + " (block) is missing.\n";
+ }
+ }
+ }
+
+ // Next?
+ if((scan->Tests & ConfigTest_LastEntry) == ConfigTest_LastEntry)
+ {
+ break;
+ }
+ scan++;
+ }
+
+ // Go through the sub configurations, one by one
+ for(std::list<std::pair<std::string, Configuration> >::const_iterator i(rConfig.mSubConfigurations.begin());
+ i != rConfig.mSubConfigurations.end(); ++i)
+ {
+ // Can this be found?
+ const ConfigurationVerify *subverify = 0;
+
+ const ConfigurationVerify *scan = rVerify.mpSubConfigurations;
+ const char *name = i->first.c_str();
+ ASSERT(name);
+ while(scan)
+ {
+ if(strcmp(scan->mpName, name) == 0)
+ {
+ // found it!
+ subverify = scan;
+ }
+
+ // Next?
+ if((scan->Tests & ConfigTest_LastEntry) == ConfigTest_LastEntry)
+ {
+ break;
+ }
+ scan++;
+ }
+
+ // Use wildcard?
+ if(subverify == 0)
+ {
+ subverify = wildcardverify;
+ }
+
+ // Verify
+ if(subverify)
+ {
+ // override const-ness here...
+ if(!Verify((Configuration&)i->second, *subverify, rConfig.mName + '.', rErrorMsg))
+ {
+ ok = false;
+ }
+ }
+ }
+ }
+
+ return ok;
+}
+
+
diff --git a/lib/common/Configuration.h b/lib/common/Configuration.h
new file mode 100755
index 00000000..4c455b0f
--- /dev/null
+++ b/lib/common/Configuration.h
@@ -0,0 +1,98 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Configuration
+// Purpose: Reading configuration files
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+
+#ifndef CONFIGURATION__H
+#define CONFIGURATION__H
+
+#include <map>
+#include <list>
+#include <vector>
+#include <string>
+#include <memory>
+
+// For defining tests
+enum
+{
+ ConfigTest_LastEntry = 1,
+ ConfigTest_Exists = 2,
+ ConfigTest_IsInt = 4,
+ ConfigTest_MultiValueAllowed = 8,
+ ConfigTest_IsBool = 16
+};
+
+class ConfigurationVerifyKey
+{
+public:
+ const char *mpName; // "*" for all other keys (not implemented yet)
+ const char *mpDefaultValue; // default for when it's not present
+ int Tests;
+ void *TestFunction; // set to zero for now, will implement later
+};
+
+class ConfigurationVerify
+{
+public:
+ const char *mpName; // "*" for all other sub config names
+ const ConfigurationVerify *mpSubConfigurations;
+ const ConfigurationVerifyKey *mpKeys;
+ int Tests;
+ void *TestFunction; // set to zero for now, will implement later
+};
+
+class FdGetLine;
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: Configuration
+// Purpose: Loading, checking, and representing configuration files
+// Created: 2003/07/23
+//
+// --------------------------------------------------------------------------
+class Configuration
+{
+private:
+ Configuration(const std::string &rName);
+public:
+ Configuration(const Configuration &rToCopy);
+ ~Configuration();
+
+ enum
+ {
+ // The character to separate multi-values
+ MultiValueSeparator = '\x01'
+ };
+
+ static std::auto_ptr<Configuration> LoadAndVerify(const char *Filename, const ConfigurationVerify *pVerify, std::string &rErrorMsg);
+ static std::auto_ptr<Configuration> Load(const char *Filename, std::string &rErrorMsg) { return LoadAndVerify(Filename, 0, rErrorMsg); }
+
+ bool KeyExists(const char *pKeyName) const;
+ const std::string &GetKeyValue(const char *pKeyName) const;
+ int GetKeyValueInt(const char *pKeyName) const;
+ bool GetKeyValueBool(const char *pKeyName) const;
+ std::vector<std::string> GetKeyNames() const;
+
+ bool SubConfigurationExists(const char *pSubName) const;
+ const Configuration &GetSubConfiguration(const char *pSubName) const;
+ std::vector<std::string> GetSubConfigurationNames() const;
+
+ std::string mName;
+ // Order of sub blocks preserved
+ typedef std::list<std::pair<std::string, Configuration> > SubConfigListType;
+ SubConfigListType mSubConfigurations;
+ // Order of keys, not preserved
+ std::map<std::string, std::string> mKeys;
+
+private:
+ static bool LoadInto(Configuration &rConfig, FdGetLine &rGetLine, std::string &rErrorMsg, bool RootLevel);
+ static bool Verify(Configuration &rConfig, const ConfigurationVerify &rVerify, const std::string &rLevel, std::string &rErrorMsg);
+};
+
+#endif // CONFIGURATION__H
+
diff --git a/lib/common/Conversion.h b/lib/common/Conversion.h
new file mode 100644
index 00000000..cba5bb08
--- /dev/null
+++ b/lib/common/Conversion.h
@@ -0,0 +1,98 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Conversion.h
+// Purpose: Convert between various types
+// Created: 9/4/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef CONVERSION__H
+#define CONVERSION__H
+
+#include <string>
+
+namespace BoxConvert
+{
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BoxConvert::Convert<to_type, from_type>(to_type &, from_type)
+ // Purpose: Convert from types to types
+ // Created: 9/4/04
+ //
+ // --------------------------------------------------------------------------
+ template<typename to_type, typename from_type>
+ inline to_type Convert(from_type From)
+ {
+ // Default conversion, simply use C++ conversion
+ return From;
+ }
+
+ // Specialise for string -> integer
+ int32_t _ConvertStringToInt(const char *pString, int Size);
+ template<>
+ inline int32_t Convert<int32_t, const std::string &>(const std::string &rFrom)
+ {
+ return BoxConvert::_ConvertStringToInt(rFrom.c_str(), 32);
+ }
+ template<>
+ inline int16_t Convert<int16_t, const std::string &>(const std::string &rFrom)
+ {
+ return BoxConvert::_ConvertStringToInt(rFrom.c_str(), 16);
+ }
+ template<>
+ inline int8_t Convert<int8_t, const std::string &>(const std::string &rFrom)
+ {
+ return BoxConvert::_ConvertStringToInt(rFrom.c_str(), 8);
+ }
+ template<>
+ inline int32_t Convert<int32_t, const char *>(const char *pFrom)
+ {
+ return BoxConvert::_ConvertStringToInt(pFrom, 32);
+ }
+ template<>
+ inline int16_t Convert<int16_t, const char *>(const char *pFrom)
+ {
+ return BoxConvert::_ConvertStringToInt(pFrom, 16);
+ }
+ template<>
+ inline int8_t Convert<int8_t, const char *>(const char *pFrom)
+ {
+ return BoxConvert::_ConvertStringToInt(pFrom, 8);
+ }
+
+ // Specialise for integer -> string
+ void _ConvertIntToString(std::string &rTo, int32_t From);
+ template<>
+ inline std::string Convert<std::string, int32_t>(int32_t From)
+ {
+ std::string r;
+ BoxConvert::_ConvertIntToString(r, From);
+ return r;
+ }
+ template<>
+ inline std::string Convert<std::string, int16_t>(int16_t From)
+ {
+ std::string r;
+ BoxConvert::_ConvertIntToString(r, From);
+ return r;
+ }
+ template<>
+ inline std::string Convert<std::string, int8_t>(int8_t From)
+ {
+ std::string r;
+ BoxConvert::_ConvertIntToString(r, From);
+ return r;
+ }
+
+ // Specialise for bool -> string
+ template<>
+ inline std::string Convert<std::string, bool>(bool From)
+ {
+ return std::string(From?"true":"false");
+ }
+};
+
+#endif // CONVERSION__H
+
diff --git a/lib/common/ConversionException.txt b/lib/common/ConversionException.txt
new file mode 100644
index 00000000..91b5fa9a
--- /dev/null
+++ b/lib/common/ConversionException.txt
@@ -0,0 +1,8 @@
+
+EXCEPTION Conversion 12
+
+Internal 0
+CannotConvertEmptyStringToInt 1
+BadStringRepresentationOfInt 2
+IntOverflowInConvertFromString 3
+BadIntSize 4
diff --git a/lib/common/ConversionString.cpp b/lib/common/ConversionString.cpp
new file mode 100644
index 00000000..9e237a77
--- /dev/null
+++ b/lib/common/ConversionString.cpp
@@ -0,0 +1,123 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ConversionString.cpp
+// Purpose: Conversions to and from strings
+// Created: 9/4/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "Conversion.h"
+#include "autogen_ConversionException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BoxConvert::_ConvertStringToInt(const char *, int)
+// Purpose: Convert from string to integer, with range checking.
+// Always does signed -- no point in unsigned as C++ type checking
+// isn't up to handling it properly.
+// If a null pointer is passed in, then returns 0.
+// Created: 9/4/04
+//
+// --------------------------------------------------------------------------
+int32_t BoxConvert::_ConvertStringToInt(const char *pString, int Size)
+{
+ // Handle null strings gracefully.
+ if(pString == 0)
+ {
+ return 0;
+ }
+
+ // Check for initial validity
+ if(*pString == '\0')
+ {
+ THROW_EXCEPTION(ConversionException, CannotConvertEmptyStringToInt)
+ }
+
+ // Convert.
+ char *numEnd = 0;
+ errno = 0; // Some platforms don't reset it.
+ long r = ::strtol(pString, &numEnd, 0);
+
+ // Check that all the characters were used
+ if(*numEnd != '\0')
+ {
+ THROW_EXCEPTION(ConversionException, BadStringRepresentationOfInt)
+ }
+
+ // Error check
+ if(r == 0 && errno == EINVAL)
+ {
+ THROW_EXCEPTION(ConversionException, BadStringRepresentationOfInt)
+ }
+
+ // Range check from strtol
+ if((r == LONG_MIN || r == LONG_MAX) && errno == ERANGE)
+ {
+ THROW_EXCEPTION(ConversionException, IntOverflowInConvertFromString)
+ }
+
+ // Check range for size of integer
+ switch(Size)
+ {
+ case 32:
+ {
+ // No extra checking needed, if this assert holds true
+ ASSERT(sizeof(long) == sizeof(int32_t));
+ }
+ break;
+
+ case 16:
+ {
+ if(r <= (0 - 0x7fff) || r > 0x7fff)
+ {
+ THROW_EXCEPTION(ConversionException, IntOverflowInConvertFromString)
+ }
+ break;
+ }
+
+ case 8:
+ {
+ if(r <= (0 - 0x7f) || r > 0x7f)
+ {
+ THROW_EXCEPTION(ConversionException, IntOverflowInConvertFromString)
+ }
+ break;
+ }
+
+ default:
+ {
+ THROW_EXCEPTION(ConversionException, BadIntSize)
+ break;
+ }
+ }
+
+ // Return number
+ return r;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BoxConvert::_ConvertIntToString(std::string &, int32_t)
+// Purpose: Convert signed interger to a string
+// Created: 9/4/04
+//
+// --------------------------------------------------------------------------
+void BoxConvert::_ConvertIntToString(std::string &rTo, int32_t From)
+{
+ char text[64]; // size more than enough
+ ::sprintf(text, "%d", From);
+ rTo = text;
+}
+
diff --git a/lib/common/DebugAssertFailed.cpp b/lib/common/DebugAssertFailed.cpp
new file mode 100755
index 00000000..2acf4602
--- /dev/null
+++ b/lib/common/DebugAssertFailed.cpp
@@ -0,0 +1,32 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: AssertFailed.cpp
+// Purpose: Assert failure code
+// Created: 2003/09/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef NDEBUG
+
+#include "Box.h"
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include "MemLeakFindOn.h"
+
+bool AssertFailuresToSyslog = false;
+
+void BoxDebugAssertFailed(char *cond, char *file, int line)
+{
+ printf("ASSERT FAILED: [%s] at %s(%d)\n", cond, file, line);
+ if(AssertFailuresToSyslog)
+ {
+ ::syslog(LOG_ERR, "ASSERT FAILED: [%s] at %s(%d)\n", cond, file, line);
+ }
+}
+
+
+#endif // NDEBUG
+
diff --git a/lib/common/DebugMemLeakFinder.cpp b/lib/common/DebugMemLeakFinder.cpp
new file mode 100755
index 00000000..e1877a13
--- /dev/null
+++ b/lib/common/DebugMemLeakFinder.cpp
@@ -0,0 +1,377 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: MemLeakFinder.cpp
+// Purpose: Memory leak finder
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+
+
+#ifndef NDEBUG
+
+#include "Box.h"
+
+#undef malloc
+#undef realloc
+#undef free
+
+#include <map>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <set>
+
+bool memleakfinder_global_enable = false;
+
+typedef struct
+{
+ size_t size;
+ const char *file;
+ int line;
+} MallocBlockInfo;
+
+typedef struct
+{
+ size_t size;
+ const char *file;
+ int line;
+ bool array;
+} ObjectInfo;
+
+namespace
+{
+ static std::map<void *, MallocBlockInfo> sMallocBlocks;
+ static std::map<void *, ObjectInfo> sObjectBlocks;
+
+ static bool sTrackMallocInSection = false;
+ static std::set<void *> sSectionMallocBlocks;
+ static bool sTrackObjectsInSection = false;
+ static std::map<void *, ObjectInfo> sSectionObjectBlocks;
+
+ static std::set<void *> sNotLeaks;
+
+ void *sNotLeaksPre[1024];
+ int sNotLeaksPreNum = 0;
+}
+
+void memleakfinder_malloc_add_block(void *b, size_t size, const char *file, int line)
+{
+ if(b != 0)
+ {
+ MallocBlockInfo i;
+ i.size = size;
+ i.file = file;
+ i.line = line;
+ sMallocBlocks[b] = i;
+
+ if(sTrackMallocInSection)
+ {
+ sSectionMallocBlocks.insert(b);
+ }
+ }
+}
+
+
+void *memleakfinder_malloc(size_t size, const char *file, int line)
+{
+ void *b = ::malloc(size);
+ if(!memleakfinder_global_enable) return b;
+
+ memleakfinder_malloc_add_block(b, size, file, line);
+
+ //TRACE4("malloc(), %d, %s, %d, %08x\n", size, file, line, b);
+ return b;
+}
+
+void *memleakfinder_realloc(void *ptr, size_t size)
+{
+ if(!memleakfinder_global_enable)
+ {
+ return ::realloc(ptr, size);
+ }
+
+ // Check it's been allocated
+ std::map<void *, MallocBlockInfo>::iterator i(sMallocBlocks.find(ptr));
+ if(i == sMallocBlocks.end())
+ {
+ TRACE1("Block %x realloc(), but not in list. Error? Or allocated in startup static objects?\n", ptr);
+ void *b = ::realloc(ptr, size);
+ memleakfinder_malloc_add_block(b, size, "FOUND-IN-REALLOC", 0);
+ return b;
+ }
+
+ void *b = ::realloc(ptr, size);
+
+ // Worked?
+ if(b != 0)
+ {
+ // Update map
+ MallocBlockInfo inf = i->second;
+ inf.size = size;
+ sMallocBlocks.erase(i);
+ sMallocBlocks[b] = inf;
+
+ if(sTrackMallocInSection)
+ {
+ std::set<void *>::iterator si(sSectionMallocBlocks.find(ptr));
+ if(si != sSectionMallocBlocks.end()) sSectionMallocBlocks.erase(si);
+ sSectionMallocBlocks.insert(b);
+ }
+ }
+
+ //TRACE3("realloc(), %d, %08x->%08x\n", size, ptr, b);
+ return b;
+}
+
+void memleakfinder_free(void *ptr)
+{
+ if(memleakfinder_global_enable)
+ {
+ // Check it's been allocated
+ std::map<void *, MallocBlockInfo>::iterator i(sMallocBlocks.find(ptr));
+ if(i != sMallocBlocks.end())
+ {
+ sMallocBlocks.erase(i);
+ }
+ else
+ {
+ TRACE1("Block %x freed, but not known. Error? Or allocated in startup static allocation?\n", ptr);
+ }
+
+ if(sTrackMallocInSection)
+ {
+ std::set<void *>::iterator si(sSectionMallocBlocks.find(ptr));
+ if(si != sSectionMallocBlocks.end()) sSectionMallocBlocks.erase(si);
+ }
+ }
+
+ //TRACE1("free(), %08x\n", ptr);
+ ::free(ptr);
+}
+
+
+void memleakfinder_notaleak_insert_pre()
+{
+ if(!memleakfinder_global_enable) return;
+ for(int l = 0; l < sNotLeaksPreNum; l++)
+ {
+ sNotLeaks.insert(sNotLeaksPre[l]);
+ }
+ sNotLeaksPreNum = 0;
+}
+
+bool is_leak(void *ptr)
+{
+ memleakfinder_notaleak_insert_pre();
+ return sNotLeaks.find(ptr) == sNotLeaks.end();
+}
+
+void memleakfinder_notaleak(void *ptr)
+{
+ memleakfinder_notaleak_insert_pre();
+ if(memleakfinder_global_enable)
+ {
+ sNotLeaks.insert(ptr);
+ }
+ else
+ {
+ sNotLeaksPre[sNotLeaksPreNum++] = ptr;
+ }
+/* {
+ std::map<void *, MallocBlockInfo>::iterator i(sMallocBlocks.find(ptr));
+ if(i != sMallocBlocks.end()) sMallocBlocks.erase(i);
+ }
+ {
+ std::set<void *>::iterator si(sSectionMallocBlocks.find(ptr));
+ if(si != sSectionMallocBlocks.end()) sSectionMallocBlocks.erase(si);
+ }
+ {
+ std::map<void *, ObjectInfo>::iterator i(sObjectBlocks.find(ptr));
+ if(i != sObjectBlocks.end()) sObjectBlocks.erase(i);
+ }*/
+}
+
+
+
+// start monitoring a section of code
+void memleakfinder_startsectionmonitor()
+{
+ sTrackMallocInSection = true;
+ sSectionMallocBlocks.clear();
+ sTrackObjectsInSection = true;
+ sSectionObjectBlocks.clear();
+}
+
+// trace all blocks allocated and still allocated since memleakfinder_startsectionmonitor() called
+void memleakfinder_traceblocksinsection()
+{
+ std::set<void *>::iterator s(sSectionMallocBlocks.begin());
+ for(; s != sSectionMallocBlocks.end(); ++s)
+ {
+ std::map<void *, MallocBlockInfo>::const_iterator i(sMallocBlocks.find(*s));
+ if(i == sMallocBlocks.end())
+ {
+ TRACE0("Logical error in section block finding\n");
+ }
+ else
+ {
+ TRACE4("Block 0x%08x size %d allocated at %s:%d\n", (int)i->first, i->second.size, i->second.file, i->second.line);
+ }
+ }
+ for(std::map<void *, ObjectInfo>::const_iterator i(sSectionObjectBlocks.begin()); i != sSectionObjectBlocks.end(); ++i)
+ {
+ TRACE5("Object%s 0x%08x size %d allocated at %s:%d\n", i->second.array?" []":"", (int)i->first, i->second.size, i->second.file, i->second.line);
+ }
+}
+
+int memleakfinder_numleaks()
+{
+ int n = 0;
+
+ for(std::map<void *, MallocBlockInfo>::const_iterator i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i)
+ {
+ if(is_leak(i->first)) ++n;
+ }
+
+ for(std::map<void *, ObjectInfo>::const_iterator i(sObjectBlocks.begin()); i != sObjectBlocks.end(); ++i)
+ {
+ if(is_leak(i->first)) ++n;
+ }
+
+ return n;
+}
+
+void memleakfinder_reportleaks_file(FILE *file)
+{
+ for(std::map<void *, MallocBlockInfo>::const_iterator i(sMallocBlocks.begin()); i != sMallocBlocks.end(); ++i)
+ {
+ if(is_leak(i->first)) ::fprintf(file, "Block 0x%08x size %d allocated at %s:%d\n", (int)i->first, i->second.size, i->second.file, i->second.line);
+ }
+ for(std::map<void *, ObjectInfo>::const_iterator i(sObjectBlocks.begin()); i != sObjectBlocks.end(); ++i)
+ {
+ if(is_leak(i->first)) ::fprintf(file, "Object%s 0x%08x size %d allocated at %s:%d\n", i->second.array?" []":"", (int)i->first, i->second.size, i->second.file, i->second.line);
+ }
+}
+
+void memleakfinder_reportleaks()
+{
+ // report to stdout
+ memleakfinder_reportleaks_file(stdout);
+}
+
+void memleakfinder_reportleaks_appendfile(const char *filename, const char *markertext)
+{
+ FILE *file = ::fopen(filename, "a");
+ if(file != 0)
+ {
+ if(memleakfinder_numleaks() > 0)
+ {
+ fprintf(file, "MEMORY LEAKS FROM PROCESS %d (%s)\n", getpid(), markertext);
+ memleakfinder_reportleaks_file(file);
+ }
+
+ ::fclose(file);
+ }
+ else
+ {
+ printf("WARNING: Couldn't open memory leak results file %s for appending\n", filename);
+ }
+}
+
+static char atexit_filename[512];
+static char atexit_markertext[512];
+static bool atexit_registered = false;
+
+void memleakfinder_atexit()
+{
+ memleakfinder_reportleaks_appendfile(atexit_filename, atexit_markertext);
+}
+
+void memleakfinder_setup_exit_report(const char *filename, const char *markertext)
+{
+ ::strcpy(atexit_filename, filename);
+ ::strcpy(atexit_markertext, markertext);
+ if(!atexit_registered)
+ {
+ atexit(memleakfinder_atexit);
+ atexit_registered = true;
+ }
+}
+
+
+
+
+void add_object_block(void *block, size_t size, const char *file, int line, bool array)
+{
+ if(!memleakfinder_global_enable) return;
+
+ if(block != 0)
+ {
+ ObjectInfo i;
+ i.size = size;
+ i.file = file;
+ i.line = line;
+ i.array = array;
+ sObjectBlocks[block] = i;
+
+ if(sTrackObjectsInSection)
+ {
+ sSectionObjectBlocks[block] = i;
+ }
+ }
+}
+
+void remove_object_block(void *block)
+{
+ if(!memleakfinder_global_enable) return;
+
+ std::map<void *, ObjectInfo>::iterator i(sObjectBlocks.find(block));
+ if(i != sObjectBlocks.end())
+ {
+ sObjectBlocks.erase(i);
+ }
+
+ if(sTrackObjectsInSection)
+ {
+ std::map<void *, ObjectInfo>::iterator i(sSectionObjectBlocks.find(block));
+ if(i != sSectionObjectBlocks.end())
+ {
+ sSectionObjectBlocks.erase(i);
+ }
+ }
+
+ // If it's not in the list, just ignore it, as lots of stuff goes this way...
+}
+
+void *operator new(size_t size, const char *file, int line)
+{
+ void *r = ::malloc(size);
+ add_object_block(r, size, file, line, false);
+ //TRACE4("new(), %d, %s, %d, %08x\n", size, file, line, r);
+ return r;
+}
+
+void *operator new[](size_t size, const char *file, int line)
+{
+ void *r = ::malloc(size);
+ add_object_block(r, size, file, line, true);
+ //TRACE4("new[](), %d, %s, %d, %08x\n", size, file, line, r);
+ return r;
+}
+
+void operator delete[](void *ptr) throw ()
+{
+ ::free(ptr);
+ remove_object_block(ptr);
+ //TRACE1("delete[]() called, %08x\n", ptr);
+}
+
+void operator delete(void *ptr) throw ()
+{
+ ::free(ptr);
+ remove_object_block(ptr);
+ //TRACE1("delete() called, %08x\n", ptr);
+}
+
+#endif // NDEBUG
diff --git a/lib/common/DebugPrintf.cpp b/lib/common/DebugPrintf.cpp
new file mode 100755
index 00000000..02c25496
--- /dev/null
+++ b/lib/common/DebugPrintf.cpp
@@ -0,0 +1,72 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: DebugPrintf.cpp
+// Purpose: Implementation of a printf function, to avoid a stdio.h include in Box.h
+// Created: 2003/09/06
+//
+// --------------------------------------------------------------------------
+
+#ifndef NDEBUG
+
+#include "Box.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include "MemLeakFindOn.h"
+
+// Use this apparently superflous printf function to avoid having to
+// include stdio.h in every file in the project.
+
+int BoxDebug_printf(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int r = vprintf(format, ap);
+ va_end(ap);
+ return r;
+}
+
+
+bool BoxDebugTraceOn = true;
+bool BoxDebugTraceToStdout = true;
+bool BoxDebugTraceToSyslog = false;
+
+int BoxDebugTrace(const char *format, ...)
+{
+ char text[512];
+ int r = 0;
+ if(BoxDebugTraceOn || BoxDebugTraceToSyslog)
+ {
+ va_list ap;
+ va_start(ap, format);
+ r = vsnprintf(text, sizeof(text), format, ap);
+ va_end(ap);
+ }
+
+ // Send to stdout if trace is on and std out is enabled
+ if(BoxDebugTraceOn && BoxDebugTraceToStdout)
+ {
+ printf("%s", text);
+ }
+
+ // But tracing to syslog is independent of tracing being on or not
+ if(BoxDebugTraceToSyslog)
+ {
+ // Remove trailing '\n', if it's there
+ if(r > 0 && text[r] == '\n')
+ {
+ text[r] = '\0';
+ --r;
+ }
+ // Log it
+ ::syslog(LOG_INFO, "TRACE: %s", text);
+ }
+
+ return r;
+}
+
+
+#endif // NDEBUG
diff --git a/lib/common/EndStructPackForWire.h b/lib/common/EndStructPackForWire.h
new file mode 100644
index 00000000..c9655cd7
--- /dev/null
+++ b/lib/common/EndStructPackForWire.h
@@ -0,0 +1,23 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: EndStructPackForWire.h
+// Purpose: End structure packing for wire
+// Created: 25/11/03
+//
+// --------------------------------------------------------------------------
+
+// No header guard -- this is intentional
+
+#ifdef STRUCTURE_PATCKING_FOR_WIRE_USE_HEADERS
+
+#pragma pack()
+
+#else
+
+ logical error -- check BoxPlatform.h and including file
+
+#endif
+
+
+
diff --git a/lib/common/EventWatchFilesystemObject.cpp b/lib/common/EventWatchFilesystemObject.cpp
new file mode 100644
index 00000000..1611d5bd
--- /dev/null
+++ b/lib/common/EventWatchFilesystemObject.cpp
@@ -0,0 +1,99 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: EventWatchFilesystemObject.cpp
+// Purpose: WaitForEvent compatible object for watching directories
+// Created: 12/3/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "EventWatchFilesystemObject.h"
+#include "autogen_CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: EventWatchFilesystemObject::EventWatchFilesystemObject(const char *)
+// Purpose: Constructor -- opens the file object
+// Created: 12/3/04
+//
+// --------------------------------------------------------------------------
+EventWatchFilesystemObject::EventWatchFilesystemObject(const char *Filename)
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ : mDescriptor(::open(Filename, O_RDONLY /*O_EVTONLY*/, 0))
+#endif
+{
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ if(mDescriptor == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileOpenError)
+ }
+#else
+ THROW_EXCEPTION(CommonException, KQueueNotSupportedOnThisPlatform)
+#endif
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: EventWatchFilesystemObject::~EventWatchFilesystemObject()
+// Purpose: Destructor
+// Created: 12/3/04
+//
+// --------------------------------------------------------------------------
+EventWatchFilesystemObject::~EventWatchFilesystemObject()
+{
+ if(mDescriptor != -1)
+ {
+ ::close(mDescriptor);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: EventWatchFilesystemObject::EventWatchFilesystemObject(const EventWatchFilesystemObject &)
+// Purpose: Copy constructor
+// Created: 12/3/04
+//
+// --------------------------------------------------------------------------
+EventWatchFilesystemObject::EventWatchFilesystemObject(const EventWatchFilesystemObject &rToCopy)
+ : mDescriptor(::dup(rToCopy.mDescriptor))
+{
+ if(mDescriptor == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+}
+
+
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: EventWatchFilesystemObject::FillInKEvent(struct kevent &, int)
+// Purpose: For WaitForEvent
+// Created: 12/3/04
+//
+// --------------------------------------------------------------------------
+void EventWatchFilesystemObject::FillInKEvent(struct kevent &rEvent, int Flags) const
+{
+ EV_SET(&rEvent, mDescriptor, EVFILT_VNODE, EV_CLEAR, NOTE_DELETE | NOTE_WRITE, 0, (void*)this);
+}
+#else
+void EventWatchFilesystemObject::FillInPoll(int &fd, short &events, int Flags) const
+{
+ THROW_EXCEPTION(CommonException, KQueueNotSupportedOnThisPlatform)
+}
+#endif
+
diff --git a/lib/common/EventWatchFilesystemObject.h b/lib/common/EventWatchFilesystemObject.h
new file mode 100644
index 00000000..d8a7245b
--- /dev/null
+++ b/lib/common/EventWatchFilesystemObject.h
@@ -0,0 +1,48 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: EventWatchFilesystemObject.h
+// Purpose: WaitForEvent compatible object for watching directories
+// Created: 12/3/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef EVENTWATCHFILESYSTEMOBJECT__H
+#define EVENTWATCHFILESYSTEMOBJECT__H
+
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ #include <sys/event.h>
+#endif
+
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: EventWatchFilesystemObject
+// Purpose: WaitForEvent compatible object for watching files and directories
+// Created: 12/3/04
+//
+// --------------------------------------------------------------------------
+class EventWatchFilesystemObject
+{
+public:
+ EventWatchFilesystemObject(const char *Filename);
+ ~EventWatchFilesystemObject();
+ EventWatchFilesystemObject(const EventWatchFilesystemObject &rToCopy);
+private:
+ // Assignment not allowed
+ EventWatchFilesystemObject &operator=(const EventWatchFilesystemObject &);
+public:
+
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ void FillInKEvent(struct kevent &rEvent, int Flags = 0) const;
+#else
+ void FillInPoll(int &fd, short &events, int Flags = 0) const;
+#endif
+
+private:
+ int mDescriptor;
+};
+
+#endif // EventWatchFilesystemObject__H
+
diff --git a/lib/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp
new file mode 100755
index 00000000..6350869d
--- /dev/null
+++ b/lib/common/ExcludeList.cpp
@@ -0,0 +1,219 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ExcludeList.cpp
+// Purpose: General purpose exclusion list
+// Created: 28/1/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#ifndef PLATFORM_REGEX_NOT_SUPPORTED
+ #include <regex.h>
+ #define EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED
+#endif
+
+#include "ExcludeList.h"
+#include "Utils.h"
+#include "Configuration.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ExcludeList::ExcludeList()
+// Purpose: Constructor. Generates an exclude list which will allow everything
+// Created: 28/1/04
+//
+// --------------------------------------------------------------------------
+ExcludeList::ExcludeList()
+ : mpAlwaysInclude(0)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ExcludeList::~ExcludeList()
+// Purpose: Destructor
+// Created: 28/1/04
+//
+// --------------------------------------------------------------------------
+ExcludeList::~ExcludeList()
+{
+#ifndef PLATFORM_REGEX_NOT_SUPPORTED
+ // free regex memory
+ while(mRegex.size() > 0)
+ {
+ regex_t *pregex = mRegex.back();
+ mRegex.pop_back();
+ // Free regex storage, and the structure itself
+ ::regfree(pregex);
+ delete pregex;
+ }
+#endif
+
+ // Clean up exceptions list
+ if(mpAlwaysInclude != 0)
+ {
+ delete mpAlwaysInclude;
+ mpAlwaysInclude = 0;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ExcludeList::AddDefiniteEntries(const std::string &)
+// Purpose: Adds a number of definite entries to the exclude list -- ones which
+// will be excluded if and only if the test string matches exactly.
+// Uses the Configuration classes' multi-value conventions, with
+// multiple entires in one string separated by Configuration::MultiValueSeparator
+// Created: 28/1/04
+//
+// --------------------------------------------------------------------------
+void ExcludeList::AddDefiniteEntries(const std::string &rEntries)
+{
+ // Split strings up
+ std::vector<std::string> ens;
+ SplitString(rEntries, Configuration::MultiValueSeparator, ens);
+
+ // Add to set of excluded strings
+ for(std::vector<std::string>::const_iterator i(ens.begin()); i != ens.end(); ++i)
+ {
+ if(i->size() > 0)
+ {
+ mDefinite.insert(*i);
+ }
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ExcludeList::AddRegexEntries(const std::string &)
+// Purpose: Adds a number of regular expression entries to the exclude list --
+// if the test expression matches any of these regex, it will be excluded.
+// Uses the Configuration classes' multi-value conventions, with
+// multiple entires in one string separated by Configuration::MultiValueSeparator
+// Created: 28/1/04
+//
+// --------------------------------------------------------------------------
+void ExcludeList::AddRegexEntries(const std::string &rEntries)
+{
+#ifndef PLATFORM_REGEX_NOT_SUPPORTED
+
+ // Split strings up
+ std::vector<std::string> ens;
+ SplitString(rEntries, Configuration::MultiValueSeparator, ens);
+
+ // Create and add new regular expressions
+ for(std::vector<std::string>::const_iterator i(ens.begin()); i != ens.end(); ++i)
+ {
+ if(i->size() > 0)
+ {
+ // Allocate memory
+ regex_t *pregex = new regex_t;
+
+ try
+ {
+ // Compile
+ if(::regcomp(pregex, i->c_str(), REG_EXTENDED | REG_NOSUB) != 0)
+ {
+ THROW_EXCEPTION(CommonException, BadRegularExpression)
+ }
+
+ // Store in list of regular expressions
+ mRegex.push_back(pregex);
+ }
+ catch(...)
+ {
+ delete pregex;
+ throw;
+ }
+ }
+ }
+
+#else
+ THROW_EXCEPTION(CommonException, RegexNotSupportedOnThisPlatform)
+#endif
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ExcludeList::IsExcluded(const std::string &)
+// Purpose: Returns true if the entry should be excluded
+// Created: 28/1/04
+//
+// --------------------------------------------------------------------------
+bool ExcludeList::IsExcluded(const std::string &rTest) const
+{
+ // Check against the always include list
+ if(mpAlwaysInclude != 0)
+ {
+ if(mpAlwaysInclude->IsExcluded(rTest))
+ {
+ // Because the "always include" list says it's 'excluded'
+ // this means it should actually be included.
+ return false;
+ }
+ }
+
+ // Is it in the set of definite entries?
+ if(mDefinite.find(rTest) != mDefinite.end())
+ {
+ return true;
+ }
+
+ // Check against regular expressions
+#ifndef PLATFORM_REGEX_NOT_SUPPORTED
+ for(std::vector<regex_t *>::const_iterator i(mRegex.begin()); i != mRegex.end(); ++i)
+ {
+ // Test against this expression
+ if(regexec(*i, rTest.c_str(), 0, 0 /* no match information required */, 0 /* no flags */) == 0)
+ {
+ // match happened
+ return true;
+ }
+ // In all other cases, including an error, just continue to the next expression
+ }
+#endif
+
+ return false;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ExcludeList::SetAlwaysIncludeList(ExcludeList *)
+// Purpose: Takes ownership of the list, deletes any pre-existing list.
+// NULL is acceptable to delete the list.
+// The AlwaysInclude list is a list of exceptions to the exclusions.
+// Created: 19/2/04
+//
+// --------------------------------------------------------------------------
+void ExcludeList::SetAlwaysIncludeList(ExcludeList *pAlwaysInclude)
+{
+ // Delete old list
+ if(mpAlwaysInclude != 0)
+ {
+ delete mpAlwaysInclude;
+ mpAlwaysInclude = 0;
+ }
+
+ // Store the pointer
+ mpAlwaysInclude = pAlwaysInclude;
+}
+
+
+
+
+
diff --git a/lib/common/ExcludeList.h b/lib/common/ExcludeList.h
new file mode 100755
index 00000000..a1954044
--- /dev/null
+++ b/lib/common/ExcludeList.h
@@ -0,0 +1,65 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ExcludeList.h
+// Purpose: General purpose exclusion list
+// Created: 28/1/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef EXCLUDELIST__H
+#define EXCLUDELIST__H
+
+#include <string>
+#include <set>
+#include <vector>
+
+// avoid including regex.h in lots of places
+#ifndef EXCLUDELIST_IMPLEMENTATION_REGEX_T_DEFINED
+ typedef int regex_t;
+#endif
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: ExcludeList
+// Purpose: General purpose exclusion list
+// Created: 28/1/04
+//
+// --------------------------------------------------------------------------
+class ExcludeList
+{
+public:
+ ExcludeList();
+ ~ExcludeList();
+
+ void AddDefiniteEntries(const std::string &rEntries);
+ void AddRegexEntries(const std::string &rEntries);
+
+ // Add exceptions to the exclusions (takes ownership)
+ void SetAlwaysIncludeList(ExcludeList *pAlwaysInclude);
+
+ // Test function
+ bool IsExcluded(const std::string &rTest) const;
+
+ // Mainly for tests
+ unsigned int SizeOfDefiniteList() const {return mDefinite.size();}
+ unsigned int SizeOfRegexList() const
+#ifndef PLATFORM_REGEX_NOT_SUPPORTED
+ {return mRegex.size();}
+#else
+ {return 0;}
+#endif
+
+private:
+ std::set<std::string> mDefinite;
+#ifndef PLATFORM_REGEX_NOT_SUPPORTED
+ std::vector<regex_t *> mRegex;
+#endif
+
+ // For exceptions to the excludes
+ ExcludeList *mpAlwaysInclude;
+};
+
+#endif // EXCLUDELIST__H
+
diff --git a/lib/common/FdGetLine.cpp b/lib/common/FdGetLine.cpp
new file mode 100755
index 00000000..dee02604
--- /dev/null
+++ b/lib/common/FdGetLine.cpp
@@ -0,0 +1,211 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: FdGetLine.cpp
+// Purpose: Line based file descriptor reading
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "FdGetLine.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// utility whitespace function
+inline bool iw(int c)
+{
+ return (c == ' ' || c == '\t' || c == '\v' || c == '\f'); // \r, \n are already excluded
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FdGetLine::FdGetLine(int)
+// Purpose: Constructor, taking file descriptor
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+FdGetLine::FdGetLine(int fd)
+ : mFileHandle(fd),
+ mLineNumber(0),
+ mBufferBegin(0),
+ mBytesInBuffer(0),
+ mPendingEOF(false),
+ mEOF(false)
+{
+ if(mFileHandle < 0) {THROW_EXCEPTION(CommonException, BadArguments)}
+ //printf("FdGetLine buffer size = %d\n", sizeof(mBuffer));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FdGetLine::~FdGetLine()
+// Purpose: Destructor
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+FdGetLine::~FdGetLine()
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FdGetLine::GetLine(bool)
+// Purpose: Returns a file from the file. If Preprocess is true, leading
+// and trailing whitespace is removed, and comments (after #)
+// are deleted.
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+std::string FdGetLine::GetLine(bool Preprocess)
+{
+ if(mFileHandle == -1) {THROW_EXCEPTION(CommonException, GetLineNoHandle)}
+
+ // EOF?
+ if(mEOF) {THROW_EXCEPTION(CommonException, GetLineEOF)}
+
+ std::string r;
+
+ bool foundLineEnd = false;
+
+ while(!foundLineEnd && !mEOF)
+ {
+ // Use any bytes left in the buffer
+ while(mBufferBegin < mBytesInBuffer)
+ {
+ int c = mBuffer[mBufferBegin++];
+ if(c == '\r')
+ {
+ // Ignore nasty Windows line ending extra chars
+ }
+ else if(c == '\n')
+ {
+ // Line end!
+ foundLineEnd = true;
+ break;
+ }
+ else
+ {
+ // Add to string
+ r += c;
+ }
+
+ // Implicit line ending at EOF
+ if(mBufferBegin >= mBytesInBuffer && mPendingEOF)
+ {
+ foundLineEnd = true;
+ }
+ }
+
+ // Check size
+ if(r.size() > FDGETLINE_MAX_LINE_SIZE)
+ {
+ THROW_EXCEPTION(CommonException, GetLineTooLarge)
+ }
+
+ // Read more in?
+ if(!foundLineEnd && mBufferBegin >= mBytesInBuffer && !mPendingEOF)
+ {
+ int bytes = ::read(mFileHandle, mBuffer, sizeof(mBuffer));
+
+ // Error?
+ if(bytes == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ // Adjust buffer info
+ mBytesInBuffer = bytes;
+ mBufferBegin = 0;
+
+ // EOF / closed?
+ if(bytes == 0)
+ {
+ mPendingEOF = true;
+ }
+ }
+
+ // EOF?
+ if(mPendingEOF && mBufferBegin >= mBytesInBuffer)
+ {
+ // File is EOF, and now we've depleted the buffer completely, so tell caller as well.
+ mEOF = true;
+ }
+ }
+
+ if(!Preprocess)
+ {
+ return r;
+ }
+ else
+ {
+ // Check for comment char, but char before must be whitespace
+ int end = 0;
+ int size = r.size();
+ while(end < size)
+ {
+ if(r[end] == '#' && (end == 0 || (iw(r[end-1]))))
+ {
+ break;
+ }
+ end++;
+ }
+
+ // Remove whitespace
+ int begin = 0;
+ while(begin < size && iw(r[begin]))
+ {
+ begin++;
+ }
+ if(!iw(r[end])) end--;
+ while(end > begin && iw(r[end]))
+ {
+ end--;
+ }
+
+ // Return a sub string
+ return r.substr(begin, end - begin + 1);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FdGetLine::DetachFile()
+// Purpose: Detaches the file handle, setting the file pointer correctly.
+// Probably not good for sockets...
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+void FdGetLine::DetachFile()
+{
+ if(mFileHandle == -1) {THROW_EXCEPTION(CommonException, GetLineNoHandle)}
+
+ // Adjust file pointer
+ int bytesOver = mBufferBegin - mBufferBegin;
+ ASSERT(bytesOver >= 0);
+ if(bytesOver > 0)
+ {
+ if(::lseek(mFileHandle, 0 - bytesOver, SEEK_CUR) == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+ }
+
+ // Unset file pointer
+ mFileHandle = -1;
+}
+
+
diff --git a/lib/common/FdGetLine.h b/lib/common/FdGetLine.h
new file mode 100755
index 00000000..fecb0371
--- /dev/null
+++ b/lib/common/FdGetLine.h
@@ -0,0 +1,61 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: FdGetLine.h
+// Purpose: Line based file descriptor reading
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+
+#ifndef FDGETLINE__H
+#define FDGETLINE__H
+
+#include <string>
+
+#ifdef NDEBUG
+ #define FDGETLINE_BUFFER_SIZE 1024
+#else
+ #define FDGETLINE_BUFFER_SIZE 4
+#endif
+
+// Just a very large upper bound for line size to avoid
+// people sending lots of data over sockets and causing memory problems.
+#define FDGETLINE_MAX_LINE_SIZE (1024*256)
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: FdGetLine
+// Purpose: Line based file descriptor reading
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+class FdGetLine
+{
+public:
+ FdGetLine(int fd);
+ ~FdGetLine();
+private:
+ FdGetLine(const FdGetLine &rToCopy);
+
+public:
+ std::string GetLine(bool Preprocess = false);
+ bool IsEOF() {return mEOF;}
+ int GetLineNumber() {return mLineNumber;}
+
+ // Call to detach, setting file pointer correctly to last bit read.
+ // Only works for lseek-able file descriptors.
+ void DetachFile();
+
+private:
+ char mBuffer[FDGETLINE_BUFFER_SIZE];
+ int mFileHandle;
+ int mLineNumber;
+ int mBufferBegin;
+ int mBytesInBuffer;
+ bool mPendingEOF;
+ bool mEOF;
+};
+
+#endif // FDGETLINE__H
+
diff --git a/lib/common/FileModificationTime.h b/lib/common/FileModificationTime.h
new file mode 100755
index 00000000..78f5c115
--- /dev/null
+++ b/lib/common/FileModificationTime.h
@@ -0,0 +1,57 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: FileModificationTime.h
+// Purpose: Function for getting file modification time.
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+
+#ifndef FILEMODIFICATIONTIME__H
+#define FILEMODIFICATIONTIME__H
+
+#include <sys/stat.h>
+
+#include "BoxTime.h"
+
+inline box_time_t FileModificationTime(struct stat &st)
+{
+#ifdef PLATFORM_stat_SHORT_mtime
+ box_time_t datamodified = ((int64_t)st.st_mtime) * (MICRO_SEC_IN_SEC_LL);
+#else
+ box_time_t datamodified = (((int64_t)st.st_mtimespec.tv_nsec) / NANO_SEC_IN_USEC_LL)
+ + (((int64_t)st.st_mtimespec.tv_sec) * (MICRO_SEC_IN_SEC_LL));
+#endif
+
+ return datamodified;
+}
+
+inline box_time_t FileAttrModificationTime(struct stat &st)
+{
+#ifdef PLATFORM_stat_SHORT_mtime
+ box_time_t statusmodified = ((int64_t)st.st_ctime) * (MICRO_SEC_IN_SEC_LL);
+#else
+ box_time_t statusmodified = (((int64_t)st.st_ctimespec.tv_nsec) / NANO_SEC_IN_USEC_LL)
+ + (((int64_t)st.st_ctimespec.tv_sec) * (MICRO_SEC_IN_SEC_LL));
+#endif
+
+ return statusmodified;
+}
+
+inline box_time_t FileModificationTimeMaxModAndAttr(struct stat &st)
+{
+#ifdef PLATFORM_stat_SHORT_mtime
+ box_time_t datamodified = ((int64_t)st.st_mtime) * (MICRO_SEC_IN_SEC_LL);
+ box_time_t statusmodified = ((int64_t)st.st_ctime) * (MICRO_SEC_IN_SEC_LL);
+#else
+ box_time_t datamodified = (((int64_t)st.st_mtimespec.tv_nsec) / NANO_SEC_IN_USEC_LL)
+ + (((int64_t)st.st_mtimespec.tv_sec) * (MICRO_SEC_IN_SEC_LL));
+ box_time_t statusmodified = (((int64_t)st.st_ctimespec.tv_nsec) / NANO_SEC_IN_USEC_LL)
+ + (((int64_t)st.st_ctimespec.tv_sec) * (MICRO_SEC_IN_SEC_LL));
+#endif
+
+ return (datamodified > statusmodified)?datamodified:statusmodified;
+}
+
+#endif // FILEMODIFICATIONTIME__H
+
diff --git a/lib/common/FileStream.cpp b/lib/common/FileStream.cpp
new file mode 100755
index 00000000..ca6894ae
--- /dev/null
+++ b/lib/common/FileStream.cpp
@@ -0,0 +1,245 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: FileStream.cpp
+// Purpose: IOStream interface to files
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "FileStream.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::FileStream(const char *, int, int)
+// Purpose: Constructor, opens file
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+FileStream::FileStream(const char *Filename, int flags, int mode)
+ : mOSFileHandle(::open(Filename, flags, mode)),
+ mIsEOF(false)
+{
+ if(mOSFileHandle < 0)
+ {
+ MEMLEAKFINDER_NOT_A_LEAK(this);
+ THROW_EXCEPTION(CommonException, OSFileOpenError)
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::FileStream(int)
+// Purpose: Constructor, using existing file descriptor
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+FileStream::FileStream(int FileDescriptor)
+ : mOSFileHandle(FileDescriptor),
+ mIsEOF(false)
+{
+ if(mOSFileHandle < 0)
+ {
+ MEMLEAKFINDER_NOT_A_LEAK(this);
+ THROW_EXCEPTION(CommonException, OSFileOpenError)
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::FileStream(const FileStream &)
+// Purpose: Copy constructor, creates a duplicate of the file handle
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+FileStream::FileStream(const FileStream &rToCopy)
+ : mOSFileHandle(::dup(rToCopy.mOSFileHandle)),
+ mIsEOF(rToCopy.mIsEOF)
+{
+ if(mOSFileHandle < 0)
+ {
+ MEMLEAKFINDER_NOT_A_LEAK(this);
+ THROW_EXCEPTION(CommonException, OSFileOpenError)
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::~FileStream()
+// Purpose: Destructor, closes file
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+FileStream::~FileStream()
+{
+ if(mOSFileHandle >= 0)
+ {
+ Close();
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::Read(void *, int)
+// Purpose: Reads bytes from the file
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+int FileStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ if(mOSFileHandle == -1) {THROW_EXCEPTION(CommonException, FileClosed)}
+ int r = ::read(mOSFileHandle, pBuffer, NBytes);
+ if(r == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileReadError)
+ }
+ if(r == 0)
+ {
+ mIsEOF = true;
+ }
+
+ return r;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::BytesLeftToRead()
+// Purpose: Returns number of bytes to read (may not be most efficient function ever)
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type FileStream::BytesLeftToRead()
+{
+ struct stat st;
+ if(::fstat(mOSFileHandle, &st) != 0)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ return st.st_size - GetPosition();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::Write(void *, int)
+// Purpose: Writes bytes to the file
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void FileStream::Write(const void *pBuffer, int NBytes)
+{
+ if(mOSFileHandle == -1) {THROW_EXCEPTION(CommonException, FileClosed)}
+ if(::write(mOSFileHandle, pBuffer, NBytes) != NBytes)
+ {
+ THROW_EXCEPTION(CommonException, OSFileWriteError)
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::GetPosition()
+// Purpose: Get position in stream
+// Created: 2003/08/21
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type FileStream::GetPosition() const
+{
+ if(mOSFileHandle == -1) {THROW_EXCEPTION(CommonException, FileClosed)}
+ off_t p = ::lseek(mOSFileHandle, 0, SEEK_CUR);
+ if(p == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ return (IOStream::pos_type)p;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::Seek(pos_type, int)
+// Purpose: Seeks within file, as lseek
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void FileStream::Seek(IOStream::pos_type Offset, int SeekType)
+{
+ if(mOSFileHandle == -1) {THROW_EXCEPTION(CommonException, FileClosed)}
+ if(::lseek(mOSFileHandle, Offset, ConvertSeekTypeToOSWhence(SeekType)) == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ // Not end of file any more!
+ mIsEOF = false;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::Close()
+// Purpose: Closes the underlying file
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void FileStream::Close()
+{
+ if(mOSFileHandle < 0)
+ {
+ THROW_EXCEPTION(CommonException, FileAlreadyClosed)
+ }
+ if(::close(mOSFileHandle) != 0)
+ {
+ THROW_EXCEPTION(CommonException, OSFileCloseError)
+ }
+ mOSFileHandle = -1;
+ mIsEOF = true;
+}
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::StreamDataLeft()
+// Purpose: Any data left to write?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool FileStream::StreamDataLeft()
+{
+ return !mIsEOF;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileStream::StreamClosed()
+// Purpose: Is the stream closed?
+// Created: 2003/08/02
+//
+// --------------------------------------------------------------------------
+bool FileStream::StreamClosed()
+{
+ return mIsEOF;
+}
+
diff --git a/lib/common/FileStream.h b/lib/common/FileStream.h
new file mode 100755
index 00000000..bb3cc459
--- /dev/null
+++ b/lib/common/FileStream.h
@@ -0,0 +1,46 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: FileStream.h
+// Purpose: FileStream interface to files
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+
+#ifndef FILESTREAM__H
+#define FILESTREAM__H
+
+#include "IOStream.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+class FileStream : public IOStream
+{
+public:
+ FileStream(const char *Filename, int flags = O_RDONLY, int mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
+ FileStream(int FileDescriptor);
+ FileStream(const FileStream &rToCopy);
+ virtual ~FileStream();
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual pos_type BytesLeftToRead();
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual pos_type GetPosition() const;
+ virtual void Seek(IOStream::pos_type Offset, int SeekType);
+ virtual void Close();
+
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+private:
+ int mOSFileHandle;
+ bool mIsEOF;
+};
+
+
+#endif // FILESTREAM__H
+
+
diff --git a/lib/common/Guards.h b/lib/common/Guards.h
new file mode 100755
index 00000000..6efc5614
--- /dev/null
+++ b/lib/common/Guards.h
@@ -0,0 +1,112 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Guards.h
+// Purpose: Classes which ensure things are closed/deleted properly when
+// going out of scope. Easy exception proof code, etc
+// Created: 2003/07/12
+//
+// --------------------------------------------------------------------------
+
+#ifndef GUARDS__H
+#define GUARDS__H
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <new>
+
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+template <int flags = O_RDONLY, int mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)>
+class FileHandleGuard
+{
+public:
+ FileHandleGuard(const char *filename)
+ : mOSFileHandle(::open(filename, flags, mode))
+ {
+ if(mOSFileHandle < 0)
+ {
+ THROW_EXCEPTION(CommonException, OSFileOpenError)
+ }
+ }
+
+ ~FileHandleGuard()
+ {
+ if(mOSFileHandle >= 0)
+ {
+ Close();
+ }
+ }
+
+ void Close()
+ {
+ if(mOSFileHandle < 0)
+ {
+ THROW_EXCEPTION(CommonException, FileAlreadyClosed)
+ }
+ if(::close(mOSFileHandle) != 0)
+ {
+ THROW_EXCEPTION(CommonException, OSFileCloseError)
+ }
+ mOSFileHandle = -1;
+ }
+
+ operator int() const
+ {
+ return mOSFileHandle;
+ }
+
+private:
+ int mOSFileHandle;
+};
+
+template<typename type>
+class MemoryBlockGuard
+{
+public:
+ MemoryBlockGuard(int BlockSize)
+ : mpBlock(::malloc(BlockSize))
+ {
+ if(mpBlock == 0)
+ {
+ throw std::bad_alloc();
+ }
+ }
+
+ ~MemoryBlockGuard()
+ {
+ free(mpBlock);
+ }
+
+ operator type() const
+ {
+ return (type)mpBlock;
+ }
+
+ type GetPtr() const
+ {
+ return (type)mpBlock;
+ }
+
+ void Resize(int NewSize)
+ {
+ void *ptrn = ::realloc(mpBlock, NewSize);
+ if(ptrn == 0)
+ {
+ throw std::bad_alloc();
+ }
+ mpBlock = ptrn;
+ }
+
+private:
+ void *mpBlock;
+};
+
+#include "MemLeakFindOff.h"
+
+#endif // GUARDS__H
+
diff --git a/lib/common/IOStream.cpp b/lib/common/IOStream.cpp
new file mode 100755
index 00000000..024eefcc
--- /dev/null
+++ b/lib/common/IOStream.cpp
@@ -0,0 +1,229 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: IOStream.cpp
+// Purpose: I/O Stream abstraction
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "IOStream.h"
+#include "CommonException.h"
+#include "Guards.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::IOStream()
+// Purpose: Constructor
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+IOStream::IOStream()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::IOStream(const IOStream &)
+// Purpose: Copy constructor (exceptions)
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+IOStream::IOStream(const IOStream &rToCopy)
+{
+ THROW_EXCEPTION(CommonException, NotSupported)
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::~IOStream()
+// Purpose: Destructor
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+IOStream::~IOStream()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::Close()
+// Purpose: Close the stream
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void IOStream::Close()
+{
+ // Do nothing by default -- let the destructor clear everything up.
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::Seek(int, int)
+// Purpose: Seek in stream (if supported)
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void IOStream::Seek(IOStream::pos_type Offset, int SeekType)
+{
+ THROW_EXCEPTION(CommonException, NotSupported)
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::GetPosition()
+// Purpose: Returns current position in stream (if supported)
+// Created: 2003/08/21
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type IOStream::GetPosition() const
+{
+ THROW_EXCEPTION(CommonException, NotSupported)
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::ConvertSeekTypeToOSWhence(int)
+// Purpose: Return an whence arg for lseek given a IOStream seek type
+// Created: 2003/08/21
+//
+// --------------------------------------------------------------------------
+int IOStream::ConvertSeekTypeToOSWhence(int SeekType)
+{
+ // Should be nicely optimised out as values are choosen in header file to match OS values.
+ int ostype = SEEK_SET;
+ switch(SeekType)
+ {
+ case SeekType_Absolute:
+ ostype = SEEK_SET;
+ break;
+ case SeekType_Relative:
+ ostype = SEEK_CUR;
+ break;
+ case SeekType_End:
+ ostype = SEEK_END;
+ break;
+
+ default:
+ THROW_EXCEPTION(CommonException, IOStreamBadSeekType)
+ }
+
+ return ostype;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::ReadFullBuffer(void *, int, int)
+// Purpose: Reads bytes into buffer, returning whether or not it managed to
+// get all the bytes required. Exception and abort use of stream
+// if this returns false.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+bool IOStream::ReadFullBuffer(void *pBuffer, int NBytes, int *pNBytesRead, int Timeout)
+{
+ int bytesToGo = NBytes;
+ char *buffer = (char*)pBuffer;
+ if(pNBytesRead) (*pNBytesRead) = 0;
+
+ while(bytesToGo > 0)
+ {
+ int bytesRead = Read(buffer, bytesToGo, Timeout);
+ if(bytesRead == 0)
+ {
+ // Timeout or something
+ return false;
+ }
+ // Increment things
+ bytesToGo -= bytesRead;
+ buffer += bytesRead;
+ if(pNBytesRead) (*pNBytesRead) += bytesRead;
+ }
+
+ // Got everything
+ return true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::WriteAllBuffered()
+// Purpose: Ensures that any data which has been buffered is written to the stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void IOStream::WriteAllBuffered()
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::BytesLeftToRead()
+// Purpose: Numbers of bytes left to read in the stream, or
+// IOStream::SizeOfStreamUnknown if this isn't known.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type IOStream::BytesLeftToRead()
+{
+ return IOStream::SizeOfStreamUnknown;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStream::CopyStreamTo(IOStream &, int Timeout)
+// Purpose: Copies the entire stream to another stream (reading from this,
+// writing to rCopyTo). Returns whether the copy completed (ie
+// StreamDataLeft() returns false)
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+bool IOStream::CopyStreamTo(IOStream &rCopyTo, int Timeout, int BufferSize)
+{
+ // Make sure there's something to do before allocating that buffer
+ if(!StreamDataLeft())
+ {
+ return true; // complete, even though nothing happened
+ }
+
+ // Buffer
+ MemoryBlockGuard<char*> buffer(BufferSize);
+
+ // Get copying!
+ while(StreamDataLeft())
+ {
+ // Read some data
+ int bytes = Read(buffer, BufferSize, Timeout);
+ if(bytes == 0 && StreamDataLeft())
+ {
+ return false; // incomplete, timed out
+ }
+
+ // Write some data
+ if(bytes != 0)
+ {
+ rCopyTo.Write(buffer, bytes);
+ }
+ }
+
+ return true; // completed
+}
+
+
diff --git a/lib/common/IOStream.h b/lib/common/IOStream.h
new file mode 100755
index 00000000..042ccca4
--- /dev/null
+++ b/lib/common/IOStream.h
@@ -0,0 +1,67 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: IOStream.h
+// Purpose: I/O Stream abstraction
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+
+#ifndef IOSTREAM__H
+#define IOSTREAM__H
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: IOStream
+// Purpose: Abstract interface to streams of data
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+class IOStream
+{
+public:
+ IOStream();
+ IOStream(const IOStream &rToCopy);
+ virtual ~IOStream();
+
+ enum
+ {
+ TimeOutInfinite = -1,
+ SizeOfStreamUnknown = -1
+ };
+
+ enum
+ {
+ SeekType_Absolute = 0,
+ SeekType_Relative = 1,
+ SeekType_End = 2
+ };
+
+ // Timeout in milliseconds
+ // Read may return 0 -- does not mean end of stream.
+ typedef int64_t pos_type;
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite) = 0;
+ virtual pos_type BytesLeftToRead(); // may return IOStream::SizeOfStreamUnknown (and will for most stream types)
+ virtual void Write(const void *pBuffer, int NBytes) = 0;
+ virtual void WriteAllBuffered();
+ virtual pos_type GetPosition() const;
+ virtual void Seek(pos_type Offset, int SeekType);
+ virtual void Close();
+
+ // Has all data that can be read been read?
+ virtual bool StreamDataLeft() = 0;
+ // Has the stream been closed (writing not possible)
+ virtual bool StreamClosed() = 0;
+
+ // Utility functions
+ bool ReadFullBuffer(void *pBuffer, int NBytes, int *pNBytesRead, int Timeout = IOStream::TimeOutInfinite);
+ bool CopyStreamTo(IOStream &rCopyTo, int Timeout = IOStream::TimeOutInfinite, int BufferSize = 1024);
+
+ static int ConvertSeekTypeToOSWhence(int SeekType);
+};
+
+
+#endif // IOSTREAM__H
+
+
diff --git a/lib/common/IOStreamGetLine.cpp b/lib/common/IOStreamGetLine.cpp
new file mode 100755
index 00000000..27a77c29
--- /dev/null
+++ b/lib/common/IOStreamGetLine.cpp
@@ -0,0 +1,227 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: IOStreamGetLine.cpp
+// Purpose: Line based file descriptor reading
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "IOStreamGetLine.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// utility whitespace function
+inline bool iw(int c)
+{
+ return (c == ' ' || c == '\t' || c == '\v' || c == '\f'); // \r, \n are already excluded
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStreamGetLine::IOStreamGetLine(int)
+// Purpose: Constructor, taking file descriptor
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+IOStreamGetLine::IOStreamGetLine(IOStream &Stream)
+ : mrStream(Stream),
+ mLineNumber(0),
+ mBufferBegin(0),
+ mBytesInBuffer(0),
+ mPendingEOF(false),
+ mEOF(false)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStreamGetLine::~IOStreamGetLine()
+// Purpose: Destructor
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+IOStreamGetLine::~IOStreamGetLine()
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStreamGetLine::GetLine(std::string &, bool, int)
+// Purpose: Gets a line from the file, returning it in rOutput. If Preprocess is true, leading
+// and trailing whitespace is removed, and comments (after #)
+// are deleted.
+// Returns true if a line is available now, false if retrying may get a line (eg timeout, signal),
+// and exceptions if it's EOF.
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+bool IOStreamGetLine::GetLine(std::string &rOutput, bool Preprocess, int Timeout)
+{
+ // EOF?
+ if(mEOF) {THROW_EXCEPTION(CommonException, GetLineEOF)}
+
+ // Initialise string to stored into
+ std::string r(mPendingString);
+ mPendingString.erase();
+
+ bool foundLineEnd = false;
+
+ while(!foundLineEnd && !mEOF)
+ {
+ // Use any bytes left in the buffer
+ while(mBufferBegin < mBytesInBuffer)
+ {
+ int c = mBuffer[mBufferBegin++];
+ if(c == '\r')
+ {
+ // Ignore nasty Windows line ending extra chars
+ }
+ else if(c == '\n')
+ {
+ // Line end!
+ foundLineEnd = true;
+ break;
+ }
+ else
+ {
+ // Add to string
+ r += c;
+ }
+
+ // Implicit line ending at EOF
+ if(mBufferBegin >= mBytesInBuffer && mPendingEOF)
+ {
+ foundLineEnd = true;
+ }
+ }
+
+ // Check size
+ if(r.size() > IOSTREAMGETLINE_MAX_LINE_SIZE)
+ {
+ THROW_EXCEPTION(CommonException, GetLineTooLarge)
+ }
+
+ // Read more in?
+ if(!foundLineEnd && mBufferBegin >= mBytesInBuffer && !mPendingEOF)
+ {
+ int bytes = mrStream.Read(mBuffer, sizeof(mBuffer), Timeout);
+
+ // Adjust buffer info
+ mBytesInBuffer = bytes;
+ mBufferBegin = 0;
+
+ // EOF / closed?
+ if(!mrStream.StreamDataLeft())
+ {
+ mPendingEOF = true;
+ }
+
+ // No data returned?
+ if(bytes == 0 && mrStream.StreamDataLeft())
+ {
+ // store string away
+ mPendingString = r;
+ // Return false;
+ return false;
+ }
+ }
+
+ // EOF?
+ if(mPendingEOF && mBufferBegin >= mBytesInBuffer)
+ {
+ // File is EOF, and now we've depleted the buffer completely, so tell caller as well.
+ mEOF = true;
+ }
+ }
+
+ if(!Preprocess)
+ {
+ rOutput = r;
+ return true;
+ }
+ else
+ {
+ // Check for comment char, but char before must be whitespace
+ int end = 0;
+ int size = r.size();
+ while(end < size)
+ {
+ if(r[end] == '#' && (end == 0 || (iw(r[end-1]))))
+ {
+ break;
+ }
+ end++;
+ }
+
+ // Remove whitespace
+ int begin = 0;
+ while(begin < size && iw(r[begin]))
+ {
+ begin++;
+ }
+ if(!iw(r[end])) end--;
+ while(end > begin && iw(r[end]))
+ {
+ end--;
+ }
+
+ // Return a sub string
+ rOutput = r.substr(begin, end - begin + 1);
+ return true;
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStreamGetLine::DetachFile()
+// Purpose: Detaches the file handle, setting the file pointer correctly.
+// Probably not good for sockets...
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+void IOStreamGetLine::DetachFile()
+{
+ // Adjust file pointer
+ int bytesOver = mBytesInBuffer - mBufferBegin;
+ ASSERT(bytesOver >= 0);
+ if(bytesOver > 0)
+ {
+ mrStream.Seek(0 - bytesOver, IOStream::SeekType_Relative);
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: IOStreamGetLine::IgnoreBufferedData(int)
+// Purpose: Ignore buffered bytes (effectively removing them from the
+// beginning of the buffered data.)
+// Cannot remove more bytes than are currently in the buffer.
+// Be careful when this is used!
+// Created: 22/12/04
+//
+// --------------------------------------------------------------------------
+void IOStreamGetLine::IgnoreBufferedData(int BytesToIgnore)
+{
+ int bytesInBuffer = mBytesInBuffer - mBufferBegin;
+ if(BytesToIgnore < 0 || BytesToIgnore > bytesInBuffer)
+ {
+ THROW_EXCEPTION(CommonException, IOStreamGetLineNotEnoughDataToIgnore)
+ }
+ mBufferBegin += BytesToIgnore;
+}
+
+
+
diff --git a/lib/common/IOStreamGetLine.h b/lib/common/IOStreamGetLine.h
new file mode 100755
index 00000000..cf152e5a
--- /dev/null
+++ b/lib/common/IOStreamGetLine.h
@@ -0,0 +1,71 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: IOStreamGetLine.h
+// Purpose: Line based file descriptor reading
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+
+#ifndef IOSTREAMGETLINE__H
+#define IOSTREAMGETLINE__H
+
+#include <string>
+
+#include "IOStream.h"
+
+#ifdef NDEBUG
+ #define IOSTREAMGETLINE_BUFFER_SIZE 1024
+#else
+ #define IOSTREAMGETLINE_BUFFER_SIZE 4
+#endif
+
+// Just a very large upper bound for line size to avoid
+// people sending lots of data over sockets and causing memory problems.
+#define IOSTREAMGETLINE_MAX_LINE_SIZE (1024*256)
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: IOStreamGetLine
+// Purpose: Line based stream reading
+// Created: 2003/07/24
+//
+// --------------------------------------------------------------------------
+class IOStreamGetLine
+{
+public:
+ IOStreamGetLine(IOStream &Stream);
+ ~IOStreamGetLine();
+private:
+ IOStreamGetLine(const IOStreamGetLine &rToCopy);
+
+public:
+ bool GetLine(std::string &rOutput, bool Preprocess = false, int Timeout = IOStream::TimeOutInfinite);
+ bool IsEOF() {return mEOF;}
+ int GetLineNumber() {return mLineNumber;}
+
+ // Call to detach, setting file pointer correctly to last bit read.
+ // Only works for lseek-able file descriptors.
+ void DetachFile();
+
+ // For doing interesting stuff with the remaining data...
+ // Be careful with this!
+ const void *GetBufferedData() const {return mBuffer + mBufferBegin;}
+ int GetSizeOfBufferedData() const {return mBytesInBuffer - mBufferBegin;}
+ void IgnoreBufferedData(int BytesToIgnore);
+ IOStream &GetUnderlyingStream() {return mrStream;}
+
+private:
+ char mBuffer[IOSTREAMGETLINE_BUFFER_SIZE];
+ IOStream &mrStream;
+ int mLineNumber;
+ int mBufferBegin;
+ int mBytesInBuffer;
+ bool mPendingEOF;
+ bool mEOF;
+ std::string mPendingString;
+};
+
+#endif // IOSTREAMGETLINE__H
+
diff --git a/lib/common/LinuxWorkaround.cpp b/lib/common/LinuxWorkaround.cpp
new file mode 100755
index 00000000..7900fa6e
--- /dev/null
+++ b/lib/common/LinuxWorkaround.cpp
@@ -0,0 +1,73 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: LinuxWorkaround.cpp
+// Purpose: Workarounds for Linux
+// Created: 2003/10/31
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <string>
+
+#include "LinuxWorkaround.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+#ifdef PLATFORM_LINUX
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: LinuxWorkaround_FinishDirentStruct(struct dirent *, const char *)
+// Purpose: Finishes off filling in a dirent structure, which Linux leaves incomplete.
+// Created: 2003/10/31
+//
+// --------------------------------------------------------------------------
+void LinuxWorkaround_FinishDirentStruct(struct dirent *entry, const char *DirectoryName)
+{
+ // From man readdir under Linux:
+ //
+ // BUGS
+ // Field d_type is not implemented as of libc6 2.1 and will always return
+ // DT_UNKNOWN (0).
+ //
+ // What kind of an OS is this?
+
+
+ // Build filename of this entry
+ std::string fn(DirectoryName);
+ fn += '/';
+ fn += entry->d_name;
+
+ // Do a stat on it
+ struct stat st;
+ if(::lstat(fn.c_str(), &st) != 0)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ // Fill in the d_type field.
+ if(S_ISREG(st.st_mode))
+ {
+ entry->d_type = DT_REG;
+ }
+ else if(S_ISDIR(st.st_mode))
+ {
+ entry->d_type = DT_DIR;
+ }
+ else if(S_ISLNK(st.st_mode))
+ {
+ entry->d_type = DT_LNK;
+ }
+ // otherwise leave it as we found it
+}
+
+#endif // PLATFORM_LINUX
+
diff --git a/lib/common/LinuxWorkaround.h b/lib/common/LinuxWorkaround.h
new file mode 100755
index 00000000..bcd27495
--- /dev/null
+++ b/lib/common/LinuxWorkaround.h
@@ -0,0 +1,20 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: LinuxWorkaround.h
+// Purpose: Workarounds for Linux
+// Created: 2003/10/31
+//
+// --------------------------------------------------------------------------
+
+#ifndef LINUXWORKAROUND__H
+#define LINUXWORKAROUND__H
+
+#ifdef PLATFORM_LINUX
+
+void LinuxWorkaround_FinishDirentStruct(struct dirent *entry, const char *DirectoryName);
+
+#endif // PLATFORM_LINUX
+
+#endif // LINUXWORKAROUND__H
+
diff --git a/lib/common/MainHelper.h b/lib/common/MainHelper.h
new file mode 100755
index 00000000..ab75af96
--- /dev/null
+++ b/lib/common/MainHelper.h
@@ -0,0 +1,42 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: MainHelper.h
+// Purpose: Helper stuff for main() programs
+// Created: 2003/08/21
+//
+// --------------------------------------------------------------------------
+
+#ifndef MAINHELPER__H
+#define MAINHELPER__H
+
+#include <stdio.h>
+
+#include "BoxException.h"
+
+#define MAINHELPER_START \
+ if(argc == 2 && ::strcmp(argv[1], "--version") == 0) \
+ { printf(BOX_VERSION "\n"); return 0; } \
+ MEMLEAKFINDER_START \
+ try {
+#define MAINHELPER_END \
+ } catch(BoxException &e) { \
+ printf("Exception: %s (%d/%d)\n", e.what(), e.GetType(), e.GetSubType()); \
+ return 1; \
+ } catch(std::exception &e) { \
+ printf("Exception: %s\n", e.what()); \
+ return 1; \
+ } catch(...) { \
+ printf("Exception: <UNKNOWN>\n"); \
+ return 1; }
+
+#ifdef BOX_MEMORY_LEAK_TESTING
+ #define MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT(file, marker) \
+ memleakfinder_setup_exit_report(file, marker);
+#else
+ #define MAINHELPER_SETUP_MEMORY_LEAK_EXIT_REPORT(file, marker)
+#endif // BOX_MEMORY_LEAK_TESTING
+
+
+#endif // MAINHELPER__H
+
diff --git a/lib/common/Makefile.extra b/lib/common/Makefile.extra
new file mode 100755
index 00000000..92e6fbb3
--- /dev/null
+++ b/lib/common/Makefile.extra
@@ -0,0 +1,11 @@
+
+MAKEEXCEPTION = ../../lib/common/makeexception.pl
+
+# AUTOGEN SEEDING
+autogen_CommonException.h autogen_CommonException.cpp: $(MAKEEXCEPTION) CommonException.txt
+ perl $(MAKEEXCEPTION) CommonException.txt
+
+# AUTOGEN SEEDING
+autogen_ConversionException.h autogen_ConversionException.cpp: $(MAKEEXCEPTION) ConversionException.txt
+ perl $(MAKEEXCEPTION) ConversionException.txt
+
diff --git a/lib/common/MemBlockStream.cpp b/lib/common/MemBlockStream.cpp
new file mode 100755
index 00000000..538a7ef8
--- /dev/null
+++ b/lib/common/MemBlockStream.cpp
@@ -0,0 +1,235 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: MemBlockStream.cpp
+// Purpose: Stream out data from any memory block
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <string.h>
+
+#include "MemBlockStream.h"
+#include "CommonException.h"
+#include "StreamableMemBlock.h"
+#include "CollectInBufferStream.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::MemBlockStream()
+// Purpose: Constructor (doesn't copy block, careful with lifetimes)
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+MemBlockStream::MemBlockStream(const void *pBuffer, int Size)
+ : mpBuffer((char*)pBuffer),
+ mBytesInBuffer(Size),
+ mReadPosition(0)
+{
+ ASSERT(pBuffer != 0);
+ ASSERT(Size >= 0);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::MemBlockStream(const StreamableMemBlock &)
+// Purpose: Constructor (doesn't copy block, careful with lifetimes)
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+MemBlockStream::MemBlockStream(const StreamableMemBlock &rBlock)
+ : mpBuffer((char*)rBlock.GetBuffer()),
+ mBytesInBuffer(rBlock.GetSize()),
+ mReadPosition(0)
+{
+ ASSERT(mpBuffer != 0);
+ ASSERT(mBytesInBuffer >= 0);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::MemBlockStream(const StreamableMemBlock &)
+// Purpose: Constructor (doesn't copy block, careful with lifetimes)
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+MemBlockStream::MemBlockStream(const CollectInBufferStream &rBuffer)
+ : mpBuffer((char*)rBuffer.GetBuffer()),
+ mBytesInBuffer(rBuffer.GetSize()),
+ mReadPosition(0)
+{
+ ASSERT(mpBuffer != 0);
+ ASSERT(mBytesInBuffer >= 0);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::MemBlockStream(const MemBlockStream &)
+// Purpose: Copy constructor
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+MemBlockStream::MemBlockStream(const MemBlockStream &rToCopy)
+ : mpBuffer(rToCopy.mpBuffer),
+ mBytesInBuffer(rToCopy.mBytesInBuffer),
+ mReadPosition(0)
+{
+ ASSERT(mpBuffer != 0);
+ ASSERT(mBytesInBuffer >= 0);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::~MemBlockStream()
+// Purpose: Destructor
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+MemBlockStream::~MemBlockStream()
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::Read(void *, int, int)
+// Purpose: As interface. But only works in read phase
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+int MemBlockStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ // Adjust to number of bytes left
+ if(NBytes > (mBytesInBuffer - mReadPosition))
+ {
+ NBytes = (mBytesInBuffer - mReadPosition);
+ }
+ ASSERT(NBytes >= 0);
+ if(NBytes <= 0) return 0; // careful now
+
+ // Copy in the requested number of bytes and adjust the read pointer
+ ::memcpy(pBuffer, mpBuffer + mReadPosition, NBytes);
+ mReadPosition += NBytes;
+
+ return NBytes;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::BytesLeftToRead()
+// Purpose: As interface. But only works in read phase
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type MemBlockStream::BytesLeftToRead()
+{
+ return (mBytesInBuffer - mReadPosition);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::Write(void *, int)
+// Purpose: As interface. But only works in write phase
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void MemBlockStream::Write(const void *pBuffer, int NBytes)
+{
+ THROW_EXCEPTION(CommonException, MemBlockStreamNotSupported)
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::GetPosition()
+// Purpose: In write phase, returns the number of bytes written, in read
+// phase, the number of bytes to go
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type MemBlockStream::GetPosition() const
+{
+ return mReadPosition;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::Seek(pos_type, int)
+// Purpose: As interface.
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void MemBlockStream::Seek(pos_type Offset, int SeekType)
+{
+ int newPos = 0;
+ switch(SeekType)
+ {
+ case IOStream::SeekType_Absolute:
+ newPos = Offset;
+ break;
+ case IOStream::SeekType_Relative:
+ newPos = mReadPosition + Offset;
+ break;
+ case IOStream::SeekType_End:
+ newPos = mBytesInBuffer + Offset;
+ break;
+ default:
+ THROW_EXCEPTION(CommonException, IOStreamBadSeekType)
+ break;
+ }
+
+ // Make sure it doesn't go over
+ if(newPos > mBytesInBuffer)
+ {
+ newPos = mBytesInBuffer;
+ }
+ // or under
+ if(newPos < 0)
+ {
+ newPos = 0;
+ }
+
+ // Set the new read position
+ mReadPosition = newPos;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::StreamDataLeft()
+// Purpose: As interface
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+bool MemBlockStream::StreamDataLeft()
+{
+ return mReadPosition < mBytesInBuffer;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: MemBlockStream::StreamClosed()
+// Purpose: As interface
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+bool MemBlockStream::StreamClosed()
+{
+ return true;
+}
+
diff --git a/lib/common/MemBlockStream.h b/lib/common/MemBlockStream.h
new file mode 100755
index 00000000..f78ff8e6
--- /dev/null
+++ b/lib/common/MemBlockStream.h
@@ -0,0 +1,52 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: MemBlockStream.h
+// Purpose: Stream out data from any memory block
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+
+#ifndef MEMBLOCKSTREAM__H
+#define MEMBLOCKSTREAM__H
+
+#include "IOStream.h"
+
+class StreamableMemBlock;
+class CollectInBufferStream;
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: MemBlockStream
+// Purpose: Stream out data from any memory block -- be careful the lifetime
+// of the block is greater than the lifetime of this stream.
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+class MemBlockStream : public IOStream
+{
+public:
+ MemBlockStream(const void *pBuffer, int Size);
+ MemBlockStream(const StreamableMemBlock &rBlock);
+ MemBlockStream(const CollectInBufferStream &rBuffer);
+ MemBlockStream(const MemBlockStream &rToCopy);
+ ~MemBlockStream();
+public:
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual pos_type BytesLeftToRead();
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual pos_type GetPosition() const;
+ virtual void Seek(pos_type Offset, int SeekType);
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+private:
+ const char *mpBuffer;
+ int mBytesInBuffer;
+ int mReadPosition;
+};
+
+#endif // MEMBLOCKSTREAM__H
+
diff --git a/lib/common/MemLeakFindOff.h b/lib/common/MemLeakFindOff.h
new file mode 100755
index 00000000..1cc98bac
--- /dev/null
+++ b/lib/common/MemLeakFindOff.h
@@ -0,0 +1,27 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: MemLeakFindOff.h
+// Purpose: Switch memory leak finding off
+// Created: 13/1/04
+//
+// --------------------------------------------------------------------------
+
+// no header guard
+
+#ifdef BOX_MEMORY_LEAK_TESTING
+
+#undef new
+
+#ifndef MEMLEAKFINDER_FULL_MALLOC_MONITORING
+ #ifdef MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
+ #undef malloc
+ #undef realloc
+ #undef free
+ #undef MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
+ #endif
+#endif
+
+#undef MEMLEAKFINDER_ENABLED
+
+#endif
diff --git a/lib/common/MemLeakFindOn.h b/lib/common/MemLeakFindOn.h
new file mode 100755
index 00000000..c20fe25a
--- /dev/null
+++ b/lib/common/MemLeakFindOn.h
@@ -0,0 +1,25 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: MemLeakFindOn.h
+// Purpose: Switch memory leak finding on
+// Created: 13/1/04
+//
+// --------------------------------------------------------------------------
+
+// no header guard
+
+#ifdef BOX_MEMORY_LEAK_TESTING
+
+#define new DEBUG_NEW
+
+#ifndef MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
+ #define malloc(X) memleakfinder_malloc(X, __FILE__, __LINE__)
+ #define realloc memleakfinder_realloc
+ #define free memleakfinder_free
+ #define MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
+#endif
+
+#define MEMLEAKFINDER_ENABLED
+
+#endif
diff --git a/lib/common/MemLeakFinder.h b/lib/common/MemLeakFinder.h
new file mode 100755
index 00000000..f5887dac
--- /dev/null
+++ b/lib/common/MemLeakFinder.h
@@ -0,0 +1,60 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: MemLeakFinder.h
+// Purpose: Memory leak finder
+// Created: 12/1/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef MEMLEAKFINDER__H
+#define MEMLEAKFINDER__H
+
+#define DEBUG_NEW new(__FILE__,__LINE__)
+
+#ifdef MEMLEAKFINDER_FULL_MALLOC_MONITORING
+ // include stdlib now, to avoid problems with having the macros defined already
+ #include <stdlib.h>
+#endif
+
+// global enable flag
+extern bool memleakfinder_global_enable;
+
+extern "C"
+{
+ void *memleakfinder_malloc(size_t size, const char *file, int line);
+ void *memleakfinder_realloc(void *ptr, size_t size);
+ void memleakfinder_free(void *ptr);
+}
+
+int memleakfinder_numleaks();
+
+void memleakfinder_reportleaks();
+
+void memleakfinder_reportleaks_appendfile(const char *filename, const char *markertext);
+
+void memleakfinder_setup_exit_report(const char *filename, const char *markertext);
+
+void memleakfinder_startsectionmonitor();
+
+void memleakfinder_traceblocksinsection();
+
+void memleakfinder_notaleak(void *ptr);
+
+void *operator new(size_t size, const char *file, int line);
+void *operator new[](size_t size, const char *file, int line);
+
+void operator delete(void *ptr) throw ();
+void operator delete[](void *ptr) throw ();
+
+// define the malloc functions now, if required
+#ifdef MEMLEAKFINDER_FULL_MALLOC_MONITORING
+ #define malloc(X) memleakfinder_malloc(X, __FILE__, __LINE__)
+ #define realloc memleakfinder_realloc
+ #define free memleakfinder_free
+ #define MEMLEAKFINDER_MALLOC_MONITORING_DEFINED
+#endif
+
+
+#endif // MEMLEAKFINDER__H
+
diff --git a/lib/common/NamedLock.cpp b/lib/common/NamedLock.cpp
new file mode 100755
index 00000000..1f6e038a
--- /dev/null
+++ b/lib/common/NamedLock.cpp
@@ -0,0 +1,144 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: NamedLock.cpp
+// Purpose: A global named lock, implemented as a lock file in file system
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#ifdef PLATFORM_LINUX
+ #include <sys/file.h>
+#endif // PLATFORM_LINUX
+#ifdef PLATFORM_CYGWIN
+ #include <sys/file.h>
+#endif // PLATFORM_CYGWIN
+
+#include "NamedLock.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: NamedLock::NamedLock()
+// Purpose: Constructor
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+NamedLock::NamedLock()
+ : mFileDescriptor(-1)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: NamedLock::~NamedLock()
+// Purpose: Destructor (automatically unlocks if locked)
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+NamedLock::~NamedLock()
+{
+ if(mFileDescriptor != -1)
+ {
+ ReleaseLock();
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: NamedLock::TryAndGetLock(const char *, int)
+// Purpose: Trys to get a lock on the name in the file system.
+// IMPORTANT NOTE: If a file exists with this name, it will be deleted.
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+bool NamedLock::TryAndGetLock(const char *Filename, int mode)
+{
+ // Check
+ if(mFileDescriptor != -1)
+ {
+ THROW_EXCEPTION(CommonException, NamedLockAlreadyLockingSomething)
+ }
+
+ // See if the lock can be got
+#ifdef PLATFORM_open_NO_O_EXLOCK
+ int fd = ::open(Filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
+ if(fd == -1)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+ if(::flock(fd, LOCK_EX | LOCK_NB) != 0)
+ {
+ ::close(fd);
+ if(errno == EWOULDBLOCK)
+ {
+ return false;
+ }
+ else
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+ }
+
+ // Success
+ mFileDescriptor = fd;
+
+ return true;
+#else
+ int fd = ::open(Filename, O_WRONLY | O_NONBLOCK | O_CREAT | O_TRUNC | O_EXLOCK, mode);
+ if(fd != -1)
+ {
+ // Got a lock, lovely
+ mFileDescriptor = fd;
+ return true;
+ }
+
+ // Failed. Why?
+ if(errno != EWOULDBLOCK)
+ {
+ // Not the expected error
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+
+ return false;
+#endif
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: NamedLock::ReleaseLock()
+// Purpose: Release the lock. Exceptions if the lock is not held
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+void NamedLock::ReleaseLock()
+{
+ // Got a lock?
+ if(mFileDescriptor == -1)
+ {
+ THROW_EXCEPTION(CommonException, NamedLockNotHeld)
+ }
+
+ // Close the file
+ if(::close(mFileDescriptor) != 0)
+ {
+ THROW_EXCEPTION(CommonException, OSFileError)
+ }
+ // Mark as unlocked
+ mFileDescriptor = -1;
+}
+
+
+
+
diff --git a/lib/common/NamedLock.h b/lib/common/NamedLock.h
new file mode 100755
index 00000000..5eac712a
--- /dev/null
+++ b/lib/common/NamedLock.h
@@ -0,0 +1,41 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: NamedLock.h
+// Purpose: A global named lock, implemented as a lock file in file system
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+
+#ifndef NAMEDLOCK__H
+#define NAMEDLOCK__H
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: NamedLock
+// Purpose: A global named lock, implemented as a lock file in file system
+// Created: 2003/08/28
+//
+// --------------------------------------------------------------------------
+class NamedLock
+{
+public:
+ NamedLock();
+ ~NamedLock();
+private:
+ // No copying allowed
+ NamedLock(const NamedLock &);
+
+public:
+ bool TryAndGetLock(const char *Filename, int mode = 0755);
+ bool GotLock() {return mFileDescriptor != -1;}
+ void ReleaseLock();
+
+
+private:
+ int mFileDescriptor;
+};
+
+#endif // NAMEDLOCK__H
+
diff --git a/lib/common/PartialReadStream.cpp b/lib/common/PartialReadStream.cpp
new file mode 100755
index 00000000..0b5c4cf6
--- /dev/null
+++ b/lib/common/PartialReadStream.cpp
@@ -0,0 +1,135 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: PartialReadStream.h
+// Purpose: Read part of another stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+#include "PartialReadStream.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: PartialReadStream::PartialReadStream(IOStream &, int)
+// Purpose: Constructor, taking another stream and the number of bytes
+// to be read from it.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+PartialReadStream::PartialReadStream(IOStream &rSource, int BytesToRead)
+ : mrSource(rSource),
+ mBytesLeft(BytesToRead)
+{
+ ASSERT(BytesToRead > 0);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: PartialReadStream::~PartialReadStream()
+// Purpose: Destructor. Won't absorb any unread bytes.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+PartialReadStream::~PartialReadStream()
+{
+ // Warn in debug mode
+ if(mBytesLeft != 0)
+ {
+ TRACE1("PartialReadStream::~PartialReadStream when mBytesLeft = %d\n", mBytesLeft);
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: PartialReadStream::Read(void *, int, int)
+// Purpose: As interface.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+int PartialReadStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ // Finished?
+ if(mBytesLeft <= 0)
+ {
+ return 0;
+ }
+
+ // Asking for more than is allowed?
+ if(NBytes > mBytesLeft)
+ {
+ // Adjust downwards
+ NBytes = mBytesLeft;
+ }
+
+ // Route the request to the source
+ int read = mrSource.Read(pBuffer, NBytes, Timeout);
+ ASSERT(read <= mBytesLeft);
+
+ // Adjust the count
+ mBytesLeft -= read;
+
+ // Return the number read
+ return read;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: PartialReadStream::BytesLeftToRead()
+// Purpose: As interface.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type PartialReadStream::BytesLeftToRead()
+{
+ return mBytesLeft;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: PartialReadStream::Write(const void *, int)
+// Purpose: As interface. But will exception.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+void PartialReadStream::Write(const void *pBuffer, int NBytes)
+{
+ THROW_EXCEPTION(CommonException, CantWriteToPartialReadStream)
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: PartialReadStream::StreamDataLeft()
+// Purpose: As interface.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+bool PartialReadStream::StreamDataLeft()
+{
+ return mBytesLeft != 0;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: PartialReadStream::StreamClosed()
+// Purpose: As interface.
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+bool PartialReadStream::StreamClosed()
+{
+ // always closed
+ return true;
+}
+
diff --git a/lib/common/PartialReadStream.h b/lib/common/PartialReadStream.h
new file mode 100755
index 00000000..42cb7aeb
--- /dev/null
+++ b/lib/common/PartialReadStream.h
@@ -0,0 +1,46 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: PartialReadStream.h
+// Purpose: Read part of another stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+
+#ifndef PARTIALREADSTREAM__H
+#define PARTIALREADSTREAM__H
+
+#include "IOStream.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: PartialReadStream
+// Purpose: Read part of another stream
+// Created: 2003/08/26
+//
+// --------------------------------------------------------------------------
+class PartialReadStream : public IOStream
+{
+public:
+ PartialReadStream(IOStream &rSource, int BytesToRead);
+ ~PartialReadStream();
+private:
+ // no copying allowed
+ PartialReadStream(const IOStream &);
+ PartialReadStream(const PartialReadStream &);
+
+public:
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual pos_type BytesLeftToRead();
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+
+private:
+ IOStream &mrSource;
+ int mBytesLeft;
+};
+
+#endif // PARTIALREADSTREAM__H
+
diff --git a/lib/common/ReadGatherStream.cpp b/lib/common/ReadGatherStream.cpp
new file mode 100755
index 00000000..9ccc3a54
--- /dev/null
+++ b/lib/common/ReadGatherStream.cpp
@@ -0,0 +1,262 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ReadGatherStream.cpp
+// Purpose: Build a stream (for reading only) out of a number of other streams.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include "ReadGatherStream.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::ReadGatherStream(bool)
+// Purpose: Constructor. Args says whether or not all the component streams will be deleted when this
+// object is deleted.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+ReadGatherStream::ReadGatherStream(bool DeleteComponentStreamsOnDestruction)
+ : mDeleteComponentStreamsOnDestruction(DeleteComponentStreamsOnDestruction),
+ mCurrentPosition(0),
+ mTotalSize(0),
+ mCurrentBlock(0),
+ mPositionInCurrentBlock(0),
+ mSeekDoneForCurrent(false)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::~ReadGatherStream()
+// Purpose: Destructor. Will delete all the stream objects, if required.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+ReadGatherStream::~ReadGatherStream()
+{
+ // Delete compoenent streams?
+ if(mDeleteComponentStreamsOnDestruction)
+ {
+ for(unsigned int l = 0; l < mComponents.size(); ++l)
+ {
+ delete mComponents[l];
+ }
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::AddComponent(IOStream *)
+// Purpose: Add a component to this stream, returning the index of this component
+// in the internal list. Use this with AddBlock()
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+int ReadGatherStream::AddComponent(IOStream *pStream)
+{
+ ASSERT(pStream != 0);
+
+ // Just add the component to the list, returning it's index.
+ int index = mComponents.size();
+ mComponents.push_back(pStream);
+ return index;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::AddBlock(int, pos_type, bool, pos_type)
+// Purpose: Add a block to the list of blocks being gathered into one stream.
+// Length is length of block to read from this component, Seek == true
+// if a seek is required, and if true, SeekTo is the position (absolute)
+// in the stream to be seeked to when this block is required.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+void ReadGatherStream::AddBlock(int Component, pos_type Length, bool Seek, pos_type SeekTo)
+{
+ // Check block
+ if(Component < 0 || Component >= (int)mComponents.size() || Length < 0 || SeekTo < 0)
+ {
+ THROW_EXCEPTION(CommonException, ReadGatherStreamAddingBadBlock);
+ }
+
+ // Add to list
+ Block b;
+ b.mLength = Length;
+ b.mSeekTo = SeekTo;
+ b.mComponent = Component;
+ b.mSeek = Seek;
+
+ mBlocks.push_back(b);
+
+ // And update the total size
+ mTotalSize += Length;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::Read(void *, int, int)
+// Purpose: As interface.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+int ReadGatherStream::Read(void *pBuffer, int NBytes, int Timeout)
+{
+ int bytesToRead = NBytes;
+ uint8_t *buffer = (uint8_t*)pBuffer;
+
+ while(bytesToRead > 0)
+ {
+ // Done?
+ if(mCurrentBlock >= mBlocks.size())
+ {
+ // Stop now, as have finished the last block
+ return NBytes - bytesToRead;
+ }
+
+ // Seek?
+ if(mPositionInCurrentBlock == 0 && mBlocks[mCurrentBlock].mSeek && !mSeekDoneForCurrent)
+ {
+ // Do seeks in this manner so that seeks are done regardless of whether the block
+ // has length > 0, and it will only be done once, and at as late a stage as possible.
+
+ mComponents[mBlocks[mCurrentBlock].mComponent]->Seek(mBlocks[mCurrentBlock].mSeekTo, IOStream::SeekType_Absolute);
+
+ mSeekDoneForCurrent = true;
+ }
+
+ // Anything in the current block?
+ if(mPositionInCurrentBlock < mBlocks[mCurrentBlock].mLength)
+ {
+ // Read!
+ int s = mBlocks[mCurrentBlock].mLength - mPositionInCurrentBlock;
+ if(s > bytesToRead) s = bytesToRead;
+
+ int r = mComponents[mBlocks[mCurrentBlock].mComponent]->Read(buffer, s, Timeout);
+
+ // update variables
+ mPositionInCurrentBlock += r;
+ buffer += r;
+ bytesToRead -= r;
+ mCurrentPosition += r;
+
+ if(r != s)
+ {
+ // Stream returned less than requested. To avoid blocking when not necessary,
+ // return now.
+ return NBytes - bytesToRead;
+ }
+ }
+ else
+ {
+ // Move to next block
+ ++mCurrentBlock;
+ mPositionInCurrentBlock = 0;
+ mSeekDoneForCurrent = false;
+ }
+ }
+
+ return NBytes - bytesToRead;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::GetPosition()
+// Purpose: As interface
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type ReadGatherStream::GetPosition() const
+{
+ return mCurrentPosition;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::BytesLeftToRead()
+// Purpose: As interface
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+IOStream::pos_type ReadGatherStream::BytesLeftToRead()
+{
+ return mTotalSize - mCurrentPosition;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::Write(const void *, int)
+// Purpose: As interface.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+void ReadGatherStream::Write(const void *pBuffer, int NBytes)
+{
+ THROW_EXCEPTION(CommonException, CannotWriteToReadGatherStream);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::StreamDataLeft()
+// Purpose: As interface.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+bool ReadGatherStream::StreamDataLeft()
+{
+ if(mCurrentBlock >= mBlocks.size())
+ {
+ // Done all the blocks
+ return false;
+ }
+
+ if(mCurrentBlock == (mBlocks.size() - 1)
+ && mPositionInCurrentBlock >= mBlocks[mCurrentBlock].mLength)
+ {
+ // Are on the last block, and have got all the data from it.
+ return false;
+ }
+
+ // Otherwise, there's more data to be read
+ return true;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ReadGatherStream::StreamClosed()
+// Purpose: As interface. But the stream is always closed.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+bool ReadGatherStream::StreamClosed()
+{
+ return true;
+}
+
+
diff --git a/lib/common/ReadGatherStream.h b/lib/common/ReadGatherStream.h
new file mode 100755
index 00000000..613ede3e
--- /dev/null
+++ b/lib/common/ReadGatherStream.h
@@ -0,0 +1,67 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: ReadGatherStream.h
+// Purpose: Build a stream (for reading only) out of a number of other streams.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+
+#ifndef READGATHERSTREAM_H
+#define READGATHERSTREAM_H
+
+#include "IOStream.h"
+
+#include <vector>
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: ReadGatherStream
+// Purpose: Build a stream (for reading only) out of a number of other streams.
+// Created: 10/12/03
+//
+// --------------------------------------------------------------------------
+class ReadGatherStream : public IOStream
+{
+public:
+ ReadGatherStream(bool DeleteComponentStreamsOnDestruction);
+ ~ReadGatherStream();
+private:
+ ReadGatherStream(const ReadGatherStream &);
+ ReadGatherStream &operator=(const ReadGatherStream &);
+public:
+
+ int AddComponent(IOStream *pStream);
+ void AddBlock(int Component, pos_type Length, bool Seek = false, pos_type SeekTo = 0);
+
+ virtual int Read(void *pBuffer, int NBytes, int Timeout = IOStream::TimeOutInfinite);
+ virtual pos_type BytesLeftToRead();
+ virtual void Write(const void *pBuffer, int NBytes);
+ virtual bool StreamDataLeft();
+ virtual bool StreamClosed();
+ virtual pos_type GetPosition() const;
+
+private:
+ bool mDeleteComponentStreamsOnDestruction;
+ std::vector<IOStream *> mComponents;
+
+ typedef struct
+ {
+ pos_type mLength;
+ pos_type mSeekTo;
+ int mComponent;
+ bool mSeek;
+ } Block;
+
+ std::vector<Block> mBlocks;
+
+ pos_type mCurrentPosition;
+ pos_type mTotalSize;
+ unsigned int mCurrentBlock;
+ pos_type mPositionInCurrentBlock;
+ bool mSeekDoneForCurrent;
+};
+
+
+#endif // READGATHERSTREAM_H
diff --git a/lib/common/StreamableMemBlock.cpp b/lib/common/StreamableMemBlock.cpp
new file mode 100755
index 00000000..4ea9e398
--- /dev/null
+++ b/lib/common/StreamableMemBlock.cpp
@@ -0,0 +1,365 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: StreamableMemBlock.cpp
+// Purpose: Memory blocks which can be loaded and saved from streams
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <new>
+#include <stdlib.h>
+#include <string.h>
+
+#include "StreamableMemBlock.h"
+#include "IOStream.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::StreamableMemBlock()
+// Purpose: Constructor, making empty block
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+StreamableMemBlock::StreamableMemBlock()
+ : mpBuffer(0),
+ mSize(0)
+{
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::StreamableMemBlock(void *, int)
+// Purpose: Create block, copying data from another bit of memory
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+StreamableMemBlock::StreamableMemBlock(void *pBuffer, int Size)
+ : mpBuffer(0),
+ mSize(0)
+{
+ AllocateBlock(Size);
+ ::memcpy(mpBuffer, pBuffer, Size);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::StreamableMemBlock(int)
+// Purpose: Create block, initialising it to all zeros
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+StreamableMemBlock::StreamableMemBlock(int Size)
+ : mpBuffer(0),
+ mSize(0)
+{
+ AllocateBlock(Size);
+ ::memset(mpBuffer, 0, Size);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::StreamableMemBlock(const StreamableMemBlock &)
+// Purpose: Copy constructor
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+StreamableMemBlock::StreamableMemBlock(const StreamableMemBlock &rToCopy)
+ : mpBuffer(0),
+ mSize(0)
+{
+ AllocateBlock(rToCopy.mSize);
+ ::memcpy(mpBuffer, rToCopy.mpBuffer, mSize);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::Set(void *, int)
+// Purpose: Set the contents of the block
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void StreamableMemBlock::Set(void *pBuffer, int Size)
+{
+ FreeBlock();
+ AllocateBlock(Size);
+ ::memcpy(mpBuffer, pBuffer, Size);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::Set(IOStream &)
+// Purpose: Set from stream. Stream must support BytesLeftToRead()
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void StreamableMemBlock::Set(IOStream &rStream, int Timeout)
+{
+ // Get size
+ IOStream::pos_type size = rStream.BytesLeftToRead();
+ if(size == IOStream::SizeOfStreamUnknown)
+ {
+ THROW_EXCEPTION(CommonException, StreamDoesntHaveRequiredProperty)
+ }
+
+ // Allocate a new block (this way to be exception safe)
+ char *pblock = (char*)malloc(size);
+ if(pblock == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ try
+ {
+ // Read in
+ if(!rStream.ReadFullBuffer(pblock, size, 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+
+ // Free the block ready for replacement
+ FreeBlock();
+ }
+ catch(...)
+ {
+ ::free(pblock);
+ throw;
+ }
+
+ // store...
+ ASSERT(mpBuffer == 0);
+ mpBuffer = pblock;
+ mSize = size;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::Set(const StreamableMemBlock &)
+// Purpose: Set from other block.
+// Created: 2003/09/06
+//
+// --------------------------------------------------------------------------
+void StreamableMemBlock::Set(const StreamableMemBlock &rBlock)
+{
+ Set(rBlock.mpBuffer, rBlock.mSize);
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::~StreamableMemBlock()
+// Purpose: Destructor
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+StreamableMemBlock::~StreamableMemBlock()
+{
+ FreeBlock();
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::FreeBlock()
+// Purpose: Protected. Frees block of memory
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void StreamableMemBlock::FreeBlock()
+{
+ if(mpBuffer != 0)
+ {
+ ::free(mpBuffer);
+ }
+ mpBuffer = 0;
+ mSize = 0;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::AllocateBlock(int)
+// Purpose: Protected. Allocate the block of memory
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void StreamableMemBlock::AllocateBlock(int Size)
+{
+ ASSERT(mpBuffer == 0);
+ if(Size > 0)
+ {
+ mpBuffer = ::malloc(Size);
+ if(mpBuffer == 0)
+ {
+ throw std::bad_alloc();
+ }
+ }
+ mSize = Size;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::ResizeBlock(int)
+// Purpose: Protected. Resizes the allocated block.
+// Created: 3/12/03
+//
+// --------------------------------------------------------------------------
+void StreamableMemBlock::ResizeBlock(int Size)
+{
+ ASSERT(mpBuffer != 0);
+ ASSERT(Size > 0);
+ if(Size > 0)
+ {
+ void *pnewBuffer = ::realloc(mpBuffer, Size);
+ if(pnewBuffer == 0)
+ {
+ throw std::bad_alloc();
+ }
+ mpBuffer = pnewBuffer;
+ }
+ mSize = Size;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::ReadFromStream(IOStream &, int)
+// Purpose: Read the block in from a stream
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void StreamableMemBlock::ReadFromStream(IOStream &rStream, int Timeout)
+{
+ // Get the size of the block
+ int32_t size_s;
+ if(!rStream.ReadFullBuffer(&size_s, sizeof(size_s), 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+
+ int size = ntohl(size_s);
+
+
+ // Allocate a new block (this way to be exception safe)
+ char *pblock = (char*)malloc(size);
+ if(pblock == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ try
+ {
+ // Read in
+ if(!rStream.ReadFullBuffer(pblock, size, 0 /* not interested in bytes read if this fails */))
+ {
+ THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
+ }
+
+ // Free the block ready for replacement
+ FreeBlock();
+ }
+ catch(...)
+ {
+ ::free(pblock);
+ throw;
+ }
+
+ // store...
+ ASSERT(mpBuffer == 0);
+ mpBuffer = pblock;
+ mSize = size;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::WriteToStream(IOStream &)
+// Purpose: Write the block to a stream
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void StreamableMemBlock::WriteToStream(IOStream &rStream) const
+{
+ int32_t sizenbo = htonl(mSize);
+ // Size
+ rStream.Write(&sizenbo, sizeof(sizenbo));
+ // Buffer
+ if(mSize > 0)
+ {
+ rStream.Write(mpBuffer, mSize);
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::WriteEmptyBlockToStream(IOStream &)
+// Purpose: Writes an empty block to a stream.
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void StreamableMemBlock::WriteEmptyBlockToStream(IOStream &rStream)
+{
+ int32_t sizenbo = htonl(0);
+ rStream.Write(&sizenbo, sizeof(sizenbo));
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::GetBuffer()
+// Purpose: Get pointer to buffer
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+void *StreamableMemBlock::GetBuffer() const
+{
+ if(mSize == 0)
+ {
+ // Return something which isn't a null pointer
+ static const int validptr = 0;
+ return (void*)&validptr;
+ }
+
+ // return the buffer
+ ASSERT(mpBuffer != 0);
+ return mpBuffer;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: StreamableMemBlock::operator==(const StreamableMemBlock &)
+// Purpose: Test for equality of memory blocks
+// Created: 2003/09/06
+//
+// --------------------------------------------------------------------------
+bool StreamableMemBlock::operator==(const StreamableMemBlock &rCompare) const
+{
+ if(mSize != rCompare.mSize) return false;
+ if(mSize == 0 && rCompare.mSize == 0) return true; // without memory comparison!
+ return ::memcmp(mpBuffer, rCompare.mpBuffer, mSize) == 0;
+}
+
+
diff --git a/lib/common/StreamableMemBlock.h b/lib/common/StreamableMemBlock.h
new file mode 100755
index 00000000..250c0aea
--- /dev/null
+++ b/lib/common/StreamableMemBlock.h
@@ -0,0 +1,71 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: StreamableMemBlock.h
+// Purpose: Memory blocks which can be loaded and saved from streams
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+
+#ifndef STREAMABLEMEMBLOCK__H
+#define STREAMABLEMEMBLOCK__H
+
+class IOStream;
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: StreamableMemBlock
+// Purpose: Memory blocks which can be loaded and saved from streams
+// Created: 2003/09/05
+//
+// --------------------------------------------------------------------------
+class StreamableMemBlock
+{
+public:
+ StreamableMemBlock();
+ StreamableMemBlock(int Size);
+ StreamableMemBlock(void *pBuffer, int Size);
+ StreamableMemBlock(const StreamableMemBlock &rToCopy);
+ ~StreamableMemBlock();
+
+ void Set(const StreamableMemBlock &rBlock);
+ void Set(void *pBuffer, int Size);
+ void Set(IOStream &rStream, int Timeout);
+ StreamableMemBlock &operator=(const StreamableMemBlock &rBlock)
+ {
+ Set(rBlock);
+ return *this;
+ }
+
+ void ReadFromStream(IOStream &rStream, int Timeout);
+ void WriteToStream(IOStream &rStream) const;
+
+ static void WriteEmptyBlockToStream(IOStream &rStream);
+
+ void *GetBuffer() const;
+
+ // Size of block
+ int GetSize() const {return mSize;}
+
+ // Buffer empty?
+ bool IsEmpty() const {return mSize == 0;}
+
+ // Clear the contents of the block
+ void Clear() {FreeBlock();}
+
+ bool operator==(const StreamableMemBlock &rCompare) const;
+
+ void ResizeBlock(int Size);
+
+protected: // be careful with these!
+ void AllocateBlock(int Size);
+ void FreeBlock();
+
+private:
+ void *mpBuffer;
+ int mSize;
+};
+
+#endif // STREAMABLEMEMBLOCK__H
+
diff --git a/lib/common/TemporaryDirectory.h b/lib/common/TemporaryDirectory.h
new file mode 100755
index 00000000..62010f79
--- /dev/null
+++ b/lib/common/TemporaryDirectory.h
@@ -0,0 +1,26 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: TemporaryDirectory.h
+// Purpose: Location of temporary directory
+// Created: 2003/10/13
+//
+// --------------------------------------------------------------------------
+
+#ifndef TEMPORARYDIRECTORY__H
+#define TEMPORARYDIRECTORY__H
+
+#include <string>
+
+#ifdef PLATFORM_STATIC_TEMP_DIRECTORY_NAME
+ // Prefix name with Box to avoid clashing with OS API names
+ inline std::string BoxGetTemporaryDirectoryName()
+ {
+ return std::string(PLATFORM_STATIC_TEMP_DIRECTORY_NAME);
+ }
+#else
+ non-static temporary directory names not supported yet
+#endif
+
+#endif // TEMPORARYDIRECTORY__H
+
diff --git a/lib/common/Test.h b/lib/common/Test.h
new file mode 100755
index 00000000..bd69cd5a
--- /dev/null
+++ b/lib/common/Test.h
@@ -0,0 +1,165 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Test.h
+// Purpose: Useful stuff for tests
+// Created: 2003/07/11
+//
+// --------------------------------------------------------------------------
+
+#ifndef TEST__H
+#define TEST__H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <stdio.h>
+
+extern int failures;
+
+#define TEST_FAIL_WITH_MESSAGE(msg) {failures++; printf("FAILURE: " msg " at " __FILE__ "(%d)\n", __LINE__);}
+#define TEST_ABORT_WITH_MESSAGE(msg) {failures++; printf("FAILURE: " msg " at " __FILE__ "(%d)\n", __LINE__); return 1;}
+
+#define TEST_THAT(condition) {if(!(condition)) TEST_FAIL_WITH_MESSAGE("Condition [" #condition "] failed")}
+#define TEST_THAT_ABORTONFAIL(condition) {if(!(condition)) TEST_ABORT_WITH_MESSAGE("Condition [" #condition "] failed")}
+
+// NOTE: The 0- bit it to allow this to work with stuff which has negative constants for flags (eg ConnectionException)
+#define TEST_CHECK_THROWS(statement, excepttype, subtype) \
+ { \
+ bool didthrow = false; \
+ try \
+ { \
+ statement; \
+ } \
+ catch(excepttype &e) \
+ { \
+ if(e.GetSubType() != ((unsigned int)excepttype::subtype) \
+ && e.GetSubType() != (unsigned int)(0-excepttype::subtype)) \
+ { \
+ throw; \
+ } \
+ didthrow = true; \
+ } \
+ catch(...) \
+ { \
+ throw; \
+ } \
+ if(!didthrow) \
+ { \
+ TEST_FAIL_WITH_MESSAGE("Didn't throw exception " #excepttype "(" #subtype ")") \
+ } \
+ }
+
+inline bool TestFileExists(const char *Filename)
+{
+ struct stat st;
+ return ::stat(Filename, &st) == 0 && (st.st_mode & S_IFDIR) == 0;
+}
+
+inline bool TestDirExists(const char *Filename)
+{
+ struct stat st;
+ return ::stat(Filename, &st) == 0 && (st.st_mode & S_IFDIR) == S_IFDIR;
+}
+
+// -1 if doesn't exist
+inline int TestGetFileSize(const char *Filename)
+{
+ struct stat st;
+ if(::stat(Filename, &st) == 0)
+ {
+ return st.st_size;
+ }
+ return -1;
+}
+
+inline int LaunchServer(const char *CommandLine, const char *pidFile)
+{
+ if(::system(CommandLine) != 0)
+ {
+ printf("Server: %s\n", CommandLine);
+ TEST_FAIL_WITH_MESSAGE("Couldn't start server");
+ return -1;
+ }
+ // time for it to start up
+ ::sleep(1);
+
+ // read pid file
+ if(!TestFileExists(pidFile))
+ {
+ printf("Server: %s\n", CommandLine);
+ TEST_FAIL_WITH_MESSAGE("Server didn't save PID file");
+ return -1;
+ }
+
+ FILE *f = fopen(pidFile, "r");
+ int pid = -1;
+ if(f == NULL || fscanf(f, "%d", &pid) != 1)
+ {
+ printf("Server: %s (pidfile %s)\n", CommandLine, pidFile);
+ TEST_FAIL_WITH_MESSAGE("Couldn't read PID file");
+ return -1;
+ }
+ fclose(f);
+
+ return pid;
+}
+
+inline bool ServerIsAlive(int pid)
+{
+ if(pid == 0) return false;
+ return ::kill(pid, 0) != -1;
+}
+
+inline bool HUPServer(int pid)
+{
+ if(pid == 0) return false;
+ return ::kill(pid, SIGHUP) != -1;
+}
+
+inline bool KillServer(int pid)
+{
+ if(pid == 0 || pid == -1) return false;
+ bool KilledOK = ::kill(pid, SIGTERM) != -1;
+ TEST_THAT(KilledOK);
+ ::sleep(1);
+ return !ServerIsAlive(pid);
+}
+
+inline void TestRemoteProcessMemLeaks(const char *filename)
+{
+#ifdef BOX_MEMORY_LEAK_TESTING
+ // Does the file exist?
+ if(!TestFileExists(filename))
+ {
+ ++failures;
+ printf("FAILURE: MemLeak report not available (file %s)\n", filename);
+ }
+ else
+ {
+ // Is it empty?
+ if(TestGetFileSize(filename) > 0)
+ {
+ ++failures;
+ printf("FAILURE: Memory leaks found in other process (file %s)\n==========\n", filename);
+ FILE *f = fopen(filename, "r");
+ char line[512];
+ while(::fgets(line, sizeof(line), f) != 0)
+ {
+ printf("%s", line);
+ }
+ fclose(f);
+ printf("==========\n");
+ }
+
+ // Delete it
+ ::unlink(filename);
+ }
+#endif
+}
+
+#endif // TEST__H
+
diff --git a/lib/common/UnixUser.cpp b/lib/common/UnixUser.cpp
new file mode 100755
index 00000000..7a60b263
--- /dev/null
+++ b/lib/common/UnixUser.cpp
@@ -0,0 +1,121 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: UnixUser.cpp
+// Purpose: Interface for managing the UNIX user of the current process
+// Created: 21/1/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <pwd.h>
+#include <unistd.h>
+
+#include "UnixUser.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: UnixUser::UnixUser(const char *)
+// Purpose: Constructor, initialises to info of given username
+// Created: 21/1/04
+//
+// --------------------------------------------------------------------------
+UnixUser::UnixUser(const char *Username)
+ : mUID(0),
+ mGID(0),
+ mRevertOnDestruction(false)
+{
+ // Get password info
+ struct passwd *pwd = ::getpwnam(Username);
+ if(pwd == 0)
+ {
+ THROW_EXCEPTION(CommonException, CouldNotLookUpUsername)
+ }
+
+ // Store UID and GID
+ mUID = pwd->pw_uid;
+ mGID = pwd->pw_gid;
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: UnixUser::UnixUser(uid_t, gid_t)
+// Purpose: Construct from given UNIX user ID and group ID
+// Created: 15/3/04
+//
+// --------------------------------------------------------------------------
+UnixUser::UnixUser(uid_t UID, gid_t GID)
+ : mUID(UID),
+ mGID(GID),
+ mRevertOnDestruction(false)
+{
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: UnixUser::~UnixUser()
+// Purpose: Destructor -- reverts to previous user if the change wasn't perminant
+// Created: 21/1/04
+//
+// --------------------------------------------------------------------------
+UnixUser::~UnixUser()
+{
+ if(mRevertOnDestruction)
+ {
+ // Revert to "real" user and group id of the process
+ if(::setegid(::getgid()) != 0
+ || ::seteuid(::getuid()) != 0)
+ {
+ THROW_EXCEPTION(CommonException, CouldNotRestoreProcessUser)
+ }
+ }
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: UnixUser::ChangeProcessUser(bool)
+// Purpose: Change the process user and group ID to the user. If Temporary == true
+// the process username will be changed back when the object is destructed.
+// Created: 21/1/04
+//
+// --------------------------------------------------------------------------
+void UnixUser::ChangeProcessUser(bool Temporary)
+{
+ if(Temporary)
+ {
+ // Change temporarily (change effective only)
+ if(::setegid(mGID) != 0
+ || ::seteuid(mUID) != 0)
+ {
+ THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser)
+ }
+
+ // Mark for change on destruction
+ mRevertOnDestruction = true;
+ }
+ else
+ {
+ // Change perminantely (change all UIDs and GIDs)
+ if(::setgid(mGID) != 0
+ || ::setuid(mUID) != 0)
+ {
+ THROW_EXCEPTION(CommonException, CouldNotChangeProcessUser)
+ }
+ }
+}
+
+
+
+
diff --git a/lib/common/UnixUser.h b/lib/common/UnixUser.h
new file mode 100755
index 00000000..c895eb2a
--- /dev/null
+++ b/lib/common/UnixUser.h
@@ -0,0 +1,37 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: UnixUser.h
+// Purpose: Interface for managing the UNIX user of the current process
+// Created: 21/1/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef UNIXUSER__H
+#define UNIXUSER__H
+
+class UnixUser
+{
+public:
+ UnixUser(const char *Username);
+ UnixUser(uid_t UID, gid_t GID);
+ ~UnixUser();
+private:
+ // no copying allowed
+ UnixUser(const UnixUser &);
+ UnixUser &operator=(const UnixUser &);
+public:
+
+ void ChangeProcessUser(bool Temporary = false);
+
+ uid_t GetUID() {return mUID;}
+ gid_t GetGID() {return mGID;}
+
+private:
+ uid_t mUID;
+ gid_t mGID;
+ bool mRevertOnDestruction;
+};
+
+#endif // UNIXUSER__H
+
diff --git a/lib/common/Utils.cpp b/lib/common/Utils.cpp
new file mode 100755
index 00000000..b4d3144b
--- /dev/null
+++ b/lib/common/Utils.cpp
@@ -0,0 +1,159 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Utils.cpp
+// Purpose: Utility function
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifdef SHOW_BACKTRACE_ON_EXCEPTION
+ #include <execinfo.h>
+ #include <stdlib.h>
+#endif
+
+#include "Utils.h"
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: SplitString(const std::string &, char, std::vector<std::string> &)
+// Purpose: Splits a string at a given character
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+void SplitString(const std::string &String, char SplitOn, std::vector<std::string> &rOutput)
+{
+ // Split it up.
+ std::string::size_type b = 0;
+ std::string::size_type e = 0;
+ while(e = String.find_first_of(SplitOn, b), e != String.npos)
+ {
+ // Get this string
+ unsigned int len = e - b;
+ if(len >= 1)
+ {
+ rOutput.push_back(String.substr(b, len));
+ }
+ b = e + 1;
+ }
+ // Last string
+ if(b < String.size())
+ {
+ rOutput.push_back(String.substr(b));
+ }
+/*#ifndef NDEBUG
+ TRACE2("Splitting string '%s' on %c\n", String.c_str(), SplitOn);
+ for(unsigned int l = 0; l < rOutput.size(); ++l)
+ {
+ TRACE2("%d = '%s'\n", l, rOutput[l].c_str());
+ }
+#endif*/
+}
+
+#ifdef SHOW_BACKTRACE_ON_EXCEPTION
+void DumpStackBacktrace()
+{
+ void *array[10];
+ size_t size;
+ char **strings;
+ size_t i;
+
+ size = backtrace (array, 10);
+ strings = backtrace_symbols (array, size);
+
+ printf ("Obtained %zd stack frames.\n", size);
+
+ for(i = 0; i < size; i++)
+ printf("%s\n", strings[i]);
+
+ free (strings);
+}
+#endif
+
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: FileExists(const char *)
+// Purpose: Does a file exist?
+// Created: 20/11/03
+//
+// --------------------------------------------------------------------------
+bool FileExists(const char *Filename, int64_t *pFileSize, bool TreatLinksAsNotExisting)
+{
+ struct stat st;
+ if(::stat(Filename, &st) != 0)
+ {
+ if(errno == ENOENT)
+ {
+ return false;
+ }
+ else
+ {
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+ }
+
+ // is it a file?
+ if((st.st_mode & S_IFDIR) == 0)
+ {
+ if(TreatLinksAsNotExisting && ((st.st_mode & S_IFLNK) != 0))
+ {
+ return false;
+ }
+
+ // Yes. Tell caller the size?
+ if(pFileSize != 0)
+ {
+ *pFileSize = st.st_size;
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: ObjectExists(const char *)
+// Purpose: Does a object exist, and if so, is it a file or a directory?
+// Created: 23/11/03
+//
+// --------------------------------------------------------------------------
+int ObjectExists(const char *Filename)
+{
+ struct stat st;
+ if(::stat(Filename, &st) != 0)
+ {
+ if(errno == ENOENT)
+ {
+ return ObjectExists_NoObject;
+ }
+ else
+ {
+ THROW_EXCEPTION(CommonException, OSFileError);
+ }
+ }
+
+ // is it a file or a dir?
+ return ((st.st_mode & S_IFDIR) == 0)?ObjectExists_File:ObjectExists_Dir;
+}
+
+
+
+
diff --git a/lib/common/Utils.h b/lib/common/Utils.h
new file mode 100755
index 00000000..5da84d9a
--- /dev/null
+++ b/lib/common/Utils.h
@@ -0,0 +1,36 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: Utils.h
+// Purpose: Utility function
+// Created: 2003/07/31
+//
+// --------------------------------------------------------------------------
+
+#ifndef UTILS__H
+#define UTILS__H
+
+#include <string>
+#include <vector>
+
+#include "MemLeakFindOn.h"
+
+void SplitString(const std::string &String, char SplitOn, std::vector<std::string> &rOutput);
+
+#ifdef SHOW_BACKTRACE_ON_EXCEPTION
+ void DumpStackBacktrace();
+#endif
+
+bool FileExists(const char *Filename, int64_t *pFileSize = 0, bool TreatLinksAsNotExisting = false);
+
+enum
+{
+ ObjectExists_NoObject = 0,
+ ObjectExists_File = 1,
+ ObjectExists_Dir = 2
+};
+int ObjectExists(const char *Filename);
+
+#include "MemLeakFindOff.h"
+
+#endif // UTILS__H
diff --git a/lib/common/WaitForEvent.cpp b/lib/common/WaitForEvent.cpp
new file mode 100644
index 00000000..e9ee58d2
--- /dev/null
+++ b/lib/common/WaitForEvent.cpp
@@ -0,0 +1,194 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: WaitForEvent.cpp
+// Purpose: Generic waiting for events, using an efficient method (platform dependent)
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+
+#include "Box.h"
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "WaitForEvent.h"
+
+#include "MemLeakFindOn.h"
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WaitForEvent::WaitForEvent()
+// Purpose: Constructor
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+WaitForEvent::WaitForEvent(int Timeout)
+ : mKQueue(::kqueue()),
+ mpTimeout(0)
+{
+ if(mKQueue == -1)
+ {
+ THROW_EXCEPTION(CommonException, CouldNotCreateKQueue)
+ }
+
+ // Set the choosen timeout
+ SetTimeout(Timeout);
+}
+#else
+WaitForEvent::WaitForEvent(int Timeout)
+ : mTimeout(Timeout),
+ mpPollInfo(0)
+{
+}
+#endif
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WaitForEvent::~WaitForEvent()
+// Purpose: Destructor
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+WaitForEvent::~WaitForEvent()
+{
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ ::close(mKQueue);
+ mKQueue = -1;
+#else
+ if(mpPollInfo != 0)
+ {
+ ::free(mpPollInfo);
+ mpPollInfo = 0;
+ }
+#endif
+}
+
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WaitForEvent::SetTimeout
+// Purpose: Sets the timeout for future wait calls
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+void WaitForEvent::SetTimeout(int Timeout)
+{
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ // Generate timeout
+ if(Timeout != TimeoutInfinite)
+ {
+ mTimeout.tv_sec = Timeout / 1000;
+ mTimeout.tv_nsec = (Timeout % 1000) * 1000000;
+ }
+
+ // Infinite or not?
+ mpTimeout = (Timeout != TimeoutInfinite)?(&mTimeout):(NULL);
+#else
+ mTimeout = Timeout;
+#endif
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: WaitForEvent::Wait(int)
+// Purpose: Wait for an event to take place. Returns a pointer to the object
+// which has been signalled, or returns 0 for the timeout condition.
+// Timeout specified in milliseconds.
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+void *WaitForEvent::Wait()
+{
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ // Event return structure
+ struct kevent e;
+ ::memset(&e, 0, sizeof(e));
+
+ switch(::kevent(mKQueue, NULL, 0, &e, 1, mpTimeout))
+ {
+ case 0:
+ // Timeout
+ return 0;
+ break;
+
+ case 1:
+ // Event happened!
+ return e.udata;
+ break;
+
+ default:
+ // Interrupted system calls aren't an error, just equivalent to a timeout
+ if(errno != EINTR)
+ {
+ THROW_EXCEPTION(CommonException, KEventErrorWait)
+ }
+ return 0;
+ break;
+ }
+#else
+ // Use poll() instead.
+ // Need to build the structures?
+ if(mpPollInfo == 0)
+ {
+ // Yes...
+ mpPollInfo = (struct pollfd *)::malloc((sizeof(struct pollfd) * mItems.size()) + 4);
+ if(mpPollInfo == 0)
+ {
+ throw std::bad_alloc();
+ }
+
+ // Build...
+ for(unsigned int l = 0; l < mItems.size(); ++l)
+ {
+ mpPollInfo[l].fd = mItems[l].fd;
+ mpPollInfo[l].events = mItems[l].events;
+ mpPollInfo[l].revents = 0;
+ }
+ }
+
+ // Make sure everything is reset (don't really have to do this, but don't trust the OS)
+ for(unsigned int l = 0; l < mItems.size(); ++l)
+ {
+ mpPollInfo[l].revents = 0;
+ }
+
+ // Poll!
+ switch(::poll(mpPollInfo, mItems.size(), mTimeout))
+ {
+ case -1:
+ // Interrupted system calls aren't an error, just equivalent to a timeout
+ if(errno != EINTR)
+ {
+ THROW_EXCEPTION(CommonException, KEventErrorWait)
+ }
+ return 0;
+ break;
+ case 0: // timed out
+ return 0;
+ break;
+ default: // got some thing...
+ // control flows on...
+ break;
+ }
+
+ // Find the item which was ready
+ for(unsigned int s = 0; s < mItems.size(); ++s)
+ {
+ if(mpPollInfo[s].revents & POLLIN)
+ {
+ return mItems[s].item;
+ break;
+ }
+ }
+#endif
+
+ return 0;
+}
+
diff --git a/lib/common/WaitForEvent.h b/lib/common/WaitForEvent.h
new file mode 100644
index 00000000..b8f79da6
--- /dev/null
+++ b/lib/common/WaitForEvent.h
@@ -0,0 +1,146 @@
+// --------------------------------------------------------------------------
+//
+// File
+// Name: WaitForEvent.h
+// Purpose: Generic waiting for events, using an efficient method (platform dependent)
+// Created: 9/3/04
+//
+// --------------------------------------------------------------------------
+
+#ifndef WAITFOREVENT__H
+#define WAITFOREVENT__H
+
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ #include <sys/event.h>
+ #include <sys/time.h>
+#else
+ #include <vector>
+ #include <poll.h>
+#endif
+
+#include "CommonException.h"
+
+#include "MemLeakFindOn.h"
+
+class WaitForEvent
+{
+public:
+ WaitForEvent(int Timeout = TimeoutInfinite);
+ ~WaitForEvent();
+private:
+ // No copying.
+ WaitForEvent(const WaitForEvent &);
+ WaitForEvent &operator=(const WaitForEvent &);
+public:
+
+ enum
+ {
+ TimeoutInfinite = -1
+ };
+
+ void SetTimeout(int Timeout = TimeoutInfinite);
+
+ void *Wait();
+
+#ifdef PLATFORM_KQUEUE_NOT_SUPPORTED
+ typedef struct
+ {
+ int fd;
+ short events;
+ void *item;
+ } ItemInfo;
+#endif
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: WaitForEvent::Add(const Type &, int)
+ // Purpose: Adds an event to the list of items to wait on. The flags are passed to the object.
+ // Created: 9/3/04
+ //
+ // --------------------------------------------------------------------------
+ template<typename T>
+ void Add(const T *pItem, int Flags = 0)
+ {
+ ASSERT(pItem != 0);
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ struct kevent e;
+ pItem->FillInKEvent(e, Flags);
+ // Fill in extra flags to say what to do
+ e.flags |= EV_ADD;
+ e.udata = (void*)pItem;
+ if(::kevent(mKQueue, &e, 1, NULL, 0, NULL) == -1)
+ {
+ THROW_EXCEPTION(CommonException, KEventErrorAdd)
+ }
+#else
+ // Add item
+ ItemInfo i;
+ pItem->FillInPoll(i.fd, i.events, Flags);
+ i.item = (void*)pItem;
+ mItems.push_back(i);
+ // Delete any pre-prepared poll info, as it's now out of date
+ if(mpPollInfo != 0)
+ {
+ ::free(mpPollInfo);
+ mpPollInfo = 0;
+ }
+#endif
+ }
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: WaitForEvent::Remove(const Type &, int)
+ // Purpose: Removes an event from the list of items to wait on. The flags are passed to the object.
+ // Created: 9/3/04
+ //
+ // --------------------------------------------------------------------------
+ template<typename T>
+ void Remove(const T *pItem, int Flags = 0)
+ {
+ ASSERT(pItem != 0);
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ struct kevent e;
+ pItem->FillInKEvent(e, Flags);
+ // Fill in extra flags to say what to do
+ e.flags |= EV_DELETE;
+ e.udata = (void*)pItem;
+ if(::kevent(mKQueue, &e, 1, NULL, 0, NULL) == -1)
+ {
+ THROW_EXCEPTION(CommonException, KEventErrorRemove)
+ }
+#else
+ if(mpPollInfo != 0)
+ {
+ ::free(mpPollInfo);
+ mpPollInfo = 0;
+ }
+ for(std::vector<ItemInfo>::iterator i(mItems.begin()); i != mItems.end(); ++i)
+ {
+ if(i->item == pItem)
+ {
+ mItems.erase(i);
+ return;
+ }
+ }
+#endif
+ }
+
+private:
+#ifndef PLATFORM_KQUEUE_NOT_SUPPORTED
+ int mKQueue;
+ struct timespec mTimeout;
+ struct timespec *mpTimeout;
+#else
+ int mTimeout;
+ std::vector<ItemInfo> mItems;
+ struct pollfd *mpPollInfo;
+#endif
+};
+
+#include "MemLeakFindOff.h"
+
+#endif // WAITFOREVENT__H
+
+
diff --git a/lib/common/makeexception.pl b/lib/common/makeexception.pl
new file mode 100755
index 00000000..c0388286
--- /dev/null
+++ b/lib/common/makeexception.pl
@@ -0,0 +1,277 @@
+#!/usr/bin/perl
+
+# global exception list file
+my $global_list = '../../ExceptionCodes.txt';
+
+
+my @exception;
+my @exception_desc;
+my $class;
+my $class_number;
+
+# read the description!
+
+open EXCEPTION_DESC,$ARGV[0] or die "Can't open $ARGV[0]";
+
+while(<EXCEPTION_DESC>)
+{
+ chomp; s/\A\s+//; s/#.+\Z//; s/\s+\Z//; s/\s+/ /g;
+ next unless m/\S/;
+
+ if(m/\AEXCEPTION\s+(.+)\s+(\d+)\Z/)
+ {
+ $class = $1;
+ $class_number = $2;
+ }
+ else
+ {
+ my ($name,$number,$description) = split /\s+/,$_,3;
+ if($name eq '' || $number =~ m/\D/)
+ {
+ die "Bad line '$_'";
+ }
+ if($exception[$number] ne '')
+ {
+ die "Duplicate exception number $number";
+ }
+ $exception[$number] = $name;
+ $exception_desc[$number] = $description;
+ }
+}
+
+die "Exception class and number not specified" unless $class ne '' && $class_number ne '';
+
+close EXCEPTION_DESC;
+
+# write the code
+print "Generating $class exception...\n";
+
+open CPP,">autogen_${class}Exception.cpp" or die "Can't open cpp file for writing";
+open H,">autogen_${class}Exception.h" or die "Can't open h file for writing";
+
+# write header file
+my $guardname = uc 'AUTOGEN_'.$class.'EXCEPTION_H';
+print H <<__E;
+
+// Auto-generated file -- do not edit
+
+#ifndef $guardname
+#define $guardname
+
+#include "BoxException.h"
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: ${class}Exception
+// Purpose: Exception
+// Created: autogen
+//
+// --------------------------------------------------------------------------
+class ${class}Exception : public BoxException
+{
+public:
+ ${class}Exception(unsigned int SubType)
+ : mSubType(SubType)
+ {
+ }
+
+ ${class}Exception(const ${class}Exception &rToCopy)
+ : mSubType(rToCopy.mSubType)
+ {
+ }
+
+ ~${class}Exception() throw ()
+ {
+ }
+
+ enum
+ {
+ ExceptionType = $class_number
+ };
+
+ enum
+ {
+__E
+
+for(my $e = 0; $e <= $#exception; $e++)
+{
+ if($exception[$e] ne '')
+ {
+ print H "\t\t".$exception[$e].' = '.$e.(($e==$#exception)?'':',')."\n"
+ }
+}
+
+print H <<__E;
+ };
+
+ virtual unsigned int GetType() const throw();
+ virtual unsigned int GetSubType() const throw();
+ virtual const char *what() const throw();
+
+private:
+ unsigned int mSubType;
+};
+
+#endif // $guardname
+__E
+
+# -----------------------------------------------------------------------------------------------------------
+
+print CPP <<__E;
+
+// Auto-generated file -- do not edit
+
+#include "Box.h"
+#include "autogen_${class}Exception.h"
+
+#include "MemLeakFindOn.h"
+
+#ifdef EXCEPTION_CODENAMES_EXTENDED
+ #ifdef EXCEPTION_CODENAMES_EXTENDED_WITH_DESCRIPTION
+static const char *whats[] = {
+__E
+
+my $last_seen = -1;
+for(my $e = 0; $e <= $#exception; $e++)
+{
+ if($exception[$e] ne '')
+ {
+ for(my $s = $last_seen + 1; $s < $e; $s++)
+ {
+ print CPP "\t\"UNUSED\",\n"
+ }
+ my $ext = ($exception_desc[$e] ne '')?" ($exception_desc[$e])":'';
+ print CPP "\t\"${class} ".$exception[$e].$ext.'"'.(($e==$#exception)?'':',')."\n";
+ $last_seen = $e;
+ }
+}
+
+print CPP <<__E;
+};
+ #else
+static const char *whats[] = {
+__E
+
+$last_seen = -1;
+for(my $e = 0; $e <= $#exception; $e++)
+{
+ if($exception[$e] ne '')
+ {
+ for(my $s = $last_seen + 1; $s < $e; $s++)
+ {
+ print CPP "\t\"UNUSED\",\n"
+ }
+ print CPP "\t\"${class} ".$exception[$e].'"'.(($e==$#exception)?'':',')."\n";
+ $last_seen = $e;
+ }
+}
+
+print CPP <<__E;
+};
+ #endif
+#endif
+
+unsigned int ${class}Exception::GetType() const throw()
+{
+ return ${class}Exception::ExceptionType;
+}
+
+unsigned int ${class}Exception::GetSubType() const throw()
+{
+ return mSubType;
+}
+
+const char *${class}Exception::what() const throw()
+{
+#ifdef EXCEPTION_CODENAMES_EXTENDED
+ if(mSubType < 0 || mSubType > (sizeof(whats) / sizeof(whats[0])))
+ {
+ return "${class}";
+ }
+ return whats[mSubType];
+#else
+ return "${class}";
+#endif
+}
+
+__E
+
+close H;
+close CPP;
+
+# update the global exception list
+my $list_before;
+my $list_after;
+my $is_after = 0;
+if(open CURRENT,$global_list)
+{
+ while(<CURRENT>)
+ {
+ next if m/\A#/;
+
+ if(m/\AEXCEPTION TYPE (\w+) (\d+)/)
+ {
+ # check that the number isn't being reused
+ if($2 == $class_number && $1 ne $class)
+ {
+ die "Class number $class_number is being used by $class and $1 -- correct this.\n";
+ }
+ if($2 > $class_number)
+ {
+ # This class comes after the current one (ensures numerical ordering)
+ $is_after = 1;
+ }
+ if($1 eq $class)
+ {
+ # skip this entry
+ while(<CURRENT>)
+ {
+ last if m/\AEND TYPE/;
+ }
+ $_ = '';
+ }
+ }
+
+ if($is_after)
+ {
+ $list_after .= $_;
+ }
+ else
+ {
+ $list_before .= $_;
+ }
+ }
+
+ close CURRENT;
+}
+
+open GLOBAL,">$global_list" or die "Can't open global exception code listing for writing";
+
+print GLOBAL <<__E;
+#
+# automatically generated file, do not edit.
+#
+# This file lists all the exception codes used by the system.
+# Use to look up more detailed descriptions of meanings of errors.
+#
+__E
+
+print GLOBAL $list_before;
+
+print GLOBAL "EXCEPTION TYPE $class $class_number\n";
+for(my $e = 0; $e <= $#exception; $e++)
+{
+ if($exception[$e] ne '')
+ {
+ my $ext = ($exception_desc[$e] ne '')?" - $exception_desc[$e]":'';
+ print GLOBAL "($class_number/$e) - ${class} ".$exception[$e].$ext."\n";
+ }
+}
+print GLOBAL "END TYPE\n";
+
+print GLOBAL $list_after;
+
+close GLOBAL;
+
+