Skip to content

Commit

Permalink
Add OBF reader and writer
Browse files Browse the repository at this point in the history
  • Loading branch information
IvanoBilenchi committed Jan 12, 2025
1 parent 1941329 commit 7ea4c45
Show file tree
Hide file tree
Showing 11 changed files with 1,899 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:
- name: Configure CMake
run: >
CC=clang cmake -B ${{env.build_dir}}
-DCOWL_READERS='functional;obf'
-DCOWL_WRITERS='functional;obf'
-DCOWL_LTO=OFF
-DCOWL_CLANG_TIDY=ON
-DCMAKE_COMPILE_WARNING_AS_ERROR=ON
Expand Down Expand Up @@ -72,6 +74,8 @@ jobs:
-DULIB_SANITIZERS=ON
-DULIB_LIBRARY_TYPE=${{matrix.lib_type}}
-DCOWL_LIBRARY_TYPE=${{matrix.lib_type}}
-DCOWL_READERS='functional;obf'
-DCOWL_WRITERS='functional;obf'
-DCOWL_ENTITY_IDS=ON
-DCOWL_CPP_TESTS=ON
-DCMAKE_COMPILE_WARNING_AS_ERROR=ON
Expand Down
13 changes: 13 additions & 0 deletions include/cowl_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@ CowlReader cowl_reader_functional(void);

#endif // COWL_READER_FUNCTIONAL

#ifdef COWL_READER_OBF

/**
* Returns the OBF syntax reader.
*
* @return OBF syntax reader.
*/
COWL_API
COWL_CONST
CowlReader cowl_reader_obf(void);

#endif // COWL_READER_OBF

/// @}

COWL_END_DECLS
Expand Down
13 changes: 13 additions & 0 deletions include/cowl_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,19 @@ CowlWriter cowl_writer_functional(void);

#endif // COWL_WRITER_FUNCTIONAL

#ifdef COWL_WRITER_OBF

/**
* Returns the OBF syntax writer.
*
* @return OBF syntax writer.
*/
COWL_API
COWL_CONST
CowlWriter cowl_writer_obf(void);

#endif // COWL_WRITER_OBF

/**
* Checks whether the writer supports stream writing.
*
Expand Down
42 changes: 42 additions & 0 deletions src/formats/obf/cowl_obf_constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @author Valerio Di Ceglie
*
* @copyright Copyright (c) 2024 SisInf Lab, Polytechnic University of Bari
* @copyright <http://swot.sisinflab.poliba.it>
* @copyright SPDX-License-Identifier: EPL-2.0
*
* @file
*/

#ifndef COWL_OBF_CONSTANTS_H
#define COWL_OBF_CONSTANTS_H

typedef enum CowlOBFLiteralType {
COWL_OLT_TYPED_LITERAL = 0,
COWL_OLT_STRING_LITERAL,
COWL_OLT_STRING_LITERAL_LANGUAGE
} CowlOBFLiteralType;

#define COWL_OBF_FORMAT_VERSION 1U

#define COWL_OBF_HEADER_IMPORT_OFFSET 0U
#define COWL_OBF_HEADER_ANNOTATION_OFFSET 1U
#define COWL_OBF_HEADER_VERSION_OFFSET 2U
#define COWL_OBF_HEADER_IRI_OFFSET 3U
#define COWL_OBF_HEADER_FORMAT_OFFSET 4U
#define COWL_OBF_HEADER_ANNOTATIONS_BITMASK (1U << COWL_OBF_HEADER_ANNOTATION_OFFSET)
#define COWL_OBF_HEADER_VERSION_BITMASK (1U << COWL_OBF_HEADER_VERSION_OFFSET)
#define COWL_OBF_HEADER_IRI_BITMASK (1U << COWL_OBF_HEADER_IRI_OFFSET)
#define COWL_OBF_HEADER_IMPORT_BITMASK (1U)

