예제 #1
0
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();
}
예제 #2
0
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();
}