diff options
author | Mike Buland <eichlan@xagasoft.com> | 2010-08-19 06:28:17 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2010-08-19 06:28:17 +0000 |
commit | 11b5a91c5884d496744911f261ed6c2b053b9940 (patch) | |
tree | 61ed65f187e0719f141d80d4e1e648aeff311024 /src | |
parent | 9dc8cc535ef5fc4ea78f967fe285fe4424ff4458 (diff) | |
download | libgats-11b5a91c5884d496744911f261ed6c2b053b9940.tar.gz libgats-11b5a91c5884d496744911f261ed6c2b053b9940.tar.bz2 libgats-11b5a91c5884d496744911f261ed6c2b053b9940.tar.xz libgats-11b5a91c5884d496744911f261ed6c2b053b9940.zip |
Wow, it pretty much all works. the float format is a little funny, I treat it
as a string, with a string header and then string data that is then turned into
a float. It's pretty much how it's going to work, unless I come up with
something revolutionary.
Diffstat (limited to 'src')
-rw-r--r-- | src/dictionary.cpp | 11 | ||||
-rw-r--r-- | src/float.cpp | 37 | ||||
-rw-r--r-- | src/float.h | 11 | ||||
-rw-r--r-- | src/gatsstream.cpp | 85 | ||||
-rw-r--r-- | src/gatsstream.h | 31 | ||||
-rw-r--r-- | src/object.cpp | 4 | ||||
-rw-r--r-- | src/unit/basic.unit | 19 | ||||
-rw-r--r-- | src/unit/io.unit | 127 |
8 files changed, 316 insertions, 9 deletions
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 | ||
78 | void Gats::Dictionary::insert( const Bu::FString &sKey, double d ) | 78 | void 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 | ||
85 | void Gats::Dictionary::insert( const Bu::FString &sKey, const char *s ) | 85 | void 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 | ||
119 | double Gats::Dictionary::getFloat( const Bu::FString &sKey ) | 119 | double 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 | ||
130 | Bu::FString Gats::Dictionary::getStr( const Bu::FString &sKey ) | 129 | Bu::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 | |||
4 | Gats::Float::Float() : | ||
5 | fVal( 0.0 ) | ||
6 | { | ||
7 | } | ||
8 | |||
9 | Gats::Float::Float( double f ) : | ||
10 | fVal( f ) | ||
11 | { | ||
12 | } | ||
13 | |||
14 | Gats::Float::~Float() | ||
15 | { | ||
16 | } | ||
17 | |||
18 | void 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 | |||
29 | void 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 | |||
4 | namespace Gats | 6 | namespace 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> |
6 | using namespace Bu; | 8 | using namespace Bu; |
7 | 9 | ||
@@ -16,7 +18,59 @@ Gats::GatsStream::~GatsStream() | |||
16 | 18 | ||
17 | Gats::Object *Gats::GatsStream::readObject() | 19 | Gats::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 | ||
22 | void Gats::GatsStream::writeObject( Gats::Object *pObject ) | 76 | void 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 | |||
90 | bool 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 | ||
6 | namespace Gats | 7 | namespace 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 | ||
22 | using namespace Bu; | 23 | using 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 | |||
23 | using namespace Bu; | ||
24 | |||
25 | suite 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 | } | ||