#define COWL_OBF_AXIOM_TYPE_SIZE 6U
#define COWL_OBF_AXIOM_ANNOT_OFFSET COWL_OBF_AXIOM_TYPE_SIZE
#define COWL_OBF_AXIOM_UTLITY_OFFSET (COWL_OBF_AXIOM_ANNOT_OFFSET + 1U)
#define COWL_OBF_AXIOM_TYPE_BITMASK ((1U << COWL_OBF_AXIOM_TYPE_SIZE) - 1U)
#define COWL_OBF_AXIOM_ANNOT_BITMASK (1U << COWL_OBF_AXIOM_ANNOT_OFFSET)
#define COWL_OBF_AXIOM_UTILITY_BITMASK (1U << COWL_OBF_AXIOM_UTLITY_OFFSET)

#define COWL_OBF_LITERAL_TYPE_BITMASK 0x03
#define COWL_OBF_STRING_COMPRESSION_OFFSET 2U

#endif // COWL_OBF_CONSTANTS_H
168 changes: 168 additions & 0 deletions src/formats/obf/cowl_obf_map.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/**
* @author Valerio Di Ceglie
*
* @copyright Copyright (c) 2024 SisInf Lab, Polytechnic University of Bari
* @copyright <http://swot.sisinflab.poliba.it>
* @copyright SPDX-License-Identifier: EPL-2.0
*
* @file
*/

#include "cowl_obf_map.h"
#include "cowl.h"
#include "ulib.h"
#include <stddef.h>
#include <stdint.h>

static inline void *uintptr_to_void(uintptr_t ptr) {
// NOLINTBEGIN(performance-no-int-to-ptr)
return (void *)ptr;
// NOLINTEND(performance-no-int-to-ptr)
}

static cowl_ret populate_standard_prefixes(CowlOBFMap *map) {
const CowlVocab *vocab = cowl_vocab();
// Update COWL_OBF_STANDARD_PREFIX_COUNT if you change the number of standard prefixes.
CowlString *ns[] = {
vocab->rdf->ns, vocab->rdfs->ns, vocab->xsd->ns, vocab->owl->ns, vocab->xml->ns,
};
CowlString *prefix[] = {
vocab->rdf->prefix, vocab->rdfs->prefix, vocab->xsd->prefix,
vocab->owl->prefix, vocab->xml->prefix,
};
cowl_ret ret = COWL_OK;
for (ulib_uint i = 0; i < COWL_OBF_STANDARD_PREFIX_COUNT; ++i) {
if ((ret = cowl_obf_map_add_prefix(map, ns[i], prefix[i]))) break;
}
return ret;
}

cowl_ret cowl_obf_map_init(CowlOBFMap *map) {
map->_idx_to_prefix = uvec(CowlObjectPtr);
map->_idx_to_ns = uvec(CowlObjectPtr);
map->_prefix_to_idx = uhmap(CowlObjectTable);
map->_idx_to_id = uvec(CowlObjectPtr);
map->_id_to_idx = uhmap(CowlObjectTable);
cowl_ret ret = populate_standard_prefixes(map);
if (ret) cowl_obf_map_deinit(map);
return ret;
}

void cowl_obf_map_deinit(CowlOBFMap *map) {
uvec_foreach (CowlObjectPtr, &map->_idx_to_prefix, e) {
cowl_release(*e.item);
}
uvec_foreach (CowlObjectPtr, &map->_idx_to_ns, e) {
cowl_release(*e.item);
}
uvec_foreach (CowlObjectPtr, &map->_idx_to_id, e) {
cowl_release(*e.item);
}
uvec_deinit(CowlObjectPtr, &map->_idx_to_id);
uvec_deinit(CowlObjectPtr, &map->_idx_to_prefix);
uvec_deinit(CowlObjectPtr, &map->_idx_to_ns);
uhash_deinit(CowlObjectTable, &map->_prefix_to_idx);
uhash_deinit(CowlObjectTable, &map->_id_to_idx);
}

