TemplateInfo *BinReader::readTemplateTypes() { if (!bytes->readBoolean()) { return NULL; } TemplateInfo *templateInfo = lmNew(NULL) TemplateInfo; templateInfo->fullTypeName = readPoolString(); templateInfo->type = getType(templateInfo->fullTypeName.c_str()); int numTypes = bytes->readInt(); for (int i = 0; i < numTypes; i++) { if (!bytes->readBoolean()) { TemplateInfo *t = lmNew(NULL) TemplateInfo; t->fullTypeName = readPoolString(); t->type = getType(t->fullTypeName.c_str()); templateInfo->types.push_back(t); } else { templateInfo->types.push_back(readTemplateTypes()); } } return templateInfo; }
NativeDelegateCallNote *NativeDelegate::prepCallbackNote() const { lmLogDebug(gNativeDelegateGroup, "Considering async callback %x", this); // Are noting currently? Just work with that. if(_activeNote) { lmLogDebug(gNativeDelegateGroup, " OUT due to activeNote already present"); return _activeNote; } // See if we should try to go async. if(_allowAsync == false) { lmLogDebug(gNativeDelegateGroup, " OUT due to async being disallowed"); return NULL; } if(smMainThreadID == platform_getCurrentThreadId()) return NULL; // Only do this for async delegates off main thread. lmLogDebug(gNativeDelegateGroup, "Prepping async callback!"); _activeNote = lmNew(NULL) NativeDelegateCallNote(this); return _activeNote; }
BitmapData* BitmapData::diff(const BitmapData* a, const BitmapData* b) { if (a->w != b->w || a->h != b->h) return NULL; BitmapData* result = lmNew(NULL) BitmapData( (size_t)a->w, (size_t)a->h ); if (result == NULL) { lmLogError(gGFXLogGroup, "Unable to allocate memory for BitmapData diff result"); return NULL; } rgba_t* pixelptr_a = reinterpret_cast<rgba_t*>(a->data); rgba_t* pixelptr_b = reinterpret_cast<rgba_t*>(b->data); rgba_t* resultptr = reinterpret_cast<rgba_t*>(result->data); for (size_t i = 0; i < a->w * a->h; i++) { Color ap(convertHostToBEndian(pixelptr_a[i])); Color bp(convertHostToBEndian(pixelptr_b[i])); Color rp(fabsf(ap.r - bp.r), fabsf(ap.g - bp.g), fabsf(ap.b - bp.b), 1.0f); rgba_t a = rp.getHex(); resultptr[i] = convertBEndianToHost(a); } return result; }
Type *TypeReader::declareType(Module *module, json_t *json) { Type *type = lmNew(NULL) Type; const char *stype = json_string_value(json_object_get(json, "type")); if (!strcmp(stype, "CLASS")) { type->attr.isClass = true; } else if (!strcmp(stype, "INTERFACE")) { type->attr.isInterface = true; } else if (!strcmp(stype, "STRUCT")) { type->attr.isStruct = true; } else if (!strcmp(stype, "DELEGATE")) { type->attr.isDelegate = true; } else if (!strcmp(stype, "ENUM")) { type->attr.isEnum = true; } else { assert(0); //, "Unknown type: %s", stype); } declareClass(type, json); return type; }
const BitmapData* BitmapData::fromFramebuffer() { int w = GFX::Graphics::getWidth(); int h = GFX::Graphics::getHeight(); // Sanity check if (w == 0 || h == 0) { lmLogError(gGFXLogGroup, "Graphics dimensions invalid %d x %d: %s", w, h, SDL_GetError()); return NULL; } BitmapData* result = lmNew(NULL) BitmapData(w, h); if (result == NULL) { lmLogError(gGFXLogGroup, "Unable to allocate memory for screenshot pixel data buffer"); return NULL; } GFX::GL_Context* ctx = GFX::Graphics::context(); utByteArray tmp; tmp.resize(result->w * result->h * DATA_BPP); ctx->glPixelStorei(GL_PACK_ALIGNMENT, 1); ctx->glReadPixels(0, 0, result->w, result->h, GL_RGBA, GL_UNSIGNED_BYTE, tmp.getDataPtr()); for (int i = result->h - 1; i >= 0; i--) { memcpy(result->data + (result->h - 1 - i) * result->w * DATA_BPP, (channel_t*)tmp.getDataPtr() + i * result->w * DATA_BPP, result->w * DATA_BPP); } return result; }
static void *loom_asset_binaryDeserializer(void *ptr, size_t size, LoomAssetCleanupCallback *dtor) { utByteArray *bytes = lmNew(NULL) utByteArray(); bytes->allocateAndCopy(ptr, (int)size); *dtor = loom_asset_binaryDtor; return bytes; }
FieldInfo *BinReader::readField(Type *type) { FieldInfo *field = lmNew(NULL) FieldInfo(); readMemberInfo(field); field->memberType.field = true; field->declaringType = type; // handle attr int numAttr = bytes->readInt(); for (int i = 0; i < numAttr; i++) { const char *attr = readPoolString(); if (!strcmp(attr, "static")) { field->attr.isStatic = true; } else if (!strcmp(attr, "public")) { field->attr.isPublic = true; } else if (!strcmp(attr, "private")) { field->attr.isPrivate = true; } else if (!strcmp(attr, "protected")) { field->attr.isProtected = true; } else if (!strcmp(attr, "native")) { field->attr.isNative = true; } else if (!strcmp(attr, "const")) { field->attr.isConst = true; } } Type *fieldType = NULL; if (bytes->readBoolean()) { fieldType = getType(readPoolString()); } field->type = fieldType; if (bytes->readBoolean()) { field->setTemplateInfo(readTemplateTypes()); } return field; }
static void enqueueLogCallback(const char *msg) { CallbackQueueNote *cqn = lmNew(NULL) CallbackQueueNote(); cqn->type = QNT_Log; cqn->text = utString(msg); loom_mutex_lock(gCallbackLock); gCallbackQueue.push_back(cqn); loom_mutex_unlock(gCallbackLock); }
static void enqueueFileChangeCallback(const char *path) { CallbackQueueNote *cqn = lmNew(NULL) CallbackQueueNote(); cqn->type = QNT_Change; cqn->text = utString(path); loom_mutex_lock(gCallbackLock); gCallbackQueue.push_back(cqn); loom_mutex_unlock(gCallbackLock); }
ConstructorInfo *BinReader::readConstructor(Type *type) { ConstructorInfo *cinfo = lmNew(NULL) ConstructorInfo(); cinfo->declaringType = type; readMethodBase(cinfo); cinfo->memberType.constructor = true; cinfo->type = getType("system.Function"); cinfo->defaultConstructor = bytes->readBoolean(); return cinfo; }
void BinWriter::writeType(json_t *jtype) { TypeIndex *tindex = lmNew(NULL) TypeIndex; typeIndexes.push_back(tindex); tindex->position = bytes.getPosition(); utString package = json_string_value(json_object_get(jtype, "package")); utString name = json_string_value(json_object_get(jtype, "name")); utString fullname = package; fullname += "."; fullname += name; tindex->iFullName = poolString(fullname.c_str()); int itype = poolJString(json_object_get(jtype, "type")); int ipackagename = poolString(package.c_str()); int iname = poolString(name.c_str()); json_t *jtypeid = json_object_get(jtype, "typeid"); assert(jtypeid && json_is_number(jtypeid)); int itypeid = (int)json_number_value(jtypeid); int isource = -1; int ilinenumber = -1; json_t *jsource = json_object_get(jtype, "source"); if (jsource && json_is_string(jsource)) { isource = poolString(json_string_value(jsource)); ilinenumber = (int)json_integer_value(json_object_get(jtype, "line")); } bytes.writeInt(itype); bytes.writeInt(ipackagename); bytes.writeInt(iname); bytes.writeInt(itypeid); bytes.writeInt(isource); bytes.writeInt(ilinenumber); writeClass(jtype); tindex->length = bytes.getPosition() - tindex->position; }
static loom_asset_t *loom_asset_getAssetByName(const char *name, int create) { utHashedString key = platform_normalizePath(name); loom_asset_t **assetPtr = gAssetHash.get(key); loom_asset_t *asset = assetPtr ? *assetPtr : NULL; if ((asset == NULL) && create) { // Create one. asset = lmNew(gAssetAllocator) loom_asset_t; asset->name = strdup(name); gAssetHash.insert(key, asset); } return asset; }
JSON* JSON::getObjectNew(const char *key) { if (!_json) { return NULL; } json_t *jobject = json_object_get(_json, key); if (!jobject || !json_is_object(jobject)) { return NULL; } return lmNew(NULL) JSON(jobject); }
JSON* JSON::getArrayArrayNew(int index) { if (!isArray()) { return NULL; } json_t *object = json_array_get(_json, index); if (!object || !json_is_array(object)) { return NULL; } return lmNew(NULL) JSON(object); }
JSON* JSON::getArrayNew(const char *key) { if (!_json) { return NULL; } json_t *jarray = json_object_get(_json, key); if (!jarray || !json_is_array(jarray)) { return NULL; } return lmNew(NULL) JSON(jarray); }
// Instate new bits/type to the asset. void instate(int _type, void *bits, LoomAssetCleanupCallback dtor) { // Swap in a new blob. if(blob) blob->decRef(); blob = lmNew(gAssetAllocator) loom_assetBlob_t(); blob->incRef(); blob->bits = bits; blob->dtor = dtor; // Update the type. type = _type; // We're by definition loaded at this point. state = loom_asset_t::Loaded; // Fire subscribers. loom_asset_notifySubscribers(name.c_str()); }
static loom_asset_t *loom_asset_getAssetByName(const char *name, int create) { loom_mutex_lock(gAssetLock); static char normalized[4096]; strncpy(normalized, name, sizeof(normalized)); platform_normalizePath(normalized); utHashedString key = normalized; loom_mutex_unlock(gAssetLock); loom_asset_t **assetPtr = gAssetHash.get(key); loom_asset_t *asset = assetPtr ? *assetPtr : NULL; if ((asset == NULL) && create) { // Create one. asset = lmNew(gAssetAllocator) loom_asset_t; asset->name = name; gAssetHash.insert(key, asset); } return asset; }
/** * Post all known files to all clients, or if specified, a single client. * * Useful for fully synching client with the current asset state. * * TODO: Optimize to use hashes to only transmit modified data, based on * client's starting assets. */ static void postAllFiles(int clientId = -1) { lmLog(gAssetAgentLogGroup, "Queueing all files for client %d.", clientId); loom_mutex_lock(gFileScannerLock); // Walk all the files. utArray<FileEntry> *list = lmNew(NULL) utArray<FileEntry>(); platform_walkFiles(".", handleFileStateWalkCallback, list); // Queue them all to be sent. for (UTsize i = 0; i < list->size(); i++) { FileModificationNote note; note.path = stringtable_insert((*list)[i].path.c_str()); note.lastSeenTime = 0; note.onlyForClient = clientId; gPendingModifications.push_back(note); } loom_mutex_unlock(gFileScannerLock); }
// Take a snapshot of the state of all our tracked files. This snapshot can // then be compared to identify changes. static utArray<FileEntry> *generateFileState(const char *root) { utArray<FileEntry> *list = lmNew(NULL) utArray<FileEntry>(); // Walk files in assets and src. char buffer[2048]; sprintf(buffer, "%s%s%s", root, platform_getFolderDelimiter(), "assets"); platform_walkFiles(buffer, handleFileStateWalkCallback, list); sprintf(buffer, "%s%s%s", root, platform_getFolderDelimiter(), "src"); platform_walkFiles(buffer, handleFileStateWalkCallback, list); sprintf(buffer, "%s%s%s", root, platform_getFolderDelimiter(), "bin"); platform_walkFiles(buffer, handleFileStateWalkCallback, list); // Sort the list into canonical order. list->sort(compareFileEntryBool); // Return the list. return list; }
const BitmapData* BitmapData::fromAsset(const char* name) { loom_asset_image_t* img = static_cast<loom_asset_image_t*>(loom_asset_lock(name, LATImage, 1)); loom_asset_unlock(name); if (img == NULL) return NULL; BitmapData* result = lmNew(NULL) BitmapData( (size_t)img->width, (size_t)img->height ); if (result == NULL) { lmLogError(gGFXLogGroup, "Unable to allocate memory for BitmapData asset data"); return NULL; } memcpy(result->data, img->bits, img->width * img->height * DATA_BPP); return result; }
MethodInfo *BinReader::readMethodInfo(Type *type) { MethodInfo *methodInfo = lmNew(NULL) MethodInfo(); methodInfo->declaringType = type; readMethodBase(methodInfo); Type *retType = NULL; if (bytes->readBoolean()) { retType = getType(readPoolString()); } methodInfo->memberType.method = true; methodInfo->type = getType("system.Function"); if (retType) { methodInfo->setReturnType(retType); } return methodInfo; }
Assembly *BinReader::loadExecutable(LSLuaState *_vm, utByteArray *byteArray) { sBytes = byteArray; vm = _vm; // load up the string pool readStringPool(); // read the type table int numTypes = sBytes->readInt(); for (UTsize i = 0; i < (UTsize)numTypes; i++) { TypeIndex *tindex = lmNew(NULL) TypeIndex; tindex->type = NULL; tindex->refIdx = sBytes->readInt(); tindex->fullName = readPoolString(); // within the ref tindex->position = sBytes->readInt(); tindex->length = sBytes->readInt(); types.insert(utHashedString(tindex->fullName), tindex); } // load up reference assemblies // write out the number of references int numRefs = sBytes->readInt(); for (int i = 0; i < numRefs; i++) { Reference *ref = lmNew(NULL) Reference; ref->name = readPoolString(); lmAssert(ref->name[0] != 0, "Assembly reference name is empty, try recompiling the .loom executable"); ref->length = sBytes->readInt(); ref->position = sBytes->readInt(); ref->loaded = false; ref->assembly = NULL; references.insert(utHashedString(ref->name), ref); // offset the types to global position for (UTsize j = 0; j < types.size(); j++) { TypeIndex *tindex = types.at(j); if (tindex->refIdx == (int)i) { tindex->position += ref->position; } } } Assembly *assembly = NULL; // declare types for (UTsize i = 0; i < types.size(); i++) { TypeIndex *tindex = types.at(i); tindex->type = lmNew(NULL) Type(); } for (UTsize i = 0; i < references.size(); i++) { Reference *ref = references.at(i); if (ref->loaded) { continue; } sBytes->setPosition(ref->position); BinReader reader; Assembly *rassembly = reader.readAssembly(vm, sBytes); ref->assembly = rassembly; if (!assembly) { assembly = rassembly; } } // cleanup for (UTsize i = 0; i < references.size(); i++) { Reference *ref = references.at(i); if (!ref->assembly) continue; ref->assembly->freeByteCode(); } sBytes = NULL; if (stringBuffer) { lmFree(NULL, (void*)stringBuffer); stringBuffer = NULL; } stringPool.clear(); references.clear(); types.clear(); vm = NULL; return assembly; }
PropertyInfo *PropertyInfoReader::deserializePropertyInfo(Type *declaringType, json_t *json) { PropertyInfo *pi = lmNew(NULL) PropertyInfo(); MemberInfoReader::deserialize(pi, json); // handle attr json_t *marray = json_object_get(json, "propertyattributes"); for (size_t i = 0; i < json_array_size(marray); i++) { utString modifier = json_string_value(json_array_get(marray, i)); if (modifier == "static") { pi->attr.isStatic = true; } else if (modifier == "public") { pi->attr.isPublic = true; } else if (modifier == "private") { pi->attr.isPrivate = true; } else if (modifier == "protected") { pi->attr.isProtected = true; } else if (modifier == "native") { pi->attr.isNative = true; } } utString stype = json_string_value(json_object_get(json, "type")); if (stype.size() > 0) { // a shortcut? pi->type = declaringType->getModule()->getAssembly()->getLuaState()->getType( stype.c_str()); assert(pi->type); } json_t *getter = json_object_get(json, "getter"); json_t *setter = json_object_get(json, "setter"); if (getter) { MethodBase *m = NULL; m = MethodReader::deserializeMethodInfo(declaringType, getter); assert(m->isMethod()); pi->getter = (MethodInfo *)m; m->setPropertyInfo(pi); } if (setter) { MethodBase *m = NULL; m = MethodReader::deserializeMethodInfo(declaringType, setter); assert(m->isMethod()); pi->setter = (MethodInfo *)m; m->setPropertyInfo(pi); } json_t *ttypes = json_object_get(json, "templatetypes"); if (ttypes && json_is_object(ttypes)) { TemplateInfo *info = MemberInfoReader::readTemplateTypeInfo(ttypes); assert(info); info->resolveTypes(Assembly::getAssembly(declaringType)->getLuaState()); pi->setTemplateInfo(info); } return pi; }
// Entry point for the socket thread. Listen for connections and incoming data, // and route it to the protocol handlers. static int socketListeningThread(void *payload) { // Listen for incoming connections. int listenPort = 12340; gListenSocket = (loom_socketId_t)-1; for ( ; ; ) { gListenSocket = loom_net_listenTCPSocket(listenPort); if (gListenSocket != (loom_socketId_t)-1) { break; } lmLogWarn(gAssetAgentLogGroup, " - Failed to acquire port %d, trying port %d", listenPort, listenPort + 1); listenPort++; } lmLog(gAssetAgentLogGroup, "Listening on port %d", listenPort); while (loom_socketId_t acceptedSocket = loom_net_acceptTCPSocket(gListenSocket)) { // Check to see if we got anybody... if (!acceptedSocket || ((int)(long)acceptedSocket == -1)) { // Process the connections. loom_mutex_lock(gActiveSocketsMutex); for (UTsize i = 0; i < gActiveHandlers.size(); i++) { AssetProtocolHandler* aph = gActiveHandlers[i]; aph->process(); // Check for ping timeout int msSincePing = loom_readTimer(aph->lastActiveTime); if (msSincePing > socketPingTimeoutMs) { gActiveHandlers.erase(i); i--; lmLog(gAssetAgentLogGroup, "Client timed out (%x)", aph->socket); loom_net_closeTCPSocket(aph->socket); lmDelete(NULL, aph); } } loom_mutex_unlock(gActiveSocketsMutex); loom_thread_sleep(10); continue; } lmLog(gAssetAgentLogGroup, "Client connected (%x)", acceptedSocket); loom_mutex_lock(gActiveSocketsMutex); gActiveHandlers.push_back(lmNew(NULL) AssetProtocolHandler(acceptedSocket)); AssetProtocolHandler *handler = gActiveHandlers.back(); handler->registerListener(lmNew(NULL) TelemetryListener()); if (TelemetryServer::isRunning()) handler->sendCommand("telemetryEnable"); // Send it all of our files. // postAllFiles(gActiveHandlers[gActiveHandlers.size()-1]->getId()); loom_mutex_unlock(gActiveSocketsMutex); } return 0; }
void DisplayObject::render(lua_State *L) { // Disable reentrancy for this function (read: don't cache to texture while caching to a texture) if (cacheAsBitmapInProgress) return; // Clear and free the cached image if the conditions apply if ((!cacheAsBitmap || !cacheAsBitmapValid) && cachedImage != NULL) { Quad* quad = static_cast<Quad*>(cachedImage); lmAssert(quad != NULL, "Cached image is invalid"); GFX::Texture::dispose(quad->getNativeTextureID()); quad->setNativeTextureID(-1); lmDelete(NULL, quad); cachedImage = NULL; cacheAsBitmapValid = false; } // Cache the contents into an image if the conditions apply if (cacheAsBitmap && !cacheAsBitmapValid && cachedImage == NULL) { cacheAsBitmapInProgress = true; // Used for displaying the texture Quad* quad = lmNew(NULL) Quad(); // Setup for getmember lualoom_pushnative<DisplayObject>(L, this); // Push function and arguments lualoom_getmember(L, -1, "getBounds"); lualoom_pushnative<DisplayObject>(L, this); lua_pushnil(L); // Call getBounds lua_call(L, 2, 1); // Returned result Loom2D::Rectangle *bounds = (Loom2D::Rectangle*) lualoom_getnativepointer(L, -1); cacheAsBitmapOffsetX = bounds->x; cacheAsBitmapOffsetY = bounds->y; lmscalar fracWidth = bounds->width; lmscalar fracHeight = bounds->height; // pop bounds Rectangle and the DisplayObject at the top lua_pop(L, 1+1); if (cacheApplyScale) { fracWidth *= scaleX; fracHeight *= scaleY; } // Convert to integers for the following math int texWidthI = static_cast<int>(ceil(fracWidth)); int texHeightI = static_cast<int>(ceil(fracHeight)); // Calculate power of 2 sizes if (cacheUseTexturesPot) { _UT_UTHASHTABLE_POW2(texWidthI); _UT_UTHASHTABLE_POW2(texHeightI); } // Calculate the resulting scale (as a consequence of pow2 sizes) // Used for 'trans' matrix lmscalar calcScaleX = texWidthI / bounds->width; lmscalar calcScaleY = texHeightI / bounds->height; // Setup texture TextureInfo *tinfo = Texture::initEmptyTexture(texWidthI, texHeightI); Texture::clear(tinfo->id, 0x000000, 0); tinfo->smoothing = TEXTUREINFO_SMOOTHING_BILINEAR; tinfo->wrapU = TEXTUREINFO_WRAP_CLAMP; tinfo->wrapV = TEXTUREINFO_WRAP_CLAMP; TextureID id = tinfo->id; // Setup quad for rendering the texture quad->setNativeTextureID(id); VertexPosColorTex* qv; qv = &quad->quadVertices[0]; qv->x = 0; qv->y = 0; qv->z = 0; qv->abgr = 0xFFFFFFFF; qv->u = 0; qv->v = 0; qv = &quad->quadVertices[1]; qv->x = (float)bounds->width; qv->y = 0; qv->z = 0; qv->abgr = 0xFFFFFFFF; qv->u = 1; qv->v = 0; qv = &quad->quadVertices[2]; qv->x = 0; qv->y = (float)bounds->height; qv->z = 0; qv->abgr = 0xFFFFFFFF; qv->u = 0; qv->v = 1; qv = &quad->quadVertices[3]; qv->x = (float)bounds->width; qv->y = (float)bounds->height; qv->z = 0; qv->abgr = 0xFFFFFFFF; qv->u = 1; qv->v = 1; quad->setNativeVertexDataInvalid(false); lmAssert(Texture::getRenderTarget() == -1, "Unsupported render target state: %d", Texture::getRenderTarget()); // Set render target to texture Texture::setRenderTarget(id); // Shift the contents down and to the right so that the elements extending // past the left and top edges don't get cut off, ignore other existing transforms Matrix trans; trans.translate(-cacheAsBitmapOffsetX, -cacheAsBitmapOffsetY); trans.scale(calcScaleX, calcScaleY); // Setup for Graphics::render lualoom_pushnative<DisplayObject>(L, this); lualoom_pushnative<Matrix>(L, &trans); lua_pushnumber(L, 1); // Render the contents into the texture Graphics::render(L); // Pop previous arguments lua_pop(L, 3); // Restore render target Texture::setRenderTarget(-1); // Set valid cached state cachedImage = quad; cacheAsBitmapValid = true; cacheAsBitmapInProgress = false; } }
void TypeReader::deserializeClass(Type *type, json_t *classJSON) { utString sbaseType = json_string_value( json_object_get(classJSON, "baseType")); if (sbaseType.size() > 0) { Type *baseType = type->getModule()->getAssembly()->getLuaState()->getType( sbaseType.c_str()); lmAssert(baseType != NULL, "Unable to resolve type '%s' referenced as base of type '%s'", sbaseType.c_str(), type->getFullName().c_str()); type->setBaseType(baseType); } json_t *jinterfaces = json_object_get(classJSON, "interfaces"); for (size_t i = 0; i < json_array_size(jinterfaces); i++) { json_t *o = json_array_get(jinterfaces, i); utString sface = json_string_value(o); Type *itype = type->getModule()->getAssembly()->getLuaState()->getType( sface.c_str()); assert(itype); type->addInterface(itype); } json_t *jdelegateTypes = json_object_get(classJSON, "delegateTypes"); for (size_t i = 0; i < json_array_size(jdelegateTypes); i++) { json_t *o = json_array_get(jdelegateTypes, i); utString stype = json_string_value(o); Type *itype = type->getModule()->getAssembly()->getLuaState()->getType( stype.c_str()); assert(itype); type->addDelegateType(itype); } utString sdelegateReturnType = json_string_value( json_object_get(classJSON, "delegateReturnType")); if (sdelegateReturnType.size() > 0) { Type *delegateReturnType = type->getModule()->getAssembly()->getLuaState()->getType( sdelegateReturnType.c_str()); assert(delegateReturnType); type->setDelegateReturnType(delegateReturnType); } // meta data MemberInfoReader::deserializeMetaInfo(type, json_object_get(classJSON, "metainfo")); // handle imports json_t *iarray = json_object_get(classJSON, "imports"); for (size_t i = 0; i < json_array_size(iarray); i++) { json_t *jimport = json_array_get(iarray, i); utString import = json_string_value(jimport); Type *timport = type->getModule()->getAssembly()->getLuaState()->getType( import.c_str()); type->addImport(timport); } json_t *jconstructor = json_object_get(classJSON, "constructor"); if (jconstructor) { MethodBase *m = NULL; m = MethodReader::deserializeConstructorInfo(type, jconstructor); type->addMember(m); } // handle fields json_t *farray = json_object_get(classJSON, "fields"); for (size_t i = 0; i < json_array_size(farray); i++) { json_t *fo = json_array_get(farray, i); FieldInfo *f = FieldInfoReader::deserializeFieldInfo(type, fo); type->addMember(f); } // handle properties json_t *parray = json_object_get(classJSON, "properties"); for (size_t i = 0; i < json_array_size(parray); i++) { json_t *po = json_array_get(parray, i); PropertyInfo *p = PropertyInfoReader::deserializePropertyInfo(type, po); type->addMember(p); } // handle methods farray = json_object_get(classJSON, "methods"); for (size_t i = 0; i < json_array_size(farray); i++) { json_t *fo = json_array_get(farray, i); MethodBase *m = NULL; m = MethodReader::deserializeMethodInfo(type, fo); type->addMember(m); } ByteCode *byteCode; byteCode = lmNew(NULL) ByteCode(); byteCode->setBase64(utString(json_string_value(json_object_get(classJSON, "bytecode_staticinitializer")))); #if LOOM_ENABLE_JIT byteCode->setBase64(utString(json_string_value(json_object_get(classJSON, "bytecode_staticinitializer_fr2")))); #endif type->setBCStaticInitializer(byteCode); byteCode = lmNew(NULL) ByteCode(); byteCode->setBase64(utString(json_string_value(json_object_get(classJSON, "bytecode_instanceinitializer")))); #if LOOM_ENABLE_JIT byteCode->setBase64(utString(json_string_value(json_object_get(classJSON, "bytecode_instanceinitializer_fr2")))); #endif type->setBCInstanceInitializer(byteCode); }
void BinWriter::writeAssembly(json_t *json) { // reserve 32 megs bytes.reserve(1024 * 1024 * 32); int itype = poolJString(json_object_get(json, "type")); const char *uid = json_string_value(json_object_get(json, "uid")); binWriters.insert(utHashedString(uid), this); int iname = poolJString(json_object_get(json, "name")); int iversion = poolJString(json_object_get(json, "version")); int iuid = poolString(uid); int iloomconfig = 0; bool executable = false; if (json_object_get(json, "executable") && json_is_true(json_object_get(json, "executable"))) { executable = true; } iloomconfig = poolJString(json_object_get(json, "loomconfig")); bool jit = false; if (json_object_get(json, "jit") && json_is_true(json_object_get(json, "jit"))) { jit = true; } bool debugbuild = false; if (json_object_get(json, "debugbuild") && json_is_true(json_object_get(json, "debugbuild"))) { debugbuild = true; } // basic info bytes.writeInt(itype); bytes.writeInt(iname); bytes.writeInt(iversion); bytes.writeInt(iuid); bytes.writeInt(iloomconfig); // write out flags bytes.writeBoolean(executable); bytes.writeBoolean(jit); bytes.writeBoolean(debugbuild); // recursively write references json_t *ref_array = json_object_get(json, "references"); lmAssert(ref_array, "Error with executable assembly, missing references section"); // write number of references bytes.writeInt((int)json_array_size(ref_array)); for (size_t j = 0; j < json_array_size(ref_array); j++) { json_t *jref = json_array_get(ref_array, j); json_t *jbinary = json_object_get(jref, "binary"); const char *refname = json_string_value(json_object_get(jref, "name")); const char *refuid = json_string_value(json_object_get(jref, "uid")); bytes.writeInt(poolString(refname)); bytes.writeInt(poolString(refuid)); // already referenced if (binWriters.get(utHashedString(refuid))) { continue; } if (executable) { lmAssert(jbinary, "Error with linked assembly %s, missing binary section", refname); utString refjson = (const char *)utBase64::decode64(json_string_value(jbinary)).getData().ptr(); BinWriter *bwriter = lmNew(NULL) BinWriter(refname); lmAssert(refjson.length() > 0, "Refjson should not be empty! %s", json_string_value(jbinary)); bwriter->writeAssembly(refjson.c_str(), (int)refjson.length()); } } writeModules(json); }
// Service our connection to the asset agent. static void loom_asset_serviceServer() { loom_mutex_lock(gAssetServerSocketLock); // Try to connect to the asset server if we aren't already, and it is set. if ((gAssetServerSocket == NULL) && ((ASSET_STREAM_HOST != NULL) && (strlen(ASSET_STREAM_HOST) > 0)) && ((platform_getMilliseconds() - gAssetServerLastConnectTryTime) > gAssetServerConnectTryInterval)) { lmLog(gAssetLogGroup, "Attempting to stream assets from %s:%d", ASSET_STREAM_HOST, ASSET_STREAM_PORT); gAssetServerLastConnectTryTime = platform_getMilliseconds(); gAssetServerSocket = loom_net_openTCPSocket(ASSET_STREAM_HOST, ASSET_STREAM_PORT, 0); gAssetConnectionOpen = false; loom_asset_notifyPendingCountChange(); loom_mutex_unlock(gAssetServerSocketLock); return; } if ((gAssetServerSocket != NULL) && (gAssetConnectionOpen == false)) { // We are waiting on the connection, see if it's writable... If not, return. if (loom_net_isSocketWritable(gAssetServerSocket) == 0) { loom_mutex_unlock(gAssetServerSocketLock); return; } if (loom_net_isSocketDead(gAssetServerSocket) == 1) { // Might be DOA, ie, connect failed. lmLog(gAssetLogGroup, "Failed to connect to asset server %s:%d", ASSET_STREAM_HOST, ASSET_STREAM_PORT); loom_net_closeTCPSocket(gAssetServerSocket); gAssetServerSocket = NULL; lmSafeDelete(NULL, gAssetProtocolHandler); gAssetConnectionOpen = false; loom_asset_notifyPendingCountChange(); loom_mutex_unlock(gAssetServerSocketLock); return; } lmLog(gAssetLogGroup, "Successfully connected to asset server %s:%d!", ASSET_STREAM_HOST, ASSET_STREAM_PORT); // Do this now to avoid clobbering error state and seeing the socket as // "open" when it is really dead. loom_net_enableSocketKeepalive(gAssetServerSocket); gAssetConnectionOpen = true; loom_asset_notifyPendingCountChange(); // Make sure we have a protocol handler. if (!gAssetProtocolHandler) { gAssetProtocolHandler = lmNew(NULL) AssetProtocolHandler(gAssetServerSocket); gAssetProtocolHandler->registerListener(lmNew(NULL) AssetProtocolFileMessageListener()); gAssetProtocolHandler->registerListener(lmNew(NULL) AssetProtocolCommandListener()); } loom_mutex_unlock(gAssetServerSocketLock); return; } // See if the socket is dead, and if so, clean up. if ((gAssetServerSocket != NULL) && (loom_net_isSocketDead(gAssetServerSocket) == 1)) { lmLog(gAssetLogGroup, "Lost connection to asset server."); loom_net_closeTCPSocket(gAssetServerSocket); gAssetServerSocket = NULL; lmSafeDelete(NULL, gAssetProtocolHandler); gAssetConnectionOpen = false; loom_asset_notifyPendingCountChange(); loom_mutex_unlock(gAssetServerSocketLock); return; } // Bail if we don't have a connection. if (!gAssetServerSocket || !gAssetConnectionOpen) { loom_mutex_unlock(gAssetServerSocketLock); return; } // Ping if we need to. if (platform_getMilliseconds() - gAssetServerLastPingTime > gAssetServerPingInterval) { gAssetProtocolHandler->sendPing(); gAssetServerLastPingTime = platform_getMilliseconds(); } // Service the asset server connection. gAssetProtocolHandler->process(); loom_mutex_unlock(gAssetServerSocketLock); }
// Compare two snapshots of file state from the above function and return a // description of any changes. static utArray<FileEntryDelta> *compareFileEntries(utArray<FileEntry> *oldList, utArray<FileEntry> *newList) { UTsize oldIndex = 0, newIndex = 0; utArray<FileEntryDelta> *deltaList = lmNew(NULL) utArray<FileEntryDelta>(); // If we have no lists, it's a trivial case. if (!oldList && !newList) { return deltaList; } // If we only have one list, then it's either all adds or all removes. if (oldList && !newList) { for (UTsize i = 0; i < oldList->size(); i++) { FileEntryDelta fed; fed.action = FileEntryDelta::Removed; fed.path = oldList->at(i).path; deltaList->push_back(fed); } return deltaList; } if (!oldList && newList) { for (UTsize i = 0; i < newList->size(); i++) { FileEntryDelta fed; fed.action = FileEntryDelta::Added; fed.path = newList->at(i).path; deltaList->push_back(fed); } return deltaList; } // Walk the two lists (which are ordered) and generate FED's based on // mismatches. for ( ; ; ) { // If we run off the end of either list, deal with the tail of the // other list after this block. if ((oldIndex >= oldList->size()) || (newIndex >= newList->size())) { break; } // Do the comparison... const FileEntry& oldEntry = oldList->at(oldIndex); const FileEntry& newEntry = newList->at(newIndex); int compareResult = compareFileEntry(oldEntry, newEntry); FileEntryDelta deltaItem; if (compareResult < 0) { deltaItem.action = FileEntryDelta::Removed; deltaItem.path = oldEntry.path; deltaList->push_back(deltaItem); oldIndex++; continue; } else if (compareResult > 0) { deltaItem.action = FileEntryDelta::Added; deltaItem.path = newEntry.path; deltaList->push_back(deltaItem); newIndex++; continue; } else { // Match on path, check for other kinds of change. if (oldEntry.modifiedTime != newEntry.modifiedTime) { // TODO: check hash. // Report a change. deltaItem.action = FileEntryDelta::Modified; deltaItem.path = newEntry.path; deltaList->push_back(deltaItem); } // Advance both. oldIndex++, newIndex++; continue; } } // Make sure we emit deletions for all remaining old items. while (oldIndex < oldList->size()) { FileEntryDelta deltaItem; deltaItem.action = FileEntryDelta::Removed; deltaItem.path = oldList->at(oldIndex).path; deltaList->push_back(deltaItem); oldIndex++; } // And emit additions for all remaining new items. while (newIndex < newList->size()) { FileEntryDelta deltaItem; deltaItem.action = FileEntryDelta::Added; deltaItem.path = newList->at(newIndex).path; deltaList->push_back(deltaItem); newIndex++; } // If the delta list needed to be canonical, we would sort by path here. // Return it! return deltaList; }
void BinWriter::writeExecutable(const char *path, json_t *sjson) { stringPool.clear(); binWriters.clear(); utByteArray bytes; // reserve 32 megs bytes.reserve(1024 * 1024 * 32); const char *name = json_string_value(json_object_get(sjson, "name")); BinWriter *bexec = lmNew(NULL) BinWriter(name); bexec->writeAssembly(sjson); // write string pool bytes.writeInt((int)stringPool.size()); // calculate entire buffer size of string pool int stringBufferSize = 0; for (UTsize i = 0; i < stringPool.size(); i++) { stringBufferSize += sizeof(int); // length stringBufferSize += (int)strlen(stringPool.keyAt(i).str().c_str()); // characters } // length of entire string buffer bytes.writeInt(stringBufferSize); for (UTsize i = 0; i < stringPool.size(); i++) { bytes.writeString(stringPool.keyAt(i).str().c_str()); } // generate the type table utArray<TypeIndex *> types; for (UTsize i = 0; i < binWriters.size(); i++) { BinWriter *bref = binWriters.at(i); for (UTsize j = 0; j < bref->typeIndexes.size(); j++) { TypeIndex *tindex = bref->typeIndexes.at(j); tindex->refIdx = (int)i; types.push_back(tindex); } } // write the type table bytes.writeInt((int)types.size()); for (UTsize i = 0; i < types.size(); i++) { TypeIndex *tindex = types.at(i); bytes.writeInt(tindex->refIdx); bytes.writeInt(tindex->iFullName); bytes.writeInt(tindex->position); bytes.writeInt(tindex->length); } // write out the number of references bytes.writeInt((int)binWriters.size()); // write out reference table (which will allow random access if we want/need it) int position = bytes.getPosition() + (binWriters.size() * (sizeof(int) * 4)); for (UTsize i = 0; i < binWriters.size(); i++) { BinWriter *bref = binWriters.at(i); // (interned) name utHashedString uid = binWriters.keyAt(i); bytes.writeInt(poolString(binWriters.at(i)->name.c_str())); // uid bytes.writeInt(poolString(binWriters.keyAt(i).str().c_str())); // length int length = bref->bytes.getPosition(); bytes.writeInt(length); // position (offset from reference table) bytes.writeInt(position); position += length; } for (UTsize i = 0; i < binWriters.size(); i++) { BinWriter *bref = binWriters.at(i); bytes.writeBytes(&bref->bytes); } int dataLength = bytes.getPosition(); Bytef *compressed = (Bytef *) lmAlloc(gBinWriterAllocator, dataLength); uLongf length = (uLongf) dataLength; int ok = compress(compressed, &length, (Bytef *) bytes.getDataPtr(), (uLong) dataLength); lmAssert(ok == Z_OK, "problem compressing executable assemby"); bytes.clear(); bytes.writeUnsignedInt(LOOM_BINARY_ID); bytes.writeUnsignedInt(LOOM_BINARY_VERSION_MAJOR); bytes.writeUnsignedInt(LOOM_BINARY_VERSION_MINOR); bytes.writeUnsignedInt((unsigned int)dataLength); utFileStream binStream; binStream.open(path, utStream::SM_WRITE); // write header binStream.write(bytes.getDataPtr(), sizeof(unsigned int) * 4); // write compressed data binStream.write(compressed, length); binStream.close(); lmFree(gBinWriterAllocator, compressed); }