static duk_ret_t js_RawFile_read(duk_context* ctx) { int n_args = duk_get_top(ctx); long num_bytes = n_args >= 1 ? duk_require_int(ctx, 0) : 0; bytearray_t* array; FILE* file; long pos; void* read_buffer; duk_push_this(ctx); file = duk_require_sphere_obj(ctx, -1, "RawFile"); duk_pop(ctx); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:read(): File has been closed"); if (n_args < 1) { // if no arguments, read entire file back to front pos = ftell(file); num_bytes = (fseek(file, 0, SEEK_END), ftell(file)); fseek(file, 0, SEEK_SET); } if (num_bytes <= 0) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "RawFile:read(): Read size out of range (%u)", num_bytes); if (!(read_buffer = malloc(num_bytes))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:read(): Failed to allocate buffer for file read"); num_bytes = (long)fread(read_buffer, 1, num_bytes, file); if (n_args < 1) // reset file position after whole-file read fseek(file, pos, SEEK_SET); if (!(array = bytearray_from_buffer(read_buffer, (int)num_bytes))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:read(): Failed to create byte array"); duk_push_sphere_bytearray(ctx, array); return 1; }
static duk_ret_t js_PointSeries(duk_context* ctx) { duk_require_object_coercible(ctx, 0); color_t color = duk_require_sphere_color(ctx, 1); size_t num_points; int x, y; ALLEGRO_VERTEX* vertices; ALLEGRO_COLOR vtx_color; size_t i; if (!duk_is_array(ctx, 0)) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "PointSeries(): First argument must be an array"); duk_get_prop_string(ctx, 0, "length"); num_points = duk_get_uint(ctx, 0); duk_pop(ctx); if (num_points < 1) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "PointSeries(): One or more vertices required"); if (num_points > INT_MAX) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "PointSeries(): Too many vertices"); if ((vertices = calloc(num_points, sizeof(ALLEGRO_VERTEX))) == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "PointSeries(): Failed to allocate vertex buffer"); vtx_color = nativecolor(color); for (i = 0; i < num_points; ++i) { duk_get_prop_index(ctx, 0, (duk_uarridx_t)i); duk_get_prop_string(ctx, 0, "x"); x = duk_require_int(ctx, -1); duk_pop(ctx); duk_get_prop_string(ctx, 0, "y"); y = duk_require_int(ctx, -1); duk_pop(ctx); duk_pop(ctx); vertices[i].x = x + 0.5; vertices[i].y = y + 0.5; vertices[i].color = vtx_color; } al_draw_prim(vertices, NULL, NULL, 0, (int)num_points, ALLEGRO_PRIM_POINT_LIST); free(vertices); return 0; }
static duk_ret_t js_CreateByteArray(duk_context* ctx) { int size = duk_require_int(ctx, 0); bytearray_t* array; if (size < 0) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "CreateByteArray(): Size cannot be negative (%i)", size); if (!(array = new_bytearray(size))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "CreateByteArray(): Failed to create new byte array (internal error)"); duk_push_sphere_bytearray(ctx, array); return 1; }
static duk_ret_t js_CreateByteArrayFromString(duk_context* ctx) { lstring_t* string = duk_require_lstring_t(ctx, 0); bytearray_t* array; if (string->length > INT_MAX) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "CreateByteArrayFromString(): Input string too large, size of byte array cannot exceed 2 GB"); if (!(array = bytearray_from_lstring(string))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "CreateByteArrayFromString(): Failed to create byte array from string (internal error)"); duk_push_sphere_bytearray(ctx, array); return 1; }
static duk_ret_t js_RawFile_set_position(duk_context* ctx) { int new_pos = duk_require_int(ctx, 0); FILE* file; duk_push_this(ctx); file = duk_require_sphere_obj(ctx, -1, "RawFile"); duk_pop(ctx); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:position - File has been closed"); if (!fseek(file, new_pos, SEEK_SET)) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:position - Failed to set read/write position"); return 0; }
static duk_ret_t js_HashRawFile(duk_context* ctx) { const char* filename = duk_require_string(ctx, 0); FILE* file; char* path; path = get_asset_path(filename, "other", false); file = fopen(path, "rb"); free(path); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "HashRawFile(): Failed to open file '%s' for reading"); fclose(file); // TODO: implement raw file hashing duk_error_ni(ctx, -1, DUK_ERR_ERROR, "HashRawFile(): Function is not yet implemented"); }
static duk_ret_t js_ByteArray_concat(duk_context* ctx) { bytearray_t* array2 = duk_require_sphere_bytearray(ctx, 0); bytearray_t* array; bytearray_t* new_array; duk_push_this(ctx); duk_get_prop_string(ctx, -1, "\xFF" "ptr"); array = duk_get_pointer(ctx, -1); duk_pop(ctx); duk_pop(ctx); if (array->size + array2->size > INT_MAX) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "ByteArray:concat(): Unable to concatenate, final size would exceed 2 GB (size1: %u, size2: %u)", array->size, array2->size); if (!(new_array = concat_bytearrays(array, array2))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "ByteArray:concat(): Failed to create concatenated byte array (internal error)"); duk_push_sphere_bytearray(ctx, new_array); return 1; }
static duk_ret_t js_RawFile_readString(duk_context* ctx) { size_t num_bytes = duk_require_uint(ctx, 0); FILE* file; void* read_buffer; duk_push_this(ctx); file = duk_require_sphere_obj(ctx, -1, "RawFile"); duk_pop(ctx); if (num_bytes <= 0 || num_bytes > INT_MAX) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "RawFile:read(): Read size out of range (%i)", num_bytes / 1048576); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:read(): File has been closed"); if (!(read_buffer = malloc(num_bytes))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:read(): Failed to allocate buffer for file read"); num_bytes = fread(read_buffer, 1, num_bytes, file); duk_push_lstring(ctx, read_buffer, num_bytes); return 1; }
static duk_ret_t js_RawFile_get_position(duk_context* ctx) { FILE* file; duk_push_this(ctx); file = duk_require_sphere_obj(ctx, -1, "RawFile"); duk_pop(ctx); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:position - File has been closed"); duk_push_int(ctx, ftell(file)); return 1; }
static duk_ret_t js_Logger_beginBlock(duk_context* ctx) { const char* title = duk_to_string(ctx, 0); logger_t* logger; duk_push_this(ctx); logger = duk_require_sphere_obj(ctx, -1, "Logger"); if (!begin_log_block(logger, title)) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "Log:beginBlock(): Failed to create new log block"); return 0; }
static duk_ret_t js_ByteArray_slice(duk_context* ctx) { int n_args = duk_get_top(ctx); int start = duk_require_int(ctx, 0); int end = (n_args >= 2) ? duk_require_int(ctx, 1) : INT_MAX; bytearray_t* array; int end_norm; bytearray_t* new_array; duk_push_this(ctx); duk_get_prop_string(ctx, -1, "\xFF" "ptr"); array = duk_get_pointer(ctx, -1); duk_pop(ctx); duk_pop(ctx); end_norm = fmin(end >= 0 ? end : array->size + end, array->size); if (end_norm < start || end_norm > array->size) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "ByteArray:slice(): Start and/or end values out of bounds (start: %i, end: %i - size: %i)", start, end_norm, array->size); if (!(new_array = slice_bytearray(array, start, end_norm - start))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "ByteArray:slice(): Failed to create sliced byte array (internal error)"); duk_push_sphere_bytearray(ctx, new_array); return 1; }
static duk_ret_t js_new_Logger(duk_context* ctx) { const char* filename = duk_get_string(ctx, 0); char* path = get_asset_path(filename, "logs", true); logger_t* logger = open_log_file(path); free(path); if (logger == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "OpenLog(): Failed to open file for logging '%s'", filename); duk_push_sphere_obj(ctx, "Logger", logger); return 1; }
static duk_ret_t js_new_Font(duk_context* ctx) { const char* filename; font_t* font; filename = duk_require_path(ctx, 0, NULL, false); font = load_font(filename); if (font == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "Font(): unable to load font file `%s`", filename); duk_push_sphere_font(ctx, font); free_font(font); return 1; }
static duk_ret_t js_Font_clone(duk_context* ctx) { font_t* dolly_font; font_t* font; duk_push_this(ctx); font = duk_require_sphere_obj(ctx, -1, "Font"); duk_pop(ctx); if (!(dolly_font = clone_font(font))) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "Font:clone(): unable to clone font"); duk_push_sphere_font(ctx, dolly_font); return 1; }
static duk_ret_t js_RawFile_close(duk_context* ctx) { FILE* file; duk_push_this(ctx); file = duk_require_sphere_obj(ctx, -1, "RawFile"); duk_push_pointer(ctx, NULL); duk_put_prop_string(ctx, -2, "\xFF" "file_ptr"); duk_pop(ctx); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:close(): File has been closed"); fclose(file); return 0; }
static duk_ret_t js_RawFile_write(duk_context* ctx) { bytearray_t* array; const void* data; FILE* file; size_t write_size; duk_push_this(ctx); file = duk_require_sphere_obj(ctx, -1, "RawFile"); duk_pop(ctx); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:write(): File has been closed"); if (duk_is_string(ctx, 0)) data = duk_get_lstring(ctx, 0, &write_size); else { array = duk_require_sphere_obj(ctx, 0, "ByteArray"); data = get_bytearray_buffer(array); write_size = get_bytearray_size(array); } if (fwrite(data, 1, write_size, file) != write_size) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:write(): Write error. The file may be read-only."); return 0; }
static duk_ret_t js_LoadFont(duk_context* ctx) { const char* filename = duk_require_string(ctx, 0); font_t* font; char* path = get_asset_path(filename, "fonts", false); font = load_font(path); free(path); if (font == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "LoadFont(): Failed to load font file '%s'", filename); duk_push_sphere_font(ctx, font); free_font(font); return 1; }
static duk_ret_t js_RawFile_get_size(duk_context* ctx) { FILE* file; long file_pos; duk_push_this(ctx); file = duk_require_sphere_obj(ctx, -1, "RawFile"); duk_pop(ctx); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "RawFile:size - File has been closed"); file_pos = ftell(file); fseek(file, 0, SEEK_END); duk_push_int(ctx, ftell(file)); fseek(file, file_pos, SEEK_SET); return 1; }
font_t* duk_require_sphere_font(duk_context* ctx, duk_idx_t index) { font_t* font; const char* type; index = duk_require_normalize_index(ctx, index); duk_require_object_coercible(ctx, index); if (!duk_get_prop_string(ctx, index, "\xFF" "sphere_type")) goto on_error; type = duk_get_string(ctx, -1); duk_pop(ctx); if (strcmp(type, "font") != 0) goto on_error; duk_get_prop_string(ctx, index, "\xFF" "ptr"); font = duk_get_pointer(ctx, -1); duk_pop(ctx); return font; on_error: duk_error_ni(ctx, -1, DUK_ERR_TYPE_ERROR, "Object is not a Sphere font"); }
bytearray_t* duk_require_sphere_bytearray(duk_context* ctx, duk_idx_t index) { bytearray_t* array; const char* type; index = duk_require_normalize_index(ctx, index); duk_require_object_coercible(ctx, index); if (!duk_get_prop_string(ctx, index, "\xFF" "sphere_type")) goto on_error; type = duk_get_string(ctx, -1); duk_pop(ctx); if (strcmp(type, "bytearray") != 0) goto on_error; duk_get_prop_string(ctx, index, "\xFF" "ptr"); array = duk_get_pointer(ctx, -1); duk_pop(ctx); return array; on_error: duk_error_ni(ctx, -1, DUK_ERR_TYPE_ERROR, "Not a Sphere byte array"); }
static duk_ret_t js_LoadSound(duk_context* ctx) { duk_int_t n_args = duk_get_top(ctx); const char* filename = duk_require_string(ctx, 0); duk_bool_t is_stream = n_args >= 2 ? duk_require_boolean(ctx, 1) : true; sound_t* sound; char* sound_path; sound_path = get_asset_path(filename, "sounds", false); sound = load_sound(sound_path, is_stream); free(sound_path); if (sound == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "LoadSound(): Failed to load sound file '%s'", filename); duk_push_sphere_sound(ctx, sound); free_sound(sound); return 1; }
static duk_ret_t js_new_RawFile(duk_context* ctx) { int n_args = duk_get_top(ctx); const char* filename = duk_require_string(ctx, 0); bool writable = n_args >= 2 ? duk_require_boolean(ctx, 1) : false; FILE* file; char* path; path = get_asset_path(filename, "other", writable); file = fopen(path, writable ? "w+b" : "rb"); free(path); if (file == NULL) duk_error_ni(ctx, -1, DUK_ERR_ERROR, "OpenRawFile(): Failed to open file '%s' for %s", filename, writable ? "writing" : "reading"); duk_push_sphere_obj(ctx, "RawFile", file); return 1; }
static duk_ret_t js_ByteArray_getProp(duk_context* ctx) { bytearray_t* array; int index; int size; duk_get_prop_string(ctx, 0, "\xFF" "ptr"); array = duk_get_pointer(ctx, -1); duk_pop(ctx); if (duk_is_number(ctx, 1)) { index = duk_to_int(ctx, 1); size = get_bytearray_size(array); if (index < 0 || index >= size) duk_error_ni(ctx, -1, DUK_ERR_RANGE_ERROR, "ByteArray[]: Index is out of bounds (%i - size: %i)", index, size); duk_push_uint(ctx, get_byte(array, index)); return 1; } else { duk_dup(ctx, 1); duk_get_prop(ctx, 0); return 1; } }
static duk_ret_t js_HashByteArray(duk_context* ctx) { // TODO: implement byte array hashing duk_error_ni(ctx, -1, DUK_ERR_ERROR, "HashByteArray(): Function is not yet implemented"); }