mirror of
https://github.com/google/pebble.git
synced 2025-07-03 05:46:21 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
249
applib-targets/emscripten/emscripten_resources.c
Normal file
249
applib-targets/emscripten/emscripten_resources.c
Normal file
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "emscripten_resources.h"
|
||||
|
||||
#include "resource/resource_storage_impl.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
} Resource;
|
||||
|
||||
#define MANIFEST_SIZE (sizeof(ResourceManifest))
|
||||
#define TABLE_ENTRY_SIZE (sizeof(ResTableEntry))
|
||||
#define MAX_RESOURCES_FOR_SYSTEM_STORE 512
|
||||
#define SYSTEM_STORE_METADATA_BYTES \
|
||||
(MANIFEST_SIZE + MAX_RESOURCES_FOR_SYSTEM_STORE * TABLE_ENTRY_SIZE)
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Custom Resources
|
||||
//
|
||||
// Custom resources in Rocky.js are implemented with a set of callbacks
|
||||
// on the javascript side which implement resource APIs
|
||||
//
|
||||
// We store those callbacks in an array and return a resource ID which
|
||||
// can then be used as if it was a valid resource
|
||||
//
|
||||
// Under the hood, we just lookup & call the initially provided callbacks
|
||||
|
||||
typedef struct {
|
||||
uint32_t resource_id;
|
||||
ResourceReadCb read;
|
||||
ResourceGetSizeCb get_size;
|
||||
} EmxCustomResource;
|
||||
|
||||
typedef struct {
|
||||
EmxCustomResource *custom_resources;
|
||||
uint32_t last_id;
|
||||
int array_size;
|
||||
int next_index;
|
||||
} CustomResList;
|
||||
|
||||
static CustomResList s_custom_res_list = {0};
|
||||
|
||||
static int prv_custom_resource_get_index(uint32_t resource_id) {
|
||||
int index;
|
||||
for (index = 0; index < s_custom_res_list.next_index; ++index) {
|
||||
if (s_custom_res_list.custom_resources[index].resource_id == resource_id) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static EmxCustomResource *prv_custom_resource_get(uint32_t resource_id) {
|
||||
int index = prv_custom_resource_get_index(resource_id);
|
||||
if (index < 0) {
|
||||
return NULL;
|
||||
} else {
|
||||
return &s_custom_res_list.custom_resources[index];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void prv_custom_resource_add(EmxCustomResource *res) {
|
||||
if (s_custom_res_list.array_size <= s_custom_res_list.next_index) {
|
||||
// grow the list
|
||||
int new_size = (s_custom_res_list.array_size + 1) * 2;
|
||||
s_custom_res_list.custom_resources = realloc(s_custom_res_list.custom_resources, new_size);
|
||||
s_custom_res_list.array_size = new_size;
|
||||
}
|
||||
|
||||
s_custom_res_list.custom_resources[s_custom_res_list.next_index] = *res;
|
||||
++s_custom_res_list.next_index;
|
||||
}
|
||||
|
||||
static void prv_custom_resource_remove(uint32_t resource_id) {
|
||||
int index = prv_custom_resource_get_index(resource_id);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
--s_custom_res_list.next_index;
|
||||
if (s_custom_res_list.next_index == index) {
|
||||
// we had the last resource, we're done
|
||||
return;
|
||||
}
|
||||
|
||||
memmove(&s_custom_res_list.custom_resources[index],
|
||||
&s_custom_res_list.custom_resources[index + 1],
|
||||
(s_custom_res_list.next_index - index) * sizeof(EmxCustomResource));
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
// System Resources
|
||||
//
|
||||
// In this case, we shove the pbpack in an emscripten "file" (baked into the resulting JS
|
||||
// and reimplement system resource APIs using standard C file I/O
|
||||
|
||||
static FILE *s_resource_file = NULL;
|
||||
|
||||
static uint32_t prv_read(uint32_t offset, void *data, size_t num_bytes) {
|
||||
if (!s_resource_file || fseek(s_resource_file, offset, SEEK_SET)) {
|
||||
printf("%s: Couldn't seek to %d\n", __FILE__, offset);
|
||||
return 0;
|
||||
}
|
||||
return fread(data, 1, num_bytes, s_resource_file);
|
||||
}
|
||||
|
||||
static ResourceManifest prv_get_manifest(void) {
|
||||
ResourceManifest manifest = {};
|
||||
prv_read(0, &manifest, sizeof(ResourceManifest));
|
||||
return manifest;
|
||||
}
|
||||
|
||||
static bool prv_get_table_entry(ResTableEntry *entry, uint32_t index) {
|
||||
uint32_t addr = sizeof(ResourceManifest) + index * sizeof(ResTableEntry);
|
||||
return prv_read(addr, entry, sizeof(ResTableEntry));
|
||||
}
|
||||
|
||||
static bool prv_get_resource(uint32_t resource_id, Resource *res) {
|
||||
*res = (Resource){
|
||||
.length = 0,
|
||||
.offset = 0,
|
||||
};
|
||||
|
||||
ResourceManifest manifest = prv_get_manifest();
|
||||
|
||||
if (resource_id > manifest.num_resources) {
|
||||
printf("%s: resource id %d > %d is out of range\n", __FILE__,
|
||||
resource_id,
|
||||
manifest.num_resources);
|
||||
return false;
|
||||
}
|
||||
|
||||
ResTableEntry entry;
|
||||
if (!prv_get_table_entry(&entry, resource_id - 1)) {
|
||||
printf("%s: Failed to read table entry for %d\n", __FILE__, resource_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((entry.resource_id != resource_id) ||
|
||||
(entry.length == 0)) {
|
||||
// empty resource
|
||||
printf("%s: Invalid resourcel for %d\n", __FILE__, resource_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
res->offset = SYSTEM_STORE_METADATA_BYTES + entry.offset;
|
||||
res->length = entry.length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// API
|
||||
|
||||
size_t emx_resources_read(ResAppNum app_num,
|
||||
uint32_t resource_id,
|
||||
uint32_t offset,
|
||||
uint8_t *buf,
|
||||
size_t num_bytes) {
|
||||
if (offset > INT_MAX || num_bytes > INT_MAX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
EmxCustomResource *custom_res = NULL;
|
||||
if (app_num != SYSTEM_APP && (custom_res = prv_custom_resource_get(resource_id))) {
|
||||
return custom_res->read(offset, buf, num_bytes);
|
||||
}
|
||||
|
||||
Resource resource = {};
|
||||
if (!prv_get_resource(resource_id, &resource)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (offset + num_bytes > resource.length) {
|
||||
if (offset >= resource.length) {
|
||||
// Can't recover from trying to read from beyond the resource. Read nothing.
|
||||
printf("%s: Reading past the end of the resource!\n", __FILE__);
|
||||
return 0;
|
||||
}
|
||||
num_bytes = resource.length - offset;
|
||||
}
|
||||
|
||||
return prv_read(offset + resource.offset, buf, num_bytes);
|
||||
}
|
||||
|
||||
size_t emx_resources_get_size(ResAppNum app_num, uint32_t resource_id) {
|
||||
EmxCustomResource *custom_res = NULL;
|
||||
if (app_num != SYSTEM_APP && (custom_res = prv_custom_resource_get(resource_id))) {
|
||||
return custom_res->get_size();
|
||||
}
|
||||
|
||||
Resource resource = {};
|
||||
if (!prv_get_resource(resource_id, &resource)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return resource.length;
|
||||
}
|
||||
|
||||
bool emx_resources_init(void) {
|
||||
s_resource_file = fopen("system_resources.pbpack", "r");
|
||||
|
||||
if (!s_resource_file) {
|
||||
printf("Error: Failed to open resources file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void emx_resources_deinit(void) {
|
||||
fclose(s_resource_file);
|
||||
}
|
||||
|
||||
uint32_t emx_resources_register_custom(ResourceReadCb read_cb, ResourceGetSizeCb get_size_cb) {
|
||||
EmxCustomResource custom_res = {
|
||||
.resource_id = ++s_custom_res_list.last_id,
|
||||
.read = read_cb,
|
||||
.get_size = get_size_cb,
|
||||
};
|
||||
prv_custom_resource_add(&custom_res);
|
||||
|
||||
return custom_res.resource_id;
|
||||
}
|
||||
|
||||
void emx_resources_remove_custom(uint32_t resource_id) {
|
||||
prv_custom_resource_remove(resource_id);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue