From 06c88a9b44d30b6051cf376568f05cbe48d6354b Mon Sep 17 00:00:00 2001 From: Ravikumar Veeramally Date: Fri, 23 Sep 2011 16:01:52 +0300 Subject: [PATCH] ndef: Parsing ndef smartposter record Parsing ndef smartposter record and caching its properties for D-Bus replies. Validating language indentifier in smartposter title records. --- src/ndef.c | 315 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 313 insertions(+), 2 deletions(-) diff --git a/src/ndef.c b/src/ndef.c index 98d2c61..e36867a 100644 --- a/src/ndef.c +++ b/src/ndef.c @@ -81,6 +81,19 @@ struct near_ndef_uri_record { uint8_t *field; }; +struct near_ndef_sp_record { + uint8_t action; + + struct near_ndef_uri_record *uri; + + uint8_t number_of_title_records; + struct near_ndef_text_record **title_records; + + uint32_t size; /* from Size record*/ + char *type; /* from Type record*/ + /* TODO add icon and other records fields*/ +}; + struct near_ndef_record { char *path; uint8_t tnf; @@ -88,6 +101,7 @@ struct near_ndef_record { struct near_ndef_text_record *text; struct near_ndef_uri_record *uri; + struct near_ndef_sp_record *sp; }; static DBusConnection *connection = NULL; @@ -289,6 +303,27 @@ static void free_uri_record(struct near_ndef_uri_record *uri) uri = NULL; } +static void free_sp_record(struct near_ndef_sp_record *sp) +{ + uint8_t i; + + if (sp == NULL) + return; + + free_uri_record(sp->uri); + + if (sp->title_records != NULL) { + for (i = 0; i < sp->number_of_title_records; i++) + free_text_record(sp->title_records[i]); + } + + g_free(sp->title_records); + g_free(sp->type); + g_free(sp); + + sp = NULL; +} + static void free_ndef_record(struct near_ndef_record *record) { if (record == NULL) @@ -297,7 +332,6 @@ static void free_ndef_record(struct near_ndef_record *record) g_free(record->path); switch (record->type) { - case RECORD_TYPE_WKT_SMART_POSTER: case RECORD_TYPE_WKT_SIZE: case RECORD_TYPE_WKT_TYPE: case RECORD_TYPE_WKT_ACTION: @@ -318,6 +352,10 @@ static void free_ndef_record(struct near_ndef_record *record) case RECORD_TYPE_WKT_URI: free_uri_record(record->uri); break; + + case RECORD_TYPE_WKT_SMART_POSTER: + free_sp_record(record->sp); + break; } g_free(record); @@ -574,6 +612,268 @@ fail: return NULL; } +/** + * @brief Validate titles records language code in Smartposter. + * There must not be two or more records with the same language identifier. + * + * @param[in] GSList * list of title recods (struct near_ndef_text_record *) + * + * @return Zero on success + * Negative value on failure + */ + +static int8_t validate_language_code_in_sp_record(GSList *titles) +{ + uint8_t i, j, length; + struct near_ndef_text_record *title1, *title2; + + DBG(""); + + if (titles == NULL) + return -EINVAL; + + length = g_slist_length(titles); + + for (i = 0; i < length; i++) { + title1 = g_slist_nth_data(titles, i); + + for (j = i + 1; j < length; j++) { + title2 = g_slist_nth_data(titles, j); + + if ((title1->language_code == NULL) && + (title2->language_code == NULL)) + continue; + + if (g_strcmp0(title1->language_code, + title2->language_code) == 0) + return -EINVAL; + } + } + + return 0; +} + +/** + * @brief Parse the smart poster record. + * + * Parse the smart poster record and cache the + * data in respective fields of smart poster structure. + * + * @note Caller responsibility to free the memory. + * + * @param[in] ndef_data NDEF raw data pointer + * @param[in] ndef_length NDEF raw data length + * @param[in] offset Sp record payload offset + * + * @return struct near_ndef_sp_record * Record on Success + * NULL on Failure + */ + +static struct near_ndef_sp_record *parse_smart_poster_record(uint8_t *ndef_data, + size_t ndef_length, size_t offset, + uint32_t payload_length) +{ + struct near_ndef_sp_record *sp_record = NULL; + uint8_t mb = 0, me = 0, i; + size_t t_offset; + GSList *titles = NULL, *temp; + + DBG(""); + + if (ndef_data == NULL || offset >= ndef_length) + return NULL; + + t_offset = offset; + sp_record = g_try_malloc0(sizeof(struct near_ndef_sp_record)); + if (sp_record == NULL) + return NULL; + + while (t_offset < (offset + payload_length)) { + uint8_t t_mb, t_me, t_sr, t_cf, t_il, t_tnf; + uint8_t type_length, il_length = 0, r_type = 0xfe; + uint8_t *type = NULL; + uint32_t payload_length; + + DBG("Record header : 0x%x", ndef_data[t_offset]); + + t_mb = RECORD_MB_BIT(ndef_data[t_offset]); + t_me = RECORD_ME_BIT(ndef_data[t_offset]); + t_sr = RECORD_SR_BIT(ndef_data[t_offset]); + t_cf = RECORD_CF_BIT(ndef_data[t_offset]); + t_il = RECORD_IL_BIT(ndef_data[t_offset]); + t_tnf = RECORD_TNF_BIT(ndef_data[t_offset]); + + if (validate_record_begin_and_end_bits(&mb, + &me, t_mb, t_me) != 0) { + DBG("validate mb me failed"); + goto fail; + } + + /* + * calculate ndef length is enough or not against id, + * typename and payload to extract Sp sub-records(eg: Uri, + * Title, Action, Size, Type and Other) + */ + t_offset++; + type_length = ndef_data[t_offset]; + t_offset++; + + if (t_sr == 1) { + payload_length = ndef_data[t_offset]; + t_offset++; + } else { + payload_length = *((uint32_t *)(ndef_data + t_offset)); + t_offset += 4; + + if (t_offset >= ndef_length) + goto fail; + } + + if (t_il == 1) { + il_length = ndef_data[t_offset]; + t_offset++; + + if (t_offset >= ndef_length) + goto fail; + } + + if ((t_offset + type_length + il_length + payload_length) + > ndef_length) + goto fail; + + if (type_length > 0) { + type = g_try_malloc0(type_length); + if (type == NULL) + goto fail; + + memcpy(type, ndef_data+t_offset, type_length); + } + + r_type = get_record_type(t_tnf, type, type_length); + + t_offset += type_length + il_length; + + switch (r_type) { + case RECORD_TYPE_WKT_HANDOVER_REQUEST: + case RECORD_TYPE_WKT_HANDOVER_SELECT: + case RECORD_TYPE_WKT_HANDOVER_CARRIER: + case RECORD_TYPE_WKT_ALTERNATIVE_CARRIER: + case RECORD_TYPE_WKT_COLLISION_RESOLUTION: + case RECORD_TYPE_WKT_ERROR: + case RECORD_TYPE_UNKNOWN: + case RECORD_TYPE_ERROR: + break; + + case RECORD_TYPE_WKT_URI: + /* URI record should be only one. */ + if (sp_record->uri != NULL) + goto fail; + + sp_record->uri = parse_uri_record(ndef_data, + ndef_length, t_offset, + payload_length); + + if (sp_record->uri == NULL) + goto fail; + + break; + + case RECORD_TYPE_WKT_TEXT: + /* + * Title records can zero or more. First fill the + * records in list and validate language identifier + * and then cache them into sp record structure. + */ + { + struct near_ndef_text_record *title; + title = parse_text_record(ndef_data, ndef_length, + t_offset, payload_length); + + if (title == NULL) + goto fail; + + titles = g_slist_append(titles, title); + } + break; + + case RECORD_TYPE_WKT_SIZE: + /* + * If paylaod length is not exactly 4 bytes + * then record is wrong. + */ + if (payload_length != 4) + goto fail; + + sp_record->size = *((uint32_t *)(ndef_data + t_offset)); + break; + + case RECORD_TYPE_WKT_TYPE: + + if (payload_length > 0) { + sp_record->type = g_try_malloc0(payload_length); + if (sp_record->type == NULL) + goto fail; + + sp_record->type = g_strndup( + (char *) ndef_data + t_offset, + payload_length); + } + + break; + + case RECORD_TYPE_WKT_ACTION: + /* + * If the action record exists, payload should be + * single byte, otherwise consider it as error. + */ + if (payload_length != 1) + goto fail; + + sp_record->action = ndef_data[t_offset]; + break; + } + + t_offset += payload_length; + } + + /* + * Code to fill smart poster record structure from + * 'titles' list. + */ + if (titles == NULL) + return sp_record; + + if (validate_language_code_in_sp_record(titles) != 0) { + DBG("language code validation failed"); + goto fail; + } + + temp = titles; + sp_record->number_of_title_records = g_slist_length(temp); + sp_record->title_records = g_try_malloc0( + sp_record->number_of_title_records * + sizeof(struct near_ndef_text_record *)); + if (sp_record->title_records == NULL) + goto fail; + + for (i = 0; i < sp_record->number_of_title_records; i++) { + sp_record->title_records[i] = temp->data; + temp = temp->next; + } + + g_slist_free(titles); + titles = NULL; + + return sp_record; + +fail: + near_error("smart poster record parsing failed"); + free_sp_record(sp_record); + g_slist_free(titles); + + return NULL; +} + int near_ndef_parse(struct near_tag *tag, uint8_t *ndef_data, size_t ndef_length) { @@ -669,7 +969,6 @@ int near_ndef_parse(struct near_tag *tag, record->type = r_type; switch (r_type) { - case RECORD_TYPE_WKT_SMART_POSTER: case RECORD_TYPE_WKT_SIZE: case RECORD_TYPE_WKT_TYPE: case RECORD_TYPE_WKT_ACTION: @@ -706,6 +1005,18 @@ int near_ndef_parse(struct near_tag *tag, } break; + + case RECORD_TYPE_WKT_SMART_POSTER: + record->sp = parse_smart_poster_record(ndef_data, + ndef_length, offset, + payload_length); + + if (record->sp == NULL) { + err = EINVAL; + goto fail; + } + + break; } n_records = __near_tag_n_records(tag); -- 2.7.4