Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members  

SerialTree-bin.cpp

00001 //  SerialTree-bin - binary file support for SerialTree
00002 //  Copyright (C) 2003 bozo & sgbeal @users.sourceforge.net
00003 //
00004 //  This program is free software; you can redistribute it and/or
00005 //  modify it under the terms of the GNU General Public License
00006 //  as published by the Free Software Foundation; either version 2
00007 //  of the License, or (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program; if not, write to the Free Software
00016 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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 //  std::ofstream savefile(filename);//, (mode & QIODevice::IO_Append ? ios::app : 
00030 //  return (savefile.good() && saveToBinaryStream(savefile) && savefile.good());
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     //  Handle the default.
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);  //  just in case.
00083     SerialTree *tree = NULL;
00084 
00085     char buf[16];
00086     is.readRawBytes(buf, 16);
00087 //wtf, how do you handle read errors with this API?
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 }  //  namespace fun

Generated on Mon Aug 11 14:06:55 2003 for libfunutil by doxygen1.2.18