void COutputStreamSerializer::SavePackage (std::ostream *s, void *rootObj, Class *rootObjClass) { PackageHeader ph; stream = s; unsigned startOffset = stream->tellp(); stream->seekp (startOffset + sizeof (PackageHeader)); ph.objDataOffset = (int)stream->tellp(); // Insert the first object that will provide references to everything ObjectID obj; obj.class_ = rootObjClass; obj.isEmbedded = false; obj.id = 0; ptrToID[rootObj] = obj; pendingObjects.push_back (ptrToID.find(rootObj)); objects.push_back (&ptrToID[rootObj]); // Save until all the referenced objects have been stored while (!pendingObjects.empty ()) { vector <ObjIDmap::iterator> po = pendingObjects; pendingObjects.clear (); for (vector<ObjIDmap::iterator>::iterator i=po.begin();i!=po.end();++i) { ObjectID& obj = (*i)->second; obj.class_->SerializeInstance (this, (*i)->first); } } // Collect a set of all used classes map<creg::Class *,ClassRef> classMap; vector <ClassRef*> classRefs; for (ObjIDmap::iterator oi = ptrToID.begin(); oi != ptrToID.end(); ++oi) { //printf ("Obj: %s\n", oi->second.class_->name.c_str()); map<creg::Class*,ClassRef>::iterator cr = classMap.find (oi->second.class_); if (cr == classMap.end()) { ClassRef *pRef = &classMap[oi->second.class_]; pRef->index = classRefs.size(); pRef->class_ = oi->second.class_; classRefs.push_back (pRef); oi->second.classIndex = pRef->index; } else oi->second.classIndex = cr->second.index; } // Write the class references ph.numObjClassRefs = classRefs.size(); ph.objClassRefOffset = (int)stream->tellp(); for (uint a=0;a<classRefs.size();a++) { WriteZStr (*stream, classRefs[a]->class_->name); // write a checksum (unused atm) int checksum = swabdword(0); stream->write ((char*)&checksum, sizeof(int)); } // Write object info ph.objTableOffset = (int)stream->tellp(); ph.numObjects = objects.size(); for (uint a=0;a<objects.size();a++) { ObjectID *o = objects[a]; PackageObject d; d.classRefIndex = o->classIndex; d.isEmbedded = o->isEmbedded ? 1 : 0; d.SwapBytes (); stream->write ((char*)&d, sizeof(PackageObject)); } // Calculate a checksum for metadata verification ph.metadataChecksum = 0; for (uint a=0;a<classRefs.size();a++) { Class *c = classRefs[a]->class_; c->CalculateChecksum (ph.metadataChecksum); } printf("Checksum: %d\n", ph.metadataChecksum); stream->seekp (startOffset); memcpy(ph.magic, CREG_PACKAGE_FILE_ID, 4); ph.SwapBytes (); stream->write ((const char *)&ph, sizeof(PackageHeader)); objects.clear(); ptrToID.clear(); }
void COutputStreamSerializer::SavePackage(std::ostream* s, void* rootObj, Class* rootObjClass) { PackageHeader ph; stream = s; unsigned startOffset = stream->tellp(); stream->write((char*)&ph, sizeof(PackageHeader)); stream->seekp(startOffset + sizeof(PackageHeader)); ph.objDataOffset = (int)stream->tellp(); // Insert dummy object with id 0 objects.push_back(ObjectRef(0, 0, true, 0)); ObjectRef* obj = &objects.back(); obj->classIndex = 0; // Insert the first object that will provide references to everything objects.push_back(ObjectRef(rootObj, objects.size(), false, rootObjClass)); obj = &objects.back(); ptrToId[rootObj].push_back(obj); pendingObjects.push_back(obj); // Save until all the referenced objects have been stored while (!pendingObjects.empty()) { const std::vector<ObjectRef*> po = pendingObjects; pendingObjects.clear(); for (std::vector<ObjectRef*>::const_iterator i = po.begin(); i != po.end(); ++i) { ObjectRef* obj = *i; SerializeObject(obj->class_, obj->ptr, obj); //LOG_SL(LOG_SECTION_CREG_SERIALIZER, L_DEBUG, "Serialized %s size:%i", obj->class_->name.c_str(), sz); } } // Collect a set of all used classes std::map<creg::Class*, ClassRef> classMap; std::vector<ClassRef*> classRefs; for (ObjectRef& oRef: objects) { if (oRef.ptr == nullptr) continue; creg::Class* c = oRef.class_; while (c) { std::map<creg::Class*, ClassRef>::iterator cr = classMap.find(c); if (cr == classMap.end()) { ClassRef* pRef = &classMap[c]; pRef->index = classRefs.size(); pRef->class_ = c; classRefs.push_back(pRef); } c = c->base(); } std::map<creg::Class*, ClassRef>::iterator cr = classMap.find(oRef.class_); oRef.classIndex = cr->second.index; } if (LOG_IS_ENABLED(L_DEBUG)) { for (auto &it: classSizes) { LOG_L(L_DEBUG, "%30s %10u %10u", it.first->name.c_str(), classCounts[it.first], it.second); } } // Write the class references & calc their checksum ph.numObjClassRefs = classRefs.size(); ph.objClassRefOffset = (int)stream->tellp(); for (uint a = 0; a < classRefs.size(); a++) { creg::Class* c = classRefs[a]->class_; WriteZStr(*stream, c->name); }; // Write object info ph.objTableOffset = (int)stream->tellp(); ph.numObjects = objects.size(); for (ObjectRef& oRef: objects) { int classRefIndex = oRef.classIndex; char isEmbedded = oRef.isEmbedded ? 1 : 0; WriteVarSizeUInt(stream, classRefIndex); stream->write((char*)&isEmbedded, sizeof(char)); char mgcnt = oRef.memberGroups.size(); WriteVarSizeUInt(stream, mgcnt); std::vector<COutputStreamSerializer::ObjectMemberGroup>::iterator j; for (j = oRef.memberGroups.begin(); j != oRef.memberGroups.end(); ++j) { std::map<creg::Class*, ClassRef>::iterator cr = classMap.find(j->membersClass); if (cr == classMap.end()) throw "Cannot find member class ref"; int cid = cr->second.index; WriteVarSizeUInt(stream, cid); unsigned int mcnt = j->members.size(); WriteVarSizeUInt(stream, mcnt); bool hasSerializerMember = false; char groupFlags = 0; if (!j->members.empty() && (j->members.back().memberId == -1)) { groupFlags |= 0x01; hasSerializerMember = true; } stream->write((char*)&groupFlags, sizeof(char)); int midx = 0; std::vector<COutputStreamSerializer::ObjectMember>::iterator k; for (k = j->members.begin(); k != j->members.end(); ++k, ++midx) { if ((k->memberId != midx) && (!hasSerializerMember || k != (j->members.end() - 1))) { throw "Invalid member id"; } WriteVarSizeUInt(stream, k->size); } } } // Calculate a checksum for metadata verification ph.metadataChecksum = 0; for (uint a = 0; a < classRefs.size(); a++) { Class* c = classRefs[a]->class_; c->CalculateChecksum(ph.metadataChecksum); } int endOffset = stream->tellp(); stream->seekp(startOffset); memcpy(ph.magic, CREG_PACKAGE_FILE_ID, 4); ph.SwapBytes(); stream->write((const char*)&ph, sizeof(PackageHeader)); LOG_SL(LOG_SECTION_CREG_SERIALIZER, L_DEBUG, "Checksum: %X\nNumber of objects saved: %i\nNumber of classes involved: %i", ph.metadataChecksum, int(objects.size()), int(classRefs.size())); stream->seekp(endOffset); ptrToId.clear(); pendingObjects.clear(); objects.clear(); }