00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <fun/SerialTree.h>
00019 #include <qfile.h>
00020
00021 namespace fun {
00022
00023 static const char *magic1 = "#SerialTree\0001\0\0\0";
00024 static const char *magic2 = "#SerialTree\0002\0\0\0";
00025
00026 bool
00027 SerialTree::saveToBinaryFile(const QString &filename, int version, int mode)
00028 {
00029
00030
00031 QFile bleh(filename);
00032 if (!bleh.open(IO_WriteOnly)) return NULL;
00033 QDataStream is(&bleh);
00034 return saveToBinaryStream(is, version);
00035 }
00036
00037 SerialTree *
00038 SerialTree::loadFromBinaryFile(const QString &filename)
00039 {
00040 QFile bleh(filename);
00041 if (!bleh.open(IO_ReadOnly)) return NULL;
00042 QDataStream is(&bleh);
00043 return loadFromBinaryStream(is);
00044 }
00045
00046 bool
00047 SerialTree::saveToBinaryStream(QDataStream &os, int version)
00048 {
00049
00050 #if BOZO_CONTEXT
00051 if (version < 1) version = 2;
00052 #else
00053 if (version < 1) version = 1;
00054 #endif // BOZO_CONTEXT
00055
00056 if (version == 1)
00057 {
00058 os.writeRawBytes(magic1, 16);
00059 return childrenToBinary1(os);
00060 }
00061 else if (version == 2)
00062 {
00063 #if BOZO_CONTEXT
00064 os.writeRawBytes(magic2, 16);
00065 contextToBinary2(os);
00066 return childrenToBinary2(os);
00067 #else
00068 NOT_DONE("no support for binary version " << dec << version << " when BOZO_CONTEXT is turned off in SerialTree.h. Sorry!");
00069 return false;
00070 #endif // BOZO_CONTEXT
00071 }
00072 else
00073 {
00074 NOT_DONE("no support for binary version " << dec << version << "!");
00075 return false;
00076 }
00077 }
00078
00079 SerialTree *
00080 SerialTree::loadFromBinaryStream(QDataStream &is)
00081 {
00082 is.setByteOrder(QDataStream::BigEndian);
00083 SerialTree *tree = NULL;
00084
00085 char buf[16];
00086 is.readRawBytes(buf, 16);
00087
00088 if (memcmp(buf, magic1, 16) == 0)
00089 {
00090 tree = new SerialTree();
00091 tree->childrenFromBinary1(is);
00092 }
00093 else if (memcmp(buf, magic2, 16) == 0)
00094 {
00095 #if BOZO_CONTEXT
00096 tree = new SerialTree();
00097 tree->contextFromBinary2(is);
00098 tree->childrenFromBinary2(is);
00099 #else
00100 NOT_DONE("SerialTree::loadFromBinaryStream() doesn't handle binary version 2 when BOZO_CONTEXT is turned off in SerialTree.h. Sorry!");
00101 return NULL;
00102 #endif // BOZO_CONTEXT
00103 }
00104 else
00105 {
00106 NOT_DONE("need to throw exception or report bad magic in SerialTree::loadFromBinaryStream()");
00107 return NULL;
00108 }
00109 if ((!tree) || (!tree->children.empty())) return tree;
00110 delete tree;
00111 return NULL;
00112 }
00113
00114 bool
00115 SerialTree::childrenToBinary1(QDataStream &os)
00116 {
00117 os << (Q_INT16)666;
00118
00119 const char *cs = getSerializableClass();
00120 if (cs)
00121 {
00122 int len = strlen(cs);
00123 os << (Q_INT16)len;
00124 os.writeRawBytes(cs, len);
00125 }
00126 else os << (Q_INT16)0;
00127
00128 os << (Q_INT32)(children.size());
00129 for (int ii = 0; ii < children.size(); ++ii)
00130 {
00131 Child *cp = children[ii];
00132 #if BOZO_CONTEXT
00133 os << context->getKeyString(cp->ikey);
00134 #else
00135 os << cp->skey;
00136 #endif // BOZO_CONTEXT
00137 os << (Q_INT8)(cp->ct);
00138 switch (cp->ct)
00139 {
00140 case Child::CT_TREE:
00141 cp->val.t->childrenToBinary1(os);
00142 break;
00143 case Child::CT_QSTRING:
00144 os << *(cp->val.s);
00145 break;
00146 #if BOZO_NATIVE
00147 case Child::CT_INT: os << (Q_INT32)cp->val.i; break;
00148 case Child::CT_UNSIGNED: os << (Q_UINT32)cp->val.u; break;
00149 case Child::CT_BOOL: os << (Q_INT8)cp->val.b; break;
00150 case Child::CT_FLOAT: os << cp->val.f; break;
00151 case Child::CT_DOUBLE: os << cp->val.d; break;
00152 #endif // BOZO_NATIVE
00153 default:
00154 NOT_DONE("argghh, didn't handle child type " << dec << cp->ct);
00155 return false;
00156 }
00157 }
00158 os << (Q_INT16)32101;
00159 return true;
00160 }
00161
00162 void
00163 SerialTree::childrenFromBinary1(QDataStream &is)
00164 {
00165 Q_INT16 buf16;
00166 is >> buf16;
00167 if (buf16 != 666)
00168 {
00169 NOT_DONE("hosed, didn't find leading guard bytes");
00170 return;
00171 }
00172
00173 is >> buf16;
00174 if (buf16 > 0)
00175 {
00176 #if BOZO_CONTEXT
00177 char *buf = (char *)malloc(buf16 + 1);
00178 is.readRawBytes(buf, buf16);
00179 buf[buf16] = '\0';
00180 setSerializableClass(buf);
00181 free(buf);
00182 #else
00183 serialClass = (char *)malloc(buf16 + 1);
00184 is.readRawBytes(serialClass, buf16);
00185 serialClass[buf16] = '\0';
00186 #endif // BOZO_CONTEXT
00187 }
00188
00189 Q_INT32 expectedkids;
00190 is >> expectedkids;
00191 children.reserve(expectedkids);
00192 for (int ii = 0; ii < expectedkids; ++ii)
00193 {
00194 Child *cp = NULL;
00195
00196 #if BOZO_CONTEXT
00197 QString ts;
00198 is >> ts;
00199 unsigned key = context->getKey(ts);
00200 #else
00201 QString key;
00202 is >> key;
00203 #endif // BOZO_CONTEXT
00204
00205 Q_INT8 ct;
00206 is >> ct;
00207 switch (ct)
00208 {
00209 case Child::CT_TREE:
00210 #if BOZO_CONTEXT
00211 cp = new Child(key, new SerialTree(context));
00212 #else
00213 cp = new Child(key, new SerialTree());
00214 #endif // BOZO_CONTEXT
00215 cp->val.t->childrenFromBinary1(is);
00216 break;
00217 case Child::CT_QSTRING:
00218 {
00219 QString s;
00220 is >> s;
00221 cp = new Child(key, new QString(s));
00222 break;
00223 }
00224 #if BOZO_NATIVE
00225 case Child::CT_INT:
00226 {
00227 Q_INT32 i;
00228 is >> i;
00229 cp = new Child(key, (int)i);
00230 break;
00231 }
00232 case Child::CT_UNSIGNED:
00233 {
00234 Q_UINT32 u;
00235 is >> u;
00236 cp = new Child(key, (unsigned)u);
00237 break;
00238 }
00239 case Child::CT_BOOL:
00240 {
00241 Q_INT8 b;
00242 is >> b;
00243 cp = new Child(key, (bool)b);
00244 break;
00245 }
00246 case Child::CT_FLOAT:
00247 {
00248 float f;
00249 is >> f;
00250 cp = new Child(key, f);
00251 break;
00252 }
00253 case Child::CT_DOUBLE:
00254 {
00255 double d;
00256 is >> d;
00257 cp = new Child(key, d);
00258 break;
00259 }
00260 #endif // BOZO_NATIVE
00261 default:
00262 NOT_DONE("argghh, didn't handle child type " << dec << ct);
00263 return;
00264 }
00265 if (cp) children.push_back(cp);
00266 }
00267
00268 is >> buf16;
00269 if (buf16 != 32101)
00270 {
00271 NOT_DONE("hosed, didn't find trailing guard bytes");
00272 return;
00273 }
00274 }
00275
00276 #if BOZO_CONTEXT
00277
00278 bool
00279 SerialTree::childrenToBinary2(QDataStream &os)
00280 {
00281 os << (Q_INT16)666;
00282
00283 os << (Q_INT16)serialClassID;
00284
00285 os << (Q_INT32)(children.size());
00286 for (int ii = 0; ii < children.size(); ++ii)
00287 {
00288 Child *cp = children[ii];
00289 os << (Q_INT16)(cp->ikey);
00290 os << (Q_INT8)(cp->ct);
00291 switch (cp->ct)
00292 {
00293 case Child::CT_TREE:
00294 cp->val.t->childrenToBinary2(os);
00295 break;
00296 case Child::CT_QSTRING:
00297 os << *(cp->val.s);
00298 break;
00299 #if BOZO_NATIVE
00300 case Child::CT_INT: os << (Q_INT32)cp->val.i; break;
00301 case Child::CT_UNSIGNED: os << (Q_UINT32)cp->val.u; break;
00302 case Child::CT_BOOL: os << (Q_INT8)cp->val.b; break;
00303 case Child::CT_FLOAT: os << cp->val.f; break;
00304 case Child::CT_DOUBLE: os << cp->val.d; break;
00305 #endif // BOZO_NATIVE
00306 default:
00307 NOT_DONE("argghh, didn't handle child type " << dec << cp->ct);
00308 return false;
00309 }
00310 }
00311 os << (Q_INT16)32101;
00312 return true;
00313 }
00314
00315 void
00316 SerialTree::childrenFromBinary2(QDataStream &is)
00317 {
00318 Q_INT16 buf16;
00319 is >> buf16;
00320 if (buf16 != 666)
00321 {
00322 NOT_DONE("hosed, didn't find leading guard bytes");
00323 return;
00324 }
00325
00326 is >> buf16;
00327 serialClassID = buf16;
00328
00329 Q_INT32 expectedkids;
00330 is >> expectedkids;
00331 children.reserve(expectedkids);
00332 for (int ii = 0; ii < expectedkids; ++ii)
00333 {
00334 Child *cp = NULL;
00335
00336 Q_INT16 key;
00337 is >> key;
00338 Q_INT8 ct;
00339 is >> ct;
00340 switch (ct)
00341 {
00342 case Child::CT_TREE:
00343 cp = new Child(key, new SerialTree(context));
00344 cp->val.t->childrenFromBinary2(is);
00345 break;
00346 case Child::CT_QSTRING:
00347 {
00348 QString s;
00349 is >> s;
00350 cp = new Child(key, new QString(s));
00351 break;
00352 }
00353 #if BOZO_NATIVE
00354 case Child::CT_INT:
00355 {
00356 Q_INT32 i;
00357 is >> i;
00358 cp = new Child(key, (int)i);
00359 break;
00360 }
00361 case Child::CT_UNSIGNED:
00362 {
00363 Q_UINT32 u;
00364 is >> u;
00365 cp = new Child(key, (unsigned)u);
00366 break;
00367 }
00368 case Child::CT_BOOL:
00369 {
00370 Q_INT8 b;
00371 is >> b;
00372 cp = new Child(key, (bool)b);
00373 break;
00374 }
00375 case Child::CT_FLOAT:
00376 {
00377 float f;
00378 is >> f;
00379 cp = new Child(key, f);
00380 break;
00381 }
00382 case Child::CT_DOUBLE:
00383 {
00384 double d;
00385 is >> d;
00386 cp = new Child(key, d);
00387 break;
00388 }
00389 #endif // BOZO_NATIVE
00390 default:
00391 NOT_DONE("argghh, didn't handle child type " << dec << ct);
00392 return;
00393 }
00394 if (cp) children.push_back(cp);
00395 }
00396
00397 is >> buf16;
00398 if (buf16 != 32101)
00399 {
00400 NOT_DONE("hosed, didn't find trailing guard bytes");
00401 return;
00402 }
00403 }
00404
00405 void
00406 SerialTree::contextToBinary2(QDataStream &os)
00407 {
00408 int ii;
00409 int sz = context->classlut.size();
00410 os << (Q_INT16)(sz - 1);
00411 for (ii = 1; ii < sz; ++ii)
00412 {
00413 int len = strlen(context->classlut[ii]);
00414 os << (Q_INT16)len;
00415 os.writeRawBytes(context->classlut[ii], len);
00416 }
00417 os << (Q_INT16)666;
00418 sz = context->keylut.size();
00419 os << (Q_INT16)(sz - 1);
00420 for (ii = 1; ii < sz; ++ii) os << *(context->keylut[ii]);
00421 }
00422
00423 void
00424 SerialTree::contextFromBinary2(QDataStream &is)
00425 {
00426 Q_INT16 buf16;
00427 is >> buf16;
00428 context->classlut.reserve(buf16 + 1);
00429 int expect = buf16;
00430 int ii;
00431 for (ii = 0; ii < expect; ++ii)
00432 {
00433 is >> buf16;
00434 char *buf = (char *)malloc(buf16 + 1);
00435 is.readRawBytes(buf, buf16);
00436 buf[buf16] = '\0';
00437 context->classlut.push_back(buf);
00438 }
00439 is >> buf16;
00440 if (buf16 != 666)
00441 {
00442 NOT_DONE("didn't find guard bytes, you are hosed!");
00443 return;
00444 }
00445 is >> buf16;
00446 context->keylut.reserve(buf16 + 1);
00447 for (ii = 0; ii < buf16; ++ii)
00448 {
00449 QString *buf = new QString;
00450 is >> (*buf);
00451 context->keylut.push_back(buf);
00452 }
00453 }
00454
00455 #endif // BOZO_CONTEXT
00456
00457 }