UVec(CowlObjectPtr) const *cowl_obf_map_get_ids(CowlOBFMap const *map) {
return &map->_idx_to_id;
}

UVec(CowlObjectPtr) const *cowl_obf_map_get_prefixes(CowlOBFMap const *map) {
return &map->_idx_to_prefix;
}

UVec(CowlObjectPtr) const *cowl_obf_map_get_namespaces(CowlOBFMap const *map) {
return &map->_idx_to_ns;
}

CowlString *cowl_obf_map_get_ns(CowlOBFMap const *map, ulib_uint idx) {
return uvec_get(CowlObjectPtr, &map->_idx_to_ns, idx);
}

ulib_uint cowl_obf_map_get_ns_idx(CowlOBFMap const *map, CowlString *namespace) {
uintptr_t idx = (uintptr_t)uhmap_get(CowlObjectTable, &map->_prefix_to_idx, namespace,
uintptr_to_void(COWL_OBF_NOT_FOUND));
return (ulib_uint)idx;
}

CowlIRIOrAnonInd *cowl_obf_map_get_id(CowlOBFMap const *map, ulib_uint idx) {
return uvec_get(CowlObjectPtr, &map->_idx_to_id, idx);
}

ulib_uint cowl_obf_map_get_id_idx(CowlOBFMap const *map, CowlIRIOrAnonInd *id) {
uintptr_t idx = (uintptr_t)uhmap_get(CowlObjectTable, &map->_id_to_idx, id,
uintptr_to_void(COWL_OBF_NOT_FOUND));
return (ulib_uint)idx;
}

cowl_ret cowl_obf_map_add_prefix(CowlOBFMap *map, CowlString *ns, CowlString *prefix) {
ulib_uint tbl_idx;
uhash_ret ret;
ret = uhash_put(CowlObjectTable, &map->_prefix_to_idx, ns, &tbl_idx);
if (ret == UHASH_ERR) return COWL_ERR_MEM;
if (ret == UHASH_PRESENT) return COWL_OK;
if (uvec_push(CowlObjectPtr, &map->_idx_to_prefix, prefix)) goto err_prefix;
if (uvec_push(CowlObjectPtr, &map->_idx_to_ns, ns)) goto err_ns;

ulib_uint index = uvec_count(CowlObjectPtr, &map->_idx_to_prefix) - 1;
uhash_value(CowlObjectTable, &map->_prefix_to_idx, tbl_idx) = uintptr_to_void(index);
cowl_retain(ns);
if (prefix) cowl_retain(prefix);

return COWL_OK;

err_ns:
uvec_pop(CowlObjectPtr, &map->_idx_to_prefix, NULL);
err_prefix:
uhash_delete(CowlObjectTable, &map->_prefix_to_idx, tbl_idx);
return COWL_ERR_MEM;
}

static inline cowl_ret add_iri_ns(CowlOBFMap *map, CowlIRI *iri) {
return cowl_obf_map_add_prefix(map, cowl_iri_get_ns(iri), NULL);
}

cowl_ret cowl_obf_map_add_primitive_fast(CowlOBFMap *map, CowlAnyPrimitive *primitive) {
CowlIRIOrAnonInd *id = cowl_get_iri(primitive);

if (id) {
if (add_iri_ns(map, id)) return COWL_ERR_MEM;
} else {
id = primitive;
}

if (uvec_push(CowlObjectPtr, &map->_idx_to_id, id)) {
return COWL_ERR_MEM;
}

cowl_retain(id);
return COWL_OK;
}

