Library::~Library() { // Decrease instance count instance_count--; // If no instances remaining, free resources. if (instance_count == 0) for (auto r : resources) unload_resource(r.second); }
/*! */ uint32_t Library::Unload(const wcl::string& file) { // static std::unordered_map<wcl::string, resource_entry_t> resources; if (resources.count(file) == 0) return WHEEL_UNINITIALISED_RESOURCE; unload_resource(resources[file]); resources.erase(file); return WHEEL_OK; }
FBD_API __bool ICBlk_del_pin(struct blk_pin_t * p) { struct cblk_pin_t *cp; struct cblk_link_t *lk; assert(p->blk->h.magic == CBLK_MAGIC); // remove all connections on this pin lk = ICBlk_first_connection(p); while(lk) { ICBlk_unlink(lk); lk = ICBlk_first_connection(p); } /* propagate this delete operation upwards */ if(p->ulink) { ICBlk_del_pin(p->ulink); /* p->ulink is not accessible here because it's already been freed */ p->ulink = NULL; } /* propagate delete operation downloads */ p->u1.x.id.llink->ulink = 0; p->blk->h.n_pins--; /* i'm dying, mother! */ cp = SAFE_CONTAINING_RECORD(p, struct cblk_pin_t, p); RtkRemoveEntryList(&cp->sibling); #ifdef F8_CONFIGURATOR unload_resource(&cp->uuid); #endif mm_free(g_hBlkHeap, cp); return __true; }
/* remove a connection */ FBD_API __bool ICBlk_unlink(struct cblk_link_t * lk) { IBlk * me; me = parent_blk(lk->t.pin->blk); assert(me->h.magic == CBLK_MAGIC); assert(me == __ucast__(ICBlk, IBlk, lk->blk)); IBlk_disconnect(lk->t.pin); RtkRemoveEntryList(&lk->sibling); me->h.u2.n_links--; // assert(me->h.u2.n_links >= 0); #ifdef F8_CONFIGURATOR unload_resource(&lk->uuid); #endif mm_free(g_hBlkHeap, lk); return __true; }
/* move_resource will decrement usage count of the source resource, note this will not necessary cause the source resource to be deleted, only if its usage count reaches zero. */ F8RES_API int move_resource( const f8_uuid * s, const f8_uuid * t ) { int r; F8_RESOURCE *tr, *sr; if(query_resource(t) >= 0){ return F8_NAME_DUPLICATE; } sr = _get_res(s); if(!sr){ return F8_OBJECT_NOT_FOUND; } if(!create_resource(t)){ return F8_LOW_MEMORY; } if(sr->refcount == 1){ /* a little optimization, if the reference count of source is 1, then no actual copy is made, instead, we move the contents of s to t, and detach s from its contents. */ tr = _get_res(t); delete tr->pItems; tr->pItems = _get_res(s)->pItems; sr->pItems = 0; _free_resource(sr); r = F8_SUCCESS; }else{ r = copy_resource(s, t); } /* this will decrement the reference count, and remove the resource entry if necessary */ unload_resource(s); return r; }
/* import a resource from disk, and if the resource has already been loaded, increment its reference count. 2005/6/24 the load_from_disk branch is obsolete. */ F8RES_API __bool load_resource( const f8_uuid * id ) { RESMAP::iterator it; it = g_Resources.find(*id); if(it != g_Resources.end()){ it->second.refcount++; return __true; } return __false; #if 0 IFileStream *fs; IF8Stream * str; char buf[43]; f8_uuid_to_string(id, buf, sizeof(buf)); strcat(buf, ".res"); fs = IFileStream_from_file(buf, "rb"); if(!fs){ return __false; } str = __ucast__(IFileStream, IF8Stream, fs); h = _load_res_stream(str); if(h){ if(*id != h->id){ /* error in library */ unload_resource(&h->id); h = 0; } } __delete__(fs); return h? __true : __false; #endif }
/* construct a resource object in memory from a stream the stream is composed of: 1) a magic 2) uuid 3) item count 4) array of items NOTE!! 1) On success, the resource item is not reference counted. If the client won't addref on the loaded resource, then the item is exposed to the garbage collector. More exactly, this proc won't addref on the resource when the resource already exists. */ static F8_RESOURCE * _load_res_stream(IF8Stream * str) { __u16 magic; RESMAP::iterator it; __u32 itemcount; c_bstr_t cbstr; f8_uuid id; __int length; void * buffer; F8_RESOURCE * res; __bool ret; // DEBUG_PRINTF(("stream %08x\n", __vcall__(str, tell, (str)))); if(!__vcall__(str, get, (str, &magic, sizeof(magic)))){ return 0; } if(magic != F8_RES_MAGIC && magic != F8_RES_MAGIC_2){ __vcall__(str, seek, (str, -sizeof(magic), SEEK_CUR)); return 0; } if(!__vcall__(str, get, (str, &id, sizeof(id)))){ return 0; } res = create_resource_bibibobo(&id, __false); if(!res){ return 0; } /* the resource has not been loaded yet */ if(!__vcall__(str, get, (str, &itemcount, sizeof(itemcount)))){ return 0; } if(res->refcount){ /* note if the resource is already present we silently eat the stream without modifing the in-memory version */ for(; itemcount; itemcount--){ if(!__vcall__(str, get, (str, &cbstr.count, sizeof(cbstr.count)))){ goto __failed; } __vcall__(str, seek, (str, cbstr.count, SEEK_CUR)); if(!__vcall__(str, get, (str, &length, sizeof(length)))){ goto __failed; } __vcall__(str, seek, (str, length, SEEK_CUR)); } }else{ for(; itemcount; itemcount--){ if(!bstr_from_stream(&cbstr, str)){ goto __failed; } if(!__vcall__(str, get, (str, &length, sizeof(length)))){ goto __failed; } if(length){ buffer = __malloc__(length); if(!buffer){ goto __failed; } if(!__vcall__(str, get, (str, buffer, length))){ goto __failed; } }else{ buffer = 0; } ret = set_res_buf(&id, buffer, length, cbstr.buffer); __free__(buffer); c_free_bstr(&cbstr); if(!ret){ goto __failed; } } } return res; __failed: /* the unload_resource will decrease the refcount */ res->refcount++; unload_resource(&id); return 0; }