aeded8f916e25dc3bf0769d459b997d74304388d
[platform/upstream/neard.git] / src / ndef.c
1 /*
2  *
3  *  neard - Near Field Communication manager
4  *
5  *  Copyright (C) 2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30
31 #include <glib.h>
32
33 #include <gdbus.h>
34
35 #include "near.h"
36
37 #define RECORD_TNF_EMPTY     0x00
38 #define RECORD_TNF_WELLKNOWN 0x01
39 #define RECORD_TNF_MIME      0x02
40 #define RECORD_TNF_URI       0x03
41 #define RECORD_TNF_EXTERNAL  0x04
42 #define RECORD_TNF_UNKNOWN   0x05
43 #define RECORD_TNF_UNCHANGED 0x06
44
45 #define RECORD_MB(record)  (((record)[0] & 0x80) >> 7)
46 #define RECORD_ME(record)  (((record)[0] & 0x40) >> 6)
47 #define RECORD_CF(record)  (((record)[0] & 0x20) >> 5)
48 #define RECORD_SR(record)  (((record)[0] & 0x10) >> 4)
49 #define RECORD_IL(record)  (((record)[0] & 0x8)  >> 3)
50 #define RECORD_TNF(record) ((record)[0] & 0x7)
51
52 void __near_ndef_destroy(struct near_ndef *ndef)
53 {
54         
55 }
56
57 static gboolean record_sp(uint8_t tnf, uint8_t *type, size_t type_length)
58 {
59         DBG("tnf 0x%x type length %zu", tnf, type_length);
60
61         if (tnf == RECORD_TNF_WELLKNOWN
62                         && type_length == 2
63                         && strncmp((char *)type, "Sp", 2) == 0)
64                 return TRUE;
65
66         return FALSE;
67
68 }
69
70 static uint8_t record_type_offset(uint8_t *record, size_t *type_length)
71 {
72         uint8_t sr, tnf, il;
73         uint32_t offset = 0;
74
75         sr = RECORD_SR(record);
76         il = RECORD_IL(record);
77         tnf = RECORD_TNF(record);
78         *type_length = record[1];
79
80         /* Record header */
81         offset += 1;
82
83         /* Type length */
84         offset += 1;
85
86         if (sr == 1)
87                 offset += 1;
88         else
89                 offset += 4;
90         
91         if (il == 1)
92                 offset += 1;
93
94         return offset;
95 }
96
97 static uint8_t record_payload_offset(uint8_t *record, size_t *payload_length)
98 {
99         uint8_t sr, tnf, il, type_length, id_length;
100         uint32_t offset = 0;
101
102         sr = RECORD_SR(record);
103         il = RECORD_IL(record);
104         tnf = RECORD_TNF(record);
105         type_length = record[1];
106
107         /* Record header */
108         offset += 1;
109
110         /* Type length */
111         offset += 1;
112
113         if (sr == 1) {
114                 *payload_length = record[offset];
115                 /* Payload length is 1 byte */
116                 offset += 1;
117         } else {
118                 *payload_length = *((uint32_t *)(record + offset));
119                 /* Payload length is 4 bytes */
120                 offset += 4;
121         }
122         
123         if (il == 1) {
124                 id_length = record[offset];
125                 offset += id_length;
126         } else {
127                 id_length = 0;
128         }       
129
130         /* Type value */
131         offset += type_length;
132
133         if (tnf == 0) {
134                 offset -= type_length;
135                 offset -= id_length;
136         }
137
138         DBG("type length %d payload length %zu id length %d offset %d", type_length, *payload_length, id_length, offset);
139
140         return offset;
141 }
142
143 struct near_ndef *__near_ndef_create(uint8_t *ndef_data, size_t ndef_length)
144 {
145         struct near_ndef *ndef;
146         struct near_ndef_record *record;
147         uint8_t *raw_record, payload_offset, type_offset;
148
149         ndef = g_try_malloc0(sizeof(struct near_ndef));
150         if (ndef == NULL)
151                 return NULL;
152
153         ndef->n_records = 0;
154         raw_record = ndef_data;
155
156         while (1) {
157                 uint8_t mb, me, sr, tnf, il;
158                 size_t i, type_length;
159         
160                 mb = RECORD_MB(raw_record);
161                 me = RECORD_ME(raw_record);
162                 sr = RECORD_SR(raw_record);
163                 il = RECORD_IL(raw_record);
164                 tnf = RECORD_TNF(raw_record);
165                 DBG("Record MB 0x%x ME 0x%x SR 0x%x IL 0x%x TNF 0x%x", mb, me, sr, il, tnf);
166
167                 if (ndef->n_records == 0 && mb != 1)
168                         return NULL;
169
170                 type_offset = record_type_offset(raw_record, &type_length);
171
172                 ndef->smart_poster = record_sp(tnf, raw_record + type_offset, type_length);
173                 if (ndef->smart_poster == TRUE) {
174                         size_t payload_length;
175
176                         DBG("Smart Poster");
177
178                         payload_offset = record_payload_offset(raw_record, &payload_length);
179
180                         raw_record += payload_offset;
181
182                         continue;
183                 }
184
185                 record = g_try_malloc0(sizeof(struct near_ndef_record));
186                 if (record == NULL) {
187                         __near_ndef_destroy(ndef);
188                         return NULL;
189                 }
190
191                 record->tnf = tnf;
192
193                 payload_offset = record_payload_offset(raw_record, &record->payload_length);
194                 record->payload = raw_record + payload_offset;
195
196                 type_offset = record_type_offset(raw_record, &record->type_length);
197                 record->type = raw_record + type_offset;
198
199                 for (i = 0; i < record->payload_length; i++)
200                         DBG("Payload[%d] %c 0x%x", i, record->payload[i], record->payload[i]);
201
202                 ndef->n_records += 1;
203                 ndef->records = g_list_append(ndef->records, record);
204
205                 if (me == 1)
206                         break;
207
208                 raw_record = record->payload + record->payload_length;
209         }
210
211         return ndef;
212 }