X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=formats%2Fctf%2Fir%2Fevent-types.c;h=74fa30473939440acf5266ce8353dabe7925827a;hb=83509119a945fc77faff869daaf48627e1c4b3fa;hp=0c8eddc000fb9d1db9debefd1065334a28ccb366;hpb=11b0cdc8d08794b52c9b07561fac1abac9b809a9;p=babeltrace.git diff --git a/formats/ctf/ir/event-types.c b/formats/ctf/ir/event-types.c index 0c8eddc0..74fa3047 100644 --- a/formats/ctf/ir/event-types.c +++ b/formats/ctf/ir/event-types.c @@ -1,9 +1,9 @@ /* * event-types.c * - * Babeltrace CTF Writer + * Babeltrace CTF IR - Event Types * - * Copyright 2013 EfficiOS Inc. + * Copyright 2013, 2014 Jérémie Galarneau * * Author: Jérémie Galarneau * @@ -28,7 +28,12 @@ #include #include +#include +#include +#include #include +#include +#include #include #include #include @@ -36,30 +41,40 @@ #include struct range_overlap_query { - int64_t range_start, range_end; + union { + uint64_t _unsigned; + int64_t _signed; + } range_start; + + union { + uint64_t _unsigned; + int64_t _signed; + } range_end; int overlaps; GQuark mapping_name; }; static -void bt_ctf_field_type_integer_destroy(struct bt_ctf_ref *); +void bt_ctf_field_type_destroy(struct bt_object *); static -void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_ref *); +void bt_ctf_field_type_integer_destroy(struct bt_ctf_field_type *); static -void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_ref *); +void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_field_type *); static -void bt_ctf_field_type_structure_destroy(struct bt_ctf_ref *); +void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_field_type *); static -void bt_ctf_field_type_variant_destroy(struct bt_ctf_ref *); +void bt_ctf_field_type_structure_destroy(struct bt_ctf_field_type *); static -void bt_ctf_field_type_array_destroy(struct bt_ctf_ref *); +void bt_ctf_field_type_variant_destroy(struct bt_ctf_field_type *); static -void bt_ctf_field_type_sequence_destroy(struct bt_ctf_ref *); +void bt_ctf_field_type_array_destroy(struct bt_ctf_field_type *); static -void bt_ctf_field_type_string_destroy(struct bt_ctf_ref *); +void bt_ctf_field_type_sequence_destroy(struct bt_ctf_field_type *); +static +void bt_ctf_field_type_string_destroy(struct bt_ctf_field_type *); static -void (* const type_destroy_funcs[])(struct bt_ctf_ref *) = { +void (* const type_destroy_funcs[])(struct bt_ctf_field_type *) = { [CTF_TYPE_INTEGER] = bt_ctf_field_type_integer_destroy, [CTF_TYPE_ENUM] = bt_ctf_field_type_enumeration_destroy, @@ -139,21 +154,80 @@ type_serialize_func const type_serialize_funcs[] = { static void bt_ctf_field_type_integer_set_byte_order(struct bt_ctf_field_type *, - int byte_order); + int byte_order, int set_native); +static +void bt_ctf_field_type_enumeration_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); static void bt_ctf_field_type_floating_point_set_byte_order( - struct bt_ctf_field_type *, int byte_order); + struct bt_ctf_field_type *, int byte_order, int set_native); +static +void bt_ctf_field_type_structure_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); +static +void bt_ctf_field_type_variant_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); +static +void bt_ctf_field_type_array_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); +static +void bt_ctf_field_type_sequence_set_byte_order(struct bt_ctf_field_type *, + int byte_order, int set_native); +/* The set_native flag only set the byte order if it is set to native */ static void (* const set_byte_order_funcs[])(struct bt_ctf_field_type *, - int) = { - [CTF_TYPE_INTEGER] = - bt_ctf_field_type_integer_set_byte_order, + int byte_order, int set_native) = { + [CTF_TYPE_INTEGER] = bt_ctf_field_type_integer_set_byte_order, + [CTF_TYPE_ENUM] = + bt_ctf_field_type_enumeration_set_byte_order, [CTF_TYPE_FLOAT] = bt_ctf_field_type_floating_point_set_byte_order, - [CTF_TYPE_ENUM ... CTF_TYPE_SEQUENCE] = NULL, + [CTF_TYPE_STRUCT] = + bt_ctf_field_type_structure_set_byte_order, + [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_set_byte_order, + [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_set_byte_order, + [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_set_byte_order, + [CTF_TYPE_STRING] = NULL, }; +static +struct bt_ctf_field_type *bt_ctf_field_type_integer_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_structure_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_variant_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_array_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy( + struct bt_ctf_field_type *); +static +struct bt_ctf_field_type *bt_ctf_field_type_string_copy( + struct bt_ctf_field_type *); + +static +struct bt_ctf_field_type *(* const type_copy_funcs[])( + struct bt_ctf_field_type *) = { + [CTF_TYPE_INTEGER] = bt_ctf_field_type_integer_copy, + [CTF_TYPE_ENUM] = bt_ctf_field_type_enumeration_copy, + [CTF_TYPE_FLOAT] = bt_ctf_field_type_floating_point_copy, + [CTF_TYPE_STRUCT] = bt_ctf_field_type_structure_copy, + [CTF_TYPE_VARIANT] = bt_ctf_field_type_variant_copy, + [CTF_TYPE_ARRAY] = bt_ctf_field_type_array_copy, + [CTF_TYPE_SEQUENCE] = bt_ctf_field_type_sequence_copy, + [CTF_TYPE_STRING] = bt_ctf_field_type_string_copy, +}; static void destroy_enumeration_mapping(struct enumeration_mapping *mapping) @@ -164,10 +238,7 @@ void destroy_enumeration_mapping(struct enumeration_mapping *mapping) static void destroy_structure_field(struct structure_field *field) { - if (field->type) { - bt_ctf_field_type_put(field->type); - } - + bt_put(field->type); g_free(field); } @@ -177,8 +248,26 @@ void check_ranges_overlap(gpointer element, gpointer query) struct enumeration_mapping *mapping = element; struct range_overlap_query *overlap_query = query; - if (mapping->range_start <= overlap_query->range_end - && overlap_query->range_start <= mapping->range_end) { + if (mapping->range_start._signed <= overlap_query->range_end._signed + && overlap_query->range_start._signed <= + mapping->range_end._signed) { + overlap_query->overlaps = 1; + overlap_query->mapping_name = mapping->string; + } + + overlap_query->overlaps |= + mapping->string == overlap_query->mapping_name; +} + +static +void check_ranges_overlap_unsigned(gpointer element, gpointer query) +{ + struct enumeration_mapping *mapping = element; + struct range_overlap_query *overlap_query = query; + + if (mapping->range_start._unsigned <= overlap_query->range_end._unsigned + && overlap_query->range_start._unsigned <= + mapping->range_end._unsigned) { overlap_query->overlaps = 1; overlap_query->mapping_name = mapping->string; } @@ -188,19 +277,37 @@ void check_ranges_overlap(gpointer element, gpointer query) } static -void bt_ctf_field_type_init(struct bt_ctf_field_type *type) +gint compare_enumeration_mappings_signed(struct enumeration_mapping **a, + struct enumeration_mapping **b) +{ + return ((*a)->range_start._signed < (*b)->range_start._signed) ? -1 : 1; +} + +static +gint compare_enumeration_mappings_unsigned(struct enumeration_mapping **a, + struct enumeration_mapping **b) +{ + return ((*a)->range_start._unsigned < (*b)->range_start._unsigned) ? -1 : 1; +} + +static +void bt_ctf_field_type_init(struct bt_ctf_field_type *type, int init_bo) { enum ctf_type_id type_id = type->declaration->id; - int ret; assert(type && (type_id > CTF_TYPE_UNKNOWN) && (type_id < NR_CTF_TYPES)); - bt_ctf_ref_init(&type->ref_count); + bt_object_init(type, bt_ctf_field_type_destroy); type->freeze = type_freeze_funcs[type_id]; type->serialize = type_serialize_funcs[type_id]; - ret = bt_ctf_field_type_set_byte_order(type, BT_CTF_BYTE_ORDER_NATIVE); - assert(!ret); + + if (init_bo) { + int ret = bt_ctf_field_type_set_byte_order(type, + BT_CTF_BYTE_ORDER_NATIVE); + assert(!ret); + } + type->declaration->alignment = 1; } @@ -227,18 +334,33 @@ int add_structure_field(GPtrArray *fields, goto end; } - bt_ctf_field_type_get(field_type); + bt_get(field_type); field->name = name_quark; field->type = field_type; g_hash_table_insert(field_name_to_index, (gpointer) (unsigned long) name_quark, (gpointer) (unsigned long) fields->len); g_ptr_array_add(fields, field); - bt_ctf_field_type_freeze(field_type); end: return ret; } +static +void bt_ctf_field_type_destroy(struct bt_object *obj) +{ + struct bt_ctf_field_type *type; + enum ctf_type_id type_id; + + type = container_of(obj, struct bt_ctf_field_type, base); + type_id = type->declaration->id; + if (type_id <= CTF_TYPE_UNKNOWN || + type_id >= NR_CTF_TYPES) { + return; + } + + type_destroy_funcs[type_id](type); +} + BT_HIDDEN int bt_ctf_field_type_validate(struct bt_ctf_field_type *type) { @@ -249,12 +371,40 @@ int bt_ctf_field_type_validate(struct bt_ctf_field_type *type) goto end; } - if (type->declaration->id == CTF_TYPE_ENUM) { + switch (type->declaration->id) { + case CTF_TYPE_ENUM: + { struct bt_ctf_field_type_enumeration *enumeration = container_of(type, struct bt_ctf_field_type_enumeration, parent); + /* Ensure enum has entries */ ret = enumeration->entries->len ? 0 : -1; + break; + } + case CTF_TYPE_SEQUENCE: + { + struct bt_ctf_field_type_sequence *sequence = + container_of(type, struct bt_ctf_field_type_sequence, + parent); + + /* length field name should be set at this point */ + ret = sequence->length_field_name->len ? 0 : -1; + break; + } + case CTF_TYPE_VARIANT: + { + struct bt_ctf_field_type_variant *variant = + container_of(type, struct bt_ctf_field_type_variant, + parent); + + if (variant->tag_name->len == 0 || !variant->tag) { + ret = -1; + } + break; + } + default: + break; } end: return ret; @@ -265,7 +415,7 @@ struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size) struct bt_ctf_field_type_integer *integer = g_new0(struct bt_ctf_field_type_integer, 1); - if (!integer || size > 64) { + if (!integer || size == 0 || size > 64) { return NULL; } @@ -274,10 +424,42 @@ struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size) integer->declaration.len = size; integer->declaration.base = BT_CTF_INTEGER_BASE_DECIMAL; integer->declaration.encoding = CTF_STRING_NONE; - bt_ctf_field_type_init(&integer->parent); + bt_ctf_field_type_init(&integer->parent, TRUE); return &integer->parent; } +int bt_ctf_field_type_integer_get_size(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->declaration->id != CTF_TYPE_INTEGER) { + ret = -1; + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + ret = (int) integer->declaration.len; +end: + return ret; +} + +int bt_ctf_field_type_integer_get_signed(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->declaration->id != CTF_TYPE_INTEGER) { + ret = -1; + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + ret = integer->declaration.signedness; +end: + return ret; +} + int bt_ctf_field_type_integer_set_signed(struct bt_ctf_field_type *type, int is_signed) { @@ -291,12 +473,23 @@ int bt_ctf_field_type_integer_set_signed(struct bt_ctf_field_type *type, } integer = container_of(type, struct bt_ctf_field_type_integer, parent); - if (is_signed && integer->declaration.len <= 1) { - ret = -1; + integer->declaration.signedness = !!is_signed; +end: + return ret; +} + +enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base( + struct bt_ctf_field_type *type) +{ + enum bt_ctf_integer_base ret = BT_CTF_INTEGER_BASE_UNKNOWN; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->declaration->id != CTF_TYPE_INTEGER) { goto end; } - integer->declaration.signedness = !!is_signed; + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + ret = integer->declaration.base; end: return ret; } @@ -330,6 +523,22 @@ end: return ret; } +enum ctf_string_encoding bt_ctf_field_type_integer_get_encoding( + struct bt_ctf_field_type *type) +{ + enum ctf_string_encoding ret = CTF_STRING_UNKNOWN; + struct bt_ctf_field_type_integer *integer; + + if (!type || type->declaration->id != CTF_TYPE_INTEGER) { + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + ret = integer->declaration.encoding; +end: + return ret; +} + int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *type, enum ctf_string_encoding encoding) { @@ -350,6 +559,43 @@ end: return ret; } +struct bt_ctf_clock *bt_ctf_field_type_integer_get_mapped_clock( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_integer *integer; + struct bt_ctf_clock *clock = NULL; + + if (!type) { + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + clock = integer->mapped_clock; + bt_get(clock); +end: + return clock; +} + +int bt_ctf_field_type_integer_set_mapped_clock( + struct bt_ctf_field_type *type, + struct bt_ctf_clock *clock) +{ + struct bt_ctf_field_type_integer *integer; + int ret = 0; + + if (!type || type->frozen) { + ret = -1; + goto end; + } + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + bt_put(integer->mapped_clock); + bt_get(clock); + integer->mapped_clock = clock; +end: + return ret; +} + struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( struct bt_ctf_field_type *integer_container_type) { @@ -359,6 +605,10 @@ struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( goto error; } + if (integer_container_type->declaration->id != CTF_TYPE_INTEGER) { + goto error; + } + enumeration = g_new0(struct bt_ctf_field_type_enumeration, 1); if (!enumeration) { goto error; @@ -366,17 +616,39 @@ struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( enumeration->parent.declaration = &enumeration->declaration.p; enumeration->parent.declaration->id = CTF_TYPE_ENUM; - bt_ctf_field_type_get(integer_container_type); + bt_get(integer_container_type); enumeration->container = integer_container_type; enumeration->entries = g_ptr_array_new_with_free_func( (GDestroyNotify)destroy_enumeration_mapping); - bt_ctf_field_type_init(&enumeration->parent); + bt_ctf_field_type_init(&enumeration->parent, FALSE); return &enumeration->parent; error: g_free(enumeration); return NULL; } +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_type( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *container_type = NULL; + struct bt_ctf_field_type_enumeration *enumeration_type; + + if (!type) { + goto end; + } + + if (type->declaration->id != CTF_TYPE_ENUM) { + goto end; + } + + enumeration_type = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + container_type = enumeration_type->container; + bt_get(container_type); +end: + return container_type; +} + int bt_ctf_field_type_enumeration_add_mapping( struct bt_ctf_field_type *type, const char *string, int64_t range_start, int64_t range_end) @@ -407,8 +679,9 @@ int bt_ctf_field_type_enumeration_add_mapping( } mapping_name = g_quark_from_string(escaped_string); - query = (struct range_overlap_query) { .range_start = range_start, - .range_end = range_end, + query = (struct range_overlap_query) { + .range_start._signed = range_start, + .range_end._signed = range_end, .mapping_name = mapping_name, .overlaps = 0 }; enumeration = container_of(type, struct bt_ctf_field_type_enumeration, @@ -427,102 +700,432 @@ int bt_ctf_field_type_enumeration_add_mapping( goto error_free; } - *mapping = (struct enumeration_mapping) {.range_start = range_start, - .range_end = range_end, .string = mapping_name}; + *mapping = (struct enumeration_mapping) { + .range_start._signed = range_start, + .range_end._signed = range_end, .string = mapping_name}; g_ptr_array_add(enumeration->entries, mapping); + g_ptr_array_sort(enumeration->entries, + (GCompareFunc)compare_enumeration_mappings_signed); error_free: free(escaped_string); end: return ret; } -struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void) +int bt_ctf_field_type_enumeration_add_mapping_unsigned( + struct bt_ctf_field_type *type, const char *string, + uint64_t range_start, uint64_t range_end) { - struct bt_ctf_field_type_floating_point *floating_point = - g_new0(struct bt_ctf_field_type_floating_point, 1); + int ret = 0; + GQuark mapping_name; + struct enumeration_mapping *mapping; + struct bt_ctf_field_type_enumeration *enumeration; + struct range_overlap_query query; + char *escaped_string; - if (!floating_point) { + if (!type || (type->declaration->id != CTF_TYPE_ENUM) || + type->frozen || + (range_end < range_start)) { + ret = -1; goto end; } - floating_point->declaration.sign = &floating_point->sign; - floating_point->declaration.mantissa = &floating_point->mantissa; - floating_point->declaration.exp = &floating_point->exp; - floating_point->sign.len = 1; - floating_point->parent.declaration = &floating_point->declaration.p; - floating_point->parent.declaration->id = CTF_TYPE_FLOAT; - floating_point->declaration.exp->len = - sizeof(float) * CHAR_BIT - FLT_MANT_DIG; - floating_point->declaration.mantissa->len = FLT_MANT_DIG - 1; - floating_point->sign.p.alignment = 1; - floating_point->mantissa.p.alignment = 1; - floating_point->exp.p.alignment = 1; - - bt_ctf_field_type_init(&floating_point->parent); -end: - return floating_point ? &floating_point->parent : NULL; -} - -int bt_ctf_field_type_floating_point_set_exponent_digits( - struct bt_ctf_field_type *type, - unsigned int exponent_digits) -{ - int ret = 0; - struct bt_ctf_field_type_floating_point *floating_point; - - if (!type || type->frozen || - (type->declaration->id != CTF_TYPE_FLOAT)) { + if (!string || strlen(string) == 0) { ret = -1; goto end; } - floating_point = container_of(type, - struct bt_ctf_field_type_floating_point, parent); - if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) && - (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) && - (exponent_digits != - sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) { + escaped_string = g_strescape(string, NULL); + if (!escaped_string) { ret = -1; goto end; } - floating_point->declaration.exp->len = exponent_digits; -end: - return ret; -} - -int bt_ctf_field_type_floating_point_set_mantissa_digits( - struct bt_ctf_field_type *type, - unsigned int mantissa_digits) -{ - int ret = 0; - struct bt_ctf_field_type_floating_point *floating_point; + mapping_name = g_quark_from_string(escaped_string); + query = (struct range_overlap_query) { + .range_start._unsigned = range_start, + .range_end._unsigned = range_end, + .mapping_name = mapping_name, + .overlaps = 0 }; + enumeration = container_of(type, struct bt_ctf_field_type_enumeration, + parent); - if (!type || type->frozen || - (type->declaration->id != CTF_TYPE_FLOAT)) { + /* Check that the range does not overlap with one already present */ + g_ptr_array_foreach(enumeration->entries, check_ranges_overlap_unsigned, + &query); + if (query.overlaps) { ret = -1; - goto end; + goto error_free; } - floating_point = container_of(type, - struct bt_ctf_field_type_floating_point, parent); - - if ((mantissa_digits != FLT_MANT_DIG) && - (mantissa_digits != DBL_MANT_DIG) && - (mantissa_digits != LDBL_MANT_DIG)) { + mapping = g_new(struct enumeration_mapping, 1); + if (!mapping) { ret = -1; - goto end; + goto error_free; } - floating_point->declaration.mantissa->len = mantissa_digits - 1; + *mapping = (struct enumeration_mapping) { + .range_start._unsigned = range_start, + .range_end._unsigned = range_end, .string = mapping_name}; + g_ptr_array_add(enumeration->entries, mapping); + g_ptr_array_sort(enumeration->entries, + (GCompareFunc)compare_enumeration_mappings_unsigned); +error_free: + free(escaped_string); end: return ret; } -struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void) +const char *bt_ctf_field_type_enumeration_get_mapping_name_unsigned( + struct bt_ctf_field_type_enumeration *enumeration_type, + uint64_t value) { - struct bt_ctf_field_type_structure *structure = - g_new0(struct bt_ctf_field_type_structure, 1); + const char *name = NULL; + struct range_overlap_query query = + (struct range_overlap_query) { + .range_start._unsigned = value, + .range_end._unsigned = value, + .overlaps = 0 }; + + g_ptr_array_foreach(enumeration_type->entries, + check_ranges_overlap_unsigned, + &query); + if (!query.overlaps) { + goto end; + } + + name = g_quark_to_string(query.mapping_name); +end: + return name; +} + +const char *bt_ctf_field_type_enumeration_get_mapping_name_signed( + struct bt_ctf_field_type_enumeration *enumeration_type, + int64_t value) +{ + const char *name = NULL; + struct range_overlap_query query = + (struct range_overlap_query) { + .range_start._signed = value, + .range_end._signed = value, + .overlaps = 0 }; + + g_ptr_array_foreach(enumeration_type->entries, check_ranges_overlap, + &query); + if (!query.overlaps) { + goto end; + } + + name = g_quark_to_string(query.mapping_name); +end: + return name; +} + +int bt_ctf_field_type_enumeration_get_mapping_count( + struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_enumeration *enumeration; + + if (!type || (type->declaration->id != CTF_TYPE_ENUM)) { + ret = -1; + goto end; + } + + enumeration = container_of(type, struct bt_ctf_field_type_enumeration, + parent); + ret = (int) enumeration->entries->len; +end: + return ret; +} + +static inline +struct enumeration_mapping *get_enumeration_mapping( + struct bt_ctf_field_type *type, int index) +{ + struct enumeration_mapping *mapping = NULL; + struct bt_ctf_field_type_enumeration *enumeration; + + enumeration = container_of(type, struct bt_ctf_field_type_enumeration, + parent); + if (index >= enumeration->entries->len) { + goto end; + } + + mapping = g_ptr_array_index(enumeration->entries, index); +end: + return mapping; +} + +int bt_ctf_field_type_enumeration_get_mapping( + struct bt_ctf_field_type *type, int index, + const char **string, int64_t *range_start, int64_t *range_end) +{ + struct enumeration_mapping *mapping; + int ret = 0; + + if (!type || index < 0 || !string || !range_start || !range_end || + (type->declaration->id != CTF_TYPE_ENUM)) { + ret = -1; + goto end; + } + + mapping = get_enumeration_mapping(type, index); + if (!mapping) { + ret = -1; + goto end; + } + + *string = g_quark_to_string(mapping->string); + *range_start = mapping->range_start._signed; + *range_end = mapping->range_end._signed; +end: + return ret; +} + +int bt_ctf_field_type_enumeration_get_mapping_unsigned( + struct bt_ctf_field_type *type, int index, + const char **string, uint64_t *range_start, uint64_t *range_end) +{ + struct enumeration_mapping *mapping; + int ret = 0; + + if (!type || index < 0 || !string || !range_start || !range_end || + (type->declaration->id != CTF_TYPE_ENUM)) { + ret = -1; + goto end; + } + + mapping = get_enumeration_mapping(type, index); + if (!mapping) { + ret = -1; + goto end; + } + + *string = g_quark_to_string(mapping->string); + *range_start = mapping->range_start._unsigned; + *range_end = mapping->range_end._unsigned; +end: + return ret; +} + +int bt_ctf_field_type_enumeration_get_mapping_index_by_name( + struct bt_ctf_field_type *type, const char *name) +{ + GQuark name_quark; + struct bt_ctf_field_type_enumeration *enumeration; + int i, ret = 0; + + if (!type || !name || + (type->declaration->id != CTF_TYPE_ENUM)) { + ret = -1; + goto end; + } + + name_quark = g_quark_try_string(name); + if (!name_quark) { + ret = -1; + goto end; + } + + enumeration = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + for (i = 0; i < enumeration->entries->len; i++) { + struct enumeration_mapping *mapping = + get_enumeration_mapping(type, i); + + if (mapping->string == name_quark) { + ret = i; + goto end; + } + } + + ret = -1; +end: + return ret; +} + +int bt_ctf_field_type_enumeration_get_mapping_index_by_value( + struct bt_ctf_field_type *type, int64_t value) +{ + struct bt_ctf_field_type_enumeration *enumeration; + int i, ret = 0; + + if (!type || (type->declaration->id != CTF_TYPE_ENUM)) { + ret = -1; + goto end; + } + + enumeration = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + for (i = 0; i < enumeration->entries->len; i++) { + struct enumeration_mapping *mapping = + get_enumeration_mapping(type, i); + + if (value >= mapping->range_start._signed && + value <= mapping->range_end._signed) { + ret = i; + goto end; + } + } + + ret = -1; +end: + return ret; +} + +int bt_ctf_field_type_enumeration_get_mapping_index_by_unsigned_value( + struct bt_ctf_field_type *type, uint64_t value) +{ + struct bt_ctf_field_type_enumeration *enumeration; + int i, ret = 0; + + if (!type || (type->declaration->id != CTF_TYPE_ENUM)) { + ret = -1; + goto end; + } + + enumeration = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + for (i = 0; i < enumeration->entries->len; i++) { + struct enumeration_mapping *mapping = + get_enumeration_mapping(type, i); + + if (value >= mapping->range_start._unsigned && + value <= mapping->range_end._unsigned) { + ret = i; + goto end; + } + } + + ret = -1; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void) +{ + struct bt_ctf_field_type_floating_point *floating_point = + g_new0(struct bt_ctf_field_type_floating_point, 1); + + if (!floating_point) { + goto end; + } + + floating_point->declaration.sign = &floating_point->sign; + floating_point->declaration.mantissa = &floating_point->mantissa; + floating_point->declaration.exp = &floating_point->exp; + floating_point->sign.len = 1; + floating_point->parent.declaration = &floating_point->declaration.p; + floating_point->parent.declaration->id = CTF_TYPE_FLOAT; + floating_point->declaration.exp->len = + sizeof(float) * CHAR_BIT - FLT_MANT_DIG; + floating_point->declaration.mantissa->len = FLT_MANT_DIG - 1; + floating_point->sign.p.alignment = 1; + floating_point->mantissa.p.alignment = 1; + floating_point->exp.p.alignment = 1; + + bt_ctf_field_type_init(&floating_point->parent, TRUE); +end: + return floating_point ? &floating_point->parent : NULL; +} + +int bt_ctf_field_type_floating_point_get_exponent_digits( + struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_floating_point *floating_point; + + if (!type || (type->declaration->id != CTF_TYPE_FLOAT)) { + ret = -1; + goto end; + } + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + ret = (int) floating_point->declaration.exp->len; +end: + return ret; +} + +int bt_ctf_field_type_floating_point_set_exponent_digits( + struct bt_ctf_field_type *type, + unsigned int exponent_digits) +{ + int ret = 0; + struct bt_ctf_field_type_floating_point *floating_point; + + if (!type || type->frozen || + (type->declaration->id != CTF_TYPE_FLOAT)) { + ret = -1; + goto end; + } + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) && + (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) && + (exponent_digits != + sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) { + ret = -1; + goto end; + } + + floating_point->declaration.exp->len = exponent_digits; +end: + return ret; +} + +int bt_ctf_field_type_floating_point_get_mantissa_digits( + struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_floating_point *floating_point; + + if (!type || (type->declaration->id != CTF_TYPE_FLOAT)) { + ret = -1; + goto end; + } + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + ret = (int) floating_point->mantissa.len + 1; +end: + return ret; +} + +int bt_ctf_field_type_floating_point_set_mantissa_digits( + struct bt_ctf_field_type *type, + unsigned int mantissa_digits) +{ + int ret = 0; + struct bt_ctf_field_type_floating_point *floating_point; + + if (!type || type->frozen || + (type->declaration->id != CTF_TYPE_FLOAT)) { + ret = -1; + goto end; + } + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + + if ((mantissa_digits != FLT_MANT_DIG) && + (mantissa_digits != DBL_MANT_DIG) && + (mantissa_digits != LDBL_MANT_DIG)) { + ret = -1; + goto end; + } + + floating_point->declaration.mantissa->len = mantissa_digits - 1; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void) +{ + struct bt_ctf_field_type_structure *structure = + g_new0(struct bt_ctf_field_type_structure, 1); if (!structure) { goto error; @@ -530,10 +1133,10 @@ struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void) structure->parent.declaration = &structure->declaration.p; structure->parent.declaration->id = CTF_TYPE_STRUCT; - bt_ctf_field_type_init(&structure->parent); structure->fields = g_ptr_array_new_with_free_func( (GDestroyNotify)destroy_structure_field); structure->field_name_to_index = g_hash_table_new(NULL, NULL); + bt_ctf_field_type_init(&structure->parent, TRUE); return &structure->parent; error: return NULL; @@ -547,510 +1150,1276 @@ int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *type, struct bt_ctf_field_type_structure *structure; if (!type || !field_type || type->frozen || - validate_identifier(field_name) || + bt_ctf_validate_identifier(field_name) || (type->declaration->id != CTF_TYPE_STRUCT) || bt_ctf_field_type_validate(field_type)) { + ret = -1; goto end; } - structure = container_of(type, - struct bt_ctf_field_type_structure, parent); - if (add_structure_field(structure->fields, - structure->field_name_to_index, field_type, field_name)) { + structure = container_of(type, + struct bt_ctf_field_type_structure, parent); + if (add_structure_field(structure->fields, + structure->field_name_to_index, field_type, field_name)) { + ret = -1; + goto end; + } +end: + return ret; +} + +int bt_ctf_field_type_structure_get_field_count( + struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_structure *structure; + + if (!type || (type->declaration->id != CTF_TYPE_STRUCT)) { + ret = -1; + goto end; + } + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + ret = (int) structure->fields->len; +end: + return ret; +} + +int bt_ctf_field_type_structure_get_field(struct bt_ctf_field_type *type, + const char **field_name, struct bt_ctf_field_type **field_type, + int index) +{ + struct bt_ctf_field_type_structure *structure; + struct structure_field *field; + int ret = 0; + + if (!type || index < 0 || (type->declaration->id != CTF_TYPE_STRUCT)) { + ret = -1; + goto end; + } + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + if (index >= structure->fields->len) { + ret = -1; + goto end; + } + + field = g_ptr_array_index(structure->fields, index); + if (field_type) { + *field_type = field->type; + bt_get(field->type); + } + if (field_name) { + *field_name = g_quark_to_string(field->name); + } +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name( + struct bt_ctf_field_type *type, + const char *name) +{ + size_t index; + GQuark name_quark; + struct structure_field *field; + struct bt_ctf_field_type_structure *structure; + struct bt_ctf_field_type *field_type = NULL; + + if (!type || !name) { + goto end; + } + + name_quark = g_quark_try_string(name); + if (!name_quark) { + goto end; + } + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + if (!g_hash_table_lookup_extended(structure->field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { + goto end; + } + + field = structure->fields->pdata[index]; + field_type = field->type; + bt_get(field_type); +end: + return field_type; +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_create( + struct bt_ctf_field_type *enum_tag, const char *tag_name) +{ + struct bt_ctf_field_type_variant *variant = NULL; + + if (tag_name && bt_ctf_validate_identifier(tag_name)) { + goto error; + } + + variant = g_new0(struct bt_ctf_field_type_variant, 1); + if (!variant) { + goto error; + } + + variant->parent.declaration = &variant->declaration.p; + variant->parent.declaration->id = CTF_TYPE_VARIANT; + variant->tag_name = g_string_new(tag_name); + variant->field_name_to_index = g_hash_table_new(NULL, NULL); + variant->fields = g_ptr_array_new_with_free_func( + (GDestroyNotify) destroy_structure_field); + if (enum_tag) { + bt_get(enum_tag); + variant->tag = container_of(enum_tag, + struct bt_ctf_field_type_enumeration, parent); + } + + bt_ctf_field_type_init(&variant->parent, TRUE); + /* A variant's alignment is undefined */ + variant->parent.declaration->alignment = 0; + return &variant->parent; +error: + return NULL; +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_type( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_variant *variant; + struct bt_ctf_field_type *tag_type = NULL; + + if (!type || (type->declaration->id != CTF_TYPE_VARIANT)) { + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + if (!variant->tag) { + goto end; + } + + tag_type = &variant->tag->parent; + bt_get(tag_type); +end: + return tag_type; +} + +const char *bt_ctf_field_type_variant_get_tag_name( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_variant *variant; + const char *tag_name = NULL; + + if (!type || (type->declaration->id != CTF_TYPE_VARIANT)) { + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + if (variant->tag_name->len == 0) { + goto end; + } + + tag_name = variant->tag_name->str; +end: + return tag_name; +} + +int bt_ctf_field_type_variant_set_tag_name( + struct bt_ctf_field_type *type, const char *name) +{ + int ret = 0; + struct bt_ctf_field_type_variant *variant; + + if (!type || type->frozen || + (type->declaration->id != CTF_TYPE_VARIANT) || + bt_ctf_validate_identifier(name)) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + g_string_assign(variant->tag_name, name); +end: + return ret; +} + +int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *field_type, + const char *field_name) +{ + size_t i; + int ret = 0; + struct bt_ctf_field_type_variant *variant; + GQuark field_name_quark = g_quark_from_string(field_name); + + if (!type || !field_type || type->frozen || + bt_ctf_validate_identifier(field_name) || + (type->declaration->id != CTF_TYPE_VARIANT) || + bt_ctf_field_type_validate(field_type)) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + + /* The user has explicitly provided a tag; validate against it. */ + if (variant->tag) { + int name_found = 0; + + /* Make sure this name is present in the enum tag */ + for (i = 0; i < variant->tag->entries->len; i++) { + struct enumeration_mapping *mapping = + g_ptr_array_index(variant->tag->entries, i); + + if (mapping->string == field_name_quark) { + name_found = 1; + break; + } + } + + if (!name_found) { + /* Validation failed */ + ret = -1; + goto end; + } + } + + if (add_structure_field(variant->fields, variant->field_name_to_index, + field_type, field_name)) { + ret = -1; + goto end; + } +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name( + struct bt_ctf_field_type *type, + const char *field_name) +{ + size_t index; + GQuark name_quark; + struct structure_field *field; + struct bt_ctf_field_type_variant *variant; + struct bt_ctf_field_type *field_type = NULL; + + if (!type || !field_name) { + goto end; + } + + name_quark = g_quark_try_string(field_name); + if (!name_quark) { + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, parent); + if (!g_hash_table_lookup_extended(variant->field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { + goto end; + } + + field = g_ptr_array_index(variant->fields, index); + field_type = field->type; + bt_get(field_type); +end: + return field_type; +} + +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag( + struct bt_ctf_field_type *type, + struct bt_ctf_field *tag) +{ + const char *enum_value; + struct bt_ctf_field_type *field_type = NULL; + + if (!type || !tag || type->declaration->id != CTF_TYPE_VARIANT) { + goto end; + } + + enum_value = bt_ctf_field_enumeration_get_mapping_name(tag); + if (!enum_value) { + goto end; + } + + /* Already increments field_type's reference count */ + field_type = bt_ctf_field_type_variant_get_field_type_by_name( + type, enum_value); +end: + return field_type; +} + +int bt_ctf_field_type_variant_get_field_count(struct bt_ctf_field_type *type) +{ + int ret = 0; + struct bt_ctf_field_type_variant *variant; + + if (!type || (type->declaration->id != CTF_TYPE_VARIANT)) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + ret = (int) variant->fields->len; +end: + return ret; + +} + +int bt_ctf_field_type_variant_get_field(struct bt_ctf_field_type *type, + const char **field_name, struct bt_ctf_field_type **field_type, + int index) +{ + struct bt_ctf_field_type_variant *variant; + struct structure_field *field; + int ret = 0; + + if (!type || index < 0 || (type->declaration->id != CTF_TYPE_VARIANT)) { + ret = -1; + goto end; + } + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + if (index >= variant->fields->len) { + ret = -1; + goto end; + } + + field = g_ptr_array_index(variant->fields, index); + if (field_type) { + *field_type = field->type; + bt_get(field->type); + } + if (field_name) { + *field_name = g_quark_to_string(field->name); + } +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_array_create( + struct bt_ctf_field_type *element_type, + unsigned int length) +{ + struct bt_ctf_field_type_array *array = NULL; + + if (!element_type || length == 0 || + bt_ctf_field_type_validate(element_type)) { + goto error; + } + + array = g_new0(struct bt_ctf_field_type_array, 1); + if (!array) { + goto error; + } + + array->parent.declaration = &array->declaration.p; + array->parent.declaration->id = CTF_TYPE_ARRAY; + + bt_get(element_type); + array->element_type = element_type; + array->length = length; + bt_ctf_field_type_init(&array->parent, FALSE); + return &array->parent; +error: + return NULL; +} + +struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_type( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *ret = NULL; + struct bt_ctf_field_type_array *array; + + if (!type || (type->declaration->id != CTF_TYPE_ARRAY)) { + goto end; + } + + array = container_of(type, struct bt_ctf_field_type_array, parent); + ret = array->element_type; + bt_get(ret); +end: + return ret; +} + +int64_t bt_ctf_field_type_array_get_length(struct bt_ctf_field_type *type) +{ + int64_t ret; + struct bt_ctf_field_type_array *array; + + if (!type || (type->declaration->id != CTF_TYPE_ARRAY)) { + ret = -1; + goto end; + } + + array = container_of(type, struct bt_ctf_field_type_array, parent); + ret = (int64_t) array->length; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( + struct bt_ctf_field_type *element_type, + const char *length_field_name) +{ + struct bt_ctf_field_type_sequence *sequence = NULL; + + if (!element_type || bt_ctf_validate_identifier(length_field_name) || + bt_ctf_field_type_validate(element_type)) { + goto error; + } + + sequence = g_new0(struct bt_ctf_field_type_sequence, 1); + if (!sequence) { + goto error; + } + + sequence->parent.declaration = &sequence->declaration.p; + sequence->parent.declaration->id = CTF_TYPE_SEQUENCE; + bt_get(element_type); + sequence->element_type = element_type; + sequence->length_field_name = g_string_new(length_field_name); + bt_ctf_field_type_init(&sequence->parent, FALSE); + return &sequence->parent; +error: + return NULL; +} + +struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *ret = NULL; + struct bt_ctf_field_type_sequence *sequence; + + if (!type || (type->declaration->id != CTF_TYPE_SEQUENCE)) { + goto end; + } + + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + ret = sequence->element_type; + bt_get(ret); +end: + return ret; +} + +const char *bt_ctf_field_type_sequence_get_length_field_name( + struct bt_ctf_field_type *type) +{ + const char *ret = NULL; + struct bt_ctf_field_type_sequence *sequence; + + if (!type || (type->declaration->id != CTF_TYPE_SEQUENCE)) { + goto end; + } + + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + ret = sequence->length_field_name->str; +end: + return ret; +} + +struct bt_ctf_field_type *bt_ctf_field_type_string_create(void) +{ + struct bt_ctf_field_type_string *string = + g_new0(struct bt_ctf_field_type_string, 1); + + if (!string) { + return NULL; + } + + string->parent.declaration = &string->declaration.p; + string->parent.declaration->id = CTF_TYPE_STRING; + bt_ctf_field_type_init(&string->parent, TRUE); + string->declaration.encoding = CTF_STRING_UTF8; + string->parent.declaration->alignment = CHAR_BIT; + return &string->parent; +} + +enum ctf_string_encoding bt_ctf_field_type_string_get_encoding( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type_string *string; + enum ctf_string_encoding ret = CTF_STRING_UNKNOWN; + + if (!type || (type->declaration->id != CTF_TYPE_STRING)) { + goto end; + } + + string = container_of(type, struct bt_ctf_field_type_string, + parent); + ret = string->declaration.encoding; +end: + return ret; +} + +int bt_ctf_field_type_string_set_encoding(struct bt_ctf_field_type *type, + enum ctf_string_encoding encoding) +{ + int ret = 0; + struct bt_ctf_field_type_string *string; + + if (!type || type->declaration->id != CTF_TYPE_STRING || + (encoding != CTF_STRING_UTF8 && + encoding != CTF_STRING_ASCII)) { + ret = -1; + goto end; + } + + string = container_of(type, struct bt_ctf_field_type_string, parent); + string->declaration.encoding = encoding; +end: + return ret; +} + +int bt_ctf_field_type_get_alignment(struct bt_ctf_field_type *type) +{ + int ret; + enum ctf_type_id type_id; + + if (!type) { + ret = -1; + goto end; + } + + if (type->frozen) { + ret = (int) type->declaration->alignment; + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(type); + switch (type_id) { + case CTF_TYPE_SEQUENCE: + { + struct bt_ctf_field_type *element = + bt_ctf_field_type_sequence_get_element_type(type); + + if (!element) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_get_alignment(element); + bt_put(element); + break; + } + case CTF_TYPE_ARRAY: + { + struct bt_ctf_field_type *element = + bt_ctf_field_type_array_get_element_type(type); + + if (!element) { + ret = -1; + goto end; + } + + ret = bt_ctf_field_type_get_alignment(element); + bt_put(element); + break; + } + case CTF_TYPE_STRUCT: + { + int i, element_count; + + element_count = bt_ctf_field_type_structure_get_field_count( + type); + if (element_count < 0) { + ret = element_count; + goto end; + } + + for (i = 0; i < element_count; i++) { + struct bt_ctf_field_type *field; + int field_alignment; + + ret = bt_ctf_field_type_structure_get_field(type, NULL, + &field, i); + if (ret) { + goto end; + } + + assert(field); + field_alignment = bt_ctf_field_type_get_alignment( + field); + bt_put(field); + if (field_alignment < 0) { + ret = field_alignment; + goto end; + } + + type->declaration->alignment = MAX(field_alignment, + type->declaration->alignment); + } + ret = (int) type->declaration->alignment; + break; + } + case CTF_TYPE_UNKNOWN: + ret = -1; + break; + default: + ret = (int) type->declaration->alignment; + break; + } +end: + return ret; +} + +static inline +int is_power_of_two(unsigned int value) +{ + return ((value & (value - 1)) == 0) && value > 0; +} + +int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *type, + unsigned int alignment) +{ + int ret = 0; + enum ctf_type_id type_id; + + /* Alignment must be a power of two */ + if (!type || type->frozen || !is_power_of_two(alignment)) { + ret = -1; + goto end; + } + + type_id = bt_ctf_field_type_get_type_id(type); + if (type_id == CTF_TYPE_UNKNOWN) { + ret = -1; + goto end; + } + + if (type->declaration->id == CTF_TYPE_STRING && + alignment != CHAR_BIT) { + ret = -1; + goto end; + } + + if (type_id == CTF_TYPE_VARIANT || type_id == CTF_TYPE_SEQUENCE || + type_id == CTF_TYPE_ARRAY) { + /* Setting an alignment on these types makes no sense */ + ret = -1; + goto end; + } + + type->declaration->alignment = alignment; + ret = 0; +end: + return ret; +} + +enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order( + struct bt_ctf_field_type *type) +{ + enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN; + int internal_byte_order = -1; + + if (!type) { + goto end; + } + + switch (type->declaration->id) { + case CTF_TYPE_INTEGER: + { + struct bt_ctf_field_type_integer *integer = container_of( + type, struct bt_ctf_field_type_integer, parent); + internal_byte_order = integer->declaration.byte_order; + break; + } + case CTF_TYPE_FLOAT: + { + struct bt_ctf_field_type_floating_point *floating_point = + container_of(type, + struct bt_ctf_field_type_floating_point, + parent); + internal_byte_order = floating_point->declaration.byte_order; + break; + } + default: + goto end; + } + + switch (internal_byte_order) { + case LITTLE_ENDIAN: + ret = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN; + break; + case BIG_ENDIAN: + ret = BT_CTF_BYTE_ORDER_BIG_ENDIAN; + break; + case 0: + ret = BT_CTF_BYTE_ORDER_NATIVE; + break; + default: + ret = BT_CTF_BYTE_ORDER_UNKNOWN; + } +end: + return ret; +} + +int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type, + enum bt_ctf_byte_order byte_order) +{ + int ret = 0; + int internal_byte_order; + enum ctf_type_id type_id; + + if (!type || type->frozen) { + ret = -1; + goto end; + } + + switch (byte_order) { + case BT_CTF_BYTE_ORDER_NATIVE: + /* Leave unset. Will be initialized by parent. */ + internal_byte_order = 0; + break; + case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: + internal_byte_order = LITTLE_ENDIAN; + break; + case BT_CTF_BYTE_ORDER_BIG_ENDIAN: + case BT_CTF_BYTE_ORDER_NETWORK: + internal_byte_order = BIG_ENDIAN; + break; + default: + ret = -1; + goto end; + } + + type_id = type->declaration->id; + if (set_byte_order_funcs[type_id]) { + set_byte_order_funcs[type_id](type, internal_byte_order, 0); + } +end: + return ret; +} + +enum ctf_type_id bt_ctf_field_type_get_type_id( + struct bt_ctf_field_type *type) +{ + if (!type) { + return CTF_TYPE_UNKNOWN; + } + + return type->declaration->id; +} + +void bt_ctf_field_type_get(struct bt_ctf_field_type *type) +{ + bt_get(type); +} + +void bt_ctf_field_type_put(struct bt_ctf_field_type *type) +{ + bt_put(type); +} + +BT_HIDDEN +void bt_ctf_field_type_freeze(struct bt_ctf_field_type *type) +{ + if (!type) { + return; + } + + type->freeze(type); +} + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_signed( + struct bt_ctf_field_type_variant *variant, + int64_t tag_value) +{ + struct bt_ctf_field_type *type = NULL; + GQuark field_name_quark; + gpointer index; + struct structure_field *field_entry; + struct range_overlap_query query = { + .range_start._signed = tag_value, + .range_end._signed = tag_value, + .mapping_name = 0, .overlaps = 0}; + + g_ptr_array_foreach(variant->tag->entries, check_ranges_overlap, + &query); + if (!query.overlaps) { + goto end; + } + + field_name_quark = query.mapping_name; + if (!g_hash_table_lookup_extended(variant->field_name_to_index, + GUINT_TO_POINTER(field_name_quark), NULL, &index)) { + goto end; + } + + field_entry = g_ptr_array_index(variant->fields, (size_t) index); + type = field_entry->type; +end: + return type; +} + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_unsigned( + struct bt_ctf_field_type_variant *variant, + uint64_t tag_value) +{ + struct bt_ctf_field_type *type = NULL; + GQuark field_name_quark; + gpointer index; + struct structure_field *field_entry; + struct range_overlap_query query = { + .range_start._unsigned = tag_value, + .range_end._unsigned = tag_value, + .mapping_name = 0, .overlaps = 0}; + + g_ptr_array_foreach(variant->tag->entries, + check_ranges_overlap_unsigned, + &query); + if (!query.overlaps) { + goto end; + } + + field_name_quark = query.mapping_name; + if (!g_hash_table_lookup_extended(variant->field_name_to_index, + GUINT_TO_POINTER(field_name_quark), NULL, &index)) { + goto end; + } + + field_entry = g_ptr_array_index(variant->fields, (size_t)index); + type = field_entry->type; +end: + return type; +} + +BT_HIDDEN +int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context) +{ + int ret; + + if (!type || !context) { ret = -1; goto end; } - if (type->declaration->alignment < field_type->declaration->alignment) { - type->declaration->alignment = - field_type->declaration->alignment; - } + ret = type->serialize(type, context); end: return ret; } -struct bt_ctf_field_type *bt_ctf_field_type_variant_create( - struct bt_ctf_field_type *enum_tag, const char *tag_name) +BT_HIDDEN +void bt_ctf_field_type_set_native_byte_order(struct bt_ctf_field_type *type, + int byte_order) { - struct bt_ctf_field_type_variant *variant = NULL; - - if (!enum_tag || validate_identifier(tag_name) || - (enum_tag->declaration->id != CTF_TYPE_ENUM)) { - goto error; + if (!type) { + return; } - variant = g_new0(struct bt_ctf_field_type_variant, 1); - if (!variant) { - goto error; + assert(byte_order == LITTLE_ENDIAN || byte_order == BIG_ENDIAN); + if (set_byte_order_funcs[type->declaration->id]) { + set_byte_order_funcs[type->declaration->id](type, + byte_order, 1); } - - variant->parent.declaration = &variant->declaration.p; - variant->parent.declaration->id = CTF_TYPE_VARIANT; - variant->tag_name = g_string_new(tag_name); - bt_ctf_field_type_init(&variant->parent); - variant->field_name_to_index = g_hash_table_new(NULL, NULL); - variant->fields = g_ptr_array_new_with_free_func( - (GDestroyNotify)destroy_structure_field); - bt_ctf_field_type_get(enum_tag); - variant->tag = container_of(enum_tag, - struct bt_ctf_field_type_enumeration, parent); - return &variant->parent; -error: - return NULL; } -int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *type, - struct bt_ctf_field_type *field_type, - const char *field_name) +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *type) { - size_t i; - int ret = 0; - int name_found = 0; - struct bt_ctf_field_type_variant *variant; - GQuark field_name_quark = g_quark_from_string(field_name); + struct bt_ctf_field_type *copy = NULL; - if (!type || !field_type || type->frozen || - validate_identifier(field_name) || - (type->declaration->id != CTF_TYPE_VARIANT) || - bt_ctf_field_type_validate(field_type)) { - ret = -1; + if (!type) { goto end; } - variant = container_of(type, struct bt_ctf_field_type_variant, parent); - /* Make sure this name is present in the enum tag */ - for (i = 0; i < variant->tag->entries->len; i++) { - struct enumeration_mapping *mapping = - g_ptr_array_index(variant->tag->entries, i); - - if (mapping->string == field_name_quark) { - name_found = 1; - break; - } - } - - if (!name_found || add_structure_field(variant->fields, - variant->field_name_to_index, field_type, field_name)) { - ret = -1; - goto end; - } + copy = type_copy_funcs[type->declaration->id](type); end: - return ret; + return copy; } -struct bt_ctf_field_type *bt_ctf_field_type_array_create( - struct bt_ctf_field_type *element_type, - unsigned int length) +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_path_create(void) { - struct bt_ctf_field_type_array *array = NULL; + struct bt_ctf_field_path *field_path = NULL; - if (!element_type || length == 0 || - bt_ctf_field_type_validate(element_type)) { - goto error; + field_path = g_new0(struct bt_ctf_field_path, 1); + if (!field_path) { + goto end; } - array = g_new0(struct bt_ctf_field_type_array, 1); - if (!array) { - goto error; + field_path->root = CTF_NODE_UNKNOWN; + field_path->path_indexes = g_array_new(TRUE, FALSE, sizeof(int)); + if (!field_path->path_indexes) { + bt_ctf_field_path_destroy(field_path); + field_path = NULL; } - - array->parent.declaration = &array->declaration.p; - array->parent.declaration->id = CTF_TYPE_ARRAY; - bt_ctf_field_type_init(&array->parent); - bt_ctf_field_type_get(element_type); - array->element_type = element_type; - array->length = length; - array->parent.declaration->alignment = - element_type->declaration->alignment; - return &array->parent; -error: - return NULL; +end: + return field_path; } -struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( - struct bt_ctf_field_type *element_type, - const char *length_field_name) -{ - struct bt_ctf_field_type_sequence *sequence = NULL; - if (!element_type || validate_identifier(length_field_name) || - bt_ctf_field_type_validate(element_type)) { - goto error; - } +BT_HIDDEN +struct bt_ctf_field_path *bt_ctf_field_path_copy( + struct bt_ctf_field_path *path) +{ + struct bt_ctf_field_path *new_path = bt_ctf_field_path_create(); - sequence = g_new0(struct bt_ctf_field_type_sequence, 1); - if (!sequence) { - goto error; + if (!new_path) { + goto end; } - sequence->parent.declaration = &sequence->declaration.p; - sequence->parent.declaration->id = CTF_TYPE_SEQUENCE; - bt_ctf_field_type_init(&sequence->parent); - bt_ctf_field_type_get(element_type); - sequence->element_type = element_type; - sequence->length_field_name = g_string_new(length_field_name); - sequence->parent.declaration->alignment = - element_type->declaration->alignment; - return &sequence->parent; -error: - return NULL; + new_path->root = path->root; + g_array_insert_vals(new_path->path_indexes, 0, + path->path_indexes->data, path->path_indexes->len); +end: + return new_path; } -struct bt_ctf_field_type *bt_ctf_field_type_string_create(void) +BT_HIDDEN +void bt_ctf_field_path_destroy(struct bt_ctf_field_path *path) { - struct bt_ctf_field_type_string *string = - g_new0(struct bt_ctf_field_type_string, 1); - - if (!string) { - return NULL; + if (!path) { + return; } - string->parent.declaration = &string->declaration.p; - string->parent.declaration->id = CTF_TYPE_STRING; - bt_ctf_field_type_init(&string->parent); - string->declaration.encoding = CTF_STRING_UTF8; - string->parent.declaration->alignment = CHAR_BIT; - return &string->parent; + if (path->path_indexes) { + g_array_free(path->path_indexes, TRUE); + } + g_free(path); } -int bt_ctf_field_type_string_set_encoding( - struct bt_ctf_field_type *type, - enum ctf_string_encoding encoding) +BT_HIDDEN +int bt_ctf_field_type_structure_get_field_name_index( + struct bt_ctf_field_type *type, const char *name) { - int ret = 0; - struct bt_ctf_field_type_string *string; + int ret; + size_t index; + GQuark name_quark; + struct bt_ctf_field_type_structure *structure; - if (!type || type->declaration->id != CTF_TYPE_STRING || - (encoding != CTF_STRING_UTF8 && - encoding != CTF_STRING_ASCII)) { + if (!type || !name || + bt_ctf_field_type_get_type_id(type) != CTF_TYPE_STRUCT) { ret = -1; goto end; } - string = container_of(type, struct bt_ctf_field_type_string, parent); - string->declaration.encoding = encoding; + name_quark = g_quark_try_string(name); + if (!name_quark) { + ret = -1; + goto end; + } + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + if (!g_hash_table_lookup_extended(structure->field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { + ret = -1; + goto end; + } + ret = (int) index; end: return ret; } -int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *type, - unsigned int alignment) +BT_HIDDEN +int bt_ctf_field_type_structure_set_field_index(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *field, int index) { int ret = 0; + struct bt_ctf_field_type_structure *structure; - /* Alignment must be bit-aligned (1) or byte aligned */ - if (!type || type->frozen || (alignment != 1 && (alignment & 0x7))) { + if (!type || !field || + bt_ctf_field_type_get_type_id(type) != CTF_TYPE_STRUCT) { ret = -1; goto end; } - if (type->declaration->id == CTF_TYPE_STRING && - alignment != CHAR_BIT) { + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + if (index < 0 || index >= structure->fields->len) { ret = -1; goto end; } - type->declaration->alignment = alignment; - ret = 0; + bt_get(field); + bt_put(((struct structure_field *) + g_ptr_array_index(structure->fields, index))->type); + ((struct structure_field *) structure->fields->pdata[index])->type = + field; end: return ret; } -int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type, - enum bt_ctf_byte_order byte_order) +BT_HIDDEN +int bt_ctf_field_type_variant_get_field_name_index( + struct bt_ctf_field_type *type, const char *name) { - int ret = 0; - int internal_byte_order; - enum ctf_type_id type_id; + int ret; + size_t index; + GQuark name_quark; + struct bt_ctf_field_type_variant *variant; - if (!type || type->frozen) { + if (!type || !name || + bt_ctf_field_type_get_type_id(type) != CTF_TYPE_VARIANT) { ret = -1; goto end; } - type_id = type->declaration->id; - switch (byte_order) { - case BT_CTF_BYTE_ORDER_NATIVE: - internal_byte_order = (G_BYTE_ORDER == G_LITTLE_ENDIAN ? - LITTLE_ENDIAN : BIG_ENDIAN); - break; - case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN: - internal_byte_order = LITTLE_ENDIAN; - break; - case BT_CTF_BYTE_ORDER_BIG_ENDIAN: - case BT_CTF_BYTE_ORDER_NETWORK: - internal_byte_order = BIG_ENDIAN; - break; - default: + name_quark = g_quark_try_string(name); + if (!name_quark) { ret = -1; goto end; } - if (set_byte_order_funcs[type_id]) { - set_byte_order_funcs[type_id](type, internal_byte_order); + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + if (!g_hash_table_lookup_extended(variant->field_name_to_index, + GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { + ret = -1; + goto end; } + ret = (int) index; end: return ret; } -void bt_ctf_field_type_get(struct bt_ctf_field_type *type) -{ - if (!type) { - return; - } - - bt_ctf_ref_get(&type->ref_count); -} - -void bt_ctf_field_type_put(struct bt_ctf_field_type *type) +BT_HIDDEN +int bt_ctf_field_type_sequence_set_length_field_path( + struct bt_ctf_field_type *type, + struct bt_ctf_field_path *path) { - enum ctf_type_id type_id; + int ret = 0; + struct bt_ctf_field_type_sequence *sequence; - if (!type) { - return; + if (!type || bt_ctf_field_type_get_type_id(type) != CTF_TYPE_SEQUENCE) { + ret = -1; + goto end; } - type_id = type->declaration->id; - assert(type_id > CTF_TYPE_UNKNOWN && type_id < NR_CTF_TYPES); - bt_ctf_ref_put(&type->ref_count, type_destroy_funcs[type_id]); -} - -BT_HIDDEN -void bt_ctf_field_type_freeze(struct bt_ctf_field_type *type) -{ - if (!type) { - return; + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + if (sequence->length_field_path) { + bt_ctf_field_path_destroy(sequence->length_field_path); } - - type->freeze(type); + sequence->length_field_path = path; +end: + return ret; } BT_HIDDEN -enum ctf_type_id bt_ctf_field_type_get_type_id( +struct bt_ctf_field_path *bt_ctf_field_type_sequence_get_length_field_path( struct bt_ctf_field_type *type) { - if (!type) { - return CTF_TYPE_UNKNOWN; - } + struct bt_ctf_field_type_sequence *sequence; - return type->declaration->id; + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + + return sequence->length_field_path; } BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_structure_get_type( - struct bt_ctf_field_type_structure *structure, - const char *name) +int bt_ctf_field_type_variant_set_tag_field_path(struct bt_ctf_field_type *type, + struct bt_ctf_field_path *path) { - struct bt_ctf_field_type *type = NULL; - struct structure_field *field; - GQuark name_quark = g_quark_try_string(name); - size_t index; + int ret = 0; + struct bt_ctf_field_type_variant *variant; - if (!name_quark) { + if (!type || bt_ctf_field_type_get_type_id(type) != CTF_TYPE_VARIANT) { + ret = -1; goto end; } - if (!g_hash_table_lookup_extended(structure->field_name_to_index, - GUINT_TO_POINTER(name_quark), NULL, (gpointer *)&index)) { - goto end; + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + if (variant->tag_path) { + bt_ctf_field_path_destroy(variant->tag_path); } - - field = structure->fields->pdata[index]; - type = field->type; + variant->tag_path = path; end: - return type; + return ret; } BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_type( - struct bt_ctf_field_type_array *array) +struct bt_ctf_field_path *bt_ctf_field_type_variant_get_tag_field_path( + struct bt_ctf_field_type *type) { - assert(array); - return array->element_type; -} + struct bt_ctf_field_type_variant *variant; -BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type( - struct bt_ctf_field_type_sequence *sequence) -{ - assert(sequence); - return sequence->element_type; + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + + return variant->tag_path; } BT_HIDDEN -struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type( - struct bt_ctf_field_type_variant *variant, - int64_t tag_value) +int bt_ctf_field_type_variant_set_tag(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *tag) { - struct bt_ctf_field_type *type = NULL; - GQuark field_name_quark; - gpointer index; - struct structure_field *field_entry; - struct range_overlap_query query = {.range_start = tag_value, - .range_end = tag_value, .mapping_name = 0, .overlaps = 0}; + int ret = 0; + struct bt_ctf_field_type_variant *variant; - g_ptr_array_foreach(variant->tag->entries, check_ranges_overlap, - &query); - if (!query.overlaps) { + if (!type || !tag || type->frozen || + bt_ctf_field_type_get_type_id(tag) != CTF_TYPE_ENUM) { + ret = -1; goto end; } - field_name_quark = query.mapping_name; - if (!g_hash_table_lookup_extended(variant->field_name_to_index, - GUINT_TO_POINTER(field_name_quark), NULL, &index)) { - goto end; + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + bt_get(tag); + if (variant->tag) { + bt_put(&variant->tag->parent); } - - field_entry = g_ptr_array_index(variant->fields, (size_t)index); - type = field_entry->type; + variant->tag = container_of(tag, struct bt_ctf_field_type_enumeration, + parent); end: - return type; + return ret; } BT_HIDDEN -int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type, - struct metadata_context *context) +int bt_ctf_field_type_variant_set_field_index(struct bt_ctf_field_type *type, + struct bt_ctf_field_type *field, int index) { - int ret; + int ret = 0; + struct bt_ctf_field_type_variant *variant; - if (!type || !context) { + if (!type || !field || + bt_ctf_field_type_get_type_id(type) != CTF_TYPE_VARIANT) { ret = -1; goto end; } - ret = type->serialize(type, context); + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + if (index < 0 || index >= variant->fields->len) { + ret = -1; + goto end; + } + + bt_get(field); + bt_put(((struct structure_field *) + g_ptr_array_index(variant->fields, index))->type); + ((struct structure_field *) variant->fields->pdata[index])->type = + field; end: return ret; } static -void bt_ctf_field_type_integer_destroy(struct bt_ctf_ref *ref) +void bt_ctf_field_type_integer_destroy(struct bt_ctf_field_type *type) { - struct bt_ctf_field_type_integer *integer; + struct bt_ctf_field_type_integer *integer = + (struct bt_ctf_field_type_integer *) type; - if (!ref) { + if (!type) { return; } - integer = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_integer, parent); + bt_put(integer->mapped_clock); g_free(integer); } static -void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_ref *ref) +void bt_ctf_field_type_enumeration_destroy(struct bt_ctf_field_type *type) { - struct bt_ctf_field_type_enumeration *enumeration; + struct bt_ctf_field_type_enumeration *enumeration = + (struct bt_ctf_field_type_enumeration *) type; - if (!ref) { + if (!type) { return; } - enumeration = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_enumeration, parent); g_ptr_array_free(enumeration->entries, TRUE); - bt_ctf_field_type_put(enumeration->container); + bt_put(enumeration->container); g_free(enumeration); } static -void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_ref *ref) +void bt_ctf_field_type_floating_point_destroy(struct bt_ctf_field_type *type) { - struct bt_ctf_field_type_floating_point *floating_point; + struct bt_ctf_field_type_floating_point *floating_point = + (struct bt_ctf_field_type_floating_point *) type; - if (!ref) { + if (!type) { return; } - floating_point = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_floating_point, parent); g_free(floating_point); } static -void bt_ctf_field_type_structure_destroy(struct bt_ctf_ref *ref) +void bt_ctf_field_type_structure_destroy(struct bt_ctf_field_type *type) { - struct bt_ctf_field_type_structure *structure; + struct bt_ctf_field_type_structure *structure = + (struct bt_ctf_field_type_structure *) type; - if (!ref) { + if (!type) { return; } - structure = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_structure, parent); g_ptr_array_free(structure->fields, TRUE); g_hash_table_destroy(structure->field_name_to_index); g_free(structure); } static -void bt_ctf_field_type_variant_destroy(struct bt_ctf_ref *ref) +void bt_ctf_field_type_variant_destroy(struct bt_ctf_field_type *type) { - struct bt_ctf_field_type_variant *variant; + struct bt_ctf_field_type_variant *variant = + (struct bt_ctf_field_type_variant *) type; - if (!ref) { + if (!type) { return; } - variant = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_variant, parent); g_ptr_array_free(variant->fields, TRUE); g_hash_table_destroy(variant->field_name_to_index); g_string_free(variant->tag_name, TRUE); - bt_ctf_field_type_put(&variant->tag->parent); + bt_put(&variant->tag->parent); + bt_ctf_field_path_destroy(variant->tag_path); g_free(variant); } static -void bt_ctf_field_type_array_destroy(struct bt_ctf_ref *ref) +void bt_ctf_field_type_array_destroy(struct bt_ctf_field_type *type) { - struct bt_ctf_field_type_array *array; + struct bt_ctf_field_type_array *array = + (struct bt_ctf_field_type_array *) type; - if (!ref) { + if (!type) { return; } - array = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_array, parent); - bt_ctf_field_type_put(array->element_type); + bt_put(array->element_type); g_free(array); } static -void bt_ctf_field_type_sequence_destroy(struct bt_ctf_ref *ref) +void bt_ctf_field_type_sequence_destroy(struct bt_ctf_field_type *type) { - struct bt_ctf_field_type_sequence *sequence; + struct bt_ctf_field_type_sequence *sequence = + (struct bt_ctf_field_type_sequence *) type; - if (!ref) { + if (!type) { return; } - sequence = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_sequence, parent); - bt_ctf_field_type_put(sequence->element_type); + bt_put(sequence->element_type); g_string_free(sequence->length_field_name, TRUE); + bt_ctf_field_path_destroy(sequence->length_field_path); g_free(sequence); } static -void bt_ctf_field_type_string_destroy(struct bt_ctf_ref *ref) +void bt_ctf_field_type_string_destroy(struct bt_ctf_field_type *type) { - struct bt_ctf_field_type_string *string; + struct bt_ctf_field_type_string *string = + (struct bt_ctf_field_type_string *) type; - if (!ref) { + if (!type) { return; } - string = container_of( - container_of(ref, struct bt_ctf_field_type, ref_count), - struct bt_ctf_field_type_string, parent); g_free(string); } @@ -1082,9 +2451,11 @@ void bt_ctf_field_type_structure_freeze(struct bt_ctf_field_type *type) struct bt_ctf_field_type_structure *structure_type = container_of( type, struct bt_ctf_field_type_structure, parent); + /* Cache the alignment */ + type->declaration->alignment = bt_ctf_field_type_get_alignment(type); generic_field_type_freeze(type); - g_ptr_array_foreach(structure_type->fields, (GFunc)freeze_structure_field, - NULL); + g_ptr_array_foreach(structure_type->fields, + (GFunc) freeze_structure_field, NULL); } static @@ -1093,9 +2464,11 @@ void bt_ctf_field_type_variant_freeze(struct bt_ctf_field_type *type) struct bt_ctf_field_type_variant *variant_type = container_of( type, struct bt_ctf_field_type_variant, parent); + /* Cache the alignment */ + type->declaration->alignment = bt_ctf_field_type_get_alignment(type); generic_field_type_freeze(type); - g_ptr_array_foreach(variant_type->fields, (GFunc)freeze_structure_field, - NULL); + g_ptr_array_foreach(variant_type->fields, + (GFunc) freeze_structure_field, NULL); } static @@ -1104,6 +2477,8 @@ void bt_ctf_field_type_array_freeze(struct bt_ctf_field_type *type) struct bt_ctf_field_type_array *array_type = container_of( type, struct bt_ctf_field_type_array, parent); + /* Cache the alignment */ + type->declaration->alignment = bt_ctf_field_type_get_alignment(type); generic_field_type_freeze(type); bt_ctf_field_type_freeze(array_type->element_type); } @@ -1114,6 +2489,8 @@ void bt_ctf_field_type_sequence_freeze(struct bt_ctf_field_type *type) struct bt_ctf_field_type_sequence *sequence_type = container_of( type, struct bt_ctf_field_type_sequence, parent); + /* Cache the alignment */ + type->declaration->alignment = bt_ctf_field_type_get_alignment(type); generic_field_type_freeze(type); bt_ctf_field_type_freeze(sequence_type->element_type); } @@ -1173,15 +2550,31 @@ int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type *type, { struct bt_ctf_field_type_integer *integer = container_of(type, struct bt_ctf_field_type_integer, parent); + int ret = 0; g_string_append_printf(context->string, - "integer { size = %zu; align = %zu; signed = %s; encoding = %s; base = %s; byte_order = %s; }", + "integer { size = %zu; align = %zu; signed = %s; encoding = %s; base = %s; byte_order = %s", integer->declaration.len, type->declaration->alignment, (integer->declaration.signedness ? "true" : "false"), get_encoding_string(integer->declaration.encoding), get_integer_base_string(integer->declaration.base), get_byte_order_string(integer->declaration.byte_order)); - return 0; + if (integer->mapped_clock) { + const char *clock_name = bt_ctf_clock_get_name( + integer->mapped_clock); + + if (!clock_name) { + ret = -1; + goto end; + } + + g_string_append_printf(context->string, + "; map = clock.%s.value", clock_name); + } + + g_string_append(context->string, "; }"); +end: + return ret; } static @@ -1192,16 +2585,30 @@ int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type, int ret; struct bt_ctf_field_type_enumeration *enumeration = container_of(type, struct bt_ctf_field_type_enumeration, parent); + struct bt_ctf_field_type *container_type; + int container_signed; ret = bt_ctf_field_type_validate(type); if (ret) { goto end; } + container_type = bt_ctf_field_type_enumeration_get_container_type(type); + if (!container_type) { + ret = -1; + goto end; + } + + container_signed = bt_ctf_field_type_integer_get_signed(container_type); + if (container_signed < 0) { + ret = container_signed; + goto error_put_container_type; + } + g_string_append(context->string, "enum : "); ret = bt_ctf_field_type_serialize(enumeration->container, context); if (ret) { - goto end; + goto error_put_container_type; } g_string_append(context->string, " { "); @@ -1209,16 +2616,34 @@ int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type, struct enumeration_mapping *mapping = enumeration->entries->pdata[entry]; - if (mapping->range_start == mapping->range_end) { - g_string_append_printf(context->string, - "\"%s\" = %" PRId64, - g_quark_to_string(mapping->string), - mapping->range_start); + if (container_signed) { + if (mapping->range_start._signed == + mapping->range_end._signed) { + g_string_append_printf(context->string, + "\"%s\" = %" PRId64, + g_quark_to_string(mapping->string), + mapping->range_start._signed); + } else { + g_string_append_printf(context->string, + "\"%s\" = %" PRId64 " ... %" PRId64, + g_quark_to_string(mapping->string), + mapping->range_start._signed, + mapping->range_end._signed); + } } else { - g_string_append_printf(context->string, - "\"%s\" = %" PRId64 " ... %" PRId64, - g_quark_to_string(mapping->string), - mapping->range_start, mapping->range_end); + if (mapping->range_start._unsigned == + mapping->range_end._unsigned) { + g_string_append_printf(context->string, + "\"%s\" = %" PRIu64, + g_quark_to_string(mapping->string), + mapping->range_start._unsigned); + } else { + g_string_append_printf(context->string, + "\"%s\" = %" PRIu64 " ... %" PRIu64, + g_quark_to_string(mapping->string), + mapping->range_start._unsigned, + mapping->range_end._unsigned); + } } g_string_append(context->string, @@ -1231,6 +2656,8 @@ int bt_ctf_field_type_enumeration_serialize(struct bt_ctf_field_type *type, context->field_name->str); g_string_assign(context->field_name, ""); } +error_put_container_type: + bt_put(container_type); end: return ret; } @@ -1316,8 +2743,13 @@ int bt_ctf_field_type_variant_serialize(struct bt_ctf_field_type *type, GString *variant_field_name = context->field_name; context->field_name = g_string_new(""); - g_string_append_printf(context->string, - "variant <%s> {\n", variant->tag_name->str); + if (variant->tag_name->len > 0) { + g_string_append_printf(context->string, + "variant <%s> {\n", variant->tag_name->str); + } else { + g_string_append(context->string, "variant {\n"); + } + context->current_indentation_level++; for (i = 0; i < variant->fields->len; i++) { struct structure_field *field = variant->fields->pdata[i]; @@ -1422,24 +2854,443 @@ int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type *type, static void bt_ctf_field_type_integer_set_byte_order(struct bt_ctf_field_type *type, - int byte_order) + int byte_order, int set_native) { struct bt_ctf_field_type_integer *integer_type = container_of(type, struct bt_ctf_field_type_integer, parent); - integer_type->declaration.byte_order = byte_order; + if (set_native) { + integer_type->declaration.byte_order = + integer_type->declaration.byte_order == 0 ? + byte_order : integer_type->declaration.byte_order; + } else { + integer_type->declaration.byte_order = byte_order; + } +} + +static +void bt_ctf_field_type_enumeration_set_byte_order( + struct bt_ctf_field_type *type, int byte_order, int set_native) +{ + struct bt_ctf_field_type_enumeration *enum_type = container_of(type, + struct bt_ctf_field_type_enumeration, parent); + + /* Safe to assume that container is an integer */ + bt_ctf_field_type_integer_set_byte_order(enum_type->container, + byte_order, set_native); } static void bt_ctf_field_type_floating_point_set_byte_order( - struct bt_ctf_field_type *type, int byte_order) + struct bt_ctf_field_type *type, int byte_order, int set_native) { struct bt_ctf_field_type_floating_point *floating_point_type = container_of(type, struct bt_ctf_field_type_floating_point, parent); - floating_point_type->declaration.byte_order = byte_order; - floating_point_type->sign.byte_order = byte_order; - floating_point_type->mantissa.byte_order = byte_order; - floating_point_type->exp.byte_order = byte_order; + if (set_native) { + floating_point_type->declaration.byte_order = + floating_point_type->declaration.byte_order == 0 ? + byte_order : + floating_point_type->declaration.byte_order; + floating_point_type->sign.byte_order = + floating_point_type->sign.byte_order == 0 ? + byte_order : floating_point_type->sign.byte_order; + floating_point_type->mantissa.byte_order = + floating_point_type->mantissa.byte_order == 0 ? + byte_order : floating_point_type->mantissa.byte_order; + floating_point_type->exp.byte_order = + floating_point_type->exp.byte_order == 0 ? + byte_order : floating_point_type->exp.byte_order; + } else { + floating_point_type->declaration.byte_order = byte_order; + floating_point_type->sign.byte_order = byte_order; + floating_point_type->mantissa.byte_order = byte_order; + floating_point_type->exp.byte_order = byte_order; + } +} + +static +void bt_ctf_field_type_structure_set_byte_order(struct bt_ctf_field_type *type, + int byte_order, int set_native) +{ + int i; + struct bt_ctf_field_type_structure *structure_type = + container_of(type, struct bt_ctf_field_type_structure, + parent); + + for (i = 0; i < structure_type->fields->len; i++) { + struct structure_field *field = g_ptr_array_index( + structure_type->fields, i); + struct bt_ctf_field_type *field_type = field->type; + + if (set_byte_order_funcs[field_type->declaration->id]) { + set_byte_order_funcs[field_type->declaration->id]( + field_type, byte_order, set_native); + } + } +} + +static +void bt_ctf_field_type_variant_set_byte_order(struct bt_ctf_field_type *type, + int byte_order, int set_native) +{ + int i; + struct bt_ctf_field_type_variant *variant_type = + container_of(type, struct bt_ctf_field_type_variant, + parent); + + for (i = 0; i < variant_type->fields->len; i++) { + struct structure_field *field = g_ptr_array_index( + variant_type->fields, i); + struct bt_ctf_field_type *field_type = field->type; + + if (set_byte_order_funcs[field_type->declaration->id]) { + set_byte_order_funcs[field_type->declaration->id]( + field_type, byte_order, set_native); + } + } +} + +static +void bt_ctf_field_type_array_set_byte_order(struct bt_ctf_field_type *type, + int byte_order, int set_native) +{ + struct bt_ctf_field_type_array *array_type = + container_of(type, struct bt_ctf_field_type_array, + parent); + + if (set_byte_order_funcs[array_type->element_type->declaration->id]) { + set_byte_order_funcs[array_type->element_type->declaration->id]( + array_type->element_type, byte_order, set_native); + } +} + +static +void bt_ctf_field_type_sequence_set_byte_order(struct bt_ctf_field_type *type, + int byte_order, int set_native) +{ + struct bt_ctf_field_type_sequence *sequence_type = + container_of(type, struct bt_ctf_field_type_sequence, + parent); + + if (set_byte_order_funcs[ + sequence_type->element_type->declaration->id]) { + set_byte_order_funcs[ + sequence_type->element_type->declaration->id]( + sequence_type->element_type, byte_order, set_native); + } +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_integer_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy; + struct bt_ctf_field_type_integer *integer, *copy_integer; + + integer = container_of(type, struct bt_ctf_field_type_integer, parent); + copy = bt_ctf_field_type_integer_create(integer->declaration.len); + if (!copy) { + goto end; + } + + copy_integer = container_of(copy, struct bt_ctf_field_type_integer, + parent); + copy_integer->declaration = integer->declaration; + if (integer->mapped_clock) { + bt_get(integer->mapped_clock); + copy_integer->mapped_clock = integer->mapped_clock; + } +end: + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy( + struct bt_ctf_field_type *type) +{ + size_t i; + struct bt_ctf_field_type *copy = NULL, *copy_container; + struct bt_ctf_field_type_enumeration *enumeration, *copy_enumeration; + + enumeration = container_of(type, struct bt_ctf_field_type_enumeration, + parent); + + /* Copy the source enumeration's container */ + copy_container = bt_ctf_field_type_copy(enumeration->container); + if (!copy_container) { + goto end; + } + + copy = bt_ctf_field_type_enumeration_create(copy_container); + if (!copy) { + goto end; + } + copy_enumeration = container_of(copy, + struct bt_ctf_field_type_enumeration, parent); + + /* Copy all enumaration entries */ + for (i = 0; i < enumeration->entries->len; i++) { + struct enumeration_mapping *mapping = g_ptr_array_index( + enumeration->entries, i); + struct enumeration_mapping* copy_mapping = g_new0( + struct enumeration_mapping, 1); + + if (!copy_mapping) { + goto error; + } + + *copy_mapping = *mapping; + g_ptr_array_add(copy_enumeration->entries, copy_mapping); + } + + copy_enumeration->declaration = enumeration->declaration; +end: + bt_put(copy_container); + return copy; +error: + bt_put(copy_container); + BT_PUT(copy); + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy; + struct bt_ctf_field_type_floating_point *floating_point, *copy_float; + + floating_point = container_of(type, + struct bt_ctf_field_type_floating_point, parent); + copy = bt_ctf_field_type_floating_point_create(); + if (!copy) { + goto end; + } + + copy_float = container_of(copy, + struct bt_ctf_field_type_floating_point, parent); + copy_float->declaration = floating_point->declaration; + copy_float->sign = floating_point->sign; + copy_float->mantissa = floating_point->mantissa; + copy_float->exp = floating_point->exp; +end: + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_structure_copy( + struct bt_ctf_field_type *type) +{ + int i; + GHashTableIter iter; + gpointer key, value; + struct bt_ctf_field_type *copy; + struct bt_ctf_field_type_structure *structure, *copy_structure; + + structure = container_of(type, struct bt_ctf_field_type_structure, + parent); + copy = bt_ctf_field_type_structure_create(); + if (!copy) { + goto end; + } + + copy_structure = container_of(copy, + struct bt_ctf_field_type_structure, parent); + + /* Copy field_name_to_index */ + g_hash_table_iter_init(&iter, structure->field_name_to_index); + while (g_hash_table_iter_next (&iter, &key, &value)) { + g_hash_table_insert(copy_structure->field_name_to_index, + key, value); + } + + for (i = 0; i < structure->fields->len; i++) { + struct structure_field *entry, *copy_entry; + struct bt_ctf_field_type *copy_field; + + copy_entry = g_new0(struct structure_field, 1); + if (!copy_entry) { + goto error; + } + + entry = g_ptr_array_index(structure->fields, i); + copy_field = bt_ctf_field_type_copy(entry->type); + if (!copy_field) { + g_free(copy_entry); + goto error; + } + + copy_entry->name = entry->name; + copy_entry->type = copy_field; + g_ptr_array_add(copy_structure->fields, copy_entry); + } + + copy_structure->declaration = structure->declaration; +end: + return copy; +error: + BT_PUT(copy); + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_variant_copy( + struct bt_ctf_field_type *type) +{ + int i; + GHashTableIter iter; + gpointer key, value; + struct bt_ctf_field_type *copy = NULL, *copy_tag = NULL; + struct bt_ctf_field_type_variant *variant, *copy_variant; + + variant = container_of(type, struct bt_ctf_field_type_variant, + parent); + if (variant->tag) { + copy_tag = bt_ctf_field_type_copy(&variant->tag->parent); + if (!copy_tag) { + goto end; + } + } + + copy = bt_ctf_field_type_variant_create(copy_tag, + variant->tag_name->len ? variant->tag_name->str : NULL); + if (!copy) { + goto end; + } + + copy_variant = container_of(copy, struct bt_ctf_field_type_variant, + parent); + + /* Copy field_name_to_index */ + g_hash_table_iter_init(&iter, variant->field_name_to_index); + while (g_hash_table_iter_next (&iter, &key, &value)) { + g_hash_table_insert(copy_variant->field_name_to_index, + key, value); + } + + for (i = 0; i < variant->fields->len; i++) { + struct structure_field *entry, *copy_entry; + struct bt_ctf_field_type *copy_field; + + copy_entry = g_new0(struct structure_field, 1); + if (!copy_entry) { + goto error; + } + + entry = g_ptr_array_index(variant->fields, i); + copy_field = bt_ctf_field_type_copy(entry->type); + if (!copy_field) { + g_free(copy_entry); + goto error; + } + + copy_entry->name = entry->name; + copy_entry->type = copy_field; + g_ptr_array_add(copy_variant->fields, copy_entry); + } + + copy_variant->declaration = variant->declaration; + if (variant->tag_path) { + copy_variant->tag_path = bt_ctf_field_path_copy( + variant->tag_path); + if (!copy_variant->tag_path) { + goto error; + } + } +end: + bt_put(copy_tag); + return copy; +error: + bt_put(copy_tag); + BT_PUT(copy); + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_array_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy = NULL, *copy_element; + struct bt_ctf_field_type_array *array, *copy_array; + + array = container_of(type, struct bt_ctf_field_type_array, + parent); + copy_element = bt_ctf_field_type_copy(array->element_type); + if (!copy_element) { + goto end; + } + + copy = bt_ctf_field_type_array_create(copy_element, array->length); + if (!copy) { + goto end; + } + + copy_array = container_of(copy, struct bt_ctf_field_type_array, + parent); + copy_array->declaration = array->declaration; +end: + bt_put(copy_element); + return copy; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy = NULL, *copy_element; + struct bt_ctf_field_type_sequence *sequence, *copy_sequence; + + sequence = container_of(type, struct bt_ctf_field_type_sequence, + parent); + copy_element = bt_ctf_field_type_copy(sequence->element_type); + if (!copy_element) { + goto end; + } + + copy = bt_ctf_field_type_sequence_create(copy_element, + sequence->length_field_name->len ? + sequence->length_field_name->str : NULL); + if (!copy) { + goto end; + } + + copy_sequence = container_of(copy, struct bt_ctf_field_type_sequence, + parent); + copy_sequence->declaration = sequence->declaration; + if (sequence->length_field_path) { + copy_sequence->length_field_path = bt_ctf_field_path_copy( + sequence->length_field_path); + if (!copy_sequence->length_field_path) { + goto error; + } + } +end: + bt_put(copy_element); + return copy; +error: + BT_PUT(copy); + goto end; +} + +static +struct bt_ctf_field_type *bt_ctf_field_type_string_copy( + struct bt_ctf_field_type *type) +{ + struct bt_ctf_field_type *copy; + struct bt_ctf_field_type_string *string, *copy_string; + + copy = bt_ctf_field_type_string_create(); + if (!copy) { + goto end; + } + + string = container_of(type, struct bt_ctf_field_type_string, + parent); + copy_string = container_of(type, struct bt_ctf_field_type_string, + parent); + copy_string->declaration = string->declaration; +end: + return copy; }