Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Examples

vos/metaobjects/misc/cod.cc

Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2003 Peter Amstutz <tetron@interreality.org>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Lesser General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This library 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 GNU
00012     Lesser General Public License for more details.
00013 
00014     You should have received a copy of the GNU Lesser General Public
00015     License along with this library; if not, write to the Free Software
00016     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00017 
00018 */
00019 
00020 #include <stdarg.h>
00021 
00022 #include <vos/metaobjects/misc/cod.hh>
00023 #include <vos/metaobjects/property/property.hh>
00024 
00025 #ifdef WIN32
00026 #define ZLIB_DLL
00027 #endif
00028 
00029 #include <zlib.h>
00030 
00031 COD::COD(iostream& io, LocalSite& l)
00032     : f(&io), ls(l), offset(0), buffersize(0), buffer(0)
00033 {
00034     ls.acquire(); // released by: destructor
00035 }
00036 
00037 COD::COD(LocalSite& l)
00038     : f(0), ls(l), offset(0), buffersize(0), buffer(0)
00039 {
00040     ls.acquire(); // released by: destructor
00041 }
00042 
00043 
00044 COD::~COD()
00045 {
00046     ls.release(); // acquired by: constructor
00047     if(buffer) free(buffer);
00048 
00049     clear();
00050 }
00051 
00052 void COD::setStream(iostream& io)
00053 {
00054     f = &io;
00055 }
00056 
00057 void COD::clear()
00058 {
00059     for(unsigned int i = 0; i < vobjectorder.size(); i++) {
00060         if(vobjectorder[i]) {
00061             if(vobjectorder[i]->vobject) vobjectorder[i]->vobject->release(); // acquired by: addVobject
00062             if(vobjectorder[i]->mb) vobjectorder[i]->mb->release(); // acquired by: addVobject
00063             delete vobjectorder[i];
00064         }
00065     }
00066     vobjectorder.resize(0);
00067     vobjectTable.clear();
00068 }
00069 
00070 int COD::addVobject(Vobject* v, bool portable, bool saveChildren)
00071 {
00072     v->acquire(); // released by: removeVobject() or destructor
00073     Entry* e = new Entry;
00074     e->vobject = v;
00075     e->mb = new MessageBlock();
00076     e->vobject->saveState(*e->mb, e->types, portable);
00077     e->savechildren = saveChildren;
00078 
00079     vobjectTable[v->getName()] = e;
00080     vobjectorder.push_back(e);
00081     e->pos = vobjectorder.size() - 1;
00082     return e->pos;
00083 }
00084 
00085 int COD::addVobject(Vobject* v, const set<string>& types, MessageBlock* mb, bool saveChildren)
00086 {
00087     v->acquire(); // released by: removeVobject() or destructor
00088     Entry* e = new Entry;
00089     e->vobject = v;
00090     mb->acquire(); // released by: removeVobject() or destructor
00091     e->mb = mb;
00092     e->types = types;
00093     e->savechildren = saveChildren;
00094 
00095     vobjectTable[v->getName()] = e;
00096     vobjectorder.push_back(e);
00097     e->pos = vobjectorder.size() - 1;
00098     return e->pos;
00099 }
00100 
00101 int COD::addVobject(Vobject* v, const deque<string>& types, MessageBlock* mb, bool saveChildren)
00102 {
00103     v->acquire(); // released by: removeVobject() or destructor
00104     Entry* e = new Entry;
00105     e->vobject = v;
00106     mb->acquire(); // released by: removeVobject() or destructor
00107     e->mb = mb;
00108     e->savechildren = saveChildren;
00109 
00110     for(unsigned int i = 0; i < types.size(); i++) {
00111         e->types.insert(types[i]);
00112     }
00113 
00114     vobjectTable[v->getName()] = e;
00115     vobjectorder.push_back(e);
00116     e->pos = vobjectorder.size() - 1;
00117     return e->pos;
00118 }
00119 
00120 
00121 int COD::numVobjects()
00122 {
00123     return vobjectorder.size();
00124 }
00125 
00126 COD::Entry* COD::getVobject(const string& name)
00127 {
00128     map<string, Entry*>::iterator i = vobjectTable.find(name);
00129     if(i != vobjectTable.end()) return (*i).second;
00130     else return 0;
00131 }
00132 
00133 COD::Entry* COD::getVobject(int pos)
00134 {
00135     if(pos < 0) pos += vobjectorder.size() + 1;
00136     if(pos >= vobjectorder.size()) return 0;
00137     else return vobjectorder[pos];
00138 }
00139 
00140 void COD::removeVobject(const string& name)
00141 {
00142     map<string, Entry*>::iterator i = vobjectTable.find(name);
00143     if(i == vobjectTable.end()) return;
00144     Entry* e = (*i).second;
00145     vobjectTable.erase(i);
00146     vobjectorder.erase(vobjectorder.begin() + e->pos);
00147 
00148     e->vobject->release();
00149     e->mb->release();
00150 
00151     delete e;
00152 }
00153 
00154 void COD::removeVobject(int pos)
00155 {
00156     if(pos < 0) pos += vobjectorder.size() + 1;
00157     if(pos >= vobjectorder.size()) return;
00158 
00159     Entry* e = vobjectorder[pos];
00160 
00161     vobjectorder.erase(vobjectorder.begin() + pos);
00162     vobjectTable.erase(e->vobject->getName());
00163 
00164     e->vobject->release();
00165     e->mb->release();
00166 
00167     delete e;
00168 }
00169 
00170 
00171 int COD::writeObjectDesc(Entry* e, bool doWrite)
00172 {
00173     unsigned char buffer[65361];
00174     int numbytes = 0;
00175     int nb;
00176 
00177     vRef<Vobject::ParentChildRelation> pcr = ls.findChild(e->vobject->getName());
00178 
00179     nb = pack(buffer, sizeof(buffer), "Sls",
00180               e->vobject->getName().c_str(), e->vobject->getName().size(),
00181               pcr->position,
00182               e->types.size());
00183     if(doWrite) write(buffer, nb);
00184     numbytes += nb;
00185 
00186     for(Vobject::TypeSet::const_iterator i = e->types.begin(); i != e->types.end(); i++)
00187     {
00188         nb = pack(buffer, sizeof(buffer), "S", (*i).c_str(), (*i).size());
00189         if(doWrite) write(buffer, nb);
00190         numbytes += nb;
00191     }
00192 
00193     nb = pack(buffer, sizeof(buffer), "s", e->mb->numMessages());
00194     if(doWrite) write(buffer, nb);
00195     numbytes += nb;
00196 
00197     for(int i = 0; i < e->mb->numMessages(); i++) {
00198         vRef<Message> m = e->mb->getMessage(i);
00199         nb = pack(buffer, sizeof(buffer), "Ss", m->getMethod().c_str(),
00200                   m->getMethod().size(), m->getNumFields());
00201         if(doWrite) write(buffer, nb);
00202         numbytes += nb;
00203 
00204         for(int n = 0; n < m->getNumFields(); n++) {
00205             const Message::Field& fl = m->getField(n);
00206             nb = pack(buffer, sizeof(buffer), "Sl", fl.key.c_str(), fl.key.size(), fl.value.size());
00207             if(doWrite) write(buffer, nb);
00208             numbytes += nb;
00209 
00210             nb = fl.value.size();
00211             if(doWrite) write(fl.value.c_str(), nb);
00212             numbytes += nb;
00213         }
00214     }
00215 
00216     return numbytes;
00217 }
00218 
00219 int COD::writeObjectChildren(Vobject* child, bool doWrite)
00220 {
00221     unsigned char buffer[65361];
00222     int numbytes = 0;
00223     int nb;
00224 
00225     const Vobject::ChildList& cl2 = child->getChildren();
00226     nb = pack(buffer, sizeof(buffer), "Sl", child->getName().c_str(),
00227               child->getName().size(), cl2.size());
00228     if(doWrite) write(buffer, nb);
00229     numbytes += nb;
00230     for(unsigned int n = 0; n < cl2.size(); n++) {
00231         Vobject::ParentChildRelation* pcr2 = cl2[n];
00232         nb = pack(buffer, sizeof(buffer), "S",
00233                   pcr2->contextual_name.c_str(),
00234                   pcr2->contextual_name.size());
00235         if(doWrite) write(buffer, nb);
00236         numbytes += nb;
00237         if(pcr2 && pcr2->child) {
00238             if(pcr2->child->isLocal() && vobjectTable.count(pcr2->child->getName())) {
00239                 nb = pack(buffer, sizeof(buffer), "S",
00240                           pcr2->child->getName().c_str(),
00241                           pcr2->child->getName().size());
00242                 if(doWrite) write(buffer, nb);
00243                 numbytes += nb;
00244             } else {
00245                 nb = pack(buffer, sizeof(buffer), "S",
00246                           pcr2->child->getURL().getString().c_str(),
00247                           pcr2->child->getURL().getString().size());
00248                 if(doWrite) write(buffer, nb);
00249                 numbytes += nb;
00250             }
00251         } else {
00252             nb = pack(buffer, sizeof(buffer), "Ss", 0);
00253             if(doWrite) write(buffer, nb);
00254             numbytes += nb;
00255         }
00256     }
00257     return numbytes;
00258 }
00259 
00260 string COD::readStr()
00261 {
00262     static int r=0;
00263     r++;
00264     unsigned char buffer[66461];
00265     unsigned short int sz;
00266     read(buffer, 2);
00267     unpack(buffer, sizeof(buffer), "s", &sz);
00268 
00269     read(buffer, sz);
00270     return string((char*)buffer, (unsigned int)sz);
00271 }
00272 
00273 unsigned short int COD::readShort()
00274 {
00275     unsigned char buffer[2];
00276     read(buffer, 2);
00277     unsigned short int nt;
00278     unpack(buffer, sizeof(buffer), "s", &nt);
00279     return nt;
00280 }
00281 
00282 unsigned long COD::readLong()
00283 {
00284     unsigned char buffer[4];
00285     read(buffer, 4);
00286     unsigned long nt;
00287     unpack(buffer, sizeof(buffer), "l", &nt);
00288     return nt;
00289 }
00290 
00291 void COD::readObjectDesc(string& name, long& pos, deque<string>& types, MessageBlock& mb)
00292 {
00293     LOG("COD", 4, "about to read name");
00294     name = readStr();
00295 
00296     LOG("COD", 4, "read name " << name);
00297 
00298     pos = readLong();
00299 
00300     LOG("COD", 4, "read pos " << pos);
00301 
00302     short int nt = readShort();
00303     for(int n = 0; n < nt; n++) {
00304         string type = readStr();
00305         types.push_back(type);
00306     }
00307 
00308     unsigned short int nm = readShort();
00309     for(int n = 0; n < nm; n++) {
00310         string method = readStr();
00311 
00312         vRef<Message> msg = new Message();
00313         msg->setMethod(method);
00314 
00315         unsigned short int nf = readShort();
00316         for(int m = 0; m < nf; m++) {
00317             string key = readStr();
00318             unsigned long vlen = readLong();
00319             char* b2 = (char*)malloc(vlen+1);
00320             read(b2, vlen);
00321             string data(b2, vlen);
00322             msg->insertField(-1, key, data, true);
00323             free(b2);
00324         }
00325 
00326         mb.insertMessage(-1, &msg);
00327     }
00328 }
00329 
00330 void COD::readObjectChildren(string& parent, deque<PCR>& children)
00331 {
00332     parent = readStr();
00333     unsigned long ch = readLong();
00334     for(unsigned int n = 0; n < ch; n++) {
00335         PCR p;
00336         p.context = readStr();
00337         p.child = readStr();
00338         children.push_back(p);
00339     }
00340 }
00341 
00342 int COD::computeSize()
00343 {
00344     int numbytes = 14;
00345 
00346     for(unsigned int i = 0; i < vobjectorder.size(); i++) {
00347         numbytes += writeObjectDesc(vobjectorder[i], false);
00348     }
00349 
00350     for(unsigned int i = 0; i < vobjectorder.size(); i++) {
00351         if(vobjectorder[i]->vobject->getChildren().size() > 0 && vobjectorder[i]->savechildren) {
00352             numbytes += writeObjectChildren(vobjectorder[i]->vobject, false);
00353         }
00354     }
00355 
00356     return numbytes;
00357 }
00358 
00359 void COD::writeCOD(bool gzip)
00360 {
00361     if(f) {
00362         unsigned int size;
00363         writeCOD(&buffer, &size, gzip);
00364         f->write((char*)buffer, size);
00365     }
00366 }
00367 
00368 void COD::write(const unsigned char* data, unsigned int size)
00369 {
00370     memcpy(buffer + offset, data, size);
00371     offset += size;
00372 }
00373 
00374 void COD::write(const char* data, unsigned int size)
00375 {
00376     memcpy(buffer + offset, data, size);
00377     offset += size;
00378 }
00379 
00380 void COD::read(unsigned char* data, unsigned int size)
00381 {
00382     if(f) {
00383         f->read((char*)data, size);
00384         if(f->eof()) throw eof();
00385     } else {
00386         if(offset + size > buffersize) throw eof();
00387         memcpy(data, buffer + offset, size);
00388         offset += size;
00389     }
00390 }
00391 
00392 void COD::read(char* data, unsigned int size)
00393 {
00394     if(f) {
00395         f->read(data, size);
00396         if(f->eof()) throw eof();
00397     } else {
00398         if(offset + size > buffersize) throw eof();
00399         memcpy(data, buffer + offset,  size);
00400         offset += size;
00401     }
00402 }
00403 
00404 void COD::writeCOD(unsigned char** data, unsigned int* size, bool gzip)
00405 {
00406     if(buffer) free(buffer);
00407     *size = buffersize = computeSize() + 1;
00408     *data = buffer = (unsigned char*)malloc(buffersize + 1);
00409     offset = 0;
00410 
00411     write("VOS", 4); // writing a \x0 deliberately
00412     char version[2] = {1, 0}; // major, minor
00413     write(version, 2);
00414 
00415     unsigned char buf[16];
00416     write(buf, pack(buf, sizeof(buf), "l", vobjectorder.size()));
00417 
00418     for(unsigned int i = 0; i < vobjectorder.size(); i++) {
00419         writeObjectDesc(vobjectorder[i]);
00420     }
00421 
00422     unsigned long objsWithChildren = 0;
00423     for(unsigned int i = 0; i < vobjectorder.size(); i++) {
00424         if(vobjectorder[i]->vobject->getChildren().size() > 0 && vobjectorder[i]->savechildren) {
00425             objsWithChildren++;
00426         }
00427     }
00428 
00429     write(buf, pack(buf, sizeof(buf), "l", objsWithChildren));
00430 
00431     for(unsigned int i = 0; i < vobjectorder.size(); i++) {
00432         if(vobjectorder[i]->vobject->getChildren().size() > 0 && vobjectorder[i]->savechildren) {
00433             writeObjectChildren(vobjectorder[i]->vobject);
00434         }
00435     }
00436 
00437     *size = offset;
00438 
00439     if(gzip) {
00440         gzipCompress((unsigned char**)data, size, (const unsigned char*)buffer, offset);
00441     }
00442 }
00443 
00444 void COD::readCOD(unsigned char* readfrom, unsigned int size)
00445 {
00446     buffer = readfrom;
00447     buffersize = size;
00448     offset = 0;
00449     readCOD();
00450     buffer = 0;
00451     buffersize = 0;
00452 }
00453 
00454 bool COD::checkCOD()
00455 {
00456     unsigned char buf[66461];
00457 
00458     read(buf, 4);
00459     if(!(buf[0] == 'V'
00460          && buf[1] == 'O'
00461          && buf[2] == 'S'
00462          && buf[3] == 0))
00463     {
00464         if(buf[0] == 31 && buf[1] == 139) {
00465             if(f) {
00466                 string comp;
00467                 comp.append((const char*)buf, 4);
00468                 while(! f->eof()) {
00469                     f->read((char*)buf, sizeof(buf));
00470                     comp.append((const char*)buf, f->gcount());
00471                 }
00472                 gzipUncompress((unsigned char**)&buffer, &buffersize, (unsigned char*)comp.c_str(), (unsigned int)comp.size());
00473             } else {
00474                 unsigned char* uncompressedbuffer;
00475                 unsigned int uncompressedsize;
00476                 gzipUncompress((unsigned char**)&uncompressedbuffer, &uncompressedsize, buffer, buffersize);
00477                 buffer = uncompressedbuffer;
00478                 buffersize = uncompressedsize;
00479             }
00480             iostream* oldf = f;
00481             f = 0;
00482             readCOD(buffer, buffersize);
00483             f = oldf;
00484             free(buffer);
00485             return false;
00486         } else {
00487             LOG("COD", 1, "This does not appear to be a COD file\n");
00488             return false;
00489         }
00490     }
00491     return true;
00492 }
00493 
00494 void COD::readCOD()
00495 {
00496     if(! checkCOD()) return;
00497 
00498     char version[2] = {0, 0}; // major, minor
00499     read(version, 2);
00500 
00501     //LOG("COD", 3, "File format version << " (int)version[0] << "." << (int)version[1]);
00502 
00503     long numobjs = readLong();
00504 
00505     map<string, string> fileToActual;
00506 
00507     for(int i = 0; i < numobjs; i++) {
00508         deque<string> types;
00509         string name;
00510         vRef<MessageBlock> mb = new MessageBlock();
00511 
00512         long pos;
00513         readObjectDesc(name, pos, types, *mb);
00514 
00515         vRef<MetaObject> newvob = ls.createMetaObject(name.c_str(), types);
00516         fileToActual[name] = newvob->getName();
00517 
00518         addVobject(&newvob, types, &mb, true);
00519 
00520         /* XXX TEMPORARY HACK */
00521         if(LocalProperty* lp = MetaObject::meta_cast<LocalProperty*>(&newvob)) {
00522             lp->initializeSecurity(ls);
00523         }
00524 
00525         for(int n = 0; n < mb->numMessages(); n++) {
00526             vRef<Message> msg = mb->getMessage(n);
00527             msg->setType("message");
00528             msg->setTo(newvob->getURL().getString());
00529             msg->setFrom(ls.getURL().getString());
00530             newvob->sendMessage(&msg);
00531         }
00532     }
00533 
00534     numobjs = readLong();
00535 
00536     for(int i = 0; i < numobjs; i++) {
00537         string parent;
00538         deque<PCR> children;
00539 
00540         readObjectChildren(parent, children);
00541         parent = fileToActual[parent];
00542 
00543         Entry* e = vobjectTable[parent];
00544         if(! e) throw eof();
00545         e->savechildren = true;
00546 
00547         LOG("COD", 4, "Looking for " << parent);
00548         vRef<Vobject::ParentChildRelation> pcr = ls.findChild(parent);
00549         LOG("COD", 4, "found it");
00550         for(unsigned int n = 0; n < children.size(); n++) {
00551             string cl = fileToActual[children[n].child];
00552             LOG("COD", 4, "Looking for " << cl << " (was " << children[n].child << ")");
00553             vRef<Vobject::ParentChildRelation> pcr2 = ls.findChild(cl);
00554             LOG("COD", 4, "found it");
00555             pcr->child->insertChild(-1, children[n].context, pcr2->child);
00556         }
00557     }
00558 }
00559 
00560 
00561 LocalSite& COD::getLocalSite()
00562 {
00563     ls.acquire();
00564     return ls;
00565 }
00566 
00567 RemoteCOD::RemoteCOD(LocalSite& l, RemoteSite& r)
00568     : COD(l), rs(r)
00569 {
00570     rs.acquire(); // released by: destructor
00571 }
00572 
00573 RemoteCOD::RemoteCOD(iostream& io, LocalSite& l, RemoteSite& r)
00574     : COD(io, l), rs(r)
00575 {
00576     rs.acquire(); // released by: destructor
00577 }
00578 
00579 RemoteCOD::~RemoteCOD()
00580 {
00581     rs.release(); // acquired by: constructor
00582 }
00583 
00584 void RemoteCOD::readCOD()
00585 {
00586     LOG("COD", 4, "Starting COD read");
00587 
00588     if(! checkCOD()) return;
00589 
00590     char version[2] = {0, 0}; // major, minor
00591     read(version, 2);
00592 
00593     LOG("COD", 3, "File format version " << (int)version[0] << "." << (int)version[1]);
00594 
00595     long numobjs = readLong();
00596 
00597     LOG("COD", 4, "expecting " << numobjs << " objects");
00598 
00599     double start, end, tot;
00600     start = getRealTime();
00601     for(int i = 0; i < numobjs; i++) {
00602         double start2, end2, tot2;
00603         start2 = getRealTime();
00604 
00605         deque<string> types;
00606         string name;
00607         vRef<MessageBlock> mb = new MessageBlock();
00608 
00609         long pos;
00610         readObjectDesc(name, pos, types, *mb);
00611 
00612         LOG("COD", 4, "read child " << name);
00613 
00614         vRef<Message> msg = new Message();
00615         msg->setType("update");
00616         msg->setMethod("core:set-child-update");
00617         msg->setFrom(rs.getURL().getString());
00618         msg->setSourceSite(&rs);
00619         msg->insertField(-1, "pos", (int)pos);
00620         msg->insertField(-1, "name", name);
00621         string path(rs.getURL().getString());
00622         path += "/";
00623         path += name;
00624         msg->insertField(-1, "path", path);
00625         if(types.size()) {
00626             for(unsigned int n = 0; n < types.size(); n++) {
00627                 msg->insertField(-1, "type", types[n]);
00628             }
00629         } else msg->insertField(-1, "type", "");
00630         rs.sendUpdateMessage(&msg);
00631         vRef<Vobject::ParentChildRelation> newvob = rs.findChild(name);
00632 
00633         addVobject(newvob->child, types, &mb, false);
00634 
00635         for(int n = 0; n < mb->numMessages(); n++) {
00636             msg = mb->getMessage(n);
00637             msg->setType("update");
00638             msg->setFrom(path);
00639             msg->setSourceSite(&rs);
00640             LOG("COD", 4, "update to " << newvob->child->getURL().getString() << " is "
00641                 << msg->getFormattedString());
00642             newvob->child->sendUpdateMessage(&msg);
00643         }
00644         
00645         end2 = getRealTime();
00646         tot2 = end2 - start2;
00647     }
00648     end = getRealTime();
00649     tot = end - start;
00650 
00651     LOG("COD", 4, "starting children read");
00652 
00653     numobjs = readLong();
00654 
00655     start = getRealTime();
00656     for(int i = 0; i < numobjs; i++) {
00657         string parent;
00658         deque<PCR> children;
00659 
00660         readObjectChildren(parent, children);
00661 
00662         vRef<Vobject::ParentChildRelation> newobj = rs.findChild(parent);
00663         vRef<Message> msg = new Message();
00664         msg->setType("update");
00665         msg->setMethod("core:set-child-update");
00666         msg->setFrom(rs.getURL().getString());
00667         msg->setSourceSite(&rs);
00668         for(unsigned int n = 0; n < children.size(); n++) {
00669             msg->insertField(-1, "pos", (int)n);
00670             msg->insertField(-1, "name", children[n].context);
00671             if(children[n].child.substr(0, 6) == "vop://") msg->insertField(-1, "path", children[n].child);
00672             else msg->insertField(-1, "path", rs.getURL().getString() + string("/") + children[n].child);
00673         }
00674         newobj->child->sendUpdateMessage(&msg);
00675     }
00676     end = getRealTime();
00677     tot = end - start;
00678 }
00679 
00680 RemoteSite& RemoteCOD::getRemoteSite()
00681 {
00682     rs.acquire();
00683     return rs;
00684 }
00685 
00686 int COD::pack(uint8_t *buf, int maxsize, char *fmt, ...)
00687 {
00688     va_list args;
00689     char* p;
00690     uint8_t* bp;
00691     uint8_t* st;
00692     uint16_t s, len;
00693     uint32_t l, i;
00694 
00695     bp=buf;
00696     va_start(args, fmt);
00697     for(p=fmt; *p; p++)
00698     {
00699         switch(*p)
00700         {
00701         case 'c':
00702             if((bp - buf + 1) > maxsize) return -1;
00703             ///*bp++ = (ub*bp++ = (uint8_t)va_arg(args, uint8_t); XXX gcc 2.96 complained about using uint8_t in va_arg
00704             *bp++ = (uint8_t)va_arg(args, int);
00705             break;
00706         case 's':
00707             //s = (uint16_t)va_arg(args, uint16_t); XXX gcc 2.96 complained about using uint8_t in va_arg
00708             if((bp - buf + 4) > maxsize) return -1;
00709             s = (uint16_t)va_arg(args, int);
00710             *bp++ = s >> 8;
00711             *bp++ = s;
00712             break;
00713         case 'l':
00714             if((bp - buf + 4) > maxsize) return -1;
00715             l = (uint32_t)va_arg(args, uint32_t);
00716             *bp++ = l >> 24;
00717             *bp++ = l >> 16;
00718             *bp++ = l >> 8;
00719             *bp++ = l;
00720             break;
00721         case 'S':
00722             st = va_arg(args, uint8_t*);
00723             len = va_arg(args, int);
00724             if((bp - buf + 2 + len) > maxsize) return -1;
00725             *bp++ = len >> 8;
00726             *bp++ = len;
00727             for(i = 0; i < len; i++)
00728                 *bp++ = *st++;
00729             break;
00730         case 'f':
00731         {
00732             if((bp - buf + 4) > maxsize) return -1;
00733             float f = (float)va_arg(args, double);
00734             uint32_t zz = *((uint32_t*)&f);
00735             *bp++ = zz >> 24;
00736             *bp++ = zz >> 16;
00737             *bp++ = zz >> 8;
00738             *bp++ = zz;
00739             break;
00740         }
00741         default:
00742             va_end(args);
00743             return -1;
00744         }
00745     }
00746     va_end(args);
00747     return (bp - buf);
00748 }
00749 
00750 int COD::unpack(const uint8_t *buf, int maxsize, char *fmt, ...)
00751 {
00752     va_list args;
00753     char* p;
00754     const uint8_t* bp;
00755     uint8_t* pc;
00756     uint16_t* ps;
00757     uint32_t* pl;
00758     uint8_t** st;
00759     int len, i;
00760 
00761     bp=buf;
00762     va_start(args, fmt);
00763     for(p=fmt; *p; p++)
00764     {
00765         switch(*p)
00766         {
00767         case 'c':
00768             if(bp - buf + 1 > maxsize) return -1;
00769             pc = va_arg(args, uint8_t*);
00770             *pc = *bp++;
00771             break;
00772         case 's':
00773             if(bp - buf + 2 > maxsize) return -1;
00774             ps = va_arg(args, uint16_t*);
00775             *ps = *bp++ << 8;
00776             *ps |= *bp++;
00777             break;
00778         case 'l':
00779             if(bp - buf + 4 > maxsize) return -1;
00780             pl = va_arg(args, uint32_t*);
00781             *pl = *bp++ << 24;
00782             *pl |= *bp++ << 16;
00783             *pl |= *bp++ << 8;
00784             *pl |= *bp++;
00785             break;
00786         case 'S':
00787             st = va_arg(args, uint8_t**);
00788             pl = va_arg(args, uint32_t*);
00789             if(bp - buf + 2 > maxsize) return -1;
00790             len = *bp++ << 8;
00791             len |= *bp++;
00792             if(bp - buf + len > maxsize) return -1;
00793             *pl = len;
00794             *st = (uint8_t*)malloc(len+1);
00795             for(i = 0; i < len; i++)
00796                 (*st)[i] = *bp++;
00797             (*st)[i] = 0;
00798             break;
00799         case 'f':
00800         {
00801             if(bp - buf + 4 > maxsize) return -1;
00802             float* f = va_arg(args, float*);
00803             uint32_t l = *bp++ << 24;
00804             l |= *bp++ << 16;
00805             l |= *bp++ << 8;
00806             l |= *bp++;
00807             *f = *((float*)&l);
00808             break;
00809         }
00810         default:
00811             va_end(args);
00812             return -1;
00813         }
00814     }
00815     va_end(args);
00816     return bp - buf;
00817 }
00818 
00819 void COD::gzipCompress(unsigned char** dest, unsigned int* destlen, const unsigned char* source, unsigned int srclen)
00820 {
00821     *destlen = srclen + (srclen/1000) + 13 + 18;
00822     *dest = (unsigned char*)malloc(*destlen);
00823 
00824     int t = time(0);
00825 
00826     // note: the gzip file format is little-endian, so we can't use
00827     // pack() and unpack() because they encode everything big-endian!
00828 
00829     (*dest)[0] = 31; // magic number
00830     (*dest)[1] = 139;  // magic number
00831     (*dest)[2] = 8;  // using the standard deflate method
00832     (*dest)[3] = 0;  // no other headers
00833     (*dest)[4] = t & 0xFF;  // timestamp
00834     (*dest)[5] = (t >> 8) & 0xFF;
00835     (*dest)[6] = (t >> 16) & 0xFF;
00836     (*dest)[7] = (t >> 24) & 0xFF;
00837     (*dest)[8] = 0; // some other flags
00838     (*dest)[9] = 255; // unknown operating system
00839 
00840     z_stream st;
00841     st.next_in = (Bytef*)source;  /* next input byte */
00842     st.avail_in = srclen;  /* number of bytes available at next_in */
00843     st.total_in = 0;  /* total nb of input bytes read so far */
00844 
00845     st.next_out = (Bytef*)(*dest + 10); /* next output byte should be put there */
00846     st.avail_out = *destlen; /* remaining free space at next_out */
00847     st.total_out = 0; /* total nb of bytes output so far */
00848 
00849     st.zalloc = 0;  /* used to allocate the internal state */
00850     st.zfree = 0;   /* used to free the internal state */
00851 
00852     deflateInit2(&st, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
00853     if(deflate(&st, Z_FINISH) != Z_STREAM_END) {
00854         throw eof();
00855     }
00856     deflateEnd(&st);
00857     *destlen = st.total_out;
00858 
00859     int crc = crc32(0, (const Bytef*)source, srclen);
00860     (*dest)[10 + *destlen + 0] = crc & 0xFF;
00861     (*dest)[10 + *destlen + 1] = (crc >> 8) & 0xFF;
00862     (*dest)[10 + *destlen + 2] = (crc >> 16) & 0xFF;
00863     (*dest)[10 + *destlen + 3] = (crc >> 24) & 0xFF;
00864     (*dest)[10 + *destlen + 4] = srclen & 0xFF;
00865     (*dest)[10 + *destlen + 5] = (srclen >> 8) & 0xFF;
00866     (*dest)[10 + *destlen + 6] = (srclen >> 16) & 0xFF;
00867     (*dest)[10 + *destlen + 7] = (srclen >> 24) & 0xFF;
00868 
00869     *destlen += 18;
00870 }
00871 
00872 void COD::gzipUncompress(unsigned char** dest, unsigned int* destlen, const unsigned char* source, unsigned int srclen)
00873 {
00874     unsigned int len = 0;
00875     unsigned int crc = 0;
00876 
00877     len = source[srclen-4]
00878         | (source[srclen-3] << 8)
00879         | (source[srclen-2] << 16)
00880         | (source[srclen-1] << 24);
00881 
00882     crc = source[srclen-8]
00883         | (source[srclen-7] << 8)
00884         | (source[srclen-6] << 16)
00885         | (source[srclen-5] << 24);
00886 
00887     *destlen = len;
00888     *dest = (unsigned char*)malloc(*destlen);
00889 
00890     // note: the gzip file format is little-endian, so we can't use
00891     // pack() and unpack() because they encode everything big-endian!
00892 
00893     if(source[0] != 31 || source[1] != 139 || source[2] != 8) throw eof();
00894 
00895     int offset = 10;
00896 
00897 #define FTEXT       0x01
00898 #define FHCRC       0x02
00899 #define FEXTRA      0x04
00900 #define FNAME       0x08
00901 #define FCOMMENT    0x10
00902 #define FRESERVED   (0x20 | 0x40 | 0x80)
00903 
00904     if(source[3] & FRESERVED) throw eof();
00905 
00906     if(source[3] & FEXTRA) {
00907         int skip = 0;
00908         skip = source[offset] | (source[offset+1] << 8);
00909         offset += 2 + skip;
00910     }
00911 
00912     if(source[3] & FNAME) {
00913         while(source[offset]) offset++;
00914         offset++;
00915     }
00916 
00917     if(source[3] & FCOMMENT) {
00918         while(source[offset]) offset++;
00919         offset++;
00920     }
00921 
00922     if(source[3] & FHCRC) {
00923         offset += 2;
00924     }
00925 
00926     z_stream st;
00927     st.next_in = (Bytef*)source + offset;  /* next input byte */
00928     st.avail_in = srclen;  /* number of bytes available at next_in */
00929     st.total_in = 0;  /* total nb of input bytes read so far */
00930 
00931     st.next_out = (Bytef*)(*dest); /* next output byte should be put there */
00932     st.avail_out = *destlen; /* remaining free space at next_out */
00933     st.total_out = 0; /* total nb of bytes output so far */
00934 
00935     st.zalloc = 0;  /* used to allocate the internal state */
00936     st.zfree = 0;   /* used to free the internal state */
00937 
00938     inflateInit2(&st, -MAX_WBITS);
00939     if(inflate(&st, Z_FINISH) != Z_STREAM_END) {
00940         throw eof();
00941     }
00942     inflateEnd(&st);
00943     *destlen = st.total_out;
00944 
00945     if(crc32(0, (const Bytef*)*dest, *destlen) != crc) {
00946         free(*dest);
00947         throw eof();
00948     }
00949 }

Generated on Tue Aug 12 03:55:44 2003 for Interreality Project - VOS by doxygen 1.3.2