cowl_ret cowl_obf_map_add_primitive(CowlOBFMap *map, CowlAnyPrimitive *primitive) {
CowlIRIOrAnonInd *id = cowl_get_iri(primitive);
bool id_is_iri = true;

if (!id) {
id_is_iri = false;
id = primitive;
}

ulib_uint tbl_idx;
uhash_ret ret = uhash_put(CowlObjectTable, &map->_id_to_idx, id, &tbl_idx);
if (ret == UHASH_ERR) return COWL_ERR_MEM;
if (ret == UHASH_PRESENT) return COWL_OK;

if (uvec_push(CowlObjectPtr, &map->_idx_to_id, id)) {
uhash_delete(CowlObjectTable, &map->_id_to_idx, tbl_idx);
return COWL_ERR_MEM;
}

ulib_uint index = uvec_count(CowlObjectPtr, &map->_idx_to_id) - 1;
uhash_value(CowlObjectTable, &map->_id_to_idx, tbl_idx) = uintptr_to_void(index);
cowl_retain(id);

return id_is_iri ? add_iri_ns(map, id) : COWL_OK;
}
49 changes: 49 additions & 0 deletions src/formats/obf/cowl_obf_map.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @author Valerio Di Ceglie
*
* @copyright Copyright (c) 2024 SisInf Lab, Polytechnic University of Bari
* @copyright <http://swot.sisinflab.poliba.it>
* @copyright SPDX-License-Identifier: EPL-2.0
*
* @file
*/

#ifndef COWL_OBF_MAP_H
#define COWL_OBF_MAP_H

#include "cowl.h"
#include "ulib.h"

typedef struct CowlOBFMap {
UVec(CowlObjectPtr) _idx_to_prefix;
UVec(CowlObjectPtr) _idx_to_ns;
UHash(CowlObjectTable) _prefix_to_idx;
UVec(CowlObjectPtr) _idx_to_id;
UHash(CowlObjectTable) _id_to_idx;
} CowlOBFMap;

typedef void CowlIRIOrAnonInd;

#define COWL_OBF_NOT_FOUND ((ulib_uint)(-1))
#define COWL_OBF_STANDARD_PREFIX_COUNT 5

cowl_ret cowl_obf_map_init(CowlOBFMap *map);
void cowl_obf_map_deinit(CowlOBFMap *map);

UVec(CowlObjectPtr) const *cowl_obf_map_get_ids(CowlOBFMap const *map);
UVec(CowlObjectPtr) const *cowl_obf_map_get_prefixes(CowlOBFMap const *map);
UVec(CowlObjectPtr) const *cowl_obf_map_get_namespaces(CowlOBFMap const *map);

CowlString *cowl_obf_map_get_ns(CowlOBFMap const *map, ulib_uint idx);
ulib_uint cowl_obf_map_get_ns_idx(CowlOBFMap const *map, CowlString *namespace);

CowlIRIOrAnonInd *cowl_obf_map_get_id(CowlOBFMap const *map, ulib_uint idx);
ulib_uint cowl_obf_map_get_id_idx(CowlOBFMap const *map, CowlIRIOrAnonInd *id);

cowl_ret cowl_obf_map_add_primitive(CowlOBFMap *map, CowlAnyPrimitive *primitive);
cowl_ret cowl_obf_map_add_prefix(CowlOBFMap *map, CowlString *ns, CowlString *prefix);

// Only use when decoding, this won't populate the primitive -> index map.
cowl_ret cowl_obf_map_add_primitive_fast(CowlOBFMap *map, CowlAnyPrimitive *primitive);

#endif // COWL_OBF_MAP_H
13 changes: 13 additions & 0 deletions src/formats/obf/reader/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Sources

set(COWL_READER_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(GLOB COWL_READER_SOURCES CONFIGURE_DEPENDS "${COWL_READER_SRC_DIR}/*.c")
list(APPEND COWL_SOURCES ${COWL_READER_SOURCES})

cmake_path(GET COWL_READER_SRC_DIR PARENT_PATH COWL_READER_SRC_DIR)
file(GLOB COWL_READER_SOURCES CONFIGURE_DEPENDS "${COWL_READER_SRC_DIR}/*.c")
list(APPEND COWL_SOURCES ${COWL_READER_SOURCES})

# Propagate changes in the parent project

set(COWL_SOURCES ${COWL_SOURCES} PARENT_SCOPE)
Loading

0 comments on commit 7ea4c45

Please sign in to comment.