The halcc stands for hal compatibility checker.
Tizen hal-apis can specify what feature and version it expects to
hal-backends in manifest file. The halcc library deserializes and
utilizes the information for checking compatibility between
hal-api and hal-backend.
For example, a hal-api specifies what it needs in xml file:
| <!--hal-api-xxx.xml-->
|
| <manifest version="1.0" type="platform" level="2">
| <hal>
| <name>AAA</name>
| <version>3.1</version>
| <transport>passthrough</transport>
| </hal>
| ...
| </manifest>
It means that the hal-api expects and requires hal-backend module name
of AAA, and version of 3.x where x >= 1.
(See semantic versioning, https://semver.org)
These are collected and tested by the halcc library.
Currently only the function below is provieded
- int halcc_check_compatibility(const char *hal_api_manifest_dir,
halcc_compatibility_cb callback, void *user_data)
: It collects manifest files at hal_api_manifest_dir and checks
whether the hal-backends have compatible what hal-apis have
specified. For each specified <hal> in manifests, callback is
invoked.
Change-Id: Ibb16c378f6fbe08750b6df7db99ee6626bcfd033
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/hal-rpmdb-checker.conf
DESTINATION /usr/lib/tmpfiles.d)
+ADD_SUBDIRECTORY(halcc)
+
ADD_SUBDIRECTORY(tests)
ADD_SUBDIRECTORY(tools/lshal)
--- /dev/null
+PROJECT(libhalcc C)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED glib-2.0 libxml-2.0)
+
+FOREACH(flag ${pkgs_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+SET(LIBHALCC_SRCS
+ ./src/hal-compatibility-checker.c
+ ./src/halcc-object.c
+ ./src/halcc-util.c
+ ./src/halcc-parser.c)
+
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${LIBHALCC_SRCS})
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} -ldl hal-api-common)
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-Wno-pointer-sign")
+SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR})
+SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES VERSION ${VERSION})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES OUTPUT_NAME halcc)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIBDIR}/hal)
+INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION ${INCLUDEDIR})
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef __HAL_COMPATIBILITY_CHECKER_H__
+#define __HAL_COMPATIBILITY_CHECKER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <hal-common.h>
+
+typedef enum halcc_compatibility_e {
+ HALCC_INCOMPATIBLE,
+ HALCC_COMPATIBLE,
+} halcc_compatibility_e;
+
+typedef void (*halcc_compatibility_cb) (enum hal_module module,
+ halcc_compatibility_e is_compatible, void *user_data);
+
+int halcc_check_compatibility(const char *hal_api_manifest_dir,
+ halcc_compatibility_cb callback, void *user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__HAL_COMPATIBILITY_CHECKER_H__
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <glib.h>
+
+#include <halcc/hal-compatibility-checker.h>
+#include <hal-common.h>
+
+#include "halcc-object.h"
+#include "halcc-parser.h"
+#include "halcc-util.h"
+
+struct callback_data {
+ halcc_compatibility_cb func;
+ void *user_data;
+};
+
+static int parse_directory(const char *manifest_dir, halcc_manifest *manifest)
+{
+ DIR *dir;
+ int dfd;
+ struct dirent *entry;
+
+ if (!manifest_dir || !manifest)
+ return -EINVAL;
+
+ dir = opendir(manifest_dir);
+ if (!dir) {
+ printf("Failed to opendir '%s', %m\n", manifest_dir);
+ return -errno;
+ }
+
+ dfd = dirfd(dir);
+
+ while ((entry = readdir(dir))) {
+ int fd = -1;
+ int ret;
+
+ if (entry->d_type != DT_REG)
+ continue;
+
+ fd = openat(dfd, entry->d_name, O_RDONLY);
+ if (fd < 0) {
+ printf("Failed to openat(), %m\n");
+ continue;
+ }
+
+ ret = halcc_parse_fd(fd, manifest);
+ if (ret < 0) {
+ printf("Failed to parse xml, ret=%d\n", ret);
+ close(fd);
+ continue;
+ }
+
+ close(fd);
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+static halcc_compatibility_e is_compatible(int major, int minor, unsigned int abi_version)
+{
+ if (abi_version == HAL_ABI_VERSION_UNKNOWN)
+ return HALCC_INCOMPATIBLE;
+
+ return HALCC_COMPATIBLE;
+}
+
+static void foreach_hal(void *data, void *user_data)
+{
+ struct callback_data *callback_data = NULL;
+ enum hal_module module;
+ halcc_hal *hal;
+ const char *hal_name = NULL;
+ int major, minor;
+ halcc_compatibility_e compatible = HALCC_INCOMPATIBLE;
+
+ hal = (halcc_hal *) data;
+ callback_data = (struct callback_data *) user_data;
+
+ assert(hal);
+ assert(callback_data);
+ assert(callback_data->func);
+
+ if (halcc_hal_get_name(hal, &hal_name) < 0 || hal_name == NULL)
+ return;
+
+ if (halcc_hal_get_version(hal, &major, &minor, NULL) < 0)
+ return;
+
+ for (module = HAL_MODULE_UNKNOWN; module < HAL_MODULE_END; ++module) {
+ char module_name[128] = { 0 , };
+ unsigned int abi_version;
+ int ret;
+
+ ret = hal_common_get_backend_module_name(module, module_name, sizeof(module_name));
+ if (ret < 0)
+ continue;
+
+ ret = strncmp(hal_name, module_name, strlen(hal_name) + 1);
+ if (ret != 0)
+ continue;
+
+ abi_version = hal_common_get_backend_abi_version(module);
+ if (abi_version == HAL_ABI_VERSION_UNKNOWN)
+ break;
+
+ compatible = is_compatible(major, minor, abi_version);
+ break;
+ }
+
+ if (module >= HAL_MODULE_END) {
+ printf("Unknown hal module: %s\n", hal_name);
+ return;
+ }
+
+ printf("%s: %s\n", hal_name, compatible ? "Compatible" : "Incompatible");
+
+ callback_data->func(module, compatible, callback_data->user_data);
+}
+
+EXPORT
+int halcc_check_compatibility(const char *hal_api_manifest_dir,
+ halcc_compatibility_cb callback, void *user_data)
+{
+ halcc_manifest *manifest = NULL;
+ struct callback_data callback_data = { 0 , };
+ int ret = 0;
+
+ if (!hal_api_manifest_dir)
+ return -EINVAL;
+
+ if (!callback)
+ return -EINVAL;
+
+ ret = halcc_manifest_new(&manifest);
+ if (ret < 0)
+ return ret;
+
+ ret = parse_directory(hal_api_manifest_dir, manifest);
+ if (ret < 0)
+ goto out;
+
+ callback_data = (struct callback_data) { callback, user_data };
+
+ halcc_manifest_foreach_hal(manifest, foreach_hal, &callback_data);
+
+out:
+ if (manifest)
+ halcc_manifest_free(g_steal_pointer(&manifest));
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glib.h>
+
+#include "halcc-object.h"
+#include "halcc-parser.h"
+#include "halcc-util.h"
+
+#define HALCC_TRANSPORT_DEFAULT HALCC_TRANSPORT_PASSTHROUGH
+
+typedef struct halcc_version {
+ int major;
+ union {
+ /**
+ * Can be used interchangeably.
+ * min_minor might be useful if max_minor is specified.
+ */
+ int minor;
+ int min_minor;
+ };
+ int max_minor;
+} halcc_version;
+
+typedef struct halcc_interface {
+ char *name;
+ char *instance_id;
+} halcc_interface;
+
+typedef struct halcc_hal {
+ char *name;
+ halcc_version version;
+ halcc_transport_e transport;
+ halcc_dependency_state_e dependency_state;
+ GHashTable *dependencies;
+ GHashTable *interfaces;
+} halcc_hal;
+
+typedef struct halcc_manifest {
+ halcc_manifest_type_e manifest_type;
+ halcc_version version;
+ int level;
+ GHashTable *hals;
+} halcc_manifest;
+
+typedef enum halcc_hash_compare_type_e {
+ HALCC_HASH_COMPARE_TYPE_BACKWARD_MINOR_VERSION,
+ HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION,
+ HALCC_HASH_COMPARE_TYPE_FORWARD_MINOR_VERSION,
+} halcc_hash_compare_type_e;
+
+typedef struct hash_hal_key {
+ halcc_hal hal;
+ halcc_hash_compare_type_e compare_type;
+} hash_hal_key;
+
+#define HASH_HAL_KEY(_name, _major, _minor, _compare_type) \
+ (hash_hal_key) { \
+ .hal = { \
+ .name = (char *) _name, \
+ .version.major = _major, \
+ .version.minor = _minor, \
+ }, \
+ .compare_type = _compare_type, \
+ }
+
+#define HASH_HAL_KEY_RAW(_hal, _compare_type) \
+ HASH_HAL_KEY((_hal)->name, \
+ (_hal)->version.major, \
+ (_hal)->version.minor, \
+ _compare_type \
+ )
+
+static void hashtable_foreach(GHashTable *table, halcc_iter_cb cb, void *user_data)
+{
+ GHashTableIter iter;
+ void *data;
+
+ if (!table || !cb)
+ return;
+
+ g_hash_table_iter_init(&iter, table);
+ while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &data))
+ cb(data, user_data);
+}
+
+static guint hal_hash(gconstpointer key)
+{
+ const halcc_hal *hal = (const halcc_hal *) key;
+
+ assert(hal);
+ assert(hal->name);
+
+ return g_str_hash(hal->name);
+}
+
+static gboolean hal_hash_equal(gconstpointer a, gconstpointer b)
+{
+ const halcc_hal *hal = (const halcc_hal *) a;
+ const hash_hal_key *key = (const hash_hal_key *) b;
+ int compare_type;
+
+ assert(hal);
+ assert(key);
+
+ if (strncmp(hal->name, key->hal.name, strlen(hal->name) + 1) != 0)
+ return false;
+
+ if (hal->version.major != key->hal.version.major)
+ return false;
+
+ compare_type = key->compare_type;
+
+ switch (compare_type) {
+ case HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION:
+ return hal->version.minor == key->hal.version.minor;
+ case HALCC_HASH_COMPARE_TYPE_BACKWARD_MINOR_VERSION:
+ return hal->version.minor <= key->hal.version.minor;
+ case HALCC_HASH_COMPARE_TYPE_FORWARD_MINOR_VERSION:
+ return hal->version.minor >= key->hal.version.minor;
+ default:
+ break;
+ }
+
+ assert(0); // unreachable
+
+ return false;
+}
+
+static void hal_hash_value_free(gpointer data)
+{
+ halcc_hal *hal = (halcc_hal *) data;
+
+ halcc_hal_free(hal);
+}
+
+static GHashTable* hashtable_hal_new(void)
+{
+ return g_hash_table_new_full(hal_hash, hal_hash_equal, NULL, hal_hash_value_free);
+}
+
+static int hashtable_hal_insert(GHashTable *hal_table, halcc_hal *hal)
+{
+ hash_hal_key key;
+
+ if (!hal_table || !hal)
+ return -EINVAL;
+
+ key = HASH_HAL_KEY_RAW(hal, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION);
+
+ if (g_hash_table_lookup_extended(hal_table, &key, NULL, NULL))
+ return -EALREADY;
+
+ g_hash_table_insert(hal_table, hal, hal);
+
+ return 0;
+}
+
+static halcc_hal* hashtable_hal_lookup(GHashTable *hal_table,
+ const char *name, int major, int minor, halcc_hash_compare_type_e type)
+{
+ hash_hal_key key;
+
+ if (!hal_table || !name)
+ return NULL;
+
+ key = HASH_HAL_KEY(name, major, minor, type);
+
+ return g_hash_table_lookup(hal_table, &key);
+}
+
+static halcc_hal* hashtable_hal_steal(GHashTable *hal_table, const char *name, int major, int minor)
+{
+ hash_hal_key key;
+ halcc_hal *hal = NULL;
+
+ if (!hal_table || !name)
+ return NULL;
+
+ key = HASH_HAL_KEY(name, major, minor, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION);
+
+ if (!g_hash_table_steal_extended(hal_table, &key, NULL, (gpointer*) &hal))
+ return NULL;
+
+ return hal;
+}
+
+static void hashtable_hal_remove(GHashTable *hal_table, const char *name, int major, int minor)
+{
+ hash_hal_key key;
+
+ if (!hal_table || !name)
+ return;
+
+ key = HASH_HAL_KEY(name, major, minor, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION);
+
+ g_hash_table_remove(hal_table, &key);
+}
+
+static guint interface_hash(gconstpointer key)
+{
+ const halcc_interface *interface = (const halcc_interface *) key;
+ char interface_str[HALCC_NAME_MAX * 2] = { 0 , };
+
+ assert(interface);
+ assert(interface->name);
+
+ if (interface->instance_id)
+ snprintf(interface_str, sizeof(interface_str), "%s.%s", interface->name, interface->instance_id);
+ else
+ snprintf(interface_str, sizeof(interface_str), "%s.default", interface->name);
+
+ return g_str_hash(interface_str);
+}
+
+static gboolean interface_hash_equal(gconstpointer a, gconstpointer b)
+{
+ const halcc_interface *interface = (const halcc_interface *) a;
+ const halcc_interface *key = (const halcc_interface *) b;
+
+ assert(interface);
+ assert(key);
+
+ return strncmp(interface->name, key->name, strlen(interface->name) + 1) == 0;
+}
+
+static void interface_hash_value_free(gpointer data)
+{
+ halcc_interface *interface = (halcc_interface *) data;
+
+ halcc_interface_free(interface);
+}
+
+static GHashTable* hashtable_interface_new(void)
+{
+ return g_hash_table_new_full(interface_hash,
+ interface_hash_equal, NULL, interface_hash_value_free);
+}
+
+static int hashtable_interface_insert(GHashTable *interface_table, halcc_interface *interface)
+{
+ g_hash_table_insert(interface_table, interface, interface);
+
+ return 0;
+}
+
+/*
+static halcc_interface* hashtable_interface_lookup(GHashTable *interface_table,
+ const char *name, const char *instance_id)
+{
+ halcc_interface key;
+
+ if (!interface_table || !name)
+ return NULL;
+
+ key = (halcc_interface) {
+ .name = (char *) name,
+ .instance_id = (char *) instance_id,
+ };
+
+ return g_hash_table_lookup(interface_table, &key);
+}
+*/
+
+static void hashtable_interface_remove(GHashTable *interface_table,
+ const char *name, const char *instance_id)
+{
+ halcc_interface key;
+
+ if (!interface_table || !name)
+ return;
+
+ key = (halcc_interface) {
+ .name = (char *) name,
+ .instance_id = (char *) instance_id,
+ };
+
+ g_hash_table_remove(interface_table, &key);
+}
+
+int halcc_manifest_new(halcc_manifest **manifest)
+{
+ halcc_manifest *m;
+
+ if (!manifest)
+ return -EINVAL;
+
+ m = calloc(1, sizeof(halcc_manifest));
+ if (!m)
+ return -ENOMEM;
+
+ *m = (halcc_manifest) {
+ .manifest_type = HALCC_UNINITIALIZED_INT,
+ .version.major = HALCC_UNINITIALIZED_INT,
+ .version.minor = HALCC_UNINITIALIZED_INT,
+ .level = HALCC_UNINITIALIZED_INT,
+ .hals = hashtable_hal_new(),
+ };
+
+ *manifest = g_steal_pointer(&m);
+
+ return 0;
+}
+
+void halcc_manifest_free(halcc_manifest *manifest)
+{
+ if (!manifest)
+ return;
+
+ g_hash_table_destroy(g_steal_pointer(&manifest->hals));
+
+ free(manifest);
+}
+
+int halcc_manifest_set_type(halcc_manifest *manifest, halcc_manifest_type_e type)
+{
+ if (!manifest)
+ return -EINVAL;
+
+ if (type < HALCC_MANIFEST_TYPE_HAL_API || type > HALCC_MANIFEST_TYPE_HAL_BACKEND)
+ return -EINVAL;
+
+
+ return halcc_util_set_int_once(&manifest->manifest_type, type, "manifest.type");
+}
+
+int halcc_manifest_get_type(halcc_manifest *manifest, halcc_manifest_type_e *type)
+{
+ if (!manifest || !type)
+ return -EINVAL;
+
+ *type = manifest->manifest_type;
+
+ return 0;
+}
+
+int halcc_manifest_set_version(halcc_manifest *manifest, int major, int minor)
+{
+ int ret;
+
+ if (!manifest)
+ return -EINVAL;
+
+ if (major < 0 || minor < 0)
+ return -EINVAL;
+
+ ret = halcc_util_set_int_once(&manifest->version.major, major, "manifest.version.major");
+ if (ret != 0)
+ return ret;
+
+ ret = halcc_util_set_int_once(&manifest->version.minor, minor, "manifest.version.minor");
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+int halcc_manifest_get_version(halcc_manifest *manifest, int *major, int *minor)
+{
+ if (!manifest || !major || !minor)
+ return -EINVAL;
+
+ *major = manifest->version.major;
+ *minor = manifest->version.minor;
+
+ return 0;
+}
+
+int halcc_manifest_set_level(halcc_manifest *manifest, int level)
+{
+ if (!manifest)
+ return -EINVAL;
+
+ return halcc_util_set_int_once(&manifest->level, level, "manifest.level");
+}
+
+int halcc_manifest_get_level(halcc_manifest *manifest, int *level)
+{
+ if (!manifest || !level)
+ return -EINVAL;
+
+ *level = manifest->level;
+
+ return 0;
+}
+
+int halcc_manifest_add_hal(halcc_manifest *manifest, halcc_hal *hal)
+{
+ if (!manifest || !hal)
+ return -EINVAL;
+
+ assert(manifest->hals);
+
+ if (!hal->name)
+ return -EINVAL;
+
+ return hashtable_hal_insert(manifest->hals, hal);
+}
+
+int halcc_manifest_find_hal(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor, halcc_hal **hal)
+{
+ halcc_hal *h;
+
+ if (!manifest || !hal_name)
+ return -EINVAL;
+
+ h = hashtable_hal_lookup(manifest->hals,
+ hal_name, major, minor, HALCC_HASH_COMPARE_TYPE_EXACT_MINOR_VERSION);
+ if (!h)
+ return -ENOTSUP;
+
+ if (hal)
+ *hal = g_steal_pointer(&h);
+
+ return 0;
+}
+
+int halcc_manifest_find_hal_raw(halcc_manifest *manifest,
+ halcc_hal *raw, halcc_hal **hal)
+{
+ return halcc_manifest_find_hal(manifest,
+ raw->name, raw->version.major, raw->version.minor, hal);
+}
+
+int halcc_manifest_find_hal_backward_compatible(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor, halcc_hal **hal)
+{
+ halcc_hal *h;
+
+ if (!manifest || !hal_name)
+ return -EINVAL;
+
+ h = hashtable_hal_lookup(manifest->hals,
+ hal_name, major, minor, HALCC_HASH_COMPARE_TYPE_BACKWARD_MINOR_VERSION);
+ if (!h)
+ return -ENOTSUP;
+
+ if (hal)
+ *hal = g_steal_pointer(&h);
+
+ return 0;
+}
+
+int halcc_manifest_find_hal_backward_compatible_raw(halcc_manifest *manifest,
+ halcc_hal *raw, halcc_hal **hal)
+{
+ return halcc_manifest_find_hal_backward_compatible(manifest,
+ raw->name, raw->version.major, raw->version.minor, hal);
+}
+
+int halcc_manifest_find_hal_forward_compatible(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor, halcc_hal **hal)
+{
+ halcc_hal *h;
+
+ if (!manifest || !hal_name)
+ return -EINVAL;
+
+ h = hashtable_hal_lookup(manifest->hals,
+ hal_name, major, minor, HALCC_HASH_COMPARE_TYPE_FORWARD_MINOR_VERSION);
+ if (!h)
+ return -ENOTSUP;
+
+ if (hal)
+ *hal = g_steal_pointer(&h);
+
+ return 0;
+}
+
+int halcc_manifest_find_hal_forward_compatible_raw(halcc_manifest *manifest,
+ halcc_hal *raw, halcc_hal **hal)
+{
+ return halcc_manifest_find_hal_forward_compatible(manifest,
+ raw->name, raw->version.major, raw->version.minor, hal);
+}
+
+int halcc_manifest_steal_hal(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor, halcc_hal **hal)
+{
+ halcc_hal *h = NULL;
+
+ if (!manifest || !hal_name)
+ return -EINVAL;
+
+ h = hashtable_hal_steal(manifest->hals, hal_name, major, minor);
+ if (!h)
+ return -ENOTSUP;
+
+ if (hal)
+ *hal = g_steal_pointer(&h);
+
+ return 0;
+}
+
+void halcc_manifest_remove_hal(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor)
+{
+ if (!manifest || !hal_name)
+ return;
+
+ hashtable_hal_remove(manifest->hals, hal_name, major, minor);
+}
+
+void halcc_manifest_foreach_hal(halcc_manifest *manifest,
+ halcc_iter_cb cb, void *user_data)
+{
+ if (!manifest || !manifest->hals || !cb)
+ return;
+
+ hashtable_foreach(manifest->hals, cb, user_data);
+}
+
+int halcc_hal_new(halcc_hal **hal)
+{
+ halcc_hal *h;
+
+ if (!hal)
+ return -EINVAL;
+
+ h = calloc(1, sizeof(halcc_hal));
+ if (!h)
+ return -ENOMEM;
+
+ h->transport = HALCC_TRANSPORT_DEFAULT;
+ h->dependency_state = HALCC_DEPENDENCY_STATE_NONE;
+ h->dependencies = hashtable_hal_new();
+ h->interfaces = hashtable_interface_new();
+
+ *hal = g_steal_pointer(&h);
+
+ return 0;
+}
+
+void halcc_hal_free(halcc_hal *hal)
+{
+ if (!hal)
+ return;
+
+ free(g_steal_pointer(&hal->name));
+ g_hash_table_destroy(g_steal_pointer(&hal->dependencies));
+ g_hash_table_destroy(g_steal_pointer(&hal->interfaces));
+ free(hal);
+}
+
+int halcc_hal_set_name(halcc_hal *hal, const char *hal_name)
+{
+ char *n;
+
+ if (!hal)
+ return -EINVAL;
+
+ if (hal->name)
+ free(g_steal_pointer(&hal->name));
+
+ if (!hal_name)
+ return 0;
+
+ n = strndup(hal_name, HALCC_NAME_MAX);
+ if (!n)
+ return -ENOMEM;
+
+ hal->name = g_steal_pointer(&n);
+
+ return 0;
+}
+
+int halcc_hal_get_name(halcc_hal *hal, const char **hal_name)
+{
+ if (!hal || !hal_name)
+ return -EINVAL;
+
+ *hal_name = hal->name;
+
+ return 0;
+}
+
+int halcc_hal_set_version(halcc_hal *hal, int major, int min_minor, int max_minor)
+{
+ if (!hal)
+ return -EINVAL;
+
+ hal->version.major = major;
+ hal->version.min_minor = min_minor;
+ hal->version.max_minor = max_minor;
+
+ return 0;
+}
+
+int halcc_hal_get_version(halcc_hal *hal, int *major, int *min_minor, int *max_minor)
+{
+ if (!hal || !major || !min_minor)
+ return -EINVAL;
+
+ *major = hal->version.major;
+ *min_minor = hal->version.min_minor;
+ if (max_minor)
+ *max_minor = hal->version.max_minor;
+
+ return 0;
+}
+
+int halcc_hal_set_transport(halcc_hal *hal, halcc_transport_e transport)
+{
+ if (!hal)
+ return -EINVAL;
+
+ hal->transport = transport;
+
+ return 0;
+}
+
+int halcc_hal_get_transport(halcc_hal *hal, halcc_transport_e *transport)
+{
+ if (!hal || !transport)
+ return -EINVAL;
+
+ assert(hal->transport >= HALCC_TRANSPORT_PASSTHROUGH);
+ assert(hal->transport <= HALCC_TRANSPORT_IPC);
+
+ *transport = hal->transport;
+
+ return 0;
+}
+
+int halcc_hal_add_dependency(halcc_hal *hal, halcc_hal *dependency)
+{
+ if (!hal || !dependency)
+ return -EINVAL;
+
+ return hashtable_hal_insert(hal->dependencies, dependency);
+}
+
+void halcc_hal_remove_dependency(halcc_hal *hal,
+ const char *dependency_hal_name, int major, int minor)
+{
+ if (!hal || !dependency_hal_name)
+ return;
+
+ hashtable_hal_remove(hal->dependencies, dependency_hal_name, major, minor);
+}
+
+void halcc_hal_foreach_dependency(halcc_hal *hal, halcc_iter_cb cb, void *user_data)
+{
+ if (!hal || !hal->dependencies || !cb)
+ return;
+
+ hashtable_foreach(hal->dependencies, cb, user_data);
+}
+
+int halcc_hal_add_interface(halcc_hal *hal, halcc_interface *interface)
+{
+ if (!hal || !interface)
+ return -EINVAL;
+
+ return hashtable_interface_insert(hal->interfaces, interface);
+}
+
+void halcc_hal_remove_interface(halcc_hal *hal,
+ const char *interface_name, const char *instance_id)
+{
+ if (!hal || !interface_name)
+ return;
+
+ hashtable_interface_remove(hal->interfaces, interface_name, instance_id);
+}
+
+void halcc_hal_foreach_interface(halcc_hal *hal, halcc_iter_cb cb, void *user_data)
+{
+ if (!hal || !hal->interfaces || !cb)
+ return;
+
+ hashtable_foreach(hal->interfaces, cb, user_data);
+}
+
+int halcc_interface_new(halcc_interface **interface)
+{
+ halcc_interface *iface;
+
+ if (!interface)
+ return -EINVAL;
+
+ iface = calloc(1, sizeof(halcc_interface));
+ if (!iface)
+ return -ENOMEM;
+
+ *interface = g_steal_pointer(&iface);
+
+ return 0;
+}
+
+void halcc_interface_free(halcc_interface *interface)
+{
+ if (!interface)
+ return;
+
+ free(g_steal_pointer(&interface->name));
+ free(g_steal_pointer(&interface->instance_id));
+ free(g_steal_pointer(&interface));
+}
+
+int halcc_interface_set_name(halcc_interface *interface, const char *interface_name)
+{
+ char *n;
+
+ if (!interface || !interface_name)
+ return -EINVAL;
+
+ n = strndup(interface_name, HALCC_NAME_MAX);
+ if (!n)
+ return -ENOMEM;
+
+ interface->name = g_steal_pointer(&n);
+
+ return 0;
+}
+
+int halcc_interface_get_name(halcc_interface *interface, const char **interface_name)
+{
+ if (!interface || !interface_name)
+ return -EINVAL;
+
+ *interface_name = interface->name;
+
+ return 0;
+}
+
+int halcc_interface_set_instance_id(halcc_interface *interface, const char *instance_id)
+{
+ char *id = NULL;
+
+ if (!interface || !instance_id)
+ return -EINVAL;
+
+ id = strndup(instance_id, HALCC_NAME_MAX);
+ if (!id)
+ return -ENOMEM;
+
+ interface->instance_id = g_steal_pointer(&id);
+
+ return 0;
+}
+
+int halcc_interface_get_instance_id(halcc_interface *interface, const char **instance_id)
+{
+ if (!interface || !instance_id)
+ return -EINVAL;
+
+ *instance_id = interface->instance_id;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef __HALCC_OBJECT_H__
+#define __HALCC_OBJECT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <glib.h>
+
+typedef enum halcc_manifest_type_e {
+ HALCC_MANIFEST_TYPE_NONE = 0,
+ HALCC_MANIFEST_TYPE_HAL_API,
+ HALCC_MANIFEST_TYPE_HAL_BACKEND,
+} halcc_manifest_type_e;
+
+typedef enum halcc_transport_e {
+ HALCC_TRANSPORT_NONE = 0,
+ HALCC_TRANSPORT_PASSTHROUGH,
+ HALCC_TRANSPORT_IPC,
+} halcc_transport_e;
+
+typedef enum halcc_dependency_state_e {
+ HALCC_DEPENDENCY_STATE_NONE = 0,
+ HALCC_DEPENDENCY_STATE_VALIDATING,
+ HALCC_DEPENDENCY_STATE_SUCCESS,
+ HALCC_DEPENDENCY_STATE_FAIL,
+} halcc_dependency_state_e;
+
+typedef struct halcc_manifest halcc_manifest;
+typedef struct halcc_hal halcc_hal;
+typedef struct halcc_interface halcc_interface;
+
+typedef void (*halcc_iter_cb) (void *, void *);
+
+int halcc_manifest_new(halcc_manifest **manifest);
+void halcc_manifest_free(halcc_manifest *manifest);
+int halcc_manifest_set_type(halcc_manifest *manifest, halcc_manifest_type_e type);
+int halcc_manifest_get_type(halcc_manifest *manifest, halcc_manifest_type_e *type);
+int halcc_manifest_set_version(halcc_manifest *manifest, int major, int minor);
+int halcc_manifest_get_version(halcc_manifest *manifest, int *major, int *minor);
+int halcc_manifest_set_level(halcc_manifest *manifest, int level);
+int halcc_manifest_get_level(halcc_manifest *manifest, int *level);
+int halcc_manifest_add_hal(halcc_manifest *manifest, halcc_hal *hal);
+int halcc_manifest_find_hal(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor, halcc_hal **hal);
+int halcc_manifest_find_hal_raw(halcc_manifest *manifest,
+ halcc_hal *raw, halcc_hal **hal);
+int halcc_manifest_find_hal_backward_compatible(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor, halcc_hal **hal);
+int halcc_manifest_find_hal_backward_compatible_raw(halcc_manifest *manifest,
+ halcc_hal *raw, halcc_hal **hal);
+int halcc_manifest_find_hal_forward_compatible(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor, halcc_hal **hal);
+int halcc_manifest_find_hal_forward_compatible_raw(halcc_manifest *manifest,
+ halcc_hal *raw, halcc_hal **hal);
+int halcc_manifest_steal_hal(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor, halcc_hal **hal);
+void halcc_manifest_remove_hal(halcc_manifest *manifest,
+ const char *hal_name, int major, int minor);
+void halcc_manifest_foreach_hal(halcc_manifest *manifest,
+ halcc_iter_cb cb, void *user_data);
+
+int halcc_hal_new(halcc_hal **hal);
+void halcc_hal_free(halcc_hal *hal);
+int halcc_hal_set_name(halcc_hal *hal, const char *hal_name);
+int halcc_hal_get_name(halcc_hal *hal, const char **hal_name);
+int halcc_hal_set_version(halcc_hal *hal, int major, int min_minor, int max_minor);
+int halcc_hal_get_version(halcc_hal *hal, int *major, int *min_minor, int *max_minor);
+int halcc_hal_set_transport(halcc_hal *hal, halcc_transport_e transport);
+int halcc_hal_get_transport(halcc_hal *hal, halcc_transport_e *transport);
+int halcc_hal_add_dependency(halcc_hal *hal, halcc_hal *dependency);
+void halcc_hal_remove_dependency(halcc_hal *hal,
+ const char *dependency_hal_name, int major, int minor);
+void halcc_hal_foreach_dependency(halcc_hal *hal, halcc_iter_cb cb, void *user_data);
+int halcc_hal_add_interface(halcc_hal *hal, halcc_interface *interface);
+void halcc_hal_remove_interface(halcc_hal *hal,
+ const char *interface_name, const char *instance_id);
+void halcc_hal_foreach_interface(halcc_hal *hal, halcc_iter_cb cb, void *user_data);
+
+int halcc_interface_new(halcc_interface **interface);
+void halcc_interface_free(halcc_interface *interface);
+int halcc_interface_set_name(halcc_interface *interface, const char *interface_name);
+int halcc_interface_get_name(halcc_interface *interface, const char **interface_name);
+int halcc_interface_set_instance_id(halcc_interface *interface, const char *instance_id);
+int halcc_interface_get_instance_id(halcc_interface *interface, const char **instance_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __HALCC_OBJECT_H__
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+
+#include "halcc-object.h"
+#include "halcc-parser.h"
+#include "halcc-util.h"
+
+#define HALCC_DESERIALIZER_VERSION_MAJOR 1
+#define HALCC_DESERIALIZER_VERSION_MINOR 0
+
+#define __xmlchar__ __attribute__((__cleanup__(free_xmlstr)))
+
+static void free_xmlstr(unsigned char **str)
+{
+ xmlFree(*str);
+}
+
+static int parse_interface(xmlNode *node, halcc_interface *interface)
+{
+ assert(node);
+ assert(interface);
+
+ if (!xmlStrEqual(node->name, "interface")) {
+ printf("Invalid interface node, %s\n", node->name);
+ return -EINVAL;
+ }
+
+ for (xmlNode *child = node->children; child; child = child->next) {
+ if (xmlStrEqual(child->name, "name")) {
+ __xmlchar__ xmlChar *name = xmlNodeGetContent(child);
+ halcc_interface_set_name(interface, name);
+ } else if (xmlStrEqual(child->name, "instance")) {
+ __xmlchar__ xmlChar *instance = xmlNodeGetContent(child);
+ halcc_interface_set_instance_id(interface, (char *) instance);
+ }
+ }
+
+ return 0;
+}
+
+static int parse_hal(xmlNode *node, halcc_hal *hal)
+{
+ int ret = 0;
+
+ assert(node);
+ assert(hal);
+
+ if (!xmlStrEqual(node->name, "hal")) {
+ printf("Invalid hal node, %s\n", node->name);
+ return -EINVAL;
+ }
+
+ for (xmlNode *child = node->children; child; child = child->next) {
+ if (xmlStrEqual(child->name, "name")) {
+ __xmlchar__ xmlChar *name = xmlNodeGetContent(child);
+
+ ret = halcc_hal_set_name(hal, name);
+ if (ret != 0)
+ printf("Failed to halcc_hal_set_name(), name=%s, ret=%d\n", name, ret);
+ } else if (xmlStrEqual(child->name, "version")) {
+ int major, min_minor, max_minor;
+ int scanned;
+ __xmlchar__ xmlChar *version = xmlNodeGetContent(child);
+
+ scanned = sscanf(version, "%d.%d-%d", &major, &min_minor, &max_minor);
+ switch (scanned) {
+ case 2: // 3.5 is equal to 3.5-5
+ max_minor = min_minor;
+ ret = halcc_hal_set_version(hal, major, min_minor, max_minor);
+ break;
+ case 3: // 3.5-8
+ ret = halcc_hal_set_version(hal, major, min_minor, max_minor);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret != 0)
+ printf("Failed to halcc_hal_set_version(), ret=%d\n", ret);
+ } else if (xmlStrEqual(child->name, "transport")) {
+ __xmlchar__ xmlChar *transport = xmlNodeGetContent(child);
+
+ if (xmlStrEqual(transport, "passthrough"))
+ ret = halcc_hal_set_transport(hal, HALCC_TRANSPORT_PASSTHROUGH);
+ else if (xmlStrEqual(transport, "IPC"))
+ ret = halcc_hal_set_transport(hal, HALCC_TRANSPORT_IPC);
+ else
+ ret = -EINVAL;
+
+ if (ret != 0)
+ printf("Failed to halcc_hal_set_transport(), %s, ret=%d\n", transport, ret);
+ } else if (xmlStrEqual(child->name, "interface")) {
+ halcc_interface *iface;
+
+ ret = halcc_interface_new(&iface);
+ if (ret != 0) {
+ printf("Failed to halcc_interface_new(), ret=%d\n", ret);
+ continue;
+ }
+
+ ret = parse_interface(child, iface);
+ if (ret != 0) {
+ printf("Failed to parse_interface(), ret=%d\n", ret);
+ halcc_interface_free(iface);
+ continue;
+ }
+
+ halcc_hal_add_interface(hal, iface);
+ iface = NULL;
+ } else if (xmlStrEqual(child->name, "dependency")) {
+ for (xmlNode *grand_child = child->children; grand_child; grand_child = grand_child->next) {
+ halcc_hal *h;
+
+ if (!xmlStrEqual(grand_child->name, "hal"))
+ continue;
+
+ ret = halcc_hal_new(&h);
+ if (ret != 0)
+ continue;
+
+ ret = parse_hal(grand_child, h);
+ if (ret != 0) {
+ halcc_hal_free(h);
+ h = NULL;
+ continue;
+ }
+
+ halcc_hal_add_dependency(hal, h);
+ h = NULL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int parse_manifest(xmlNode *node, halcc_manifest *manifest)
+{
+ int ret;
+ xmlChar *prop;
+ int major;
+ int minor;
+ int level;
+
+ assert(node);
+ assert(manifest);
+
+ if (!xmlStrEqual(node->name, "manifest")) {
+ printf("Invalid manifest node, %s\n", node->name);
+ return -EINVAL;
+ }
+
+ // version
+ prop = xmlGetProp(node, "version");
+ if (!prop) {
+ printf("Failed to xmlGetProp() \"version\"\n");
+ return -EINVAL;
+ }
+
+ ret = sscanf(prop, "%d.%d", &major, &minor);
+ xmlFree(prop);
+
+ if (ret != 2) {
+ printf("Failed to scan version, ret=%d\n", ret);
+ return -EINVAL;
+ }
+
+ if (major != HALCC_DESERIALIZER_VERSION_MAJOR || minor != HALCC_DESERIALIZER_VERSION_MINOR) {
+ printf("Manifest scheme doesn't match. Requires manifest version %d.%d\n",
+ HALCC_DESERIALIZER_VERSION_MAJOR, HALCC_DESERIALIZER_VERSION_MINOR);
+ return -ENOTSUP;
+ }
+
+ ret = halcc_manifest_set_version(manifest, major, minor);
+ if (ret != 0) {
+ printf("Failed to halcc_manifest_set_version(), ret=%d\n", ret);
+ return -EINVAL;
+ }
+
+ // type
+ prop = xmlGetProp(node, "type");
+ if (!prop) {
+ printf("Failed to xmlGetProp() \"type\"\n");
+ return -EINVAL;
+ }
+
+ if (xmlStrEqual(prop, "platform")) {
+ ret = halcc_manifest_set_type(manifest, HALCC_MANIFEST_TYPE_HAL_API);
+ if (ret != 0)
+ printf("Failed to halcc_manifest_set_type() HALCC_MANIFEST_TYPE_HAL_API, ret=%d\n", ret);
+ } else if (xmlStrEqual(prop, "device")) {
+ ret = halcc_manifest_set_type(manifest, HALCC_MANIFEST_TYPE_HAL_BACKEND);
+ if (ret != 0)
+ printf("Failed to halcc_manifest_set_type() HALCC_MANIFEST_TYPE_HAL_BACKEND, ret=%d\n", ret);
+ } else {
+ printf("Invalid type property=%s\n", prop);
+ ret = -EINVAL;
+ }
+
+ xmlFree(prop);
+
+ if (ret != 0)
+ return ret;
+
+ // level
+ prop = xmlGetProp(node, "level");
+ if (!prop) {
+ printf("Failed to xmlGetProp() \"level\"\n");
+ return -EINVAL;
+ }
+
+ ret = sscanf(prop, "%d", &level);
+ xmlFree(prop);
+
+ if (ret != 1) {
+ printf("Failed to scan manifest level\n");
+ return -EINVAL;
+ }
+
+ ret = halcc_manifest_set_level(manifest, level);
+ if (ret != 0) {
+ printf("Failed to halcc_manifest_set_level(), ret=%d\n", ret);
+ return ret;
+ }
+
+ for (xmlNode *child = node->children; child; child = child->next) {
+ halcc_hal *h;
+
+ if (!xmlStrEqual(child->name, "hal"))
+ continue;
+
+ ret = halcc_hal_new(&h);
+ if (ret != 0) {
+ printf("Failed to halcc_hal_new(), ret=%d\n", ret);
+ continue;
+ }
+
+ ret = parse_hal(child, h);
+ if (ret != 0) {
+ printf("Failed to parse_hal(), ret=%d\n", ret);
+ halcc_hal_free(h);
+ h = NULL;
+ continue;
+ }
+
+ halcc_manifest_add_hal(manifest, h);
+ h = NULL;
+ }
+
+ return 0;
+}
+
+
+static int parse_xml_doc(xmlDoc *doc, halcc_manifest *manifest)
+{
+ xmlNode *root = NULL;
+ int ret;
+
+ if (!doc || !manifest)
+ return -EINVAL;
+
+ root = xmlDocGetRootElement(doc);
+ if (!root) {
+ printf("Failed to get root element\n");
+ return -EINVAL;
+ }
+
+ ret = parse_manifest(root, manifest);
+ if (ret != 0) {
+ printf("Failed to parse_manifest(), ret=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int halcc_parse_fd(int fd, halcc_manifest *manifest)
+{
+ xmlDoc *doc = NULL;
+ int ret = 0;
+
+ if (!manifest) {
+ printf("Invalid manifest\n");
+ return -EINVAL;
+ }
+
+ doc = xmlReadFd(fd, NULL, NULL, 0);
+ if (!doc) {
+ printf("Failed to read doc %d\n", fd);
+ return -ENOENT;
+ }
+
+ ret = parse_xml_doc(doc, manifest);
+
+ xmlFreeDoc(doc);
+
+ return ret;
+}
+
+int halcc_parse_path(const char *filepath, halcc_manifest *manifest)
+{
+ xmlDoc *doc = NULL;
+ int ret = 0;
+
+ if (!filepath || !manifest) {
+ printf("Invalid filepath or manifest\n");
+ return -EINVAL;
+ }
+
+ doc = xmlReadFile(filepath, NULL, 0);
+ if (!doc) {
+ printf("Failed to read doc %s\n", filepath);
+ return -ENOENT;
+ }
+
+ ret = parse_xml_doc(doc, manifest);
+
+ xmlFreeDoc(doc);
+
+ return ret;
+}
+
+int halcc_parse_string(const char *string, int len, halcc_manifest *manifest)
+{
+ xmlDoc *doc = NULL;
+ int ret = 0;
+
+ if (!string || !manifest) {
+ printf("Invalid string or manifest\n");
+ return -EINVAL;
+ }
+
+ doc = xmlReadMemory(string, len, NULL, NULL, 0);
+ if (!doc) {
+ printf("Failed to read xml string\n");
+ return -ENOENT;
+ }
+
+ ret = parse_xml_doc(doc, manifest);
+
+ xmlFreeDoc(doc);
+
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef __HALCC_PARSER_H__
+#define __HALCC_PARSER_H__
+
+#include "halcc-object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int halcc_parse_fd(int fd, halcc_manifest *manifest);
+int halcc_parse_path(const char *filepath, halcc_manifest *manifest);
+int halcc_parse_string(const char *string, int len, halcc_manifest *manifest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __HALCC_PARSER_H__
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+
+#include "halcc-util.h"
+
+int halcc_util_set_int_once(void *buf, int value, const char *buf_desc)
+{
+ int old_value;
+
+ if (!buf)
+ return -EINVAL;
+
+ old_value = *(int *) buf;
+
+ if (old_value != HALCC_UNINITIALIZED_INT && old_value != value) {
+ printf("Cannot modify initialized value, %s, %d to %d\n",
+ buf_desc ? : "Unknown", old_value, value);
+ return -EALREADY;
+ }
+
+ *(int *) buf = value;
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef __HALCC_UTIL_H__
+#define __HALCC_UTIL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EXPORT __attribute__((visibility("default")))
+#define HALCC_NAME_MAX 128
+#define HALCC_UNINITIALIZED_INT (-1)
+
+/**
+ * Modifies buffer pointed by 'buf' to 'value' only when the buffer
+ * has value of HALCC_UNINITIALIZED_INT. Once it has changed to value other
+ * than HALCC_UNINITIALIZED_INT and trying to change the value, the buffer
+ * remains unchanged and this function returns -EALREADY.
+ */
+int halcc_util_set_int_once(void *buf, int value, const char *buf_desc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __HALCC_UTIL_H__
prefix=@PREFIX@
exec_prefix=@EXEC_PREFIX@/hal
libdir=@LIBDIR@/hal
-includedir=@INCLUDEDIR@/hal
+include_halapi_dir=@INCLUDEDIR@/hal
+include_halcc_dir=@INCLUDEDIR@/halcc
Name: ${package_name}
Description: ${package_name} interface
Version: @VERSION@
Requires:
-Libs: -L${libdir} -l${package_name}
-Cflags: -I${includedir}
-CXXflags: -I${includedir}
+Libs: -L${libdir} -l${package_name} -lhalcc
+Cflags: -I${include_halapi_dir} -I${include_halcc_dir}
+CXXflags: -I${include_halapi_dir} -I${include_halcc_dir}
BuildRequires: pkgconfig(dlog)
BuildRequires: pkgconfig(gio-2.0)
BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(libxml-2.0)
BuildRequires: pkgconfig(gmock)
BuildRequires: pkgconfig(systemd)
%files -n %{devel_name}
%defattr(-,root,root,-)
%{_includedir}/hal/*.h
+%{_includedir}/halcc/*.h
%{_libdir}/pkgconfig/*.pc
%{_sysconfdir}/rpm/macros.hal-api
ENABLE_TESTING()
SET(HAL_API_COMMON_UNITTEST "hal-api-common-unittest")
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Werror")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Werror -Wno-pointer-sign")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++14 -Wall -Werror")
+#INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/halcc/include)
+
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ UNITTEST_SRCS)
-ADD_EXECUTABLE(${HAL_API_COMMON_UNITTEST} ${UNITTEST_SRCS})
+AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/halcc/src/ LIBHALCC_SRCS)
+ADD_EXECUTABLE(${HAL_API_COMMON_UNITTEST} ${UNITTEST_SRCS} ${LIBHALCC_SRCS})
TARGET_INCLUDE_DIRECTORIES(${HAL_API_COMMON_UNITTEST} PUBLIC
- "${CMAKE_CURRENT_SOURCE_DIR}/../../include"
+ "${CMAKE_SOURCE_DIR}/include"
+ "${CMAKE_SOURCE_DIR}/halcc/include"
)
INCLUDE(FindPkgConfig)
-pkg_check_modules(hal_api_common_unittest_pkgs REQUIRED gmock)
+pkg_check_modules(hal_api_common_unittest_pkgs REQUIRED gmock glib-2.0 libxml-2.0)
FOREACH(flag ${hal_api_common_unittest_pkgs_CFLAGS})
SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <string.h>
+#include <gtest/gtest.h>
+
+#include <halcc/hal-compatibility-checker.h>
+#include "../../halcc/src/halcc-object.h"
+#include "../../halcc/src/halcc-parser.h"
+
+using namespace std;
+
+static char g_manifest_xml[] =
+"<manifest version=\"1.0\" type=\"platform\" level=\"7\">"
+" <hal>"
+" <name>hal.device.display</name>"
+" <version>1.5</version>"
+" <transport>passthrough</transport>"
+" <interface>"
+" <name>hal_backend_device_display_data</name>"
+" </interface>"
+" <dependency>"
+" <hal>"
+" <name>hal.device.board</name>"
+" <version>1.0</version>"
+" <transport>passthrough</transport>"
+" <interface>"
+" <name>hal_backend_device_board_data</name>"
+" </interface>"
+" </hal>"
+" <hal>"
+" <name>hal.tdm</name>"
+" <version>1.0</version>"
+" <transport>passthrough</transport>"
+" <interface>"
+" <name>hal_backend_tdm_data</name>"
+" </interface>"
+" </hal>"
+" </dependency>"
+" </hal>"
+" <hal>"
+" <name>hal.something</name>"
+" <version>2.34</version>"
+" <transport>passthrough</transport>"
+" <interface>"
+" <name>hal_backend_something_data</name>"
+" </interface>"
+" </hal>"
+" <hal>"
+" <name>hal.test</name>"
+" <version>4.8</version>"
+" <transport>passthrough</transport>"
+" <interface>"
+" <name>hal_backend_test_data</name>"
+" </interface>"
+" </hal>"
+"</manifest>";
+
+class HalccObjectTest : public ::testing::Test
+{
+ protected:
+ static void SetUpTestSuite() {
+ int ret;
+
+ ret = halcc_manifest_new(&g_manifest);
+ ASSERT_EQ(ret, 0);
+
+ ret = halcc_parse_string(g_manifest_xml, sizeof(g_manifest_xml), g_manifest);
+ ASSERT_EQ(ret, 0);
+
+ ret = halcc_manifest_find_hal(g_manifest, "hal.test", 4, 8, &g_hal);
+ ASSERT_EQ(ret, 0);
+ }
+
+ static void TearDownTestSuite() {
+ halcc_manifest_free(g_manifest);
+ g_manifest = NULL;
+
+ }
+
+ void SetUp() override {
+
+ }
+
+ void TearDown() override {
+
+ }
+
+ static halcc_manifest *g_manifest;
+ static halcc_hal *g_hal;
+ static halcc_interface *g_interface;
+};
+
+halcc_manifest* HalccObjectTest::g_manifest = NULL;
+halcc_hal* HalccObjectTest::g_hal = NULL;
+halcc_interface* HalccObjectTest::g_interface = NULL;
+
+TEST_F(HalccObjectTest, manifest_get_type)
+{
+ halcc_manifest_type_e type;
+ int ret;
+
+ ret = halcc_manifest_get_type(g_manifest, &type);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(type, HALCC_MANIFEST_TYPE_HAL_API);
+}
+
+TEST_F(HalccObjectTest, manifest_get_version)
+{
+ int major, minor;
+ int ret;
+
+ ret = halcc_manifest_get_version(g_manifest, &major, &minor);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(major, 1);
+ ASSERT_EQ(minor, 0);
+}
+
+TEST_F(HalccObjectTest, manifest_get_level)
+{
+ int level;
+ int ret;
+
+ ret = halcc_manifest_get_level(g_manifest, &level);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(level, 7);
+}
+
+TEST_F(HalccObjectTest, manifest_find_hal_success)
+{
+ halcc_hal *hal = NULL;
+ int ret;
+
+ ret = halcc_manifest_find_hal(g_manifest, "hal.device.display", 1, 5, &hal);
+ ASSERT_EQ(ret, 0);
+}
+
+TEST_F(HalccObjectTest, manifest_find_hal_fail)
+{
+ halcc_hal *hal = NULL;
+ int ret;
+
+ ret = halcc_manifest_find_hal(g_manifest, "hal.device.display", 1, 4, &hal);
+ ASSERT_EQ(ret, -ENOTSUP);
+
+ ret = halcc_manifest_find_hal(g_manifest, "hal.device.display", 1, 6, &hal);
+ ASSERT_EQ(ret, -ENOTSUP);
+
+ ret = halcc_manifest_find_hal(g_manifest, "hal.device.display", 2, 4, &hal);
+ ASSERT_EQ(ret, -ENOTSUP);
+}
+
+TEST_F(HalccObjectTest, manifest_find_hal_backward_compatible_success)
+{
+ halcc_hal *hal = NULL;
+ int ret;
+
+ ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 1, 5, &hal);
+ ASSERT_EQ(ret, 0);
+
+ ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 1, 6, &hal);
+ ASSERT_EQ(ret, 0);
+
+ ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 1, 100, &hal);
+ ASSERT_EQ(ret, 0);
+}
+
+TEST_F(HalccObjectTest, manifest_find_hal_backward_compatible_fail)
+{
+ halcc_hal *hal = NULL;
+ int ret;
+
+ ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 1, 4, &hal);
+ ASSERT_EQ(ret, -ENOTSUP);
+
+ ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 2, 4, &hal);
+ ASSERT_EQ(ret, -ENOTSUP);
+
+ ret = halcc_manifest_find_hal_backward_compatible(g_manifest, "hal.device.display", 2, 5, &hal);
+ ASSERT_EQ(ret, -ENOTSUP);
+}
+
+TEST_F(HalccObjectTest, manifest_find_hal_steal_success)
+{
+ halcc_hal *hal = NULL;
+ const char *hal_name;
+ int major, minor;
+ int ret;
+
+ ret = halcc_manifest_steal_hal(g_manifest, "hal.something", 2, 34, &hal);
+ ASSERT_EQ(ret, 0);
+
+ ret = halcc_hal_get_name(hal, &hal_name);
+ ASSERT_EQ(ret, 0);
+ ASSERT_STREQ(hal_name, "hal.something");
+
+ ret = halcc_hal_get_version(hal, &major, &minor, NULL);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(major, 2);
+ ASSERT_EQ(minor, 34);
+
+ // Shouldn't be there
+ ret = halcc_manifest_find_hal(g_manifest, "hal.something", 2, 34, &hal);
+ ASSERT_EQ(ret, -ENOTSUP);
+
+ ret = halcc_manifest_add_hal(g_manifest, hal);
+ ASSERT_EQ(ret, 0);
+
+ ret = halcc_manifest_find_hal(g_manifest, "hal.something", 2, 34, &hal);
+ ASSERT_EQ(ret, 0);
+
+ ret = halcc_hal_get_name(hal, &hal_name);
+ ASSERT_EQ(ret, 0);
+ ASSERT_STREQ(hal_name, "hal.something");
+
+ ret = halcc_hal_get_version(hal, &major, &minor, NULL);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(major, 2);
+ ASSERT_EQ(minor, 34);
+}