diff --git a/plugins/media/makefile b/plugins/media/makefile index 46b8dd78..b6181e2a 100644 --- a/plugins/media/makefile +++ b/plugins/media/makefile @@ -10,7 +10,7 @@ libctrmedia.so: media.o ld ${LDFLAGS} -lcurl -lSDL2 -lSDL2_image -lSDL2_ttf -lSDL2_mixer -o libctrmedia.so media.o media.o: - cc -I . -c media.c -I /usr/include/SDL -I ../../i18n/${ISO} -I i18n/${ISO} -Wall -Werror -fPIC -o media.o + cc -D LIBCURL -D FFI -I . -c media.c -I /usr/include/SDL -I ../../i18n/${ISO} -I i18n/${ISO} -Wall -Werror -fPIC -o media.o clean: rm -rf libctrmedia.so diff --git a/plugins/media/makefile.win64 b/plugins/media/makefile.win64 index 7799ca2d..518fd82e 100644 --- a/plugins/media/makefile.win64 +++ b/plugins/media/makefile.win64 @@ -8,10 +8,10 @@ install-libctrmedia.dll: libctrmedia.dll install libctrmedia.dll ../../mods/media/ libctrmedia.dll: media.o - $(CC) ${LDFLAGS} media.o -lcurl -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2_ttf ../../ctr${ISO}import.lib -o libctrmedia.dll + $(CC) ${LDFLAGS} media.o -lffi -lcurl -lSDL2 -lSDL2_image -lSDL2_mixer -lSDL2_ttf ../../ctr${ISO}import.lib -o libctrmedia.dll media.o: - $(CC) ${CFLAGS} -I /usr/x86_64-w64-mingw32/include -I /usr/include/SDL2 -I ../../i18n/${ISO} -I i18n/${ISO} -c media.c -Wall -Werror -fPIC -o media.o + $(CC) ${CFLAGS} -D LIBCURL -D FFI -I /usr/x86_64-w64-mingw32/include -I /usr/include/SDL2 -I ../../i18n/${ISO} -I i18n/${ISO} -c media.c -Wall -Werror -fPIC -o media.o clean: rm media.o \ No newline at end of file diff --git a/plugins/media/media.c b/plugins/media/media.c index a08f0eee..ec962103 100644 --- a/plugins/media/media.c +++ b/plugins/media/media.c @@ -10,15 +10,11 @@ #define PL_MPEG_IMPLEMENTATION -#ifndef CTRTEST #include "pl_mpeg.h" #include #include #include #include -#else -#include "mock.h" -#endif #include #include @@ -26,10 +22,15 @@ #include #include -#ifndef EXPORT_ANDROID + +#ifdef LIBCURL #include #endif +#ifdef FFI +#include +#endif + SDL_Window* CtrMediaWindow = NULL; SDL_Renderer* CtrMediaRenderer = NULL; @@ -74,7 +75,7 @@ struct CtrMediaTextRenderCacheItem { int state; }; typedef struct CtrMediaTextRenderCacheItem CtrMediaTextRenderCacheItem; -CtrMediaTextRenderCacheItem CtrMediaEdCache[100]; +CtrMediaTextRenderCacheItem CtrMediaEdCache[400]; struct CtrMediaAutoReplaceRule { char* word; char* replacement; @@ -137,6 +138,8 @@ ctr_object* musicObject; ctr_object* audioObject; ctr_object* networkObject; ctr_object* packageObject; +ctr_object* CtrMediaFFIObjectBase; +ctr_object* CtrMediaDataBlob; SDL_GameController* gameController; uint8_t CtrMediaEventListenFlagKeyUp; @@ -186,7 +189,7 @@ void ctr_internal_media_reset() { ctr_heap_free(rule->word); ctr_heap_free(rule->replacement); } - for(i = 0; i < 100; i++) { + for(i = 0; i < 400; i++) { CtrMediaEdCache[i].surface = NULL; CtrMediaEdCache[i].text = NULL; CtrMediaEdCache[i].state = 0; @@ -2013,7 +2016,7 @@ ctr_object* ctr_network_new(ctr_object* myself, ctr_argument* argumentList) { return instance; } -#ifndef EXPORT_ANDROID +#ifdef LIBCURL char* CtrMediaCurlBuffer; size_t CtrMediaCurlBufferSize; size_t CtrMediaCurlBytesRead; @@ -2079,8 +2082,6 @@ ctr_object* ctr_network_basic_text_send(ctr_object* myself, ctr_argument* argume } return result; } -#else -extern ctr_object* ctr_network_basic_text_send(ctr_object* myself, ctr_argument* argumentList); #endif /** @@ -2835,9 +2836,8 @@ void ctr_internal_img_render_text(ctr_object* myself) { text_width = 0; text_height = 0; if (text_in_view) { - int viewline = textLine - CtrMediaCursorOffsetY; - int cacheoffset = CtrMediaCursorOffsetY % 100; + int cacheoffset = CtrMediaCursorOffsetY % 200; int q = cacheoffset + viewline; if ( CtrMediaEdCache[q].surface && CtrMediaEdCache[q].state == state @@ -2849,6 +2849,7 @@ void ctr_internal_img_render_text(ctr_object* myself) { } else { buffsize = i-line_segment_start; + //memleak + optimization possible buff = malloc(buffsize + 1); memcpy(buff, image->text+line_segment_start, i-line_segment_start); memcpy(buff+(i-line_segment_start), "\0", 1); @@ -3203,6 +3204,616 @@ ctr_object* ctr_package_new_set(ctr_object* myself, ctr_argument* argumentList) return instance; } +#ifdef FFI +ctr_object* ctr_ffi_object_new(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* instance = ctr_internal_create_object(CTR_OBJECT_TYPE_OTOBJECT); + instance->link = myself; + return instance; +} + + +void ctr_media_blob_destructor(ctr_resource* resource_value) { + // the destructor cant remove the memory automatically + // because upon returning from a c-function it is not known + // whether the memory belongs to us or to the called function + // you have to call free / freestruct. +} + +ffi_type* ctr_internal_media_ffi_map_type(char* description); +void* ctr_internal_media_ffi_convert_value(ffi_type* type, ctr_object* obj); + +ctr_object* ctr_blob_deref(ctr_object* myself, ctr_argument* argumentList) { + myself->value.rvalue->ptr = (void*) *((void**)myself->value.rvalue->ptr); + return myself; +} + +ctr_object* ctr_blob_fill(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* arr = argumentList->object; + for(int i = 0; i < arr->value.avalue->head; i++) { + *((char*)myself->value.rvalue->ptr + i) = (char) ctr_tonum(*(arr->value.avalue->elements + i)); + } + return myself; +} + +ctr_object* ctr_blob_free(ctr_object* myself, ctr_argument* argumentList) { + ctr_heap_free(myself->value.rvalue->ptr); + myself->value.rvalue->ptr = NULL; + return myself; +} + + +ctr_object* ctr_blob_tostring(ctr_object* myself, ctr_argument* argumentList) { + return ctr_build_string_from_cstring(myself->value.rvalue->ptr); +} + + + +ctr_object* ctr_blob_new_set(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* instance = ctr_internal_create_object(CTR_OBJECT_TYPE_OTEX); + instance->link = myself; + size_t size = (size_t) ctr_tonum(argumentList->object); + ctr_resource* buffer = ctr_heap_allocate(sizeof(ctr_resource)); + buffer->ptr = ctr_heap_allocate(size); + buffer->destructor = &ctr_media_blob_destructor; + instance->value.rvalue = buffer; + instance->info.sticky = 1; + return instance; +} + +ctr_object* ctr_blob_utf8_set(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* instance = ctr_internal_create_object(CTR_OBJECT_TYPE_OTEX); + instance->link = myself; + ctr_resource* buffer = ctr_heap_allocate(sizeof(ctr_resource)); + buffer->ptr = ctr_heap_allocate_cstring(argumentList->object); + buffer->destructor = &ctr_media_blob_destructor; + instance->value.rvalue = buffer; + instance->info.sticky = 1; + return instance; +} + +ffi_type* ctr_internal_media_ffi_map_type_obj(ctr_object* obj); +ctr_object* ctr_blob_new_set_type(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* instance = ctr_internal_create_object(CTR_OBJECT_TYPE_OTEX); + instance->link = myself; + ctr_resource* buffer; + ffi_type* type = ctr_internal_media_ffi_map_type_obj(argumentList->next->object); + if (type) { + buffer = ctr_heap_allocate(sizeof(ctr_resource)); + buffer->destructor = &ctr_media_blob_destructor; + buffer->ptr = ctr_internal_media_ffi_convert_value(type, argumentList->object); + } else { + buffer = NULL; + } + instance->value.rvalue = buffer; + instance->info.sticky = 1; + return instance; +} + + +ctr_object* ctr_blob_read(ctr_object* myself, ctr_argument* argumentList) { + ctr_argument* pushArg; + ctr_argument* elnumArg; + ctr_object* elnum; + ctr_object* startElement = ctr_internal_cast2number(argumentList->object); + ctr_object* count = ctr_internal_cast2number(argumentList->next->object); + int start = (int) startElement->value.nvalue; + int len = (int) count->value.nvalue; + int i = 0; + ctr_object* newArray = ctr_array_new(CtrStdArray, NULL); + for(i = start; i < start + len; i++) { + pushArg = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); + elnumArg = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); + elnum = ctr_build_number_from_float((ctr_number) i); + elnumArg->object = elnum; + pushArg->object = ctr_build_number_from_float( (ctr_number) *((char*) myself->value.rvalue->ptr + (i - 1)) ); + ctr_array_push(newArray, pushArg); + ctr_heap_free( elnumArg ); + ctr_heap_free( pushArg ); + } + return newArray; +} + + +struct CtrMediaFFI { + void* handle; + void* symbol; + ffi_type* args[20]; + ffi_type* rtype; + int nargs; + ffi_cif* cif; + ctr_object* owner; +}; +typedef struct CtrMediaFFI CtrMediaFFI; + +struct ctr_media_test_struct { + int a; + int b; +}; +typedef struct ctr_media_test_struct ctr_media_test_struct; + +int ctr_media_internal_structtest(ctr_media_test_struct sum) { + printf("sum of %d and %d is: %d \n", sum.a, sum.b, sum.a + sum.b); + return sum.a + sum.b; +} + +void ctr_media_ffi_destructor(ctr_resource* resource_value) { + CtrMediaFFI* ff = (CtrMediaFFI*) resource_value->ptr; + ctr_heap_free(ff->cif); + ff->cif = NULL; + ctr_heap_free(ff); +} + + +ffi_type* ctr_internal_media_ffi_map_type(char* description) { + if (strcmp(description, "void")==0) { + return &ffi_type_void; + } else if (strcmp(description, "int")==0) { + return &ffi_type_sint; + } else if (strcmp(description,"uint32_t")==0) { + return &ffi_type_uint32; + } else if (strcmp(description,"pointer")==0) { + return &ffi_type_pointer; + } else if (strcmp(description,"ulong")==0) { + return &ffi_type_ulong; + } + return NULL; +} + + +ffi_type* ctr_internal_media_ffi_map_type_obj(ctr_object* obj) { + ffi_type* result; + if (obj->info.type == CTR_OBJECT_TYPE_OTSTRING) { + char* description = ctr_heap_allocate_cstring(obj); + result = ctr_internal_media_ffi_map_type(description); + ctr_heap_free(description); + } else { + result = obj->value.rvalue->ptr; + } + return result; +} + +ctr_object* ctr_blob_new_struct(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* instance = ctr_internal_create_object(CTR_OBJECT_TYPE_OTEX); + instance->link = myself; + ctr_resource* buffer = ctr_heap_allocate(sizeof(ctr_resource)); + buffer->destructor = &ctr_media_blob_destructor; + ffi_type* cstruct = ctr_heap_allocate(sizeof(ffi_type)); + cstruct->type = FFI_TYPE_STRUCT; + cstruct->alignment = 0; + cstruct->size = 0; + if (argumentList->object->info.type == CTR_OBJECT_TYPE_OTARRAY) { + ctr_object* arr = argumentList->object; + int nargs = arr->value.avalue->head; + cstruct->elements = (ffi_type**) ctr_heap_allocate(sizeof(ffi_type*) * (nargs+1)); + int i; + for (i = 0; i < nargs; i++) { + cstruct->elements[i] = ctr_internal_media_ffi_map_type_obj(*(arr->value.avalue->elements + i)); + } + cstruct->elements[i] = NULL; + } + buffer->ptr = cstruct; + instance->value.rvalue = buffer; + return instance; +} + +ctr_object* ctr_blob_free_struct(ctr_object* myself, ctr_argument* argumentList) { + if (myself->info.type == CTR_OBJECT_TYPE_OTEX) { + ctr_resource* buffer = (ctr_resource*) myself->value.rvalue; + ffi_type* cstruct = (ffi_type*) buffer->ptr; + if (cstruct->elements) { + ctr_heap_free(cstruct->elements); + } + } + return CtrStdNil; +} + +void* ctr_internal_media_ffi_convert_value(ffi_type* type, ctr_object* obj) { + //allocate for return type, must be at least ffi_arg + ctr_size size = type->size; + if (obj == NULL) { + if (type->size < sizeof(ffi_arg)) { + size = sizeof(ffi_arg); + } + } + void* ptr = ctr_heap_allocate(size); + if (obj != NULL) { + if (type == &ffi_type_uint8) { + *((uint8_t*)ptr) = (uint8_t) ctr_tonum(obj); + } else if (type == &ffi_type_sint8) { + *((int8_t*)ptr) = (int8_t) ctr_tonum(obj); + } else if (type == &ffi_type_uint16) { + *((uint16_t*)ptr) = (uint16_t) ctr_tonum(obj); + } else if (type == &ffi_type_sint16) { + *((int16_t*)ptr) = (int16_t) ctr_tonum(obj); + } else if (type == &ffi_type_uint32) { + *((uint32_t*)ptr) = (uint32_t) ctr_tonum(obj); + } else if (type == &ffi_type_sint32) { + *((int32_t*)ptr) = (int32_t) ctr_tonum(obj); + } else if (type == &ffi_type_uint64) { + *((uint64_t*)ptr) = (uint64_t) ctr_tonum(obj); + } else if (type == &ffi_type_sint64) { + *((int64_t*)ptr) = (int64_t) ctr_tonum(obj); + } else if (type == &ffi_type_float) { + *((float*)ptr) = (float) ctr_tonum(obj); + } else if (type == &ffi_type_double) { + *((double*)ptr) = (double) ctr_tonum(obj); + } else if (type == &ffi_type_uchar) { + *((unsigned char*)ptr) = (unsigned char) ctr_tonum(obj); + } else if (type == &ffi_type_schar) { + *((char*)ptr) = (char) ctr_tonum(obj); + } else if (type == &ffi_type_ushort) { + *((unsigned short*)ptr) = (unsigned short) ctr_tonum(obj); + } else if (type == &ffi_type_sshort) { + *((short*)ptr) = (short) ctr_tonum(obj); + } else if (type == &ffi_type_uint) { + *((unsigned int*)ptr) = (unsigned int) ctr_tonum(obj); + } else if (type == &ffi_type_sint) { + *((int*)ptr) = (int) ctr_tonum(obj); + } else if (type == &ffi_type_ulong) { + *((unsigned long*)ptr) = (unsigned long) ctr_tonum(obj); + } else if (type == &ffi_type_slong) { + *((long*)ptr) = (long) ctr_tonum(obj); + } else if (type == &ffi_type_pointer) { + if (obj == CtrStdNil) { + *((void**)ptr) = NULL; + } + else if (obj->link == CtrMediaDataBlob) { + *((void**)ptr) = (void*) obj->value.rvalue->ptr; + } + else { + ctr_error("FFI Pointer requires Blob.\n", 0); + } + } else { + memcpy(ptr, obj->value.rvalue->ptr, type->size); + } + } + return ptr; +} + +ctr_object* ctr_internal_media_ffi_convert_value_back(ffi_type* type, void* ptr) { + ctr_object* result = CtrStdNil; + if (type == &ffi_type_void) { + result = CtrStdNil; + } else if (type == &ffi_type_uint8) { + result = ctr_build_number_from_float( (ctr_number) *((uint8_t*) ptr) ); + } else if (type == &ffi_type_sint8) { + result = ctr_build_number_from_float( (ctr_number) *((int8_t*) ptr) ); + } else if (type == &ffi_type_uint16) { + result = ctr_build_number_from_float( (ctr_number) *((uint16_t*) ptr) ); + } else if (type == &ffi_type_sint16) { + result = ctr_build_number_from_float( (ctr_number) *((int16_t*) ptr) ); + } else if (type == &ffi_type_uint32) { + result = ctr_build_number_from_float( (ctr_number) *((uint32_t*) ptr) ); + } else if (type == &ffi_type_sint32) { + result = ctr_build_number_from_float( (ctr_number) *((int32_t*) ptr) ); + } else if (type == &ffi_type_uint64) { + result = ctr_build_number_from_float( (ctr_number) *((uint64_t*) ptr) ); + } else if (type == &ffi_type_sint64) { + result = ctr_build_number_from_float( (ctr_number) *((int64_t*) ptr) ); + } else if (type == &ffi_type_float) { + result = ctr_build_number_from_float( (ctr_number) *((float*) ptr) ); + } else if (type == &ffi_type_double) { + result = ctr_build_number_from_float( (ctr_number) *((double*) ptr) ); + } else if (type == &ffi_type_uchar) { + result = ctr_build_number_from_float( (ctr_number) *((unsigned char*) ptr) ); + } else if (type == &ffi_type_schar) { + result = ctr_build_number_from_float( (ctr_number) *((char*) ptr) ); + } else if (type == &ffi_type_ushort) { + result = ctr_build_number_from_float( (ctr_number) *((unsigned short*) ptr) ); + } else if (type == &ffi_type_sshort) { + result = ctr_build_number_from_float( (ctr_number) *((short*) ptr) ); + } else if (type == &ffi_type_uint) { + result = ctr_build_number_from_float( (ctr_number) *((unsigned int*) ptr) ); + } else if (type == &ffi_type_sint) { + result = ctr_build_number_from_float( (ctr_number) *((int*) ptr) ); + } else if (type == &ffi_type_ulong) { + result = ctr_build_number_from_float( (ctr_number) *((unsigned long*) ptr) ); + } else if (type == &ffi_type_slong) { + result = ctr_build_number_from_float( (ctr_number) *((long*) ptr) ); + } else if (type == &ffi_type_pointer) { + ctr_object* instance = ctr_internal_create_object(CTR_OBJECT_TYPE_OTEX); + instance->link = CtrMediaDataBlob; + ctr_resource* buffer = ctr_heap_allocate(sizeof(ctr_resource)); + buffer->ptr = *((void**)ptr); + buffer->destructor = &ctr_media_blob_destructor; + instance->value.rvalue = buffer; + instance->info.sticky = 1; + result = instance; + } + return result; +} + +CtrMediaFFI* ctr_internal_media_ffi_get(ctr_object* obj, ctr_object* property) { + ctr_object* resource_holder = ctr_internal_object_find_property( + obj, + ctr_internal_cast2string( property ), + 0 + ); + if (!resource_holder) { + return NULL; + } + ctr_resource* resource = resource_holder->value.rvalue; + if (!resource) { + return NULL; + } + CtrMediaFFI* ff = (CtrMediaFFI*) resource->ptr; + return ff; +} + +ctr_object* ctr_media_ffi_respond_to_and_and_and(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* result; + void* return_value; + CtrMediaFFI* ff = ctr_internal_media_ffi_get(myself, argumentList->object); + if (!ff) { + return ctr_error("Unable to find FFI property.", 0); + } + void* values[3]; + values[0] = ctr_internal_media_ffi_convert_value(ff->args[0], argumentList->next->object); + values[1] = ctr_internal_media_ffi_convert_value(ff->args[1], argumentList->next->next->object); + values[2] = ctr_internal_media_ffi_convert_value(ff->args[2], argumentList->next->next->next->object); + return_value = ctr_internal_media_ffi_convert_value(ff->rtype, NULL); + ffi_call(ff->cif, ff->symbol, return_value, values); + result = ctr_internal_media_ffi_convert_value_back(ff->rtype, return_value); + ctr_heap_free(values[0]); + ctr_heap_free(values[1]); + ctr_heap_free(values[2]); + ctr_heap_free(return_value); + return result; +} + +ctr_object* ctr_media_ffi_respond_to_and_and(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* result; + void* return_value; + CtrMediaFFI* ff = ctr_internal_media_ffi_get(myself, argumentList->object); + if (!ff) { + return ctr_error("Unable to find FFI property.", 0); + } + void* values[20]; + values[0] = ctr_internal_media_ffi_convert_value(ff->args[0], argumentList->next->object); + values[1] = ctr_internal_media_ffi_convert_value(ff->args[1], argumentList->next->next->object); + return_value = ctr_internal_media_ffi_convert_value(ff->rtype, NULL); + ffi_call(ff->cif, ff->symbol, return_value, values); + result = ctr_internal_media_ffi_convert_value_back(ff->rtype, return_value); + ctr_heap_free(values[0]); + ctr_heap_free(values[1]); + ctr_heap_free(return_value); + return result; +} + +ctr_object* ctr_media_ffi_respond_to_and(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* result; + ctr_object* arr; + void* return_value; + CtrMediaFFI* ff = ctr_internal_media_ffi_get(myself, argumentList->object); + if (!ff) { + return ctr_error("Unable to find FFI property.", 0); + } + void* values[20]; + if (argumentList->next->object->info.type == CTR_OBJECT_TYPE_OTARRAY) { + arr = argumentList->next->object; + if (arr->value.avalue->head>20) { + return ctr_error("Too many parameters for FFI.", 0); + } + for(int i = 0; ivalue.avalue->head; i++) { + if (i > ff->nargs) break; + values[i] = ctr_internal_media_ffi_convert_value(ff->args[i], *(arr->value.avalue->elements+i)); + } + } else { + values[0] = ctr_internal_media_ffi_convert_value(ff->args[0], argumentList->next->object); + } + return_value = ctr_internal_media_ffi_convert_value(ff->rtype, NULL); + ffi_call(ff->cif, ff->symbol, return_value, values); + result = ctr_internal_media_ffi_convert_value_back(ff->rtype, return_value); + if (argumentList->next->object->info.type == CTR_OBJECT_TYPE_OTARRAY) { + arr = argumentList->next->object; + for(int i = 0; ivalue.avalue->head; i++) { + if (i > ff->nargs) break; + ctr_heap_free(values[i]); + } + } else { + ctr_heap_free(values[0]); + } + ctr_heap_free(return_value); + return result; +} + +ctr_object* ctr_media_ffi_respond_to(ctr_object* myself, ctr_argument* argumentList) { + ctr_object* result; + void* return_value; + CtrMediaFFI* ff = ctr_internal_media_ffi_get(myself, argumentList->object); + if (!ff) { + return ctr_error("Unable to find FFI property.", 0); + } + return_value = ctr_internal_media_ffi_convert_value(ff->rtype, NULL); + ffi_call(ff->cif, ff->symbol, return_value, NULL); + result = ctr_internal_media_ffi_convert_value_back(ff->rtype, return_value); + ctr_heap_free(return_value); + return result; +} + +/** + * FFI creates objects in the world whose properties + * contain function names and call definitions. + * The generic methods are then used to map those properties + * to messages. + */ +CtrMediaFFI* CtrMediaPreviousFFIEntry = NULL; +void ctr_internal_media_ffi(ctr_object* ffispec) { + char* library_path; + char* symbol_name; + char* ffi_property_name; + char* rtype_desc; + CtrMediaFFI* ff; + ctr_object* arg1; + ctr_object* arg2; + ctr_object* arg3; + ctr_object* arg4; + ctr_object* arg5; + ctr_object* arg6; + ctr_object* arg7 = NULL; + ctr_object* cif_resource_holder; + ctr_resource* resource; + // Check number of required arguments for FFI-binding + if (ffispec->value.avalue->head < 6) { + ctr_error("Too few arguments to create FFI binding",0); + return; + } + // Load arguments + arg1 = *(ffispec->value.avalue->elements + 0); + arg2 = *(ffispec->value.avalue->elements + 1); + arg3 = *(ffispec->value.avalue->elements + 2); + arg4 = *(ffispec->value.avalue->elements + 3); + arg5 = *(ffispec->value.avalue->elements + 4); + arg6 = *(ffispec->value.avalue->elements + 5); + if (ffispec->value.avalue->head == 7) { + arg7 = *(ffispec->value.avalue->elements + 6); + } + // Create FFI entry + ff = ctr_heap_allocate(sizeof(CtrMediaFFI)); + if (!ff) { + ctr_error("Unable to allocate FFI handle.", 0); + return; + } + ff->cif = ctr_heap_allocate(sizeof(ffi_cif)); + // Load dynamic library + if (arg1 == CtrStdNil) { + if (CtrMediaPreviousFFIEntry) { + ff->handle = CtrMediaPreviousFFIEntry->handle; + } else { + ctr_error("No FFI handle", 0); + return; + } + } else { + library_path = ctr_heap_allocate_cstring(ctr_internal_cast2string(arg1)); + #ifdef WIN + ff->handle = LoadLibrary(library_path); + #else + ff->handle = dlopen(library_path, RTLD_NOW); + #endif + ctr_heap_free(library_path); + if ( !ff->handle ) { + #if defined WIN + ctr_error("Unable to open library",0); + #else + ctr_error(dlerror(),0); + #endif + return; + } + } + // Obtain symbol reference + if (arg2 == CtrStdNil) { + if (CtrMediaPreviousFFIEntry) { + ff->symbol = CtrMediaPreviousFFIEntry->symbol; + } else { + ctr_error("No FFI symbol", 0); + return; + } + } else { + symbol_name = ctr_heap_allocate_cstring(ctr_internal_cast2string(arg2)); + if (strcmp("@structtest", symbol_name)==0) { + ff->symbol = &ctr_media_internal_structtest; + ctr_heap_free(symbol_name); + } else { + #ifdef WIN + ff->symbol = GetProcAddress( ff->handle, symbol_name ); + #else + ff->symbol = dlsym( ff->handle, symbol_name ); + #endif + ctr_heap_free(symbol_name); + if (!ff->symbol) { + #ifdef WIN + ctr_error("No symbol",0); + #else + ctr_error(dlerror(),0); + #endif + return; + } + } + } + // Build the argument list + if (arg3->link != CtrStdArray) { + ctr_error("No FFI arguments", 0); + return; + } + // Load the number of arguments + ff->nargs = arg3->value.avalue->head; + //No more than 20 arguments are supported for an FFI binding + if (ff->nargs > 20) { + ctr_error("FFI: up to 20 arguments supported per call.", 0); + return; + } + for(int i = 0; inargs; i++) { + ff->args[i] = ctr_internal_media_ffi_map_type_obj(*(arg3->value.avalue->elements + i)); + if (!ff->args[i]) { + ctr_error("Unable to map argument type.", 0); + return; + } + + } + // Build the return type + rtype_desc = ctr_heap_allocate_cstring(ctr_internal_cast2string(arg4)); + ff->rtype = NULL; + ff->rtype = ctr_internal_media_ffi_map_type(rtype_desc); + ctr_heap_free(rtype_desc); + + if (!ff->rtype) { + ctr_error("Invalid FFI return type.",0); + return; + } + ffi_status ok; + if (arg7) { + ok = ffi_prep_cif_var(ff->cif, FFI_DEFAULT_ABI, (int) arg7->value.nvalue, ff->nargs, ff->rtype, ff->args); + } else { + ok = ffi_prep_cif(ff->cif, FFI_DEFAULT_ABI, ff->nargs, ff->rtype, ff->args); + } + if (ok != FFI_OK) { + ctr_error("Invalid FFI function signature",0); + return; + } + // Create the owner object in the world + if (arg5 == CtrStdNil) { + if (CtrMediaPreviousFFIEntry) { + ff->owner = CtrMediaPreviousFFIEntry->owner; + } else { + ctr_error("No FFI bridge object",0); + return; + } + } else { + ff->owner = ctr_internal_create_object(CTR_OBJECT_TYPE_OTOBJECT); + ff->owner->link = CtrMediaFFIObjectBase; + ctr_internal_object_add_property( + CtrStdWorld, + ctr_internal_cast2string(arg5), + ff->owner, + CTR_CATEGORY_PUBLIC_PROPERTY + ); + } + // Create the message bridge + if (arg6 == CtrStdNil) { + ctr_error("FFI: no message mapping",0); + return; + } + resource = ctr_heap_allocate(sizeof(ctr_resource)); + resource->ptr = ff; + resource->type = 2; + resource->destructor = &ctr_media_ffi_destructor; + cif_resource_holder = ctr_internal_create_object(CTR_OBJECT_TYPE_OTEX); + cif_resource_holder->value.rvalue = resource; + ffi_property_name = ctr_heap_allocate_cstring( + ctr_internal_cast2string(arg6) + ); + ctr_internal_object_property( + ff->owner, + ffi_property_name, + cif_resource_holder + ); + ctr_heap_free(ffi_property_name); + // Succesfully created FFI bridge, store this bridge in cache + CtrMediaPreviousFFIEntry = ff; +} + +#endif + /** * @def * [ Media ] link: [ Package ] @@ -3217,7 +3828,13 @@ ctr_object* ctr_package_new_set(ctr_object* myself, ctr_argument* argumentList) * en: After linking an asset package, all resources will be retrieved from the package instead of disk. */ ctr_object* ctr_media_link_package(ctr_object* myself, ctr_argument* argumentList) { - if (argumentList->object->link != packageObject) { + if (argumentList->object->link == CtrStdArray) { + #ifdef FFI + ctr_internal_media_ffi(argumentList->object); + #else + ctr_error("FFI not available.", 0); + #endif + } else if (argumentList->object->link != packageObject) { ctr_error("Not an asset package.\n", 0); } CtrMediaAssetPackage = argumentList->object; @@ -3526,6 +4143,20 @@ void begin(){ #endif ctr_internal_media_reset(); ctr_internal_media_init(); + #ifdef FFI + CtrMediaDataBlob = ctr_media_new(CtrStdObject, NULL); + CtrMediaDataBlob->link = CtrStdObject; + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( "nieuw:" ), &ctr_blob_new_set); + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( "tekst" ), &ctr_blob_tostring); + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( "vul:" ), &ctr_blob_fill); + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( "utf8:" ), &ctr_blob_utf8_set); + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( "nieuw:type:" ), &ctr_blob_new_set_type); + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( "deref" ), &ctr_blob_deref); + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( "free" ), &ctr_blob_free); + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( "struct:" ), &ctr_blob_new_struct); + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( "freestruct" ), &ctr_blob_free_struct); + ctr_internal_create_func(CtrMediaDataBlob, ctr_build_string_from_cstring( CTR_DICT_FROM_LENGTH ), &ctr_blob_read); + #endif colorObject = ctr_media_new(CtrStdObject, NULL); colorObject->link = CtrStdObject; ctr_internal_create_func(colorObject, ctr_build_string_from_cstring( CTR_DICT_NEW ), &ctr_color_new ); @@ -3619,12 +4250,23 @@ void begin(){ networkObject = ctr_network_new(CtrStdObject, NULL); networkObject->link = CtrStdObject; ctr_internal_create_func(networkObject, ctr_build_string_from_cstring( CTR_DICT_NEW ), &ctr_network_new ); + #ifdef LIBCURL ctr_internal_create_func(networkObject, ctr_build_string_from_cstring(CTR_DICT_SEND_TEXT_MESSAGE), &ctr_network_basic_text_send ); + #endif packageObject = ctr_package_new(CtrStdObject, NULL); packageObject->link = CtrStdObject; ctr_internal_create_func(packageObject, ctr_build_string_from_cstring( CTR_DICT_NEW_SET ), &ctr_package_new_set ); ctr_internal_create_func(packageObject, ctr_build_string_from_cstring(CTR_DICT_APPEND), &ctr_package_add ); ctr_internal_object_add_property(CtrStdWorld, ctr_build_string_from_cstring( CTR_DICT_MEDIA_PLUGIN_ID ), mediaObject, CTR_CATEGORY_PUBLIC_PROPERTY); + #ifdef FFI + CtrMediaFFIObjectBase = ctr_ffi_object_new(CtrStdObject, NULL); + CtrMediaFFIObjectBase->link = CtrStdObject; + ctr_internal_create_func(CtrMediaFFIObjectBase, ctr_build_string_from_cstring( CTR_DICT_RESPOND_TO ), &ctr_media_ffi_respond_to ); + ctr_internal_create_func(CtrMediaFFIObjectBase, ctr_build_string_from_cstring( CTR_DICT_RESPOND_TO_AND ), &ctr_media_ffi_respond_to_and ); + ctr_internal_create_func(CtrMediaFFIObjectBase, ctr_build_string_from_cstring( CTR_DICT_RESPOND_TO_AND_AND ), &ctr_media_ffi_respond_to_and_and ); + ctr_internal_create_func(CtrMediaFFIObjectBase, ctr_build_string_from_cstring( CTR_DICT_RESPOND_TO_AND_AND_AND ), &ctr_media_ffi_respond_to_and_and_and ); + ctr_internal_object_add_property(CtrStdWorld, ctr_build_string_from_cstring("Blob"), CtrMediaDataBlob, CTR_CATEGORY_PUBLIC_PROPERTY); + #endif ctr_internal_object_add_property(CtrStdWorld, ctr_build_string_from_cstring( CTR_DICT_IMAGE_OBJECT ), imageObject, CTR_CATEGORY_PUBLIC_PROPERTY); ctr_internal_object_add_property(CtrStdWorld, ctr_build_string_from_cstring( CTR_DICT_COLOR_OBJECT ), colorObject, CTR_CATEGORY_PUBLIC_PROPERTY); ctr_internal_object_add_property(CtrStdWorld, ctr_build_string_from_cstring( CTR_DICT_POINT_OBJECT ), pointObject, CTR_CATEGORY_PUBLIC_PROPERTY);