-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathNDEF_TXT.cpp
More file actions
318 lines (270 loc) · 8.86 KB
/
NDEF_TXT.cpp
File metadata and controls
318 lines (270 loc) · 8.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/* NDEF_URI - Handle URI NFC NDEF records
*
* Copyright (c) 2015 Eric Brundick <spirilis [at] linux dot com>
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "NDEF_TXT.h"
const uint8_t ndef_txt_record_type = 'T';
NDEF_TXT::NDEF_TXT()
{
tnf = NDEF_TNF_WELLKNOWN;
type_length = 1;
type = (char *)&ndef_txt_record_type;
id_length = 0;
id = NULL;
payload_length = 0;
payload_buf_maxlen = 0;
payload = NULL;
// English by default
strcpy(lang, "en");
lang_length = 2;
is_utf16 = false; // UTF-8 by default
}
NDEF_TXT::NDEF_TXT(const char *lang_)
{
tnf = NDEF_TNF_WELLKNOWN;
type_length = 1;
type = (char *)&ndef_txt_record_type;
id_length = 0;
id = NULL;
payload_length = 0;
payload_buf_maxlen = 0;
payload = NULL;
lang_length = strlen(lang_);
if (lang_length > 8) { // Invalid for this library; use "en" per defaults.
strcpy(lang, "en");
lang_length = 2;
} else {
strncpy(lang, lang_, lang_length);
}
is_utf16 = false; // UTF-8 by default
}
NDEF_TXT::NDEF_TXT(const char *lang_, const char *text_, boolean utf16)
{
tnf = NDEF_TNF_WELLKNOWN;
type_length = 1;
type = (char *)&ndef_txt_record_type;
id_length = 0;
id = NULL;
payload = (uint8_t *)text_;
payload_length = strlen(text_);
payload_buf_maxlen = 0;
lang_length = strlen(lang_);
if (lang_length > 8) { // Invalid for this library; use "en" per defaults.
strcpy(lang, "en");
lang_length = 2;
} else {
strncpy(lang, lang_, lang_length);
}
is_utf16 = utf16;
}
void NDEF_TXT::setLanguage(const char *lang_)
{
lang_length = strlen(lang_);
if (lang_length > 8) { // Invalid for this library; bail without changing
return;
} else {
strncpy(lang, lang_, lang_length);
}
}
/* Perform a semi-intelligent test comparing the intended language "l" with
* the actual language specifier to see if it's a subset; e.g. for lang[] = "en-US",
* searching for l[] = "en" should suffice.
*/
boolean NDEF_TXT::testLanguage(const char *l)
{
int i;
char langlow[9], llow[9];
if (l == NULL)
return false;
size_t llen = strlen(l);
if (!llen)
return false;
if (llen > lang_length)
return false;
// Copy strings into temporary buffers with lowercase
for (i=0; i < lang_length; i++) {
langlow[i] = lang[i];
if (langlow[i] >= 'A' && langlow[i] <= 'Z')
langlow[i] += 32;
}
langlow[i] = '\0';
for (i=0; i < llen; i++) {
llow[i] = l[i];
if (llow[i] >= 'A' && llow[i] <= 'Z')
llow[i] += 32;
}
llow[i] = '\0';
// Compare
if (llen == lang_length) {
if (!strncmp(llow, langlow, llen))
return true;
return false;
}
if (strchr(llow, '-') == NULL && langlow[llen] == '-' && !strncmp(llow, langlow, llen)) // Search is specifying a subset, e.g. "en" out of "en-US"
return true;
return false;
}
int NDEF_TXT::setText(const char *text)
{
if (!payload_buf_maxlen) {
// No payload buffer exists, so instead we must be intending to replace the payload entirely
payload = (uint8_t *)text;
payload_length = strlen(text);
return payload_length;
}
// Payload buffer exists; stuff it with as much as can fit
size_t tlen = strlen(text);
if (tlen > payload_buf_maxlen)
tlen = payload_buf_maxlen;
strncpy((char *)payload, text, tlen);
payload_length = tlen;
return tlen;
}
size_t NDEF_TXT::write(const uint8_t *text, size_t len)
{
if (!payload_buf_maxlen)
return 0; // Not possible! This isn't a general-purpose writable buffer.
if (len > (payload_buf_maxlen - payload_length))
len = payload_buf_maxlen - payload_length;
strncat((char *)payload, (const char *)text, len);
payload_length += len;
return len;
}
size_t NDEF_TXT::write(uint8_t c)
{
if (!payload_buf_maxlen)
return 0; // Not possible! This isn't a general-purpose writable buffer.
if (payload_length == payload_buf_maxlen)
return 0; // No more room!
payload[payload_length++] = c;
payload[payload_length] = '\0';
return 1;
}
int NDEF_TXT::sendTo(Print &p, boolean first_msg, boolean last_msg)
{
uint32_t real_plen = payload_length + lang_length + 1;
int printedSize = 0;
uint8_t msghdr;
// Output valid NDEF binary format
msghdr = 0x00;
if (first_msg)
msghdr |= NDEF_FIELD_MB;
if (last_msg)
msghdr |= NDEF_FIELD_ME;
if (real_plen > 254) {
p.write(tnf | msghdr); // SR cleared, using 32-bit Payload Length
} else {
p.write(tnf | msghdr | NDEF_FIELD_SR);
}
p.write(1); // Length of TYPE field
printedSize = 2;
if (real_plen > 254) {
// PAYLOAD_LENGTH is a 32-bit Big-Endian unsigned integer
p.write((uint8_t) (real_plen >> 24));
p.write((uint8_t) ((real_plen >> 16) & 0xFF));
p.write((uint8_t) ((real_plen >> 8) & 0xFF));
p.write((uint8_t) (real_plen & 0xFF));
printedSize += 4;
} else {
// PAYLOAD_LENGTH is an 8-bit unsigned integer
p.write(real_plen);
printedSize++;
}
p.write((uint8_t) type[0]); // TYPE
// PAYLOAD
if (is_utf16)
p.write(NDEF_RTD_TEXT_STATUS_UTF16 | lang_length);
else
p.write(lang_length);
printedSize += 2;
p.write((const uint8_t *)lang, lang_length);
printedSize += lang_length;
p.write((const uint8_t *)payload, payload_length);
printedSize += payload_length;
// NOTE: printedSize may be a smaller variable than payload_length
return printedSize;
}
int NDEF_TXT::import(Stream &s)
{
int c, ndef_hdr;
size_t plen, plen_write, llen;
uint8_t plen32[4];
// Requires setPayloadBuffer() to have been used previously
if (payload == NULL || payload_buf_maxlen < 1)
return -1; // Not going to bother attempting to read
// read NDEF header byte
c = s.read(); if (c < 0) return -1;
if ( (c & NDEF_FIELD_IL) || ((c & 0x03) != NDEF_TNF_WELLKNOWN) )
return -1; // Not a URI RTD...
ndef_hdr = c;
// read TYPE_LENGTH
c = s.read(); if (c < 0) return -1;
if (c != 0x01)
return -1; // Not a URI RTD, as the TYPE field should be a single character
// read PAYLOAD_LENGTH
if (ndef_hdr & NDEF_FIELD_SR) {
c = s.read(); if (c < 0) return -1;
plen = c;
} else {
if (s.readBytes((char *)&plen32[0], 4) < 4)
return -1;
plen = ((uint32_t) plen32[0]) << 24 |
((uint32_t) plen32[1]) << 16 |
((uint32_t) plen32[2]) << 8 |
((uint32_t) plen32[3]);
}
payload_length = plen - 1; // Length of non-abbreviation portion
// read TYPE
c = s.read(); if (c < 0) return -1;
if (c != type[0])
return -1;
// read PAYLOAD
c = s.read(); if (c < 0) return -1;
if ( (c & 0x3F) < 1 || (c & 0x40) )
return -1; // Invalid abbreviation byte
if (c & NDEF_RTD_TEXT_STATUS_UTF16)
is_utf16 = true;
else
is_utf16 = false;
plen--;
// read LANGUAGE
llen = c & 0x3F;
if (llen > 8)
return -1; // We're not supporting >8 byte language codes for now
if (s.readBytes(lang, llen) < llen)
return -1;
lang_length = llen;
plen -= llen;
plen_write = plen; // Max # of bytes writable to payload[] before we just read & discard
if (payload_buf_maxlen < plen_write)
plen_write = payload_buf_maxlen;
if (s.readBytes((char *)payload, plen_write) < plen_write)
return -1;
// Drain remaining bytes that wouldn't fit into payload[] buffer
plen -= plen_write;
while (plen && c != -1) {
c = s.read();
plen--;
}
// All done!
return plen_write;
}