]> git.vomp.tv Git - vompclient.git/blob - serialize.cc
92720f4c0b5b40af943954911d60855d4faf2d8a
[vompclient.git] / serialize.cc
1 /*
2     Copyright 2004-2005 Chris Tallon, Andreas Vogel
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "serialize.h"
22 #include <stdlib.h>
23 #ifndef WIN32
24 #include <arpa/inet.h>
25 #else
26 #include <winsock2.h>
27 #endif
28
29
30 #ifndef SNPRINTF
31 #define SNPRINTF snprintf
32 #endif
33
34 #define BUFFERINCREASE 1024
35
36 int SerializeBuffer::seek(int amount) {
37   UCHAR *np=current+amount;
38   if (np < start || np > end) return -1;
39   current=np;
40   return 0;
41 }
42
43 void SerializeBuffer::rewind() {
44   current=start;
45 }
46
47 int SerializeBuffer::checkSpace(int amount) {
48   if ((current+amount) <= end) return 0;
49   if (owning && autoincrease) {
50      if (start+size > current+amount) {
51        end=start+size;
52        return 0;
53      }
54      UCHAR *ns=new UCHAR[size+BUFFERINCREASE];
55      if (!ns) return -1;
56      memcpy(ns,start,end-start);
57      size=size+BUFFERINCREASE;
58      end=ns+size;
59      if (useMalloc) free( start);
60      else delete [] start;
61      start=ns;
62      return 0;
63   }
64   return -1;
65 }
66
67 SerializeBuffer::~SerializeBuffer() {
68   if (owning) {
69     if (useMalloc) free(start);
70     else delete[] start;
71     start=NULL;
72   }
73 }
74 SerializeBuffer::SerializeBuffer(ULONG sz,bool isMalloc,bool ai){
75   autoincrease=ai;
76   useMalloc=isMalloc;
77   if (isMalloc) {
78     start=(UCHAR *)malloc(sz);
79   }
80   else {
81     start=new UCHAR[sz];
82   }
83   end=start;
84   current=start;
85   size=sz;
86   owning=true;
87 }
88     //constructor for SerializeBuffers with external buffers
89 SerializeBuffer::SerializeBuffer(UCHAR *buffer,ULONG sz,bool ow,bool isMalloc,bool ai) {
90   useMalloc=isMalloc;
91   autoincrease=ai;
92   owning=ow;
93   size=sz;
94   start=buffer;
95   current=start;
96   end=start+size;
97 }
98 /**
99   * helper for serialize and deserialize
100   * always return != if no space
101   * advance buffer pointer
102   */
103
104 int SerializeBuffer::encodeLong(ULONG data) {
105   if (checkSpace( (int)sizeof(ULONG))!=0) return -1;
106   *((ULONG *)(current))=htonl(data); 
107   current+=sizeof(ULONG);
108   return 0;
109 }
110 int SerializeBuffer::encodeShort(USHORT data) {
111   if (checkSpace( (int)sizeof(USHORT))!=0) return -1;
112   *((USHORT *)(current))=htons(data); 
113   current+=sizeof(USHORT);
114   return 0;
115 }
116 int SerializeBuffer::encodeByte(UCHAR data) {
117   if (checkSpace( (int)sizeof(UCHAR))!=0) return -1;
118   *((UCHAR *)(current))=data; 
119   current+=sizeof(UCHAR);
120   return 0;
121 }
122 int SerializeBuffer::encodeLongLong(ULLONG data) {
123   if (checkSpace( (int)sizeof(ULLONG))!=0) return -1;
124   *((ULONG *)(current))=htonl((data>>32) & 0xffffffff); 
125   current+=sizeof(ULONG);
126   *((ULONG *)(current))=htonl(data & 0xffffffff); 
127   current+=sizeof(ULONG);
128   return 0;
129 }
130 //string: 4 len, string with 0
131 int SerializeBuffer::encodeString(const char *str) {
132   if (checkSpace( (int)sizeof(ULONG))!=0) return -1;
133   ULONG len=0;
134   if (str) len=strlen(str)+1;
135   *((ULONG *)(current))=htonl(len); 
136   current+=sizeof(ULONG);
137   if (len == 0) return 0;
138   if (checkSpace((int)len)!=0) return -1;
139   strcpy((char *) current,str);
140   current+=len;
141   return 0;
142 }
143 int SerializeBuffer::decodeLong( int &data) {
144   if (checkSpace( (int)sizeof(ULONG))!=0) return -1;
145   data=(int)ntohl(*((ULONG *)(current))); 
146   current+=sizeof(ULONG);
147   return 0;
148 }
149 int SerializeBuffer::decodeLong(ULONG &data) {
150   if (checkSpace( (int)sizeof(ULONG))!=0) return -1;
151   data=ntohl(*((ULONG *)(current))); 
152   current+=sizeof(ULONG);
153   return 0;
154 }
155 int SerializeBuffer::decodeShort(USHORT &data) {
156   if (checkSpace( (int)sizeof(USHORT))!=0) return -1;
157   data=ntohs(*((USHORT *)(current))); 
158   current+=sizeof(USHORT);
159   return 0;
160 }
161 int SerializeBuffer::decodeByte(UCHAR &data) {
162   if (checkSpace( (int)sizeof(UCHAR))!=0) return -1;
163   data=*((UCHAR *)current);
164   current+=sizeof(UCHAR);
165   return 0;
166 }
167 int SerializeBuffer::decodeLongLong(ULLONG &data) {
168   if (checkSpace( (int)sizeof(ULLONG))!=0) return -1;
169   ULLONG hd=ntohl(*((ULONG *)(current))); 
170   current+=sizeof(ULONG);
171   ULLONG ld=ntohl(*((ULONG *)(current))); 
172   current+=sizeof(ULONG);
173   data=(hd << 32) | ld;
174   return 0;
175 }
176 //string: 4 len, string with 0
177 int SerializeBuffer::decodeString(ULONG &len, char *&strbuf) {
178   strbuf=NULL;
179   len=0;
180   if (checkSpace( (int)sizeof(ULONG))!=0) return -1;
181   len=ntohl(*((ULONG *)(current))); 
182   current+=sizeof(ULONG);
183   if (len == 0) return 0;
184   if (checkSpace((int)len)!=0) return -1;
185   strbuf=new char[len];
186   strncpy(strbuf,(char *)current,len);
187   *(strbuf+len-1)=0;
188   current+=len;
189   return 0;
190 }
191
192
193 UCHAR * SerializeBuffer::steelBuffer() {
194   UCHAR *rt=start;
195   owning=false;
196   autoincrease=false;
197   return rt;
198 }
199
200 int Serializable::getSerializedStringLen(const char * str) {
201   int rt=4;
202   if (str) rt+=strlen(str)+1;
203   return rt;
204 }
205
206 USHORT Serializable::getVersion() {
207   return version;
208 }
209
210
211 Serializable::Serializable() {
212   version=1;
213 }
214 Serializable::~Serializable(){}
215
216 int Serializable::getSerializedLen() {
217   //2version+4len
218   return 6 + getSerializedLenImpl();
219 }
220 int Serializable::serialize(SerializeBuffer *b) {
221   UCHAR *ptr=b->getCurrent();
222   if (b->encodeShort(version) != 0) return -1;
223   if (b->encodeLong(0) != 0) return -1; //dummy len
224   if (serializeImpl(b) != 0) return -1;
225   UCHAR *ep=b->getCurrent();
226   //now write the len
227   int len=ep-ptr-6;
228   if (len < 0) return -1 ; //internal error
229   b->seek(ptr-ep+2); //to len field
230   if (b->encodeLong(len) != 0) return -1;
231   b->seek(ep-b->getCurrent()); //back to end
232   return 0;
233 }
234
235 int Serializable::deserialize(SerializeBuffer *b) {
236   USHORT vers=0;
237   if (b->decodeShort(vers) != 0) return -1;
238   ULONG len=0;
239   if (b->decodeLong(len) != 0) return -1;
240   UCHAR *data=b->getCurrent();
241   if (data+len > b->getEnd()) return -1;
242   //TODO: set end temp. to current+len
243   //for better error handling in deserializeImpl
244   if (deserializeImpl(b) != 0) return -1;
245   //ensure we go to end of this element regardless of the things we know
246   b->seek(data+len-b->getCurrent());
247   return 0;
248 }
249   
250 SerializableList::SerializableList() {
251   version=1;
252   encodeOnly=false;
253 }
254 SerializableList::~SerializableList(){}
255
256 int SerializableList::addParam(Serializable *p,USHORT v) {
257   if (v < version || p == NULL) return -1;
258   Pentry entry;
259   entry.ptype=TSER;
260   entry.ptr.pser=p;
261   entry.version=v;
262   list.push_back(entry);
263   version=v;
264   return 0;
265 }
266 int SerializableList::addParam(USHORT *p,USHORT v) {
267   if (v < version || p == NULL) return -1;
268   Pentry entry;
269   entry.ptype=TUSHORT;
270   entry.ptr.pshort=p;
271   entry.version=v;
272   list.push_back(entry);
273   version=v;
274   return 0;
275 }
276 int SerializableList::addParam(ULONG *p,USHORT v) {
277   if (v < version || p == NULL) return -1;
278   Pentry entry;
279   entry.ptype=TULONG;
280   entry.ptr.plong=p;
281   entry.version=v;
282   list.push_back(entry);
283   version=v;
284   return 0;
285 }
286 int SerializableList::addParam(ULLONG *p,USHORT v) {
287   if (v < version || p == NULL) return -1;
288   Pentry entry;
289   entry.ptype=TULLONG;
290   entry.ptr.pllong=p;
291   entry.version=v;
292   list.push_back(entry);
293   version=v;
294   return 0;
295 }
296 int SerializableList::addParam(char **p,USHORT v) {
297   if (v < version || p == NULL) return -1;
298   Pentry entry;
299   entry.ptype=TCHAR;
300   entry.ptr.pchar=p;
301   entry.version=v;
302   list.push_back(entry);
303   version=v;
304   return 0;
305 }
306
307 bool SerializableList::Pentry::isEqual(void *p,SerializableList::Ptypes t) {
308   void *cmp=NULL;
309   switch(t) {
310     case TUSHORT:
311       cmp=(void *)ptr.pshort;
312       break;
313     case TULONG:
314       cmp=(void *)ptr.plong;
315       break;
316     case TULLONG:
317       cmp=(void *)ptr.pllong;
318       break;
319     case TSER:
320       cmp=(void *)ptr.pser;
321       break;
322     case TCHAR:
323       cmp=(void *)ptr.pchar;
324       break;
325     case TUNKNOWN:
326       break;
327   }
328   return p==cmp;
329 }
330
331 SerializableList::Pentry *SerializableList::findEntry(void *p,SerializableList::Ptypes t) {
332   for (vector<Pentry>::iterator it=list.begin();it<list.end();it++) {
333     if ( (*it).isEqual(p,t)) return &(*it);
334   }
335   return NULL;
336 }
337 bool SerializableList::isDeserialized(Serializable *p){
338   SerializableList::Pentry *e=findEntry(p,TSER);
339   if (!e) return false;
340   return e->isDeserialized;
341 }
342 bool SerializableList::isDeserialized(USHORT *p){
343   SerializableList::Pentry *e=findEntry(p,TUSHORT);
344   if (!e) return false;
345   return e->isDeserialized;
346 }
347 bool SerializableList::isDeserialized(ULONG *p){
348   SerializableList::Pentry *e=findEntry(p,TULONG);
349   if (!e) return false;
350   return e->isDeserialized;
351 }
352
353 bool SerializableList::isDeserialized(ULLONG *p){
354   SerializableList::Pentry *e=findEntry(p,TULLONG);
355   if (!e) return false;
356   return e->isDeserialized;
357 }
358
359 bool SerializableList::isDeserialized(char **p){
360   SerializableList::Pentry *e=findEntry(p,TCHAR);
361   if (!e) return false;
362   return e->isDeserialized;
363 }
364
365 int SerializableList::getSerializedLenImpl(){
366   int rt=0;
367   for (vector<Pentry>::iterator it=list.begin();it<list.end();it++) {
368     switch((*it).ptype){
369       case TUSHORT:
370         rt+=sizeof(USHORT);
371         break;
372       case TULONG:
373         rt+=sizeof(ULONG);
374         break;
375       case TULLONG:
376         rt+=sizeof(ULLONG);
377         break;
378       case TCHAR:
379         rt+=getSerializedStringLen(*((*it).ptr.pchar));
380         break;
381       case TSER:
382         rt+=(*it).ptr.pser->getSerializedLen();
383         break;
384       case TUNKNOWN:
385         break;
386     }
387   }
388   return rt;
389 }
390
391 int SerializableList::serializeImpl(SerializeBuffer *b){
392   for (vector<Pentry>::iterator it=list.begin();it<list.end();it++) {
393     switch((*it).ptype){
394       case TUSHORT:
395         if (b->encodeShort(*(*it).ptr.pshort) != 0) return -1;
396         break;
397       case TULONG:
398         if (b->encodeLong(*(*it).ptr.plong) != 0) return -1;
399         break;
400       case TULLONG:
401         if (b->encodeLongLong(*(*it).ptr.pllong) != 0) return -1;
402         break;
403       case TCHAR:
404         if (b->encodeString(*(*it).ptr.pchar) != 0) return -1;
405         break;
406       case TSER:
407         if ((*it).ptr.pser->serialize(b) != 0) return -1;
408         break;
409       case TUNKNOWN:
410         break;
411     }
412   }
413   return 0;
414 }
415
416 int SerializableList::deserializeImpl(SerializeBuffer *b){
417   ULONG dlen=0;
418   for (vector<Pentry>::iterator it=list.begin();it<list.end();it++) {
419     if ((*it).version > version) {
420       //OK - we received an older version - stop here
421       break;
422     }
423     switch((*it).ptype){
424       case TUSHORT:
425         if (b->decodeShort(*(*it).ptr.pshort) != 0) return -1;
426         break;
427       case TULONG:
428         if (b->decodeLong(*(*it).ptr.plong) != 0) return -1;
429         break;
430       case TULLONG:
431         if (b->decodeLongLong(*(*it).ptr.pllong) != 0) return -1;
432         break;
433       case TCHAR:
434         if (b->decodeString(dlen,*(*it).ptr.pchar) != 0) return -1;
435         break;
436       case TSER:
437         if ((*it).ptr.pser->deserialize(b) != 0) return -1;
438         break;
439       case TUNKNOWN:
440         break;
441     }
442     (*it).isDeserialized=true;
443   }
444   return 0;
445 }
446
447