1 | /* |
---|
2 | * ---------------------------------------------------------------------- |
---|
3 | * Rappture::Serializer |
---|
4 | * The object collects a series of other objects together and |
---|
5 | * serializes them into a single byte stream. That stream can |
---|
6 | * be written to a file, send over a socket, and so forth. The |
---|
7 | * resulting stream can be loaded by a Serializer and the objects |
---|
8 | * can be reconstituted to their original form. |
---|
9 | * |
---|
10 | * ====================================================================== |
---|
11 | * AUTHOR: Michael McLennan, Purdue University |
---|
12 | * Copyright (c) 2004-2012 HUBzero Foundation, LLC |
---|
13 | * |
---|
14 | * See the file "license.terms" for information on usage and |
---|
15 | * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
16 | * ====================================================================== |
---|
17 | */ |
---|
18 | #include <assert.h> |
---|
19 | #include <sstream> |
---|
20 | #include "RpSerializer.h" |
---|
21 | |
---|
22 | using namespace Rappture; |
---|
23 | |
---|
24 | Serializer::Serializer() |
---|
25 | { |
---|
26 | } |
---|
27 | |
---|
28 | Serializer::~Serializer() |
---|
29 | { |
---|
30 | } |
---|
31 | |
---|
32 | Outcome |
---|
33 | Serializer::deserialize(const char* bytes, int nbytes) |
---|
34 | { |
---|
35 | Outcome result; |
---|
36 | std::string token; |
---|
37 | |
---|
38 | clear(); |
---|
39 | SerialBuffer buffer(bytes, nbytes); |
---|
40 | |
---|
41 | // read the format and make sure we've got the right reader |
---|
42 | token = buffer.readString(); |
---|
43 | if (token != "RpSerial:A") { |
---|
44 | std::string errmsg("can't deserialize stream: "); |
---|
45 | errmsg += "bad marker \""; |
---|
46 | errmsg += token; |
---|
47 | errmsg += "\" (should be RpSerial:A)"; |
---|
48 | return result.error(errmsg.data()); |
---|
49 | } |
---|
50 | |
---|
51 | // get the number of objects to read |
---|
52 | int nobj = buffer.readInt(); |
---|
53 | if (nobj < 0) { |
---|
54 | std::string errmsg("can't deserialize stream: "); |
---|
55 | errmsg += "corrupt data (number of objects is negative)"; |
---|
56 | return result.error(errmsg.data()); |
---|
57 | } |
---|
58 | |
---|
59 | // read out the expected number of objects from the list |
---|
60 | for (int i=0; i < nobj && !buffer.atEnd(); i++) { |
---|
61 | token = buffer.readString(); |
---|
62 | if (token != "RpObj:") { |
---|
63 | std::string errmsg("can't deserialize stream: "); |
---|
64 | errmsg += "bad marker \""; |
---|
65 | errmsg += token; |
---|
66 | errmsg += "\" (should be RpObj:)"; |
---|
67 | return result.error(errmsg.data()); |
---|
68 | } |
---|
69 | std::string id = buffer.readString(); |
---|
70 | |
---|
71 | Ptr<Serializable> objPtr; |
---|
72 | result = Serializable::deserialize(buffer, &objPtr); |
---|
73 | |
---|
74 | // if there was an error, then bail out |
---|
75 | if (result != 0) { |
---|
76 | std::ostringstream context; |
---|
77 | context << "while deserializing object #" << i+1 |
---|
78 | << " of " << nobj; |
---|
79 | return result.addContext(context.str().data()); |
---|
80 | } |
---|
81 | |
---|
82 | // add the object to the known list |
---|
83 | _id2obj[id] = objPtr; |
---|
84 | SerializerId2Obj::iterator iter = _id2obj.find(id); |
---|
85 | const char* key = (*iter).first.data(); |
---|
86 | _idlist.push_back(key); |
---|
87 | } |
---|
88 | |
---|
89 | return result; |
---|
90 | } |
---|
91 | |
---|
92 | Ptr<SerialBuffer> |
---|
93 | Serializer::serialize() |
---|
94 | { |
---|
95 | Ptr<SerialBuffer> bufferPtr( new SerialBuffer() ); |
---|
96 | bufferPtr->writeString("RpSerial:A"); |
---|
97 | |
---|
98 | // write out number of objects in the stream |
---|
99 | bufferPtr->writeInt(_idlist.size()); |
---|
100 | |
---|
101 | // write out each object in the list, in order |
---|
102 | for (unsigned int i=0; i < _idlist.size(); i++) { |
---|
103 | const char* id = _idlist.at(i); |
---|
104 | Ptr<Serializable> objPtr = _id2obj[id]; |
---|
105 | |
---|
106 | bufferPtr->writeString("RpObj:"); |
---|
107 | bufferPtr->writeString(id); |
---|
108 | objPtr->serialize(*bufferPtr.pointer()); |
---|
109 | } |
---|
110 | return bufferPtr; |
---|
111 | } |
---|
112 | |
---|
113 | int |
---|
114 | Serializer::size() const |
---|
115 | { |
---|
116 | return _idlist.size(); |
---|
117 | } |
---|
118 | |
---|
119 | Ptr<Serializable> |
---|
120 | Serializer::get(int pos) const |
---|
121 | { |
---|
122 | Serializer *nonconst = (Serializer*)this; |
---|
123 | assert(pos >= 0 && (unsigned int)pos < _idlist.size()); |
---|
124 | |
---|
125 | std::string id(_idlist[pos]); |
---|
126 | return nonconst->_id2obj[id]; |
---|
127 | } |
---|
128 | |
---|
129 | Serializer& |
---|
130 | Serializer::clear() |
---|
131 | { |
---|
132 | _id2obj.clear(); |
---|
133 | _idlist.clear(); |
---|
134 | return *this; |
---|
135 | } |
---|
136 | |
---|
137 | const char* |
---|
138 | Serializer::add(Serializable* objPtr) |
---|
139 | { |
---|
140 | const char* key = NULL; |
---|
141 | |
---|
142 | // build a unique string that represents this object |
---|
143 | std::ostringstream idbuffer; |
---|
144 | idbuffer << (void*)objPtr; |
---|
145 | std::string id(idbuffer.str()); |
---|
146 | |
---|
147 | // have we already registered this object? |
---|
148 | SerializerId2Obj::iterator iter = _id2obj.find(id); |
---|
149 | if (iter == _id2obj.end()) { |
---|
150 | // if not, then add to map and also to list of all objects |
---|
151 | _id2obj[id] = Ptr<Serializable>(objPtr); |
---|
152 | iter = _id2obj.find(id); |
---|
153 | key = (*iter).first.data(); |
---|
154 | _idlist.push_back(key); |
---|
155 | } else { |
---|
156 | // if so, then update map |
---|
157 | key = (*iter).first.data(); |
---|
158 | _id2obj[id] = Ptr<Serializable>(objPtr); |
---|
159 | } |
---|
160 | return key; |
---|
161 | } |
---|