aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--default.bld2
-rw-r--r--src/dictionary.cpp11
-rw-r--r--src/float.cpp37
-rw-r--r--src/float.h11
-rw-r--r--src/gatsstream.cpp85
-rw-r--r--src/gatsstream.h31
-rw-r--r--src/object.cpp4
-rw-r--r--src/unit/basic.unit19
-rw-r--r--src/unit/io.unit127
9 files changed, 317 insertions, 10 deletions
diff --git a/default.bld b/default.bld
index ae6c61b..d78fbd3 100644
--- a/default.bld
+++ b/default.bld
@@ -46,7 +46,7 @@ target files("src/unit/*.unit").replace("src/","").replace(".unit","")
46 requires "libbu++.a"; 46 requires "libbu++.a";
47 tag ["tests", "unit tests"]; 47 tag ["tests", "unit tests"];
48 CXXFLAGS += "-I."; 48 CXXFLAGS += "-I.";
49 LDFLAGS += "-L. -lbu++ -lgats"; 49 LDFLAGS += "-L. -lgats -lbu++";
50} 50}
51 51
52rule "unit" 52rule "unit"
diff --git a/src/dictionary.cpp b/src/dictionary.cpp
index 2223c8b..1a9549f 100644
--- a/src/dictionary.cpp
+++ b/src/dictionary.cpp
@@ -77,9 +77,9 @@ void Gats::Dictionary::insert( const Bu::FString &sKey, bool b )
77 77
78void Gats::Dictionary::insert( const Bu::FString &sKey, double d ) 78void Gats::Dictionary::insert( const Bu::FString &sKey, double d )
79{ 79{
80// Bu::Hash<Gats::String, Gats::Object *>::insert( 80 Bu::Hash<Gats::String, Gats::Object *>::insert(
81// sKey, new Gats::Float( d ) 81 sKey, new Gats::Float( d )
82// ); 82 );
83} 83}
84 84
85void Gats::Dictionary::insert( const Bu::FString &sKey, const char *s ) 85void Gats::Dictionary::insert( const Bu::FString &sKey, const char *s )
@@ -117,14 +117,13 @@ int64_t Gats::Dictionary::getInt( const Bu::FString &sKey )
117} 117}
118 118
119double Gats::Dictionary::getFloat( const Bu::FString &sKey ) 119double Gats::Dictionary::getFloat( const Bu::FString &sKey )
120{/* 120{
121 Gats::Boolean *pOb = dynamic_cast<Gats::Boolean *>( get( sKey ) ); 121 Gats::Boolean *pOb = dynamic_cast<Gats::Boolean *>( get( sKey ) );
122 if( pOb ) 122 if( pOb )
123 throw Bu::ExceptionBase("Cannot cast item '%s' to bool.", 123 throw Bu::ExceptionBase("Cannot cast item '%s' to bool.",
124 sKey.getStr() ); 124 sKey.getStr() );
125 125
126 return pOb->getValue();*/ 126 return pOb->getValue();
127 return 0.0;
128} 127}
129 128
130Bu::FString Gats::Dictionary::getStr( const Bu::FString &sKey ) 129Bu::FString Gats::Dictionary::getStr( const Bu::FString &sKey )
diff --git a/src/float.cpp b/src/float.cpp
index e69de29..e257b37 100644
--- a/src/float.cpp
+++ b/src/float.cpp
@@ -0,0 +1,37 @@
1#include "gats/float.h"
2#include "gats/integer.h"
3
4Gats::Float::Float() :
5 fVal( 0.0 )
6{
7}
8
9Gats::Float::Float( double f ) :
10 fVal( f )
11{
12}
13
14Gats::Float::~Float()
15{
16}
17
18void Gats::Float::write( Bu::Stream &rOut ) const
19{
20 char buf[50];
21
22 int iSize = snprintf( buf, 50, "%la", fVal );
23
24 rOut.write("f", 1 );
25 Gats::Integer::writePackedInt( rOut, iSize );
26 rOut.write( buf, iSize );
27}
28
29void Gats::Float::read( Bu::Stream &rIn, char cType )
30{
31 int iSize;
32 Gats::Integer::readPackedInt( rIn, iSize );
33 char buf[50];
34 rIn.read( buf, iSize );
35 sscanf( buf, "%la", &fVal );
36}
37
diff --git a/src/float.h b/src/float.h
index cf20010..1b3a06a 100644
--- a/src/float.h
+++ b/src/float.h
@@ -1,16 +1,25 @@
1#ifndef GATS_FLOAT_H 1#ifndef GATS_FLOAT_H
2#define GATS_FLOAT_H 2#define GATS_FLOAT_H
3 3
4#include "gats/object.h"
5
4namespace Gats 6namespace Gats
5{ 7{
6 class Float 8 class Float : public Gats::Object
7 { 9 {
8 public: 10 public:
9 Float(); 11 Float();
10 Float( double f ); 12 Float( double f );
11 virtual ~Float(); 13 virtual ~Float();
12 14
15 virtual Type getType() const { return typeFloat; }
16 double getValue() const { return fVal; }
17
18 virtual void write( Bu::Stream &rOut ) const;
19 virtual void read( Bu::Stream &rIn, char cType );
20
13 private: 21 private:
22 double fVal;
14 }; 23 };
15} 24}
16 25
diff --git a/src/gatsstream.cpp b/src/gatsstream.cpp
index 4b9cadf..38adfbb 100644
--- a/src/gatsstream.cpp
+++ b/src/gatsstream.cpp
@@ -1,7 +1,9 @@
1#include "gats/gatsstream.h" 1#include "gats/gatsstream.h"
2#include "gats/object.h" 2#include "gats/object.h"
3 3
4#include <bu/sio.h> 4#include <arpa/inet.h>
5
6// #include <bu/sio.h>
5#include <bu/nullstream.h> 7#include <bu/nullstream.h>
6using namespace Bu; 8using namespace Bu;
7 9
@@ -16,7 +18,59 @@ Gats::GatsStream::~GatsStream()
16 18
17Gats::Object *Gats::GatsStream::readObject() 19Gats::Object *Gats::GatsStream::readObject()
18{ 20{
21 char buf[1500];
22
23 // sio << "Gats::GatsStream::readObject(): Scanning for object header." << sio.nl;
24 do
25 {
26 if( qbRead.getSize() < 5 )
27 {
28 // sio << "Gats::GatsStream::readObject(): reading header data, need 5b, have " << qbRead.getSize() << "b." << sio.nl;
29 int iRead = rStream.read( buf, 5-qbRead.getSize() );
30 qbRead.write( buf, iRead );
31
32 if( qbRead.getSize() < 5 )
33 return NULL;
34 }
35 } while( !skipReadNulls() );
36
37 uint8_t uVer;
38 qbRead.peek( &uVer, 1 );
39 // sio << "Gats::GatsStream::readObject(): Packet version: " << (int)uVer << sio.nl;
40
41 int32_t iSize;
42 qbRead.peek( &iSize, 4, 1 );
43 iSize = ntohl( iSize );
44 // sio << "Gats::GatsStream::readObject(): Header read, looking for " << iSize << "b, we have " << qbRead.getSize() << "b." << sio.nl;
45 while( qbRead.getSize() < iSize )
46 {
47 int32_t iRead = iSize - qbRead.getSize();
48 if( iRead > 1500 )
49 iRead = 1500;
50 // sio << "Gats::GatsStream::readObject(): Attempting to read " << iRead << "b." << sio.nl;
51 int32_t iReal = rStream.read( buf, iRead );
52 // sio << "Gats::GatsStream::readObject(): Read " << iReal << "b." << sio.nl;
53 qbRead.write( buf, iReal );
54 if( iReal < iRead )
55 {
56 // sio << "Gats::GatsStream::readObject(): Insufficient data read in block, bailing on read." << sio.nl;
57 return NULL;
58 }
59 }
60
61 if( qbRead.getSize() < iSize )
62 {
63 // sio << "Gats::GatsStream::readObject(): Somehow, we still don't have enough data, bailing." << sio.nl;
64 return NULL;
65 }
66
67 // sio << "Gats::GatsStream::readObject(): We have " << qbRead.getSize() << "b of " << iSize << "b, time to read the object." << sio.nl;
19 68
69 qbRead.seek( 5 );
70 Gats::Object *pObj = Gats::Object::read( qbRead );
71
72 // sio << "Gats::GatsStream::readObject(): Read completed, there are " << qbRead.getSize() << "b left in the buffer." << sio.nl;
73 return pObj;
20} 74}
21 75
22void Gats::GatsStream::writeObject( Gats::Object *pObject ) 76void Gats::GatsStream::writeObject( Gats::Object *pObject )
@@ -24,6 +78,33 @@ void Gats::GatsStream::writeObject( Gats::Object *pObject )
24 Bu::NullStream ns; 78 Bu::NullStream ns;
25 pObject->write( ns ); 79 pObject->write( ns );
26 80
27 sio << "Object consumed " << ns.tell() << "b." << sio.nl; 81 uint8_t uBuf = 1;
82 int32_t iSize = htonl( ns.tell()+5 );
83 rStream.write( &uBuf, 1 );
84 rStream.write( &iSize, 4 );
85 pObject->write( rStream );
86
87 // sio << "Object consumed " << ns.tell() << "b." << sio.nl;
88}
89
90bool Gats::GatsStream::skipReadNulls()
91{
92 char buf;
93
94 // sio << "Gats::GatsStream::skipReadNulls(): Scanning for nulls, " << qbRead.getSize() << "b." << sio.nl;
95 bool bHaveSeeked = false;
96 for(;;)
97 {
98 if( qbRead.peek( &buf, 1 ) == 0 )
99 return false;
100 if( buf != 0 )
101 return !bHaveSeeked; //true;
102 else
103 {
104 // sio << "Gats::GatsStream::skipReadNulls(): Null byte read, not header yet..." << sio.nl;
105 qbRead.seek( 1 );
106 bHaveSeeked = true;
107 }
108 }
28} 109}
29 110
diff --git a/src/gatsstream.h b/src/gatsstream.h
index d668c28..b5efb87 100644
--- a/src/gatsstream.h
+++ b/src/gatsstream.h
@@ -2,6 +2,7 @@
2#define GATS_STREAM_H 2#define GATS_STREAM_H
3 3
4#include <bu/stream.h> 4#include <bu/stream.h>
5#include <bu/queuebuf.h>
5 6
6namespace Gats 7namespace Gats
7{ 8{
@@ -13,11 +14,41 @@ namespace Gats
13 GatsStream( Bu::Stream &rStream ); 14 GatsStream( Bu::Stream &rStream );
14 virtual ~GatsStream(); 15 virtual ~GatsStream();
15 16
17 /**
18 * Read an object packet from the assosiated stream. This will make
19 * every effort to only read exactly enough data to describe one packet,
20 * in case you want to do other things with your stream. It will
21 * automatically skip NULL byte spacing between packets, which makes
22 * a convinient padding method for encrypted data streams. Since
23 * sizing information is available in the packet header exact amounts
24 * of data can be read, however this function doesn't assume that it
25 * can read the entire object in one operation. If it fails to read
26 * a complete packet in one call, it will keep the data it's read so
27 * far buffered and return NULL, ready for another attempt. You can
28 * use the function hasReadBuffer() to deterimne if readObject()
29 * has read part of an object packet or not. If readObject returns
30 * non-null then hasReadBuffer should return false on it's next call.
31 */
16 Gats::Object *readObject(); 32 Gats::Object *readObject();
33
34 /**
35 * Write an object
36 */
17 void writeObject( Gats::Object *pObject ); 37 void writeObject( Gats::Object *pObject );
18 38
39 /**
40 * Tells you if there is data still in the read buffer, i.e. that a
41 * packet is part way through being read. If readObject has returned
42 * non-null in the most recent call, this should always be false.
43 */
44 bool hasReadBuffer() { return qbRead.getSize() > 0; }
45
46 private:
47 bool skipReadNulls();
48
19 private: 49 private:
20 Bu::Stream &rStream; 50 Bu::Stream &rStream;
51 Bu::QueueBuf qbRead;
21 }; 52 };
22}; 53};
23 54
diff --git a/src/object.cpp b/src/object.cpp
index 4c1f3ca..9176b49 100644
--- a/src/object.cpp
+++ b/src/object.cpp
@@ -45,6 +45,10 @@ Gats::Object *Gats::Object::read( Bu::Stream &rIn )
45 pObj = new Gats::Dictionary(); 45 pObj = new Gats::Dictionary();
46 break; 46 break;
47 47
48 case 'f':
49 pObj = new Gats::Float();
50 break;
51
48 case 'e': 52 case 'e':
49 return NULL; 53 return NULL;
50 54
diff --git a/src/unit/basic.unit b/src/unit/basic.unit
index 744d679..d0309ee 100644
--- a/src/unit/basic.unit
+++ b/src/unit/basic.unit
@@ -18,6 +18,7 @@
18#include "bu/sio.h" 18#include "bu/sio.h"
19 19
20#include <stdlib.h> 20#include <stdlib.h>
21#include <math.h>
21 22
22using namespace Bu; 23using namespace Bu;
23 24
@@ -120,6 +121,24 @@ suite Basic
120 } 121 }
121 } 122 }
122 123
124 test floats
125 {
126 Bu::MemBuf mb;
127
128 Gats::Float( M_PI ).write( mb );
129
130 mb.setPos( 0 );
131
132 Gats::Object *pObj = Gats::Object::read( mb );
133 unitTest( pObj != NULL );
134 unitTest( pObj->getType() == Gats::typeFloat );
135 Gats::Float *pFlt = dynamic_cast<Gats::Float *>(pObj);
136 sio << "old = " << M_PI << ", new = " << pFlt->getValue() << sio.nl;
137 unitTest( pFlt->getValue() == M_PI );
138
139 delete pObj;
140 }
141
123 test dictionary 142 test dictionary
124 { 143 {
125 MemBuf mb; 144 MemBuf mb;
diff --git a/src/unit/io.unit b/src/unit/io.unit
new file mode 100644
index 0000000..3e9c82c
--- /dev/null
+++ b/src/unit/io.unit
@@ -0,0 +1,127 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2010 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "gats/dictionary.h"
10#include "gats/integer.h"
11#include "gats/float.h"
12#include "gats/list.h"
13#include "gats/boolean.h"
14#include "gats/string.h"
15#include "gats/gatsstream.h"
16
17#include "bu/membuf.h"
18#include "bu/list.h"
19#include "bu/sio.h"
20
21#include <stdlib.h>
22
23using namespace Bu;
24
25suite Basic
26{
27 test basic
28 {
29 Bu::FString sTmpFileName("temp-XXXXXXXXX");
30 Bu::File fIo = tempFile( sTmpFileName );
31
32 {
33 Gats::Dictionary dTest;
34 dTest.insert("age", 27 );
35 dTest.insert("firstName", "Mike");
36 dTest.insert("lastName", "Buland");
37 dTest.insert("awake", true );
38
39 Gats::GatsStream sGats( fIo );
40 sGats.writeObject( &dTest );
41 }
42
43 fIo.setPos( 0 );
44
45 {
46 Gats::GatsStream sGats( fIo );
47 Gats::Object *pObj = sGats.readObject();
48 unitTest( pObj != NULL );
49 unitTest( pObj->getType() == Gats::typeDictionary );
50 Gats::Dictionary *pDic = dynamic_cast<Gats::Dictionary *>(pObj);
51 unitTest( pDic->getSize() == 4 );
52 unitTest( pDic->getInt("age") == 27 );
53 unitTest( pDic->getStr("firstName") == "Mike" );
54 unitTest( pDic->getStr("lastName") == "Buland" );
55 unitTest( pDic->getBool("awake") == true );
56
57 delete pDic;
58 }
59 }
60
61 test spacers
62 {
63 Bu::FString sTmpFileName("temp-XXXXXXXXX");
64 Bu::File fIo = tempFile( sTmpFileName );
65
66 {
67 Gats::GatsStream sGats( fIo );
68 Gats::Integer i( -157 );
69 sGats.writeObject( &i );
70 fIo.write( "\x00\x00\x00", 3 );
71 Gats::String s("negative one hundred and fifty seven");
72 sGats.writeObject( &s );
73 }
74
75 fIo.setPos( 0 );
76
77 {
78 Gats::GatsStream sGats( fIo );
79 Gats::Object *pObj1 = sGats.readObject();
80 unitTest( pObj1 != NULL );
81 unitTest( pObj1->getType() == Gats::typeInteger );
82 unitTest( dynamic_cast<Gats::Integer *>(pObj1)->getValue() == -157 );
83
84 Gats::Object *pObj2 = sGats.readObject();
85 unitTest( pObj2 != NULL );
86 unitTest( pObj2->getType() == Gats::typeString );
87 unitTest( *dynamic_cast<Gats::String *>(pObj2) ==
88 "negative one hundred and fifty seven" );
89
90 delete pObj1;
91 delete pObj2;
92 }
93 }
94 test biggerSpacers
95 {
96 Bu::FString sTmpFileName("temp-XXXXXXXXX");
97 Bu::File fIo = tempFile( sTmpFileName );
98
99 {
100 Gats::GatsStream sGats( fIo );
101 Gats::Integer i( -157 );
102 sGats.writeObject( &i );
103 fIo.write( "\x00\x00\x00\x00\x00\x00\x00\x00\x00", 9 );
104 Gats::String s("negative one hundred and fifty seven");
105 sGats.writeObject( &s );
106 }
107
108 fIo.setPos( 0 );
109
110 {
111 Gats::GatsStream sGats( fIo );
112 Gats::Object *pObj1 = sGats.readObject();
113 unitTest( pObj1 != NULL );
114 unitTest( pObj1->getType() == Gats::typeInteger );
115 unitTest( dynamic_cast<Gats::Integer *>(pObj1)->getValue() == -157 );
116
117 Gats::Object *pObj2 = sGats.readObject();
118 unitTest( pObj2 != NULL );
119 unitTest( pObj2->getType() == Gats::typeString );
120 unitTest( *dynamic_cast<Gats::String *>(pObj2) ==
121 "negative one hundred and fifty seven" );
122
123 delete pObj1;
124 delete pObj2;
125 }
126 }
127}