1 /******************************************************************************
2 *
3 * Copyright (C) 2010-2013 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19
20 /******************************************************************************
21 *
22 * This file contains source code for some utility functions to help parse
23 * and build NFC Data Exchange Format (NDEF) messages
24 *
25 ******************************************************************************/
26 #include <string.h>
27 #include "ndef_utils.h"
28
29 /*******************************************************************************
30 **
31 ** Static Local Functions
32 **
33 *******************************************************************************/
34
35
36 /*******************************************************************************
37 **
38 ** Function shiftdown
39 **
40 ** Description shift memory down (to make space to insert a record)
41 **
42 *******************************************************************************/
shiftdown(UINT8 * p_mem,UINT32 len,UINT32 shift_amount)43 static void shiftdown (UINT8 *p_mem, UINT32 len, UINT32 shift_amount)
44 {
45 register UINT8 *ps = p_mem + len - 1;
46 register UINT8 *pd = ps + shift_amount;
47 register UINT32 xx;
48
49 for (xx = 0; xx < len; xx++)
50 *pd-- = *ps--;
51 }
52
53 /*******************************************************************************
54 **
55 ** Function shiftup
56 **
57 ** Description shift memory up (to delete a record)
58 **
59 *******************************************************************************/
shiftup(UINT8 * p_dest,UINT8 * p_src,UINT32 len)60 static void shiftup (UINT8 *p_dest, UINT8 *p_src, UINT32 len)
61 {
62 register UINT8 *ps = p_src;
63 register UINT8 *pd = p_dest;
64 register UINT32 xx;
65
66 for (xx = 0; xx < len; xx++)
67 *pd++ = *ps++;
68 }
69
70 /*******************************************************************************
71 **
72 ** Function NDEF_MsgValidate
73 **
74 ** Description This function validates an NDEF message.
75 **
76 ** Returns TRUE if all OK, or FALSE if the message is invalid.
77 **
78 *******************************************************************************/
NDEF_MsgValidate(UINT8 * p_msg,UINT32 msg_len,BOOLEAN b_allow_chunks)79 tNDEF_STATUS NDEF_MsgValidate (UINT8 *p_msg, UINT32 msg_len, BOOLEAN b_allow_chunks)
80 {
81 UINT8 *p_rec = p_msg;
82 UINT8 *p_end = p_msg + msg_len;
83 UINT8 rec_hdr=0, type_len, id_len;
84 int count;
85 UINT32 payload_len;
86 BOOLEAN bInChunk = FALSE;
87
88 if ( (p_msg == NULL) || (msg_len < 3) )
89 return (NDEF_MSG_TOO_SHORT);
90
91 /* The first record must have the MB bit set */
92 if ((*p_msg & NDEF_MB_MASK) == 0)
93 return (NDEF_MSG_NO_MSG_BEGIN);
94
95 /* The first record cannot be a chunk */
96 if ((*p_msg & NDEF_TNF_MASK) == NDEF_TNF_UNCHANGED)
97 return (NDEF_MSG_UNEXPECTED_CHUNK);
98
99 for (count = 0; p_rec < p_end; count++)
100 {
101 /* if less than short record header */
102 if (p_rec + 3 > p_end)
103 return (NDEF_MSG_TOO_SHORT);
104
105 rec_hdr = *p_rec++;
106
107 /* The second and all subsequent records must NOT have the MB bit set */
108 if ( (count > 0) && (rec_hdr & NDEF_MB_MASK) )
109 return (NDEF_MSG_EXTRA_MSG_BEGIN);
110
111 /* Type field length */
112 type_len = *p_rec++;
113
114 /* Payload length - can be 1 or 4 bytes */
115 if (rec_hdr & NDEF_SR_MASK)
116 payload_len = *p_rec++;
117 else
118 {
119 /* if less than 4 bytes payload length */
120 if (p_rec + 4 > p_end)
121 return (NDEF_MSG_TOO_SHORT);
122
123 BE_STREAM_TO_UINT32 (payload_len, p_rec);
124 }
125
126 /* ID field Length */
127 if (rec_hdr & NDEF_IL_MASK)
128 {
129 /* if less than 1 byte ID field length */
130 if (p_rec + 1 > p_end)
131 return (NDEF_MSG_TOO_SHORT);
132
133 id_len = *p_rec++;
134 }
135 else
136 id_len = 0;
137
138 /* A chunk must have type "unchanged", and no type or ID fields */
139 if (rec_hdr & NDEF_CF_MASK)
140 {
141 if (!b_allow_chunks)
142 return (NDEF_MSG_UNEXPECTED_CHUNK);
143
144 /* Inside a chunk, the type must be unchanged and no type or ID field i sallowed */
145 if (bInChunk)
146 {
147 if ( (type_len != 0) || (id_len != 0) || ((rec_hdr & NDEF_TNF_MASK) != NDEF_TNF_UNCHANGED) )
148 return (NDEF_MSG_INVALID_CHUNK);
149 }
150 else
151 {
152 /* First record of a chunk must NOT have type "unchanged" */
153 if ((rec_hdr & NDEF_TNF_MASK) == NDEF_TNF_UNCHANGED)
154 return (NDEF_MSG_INVALID_CHUNK);
155
156 bInChunk = TRUE;
157 }
158 }
159 else
160 {
161 /* This may be the last guy in a chunk. */
162 if (bInChunk)
163 {
164 if ( (type_len != 0) || (id_len != 0) || ((rec_hdr & NDEF_TNF_MASK) != NDEF_TNF_UNCHANGED) )
165 return (NDEF_MSG_INVALID_CHUNK);
166
167 bInChunk = FALSE;
168 }
169 else
170 {
171 /* If not in a chunk, the record must NOT have type "unchanged" */
172 if ((rec_hdr & NDEF_TNF_MASK) == NDEF_TNF_UNCHANGED)
173 return (NDEF_MSG_INVALID_CHUNK);
174 }
175 }
176
177 /* An empty record must NOT have a type, ID or payload */
178 if ((rec_hdr & NDEF_TNF_MASK) == NDEF_TNF_EMPTY)
179 {
180 if ( (type_len != 0) || (id_len != 0) || (payload_len != 0) )
181 return (NDEF_MSG_INVALID_EMPTY_REC);
182 }
183
184 if ((rec_hdr & NDEF_TNF_MASK) == NDEF_TNF_UNKNOWN)
185 {
186 if (type_len != 0)
187 return (NDEF_MSG_LENGTH_MISMATCH);
188 }
189
190 /* Point to next record */
191 p_rec += (payload_len + type_len + id_len);
192
193 if (rec_hdr & NDEF_ME_MASK)
194 break;
195
196 rec_hdr = 0;
197 }
198
199 /* The last record should have the ME bit set */
200 if ((rec_hdr & NDEF_ME_MASK) == 0)
201 return (NDEF_MSG_NO_MSG_END);
202
203 /* p_rec should equal p_end if all the length fields were correct */
204 if (p_rec != p_end)
205 return (NDEF_MSG_LENGTH_MISMATCH);
206
207 return (NDEF_OK);
208 }
209
210 /*******************************************************************************
211 **
212 ** Function NDEF_MsgGetNumRecs
213 **
214 ** Description This function gets the number of records in the given NDEF
215 ** message.
216 **
217 ** Returns The record count, or 0 if the message is invalid.
218 **
219 *******************************************************************************/
NDEF_MsgGetNumRecs(UINT8 * p_msg)220 INT32 NDEF_MsgGetNumRecs (UINT8 *p_msg)
221 {
222 UINT8 *p_rec = p_msg;
223 UINT8 rec_hdr, type_len, id_len;
224 int count;
225 UINT32 payload_len;
226
227 for (count = 0; ; )
228 {
229 count++;
230
231 rec_hdr = *p_rec++;
232
233 if (rec_hdr & NDEF_ME_MASK)
234 break;
235
236 /* Type field length */
237 type_len = *p_rec++;
238
239 /* Payload length - can be 1 or 4 bytes */
240 if (rec_hdr & NDEF_SR_MASK)
241 payload_len = *p_rec++;
242 else
243 BE_STREAM_TO_UINT32 (payload_len, p_rec);
244
245 /* ID field Length */
246 if (rec_hdr & NDEF_IL_MASK)
247 id_len = *p_rec++;
248 else
249 id_len = 0;
250
251 /* Point to next record */
252 p_rec += (payload_len + type_len + id_len);
253 }
254
255 /* Return the number of records found */
256 return (count);
257 }
258
259 /*******************************************************************************
260 **
261 ** Function NDEF_MsgGetRecLength
262 **
263 ** Description This function returns length of the current record in the given
264 ** NDEF message.
265 **
266 ** Returns Length of record
267 **
268 *******************************************************************************/
NDEF_MsgGetRecLength(UINT8 * p_cur_rec)269 UINT32 NDEF_MsgGetRecLength (UINT8 *p_cur_rec)
270 {
271 UINT8 rec_hdr, type_len, id_len;
272 UINT32 rec_len = 0;
273 UINT32 payload_len;
274
275 /* Get the current record's header */
276 rec_hdr = *p_cur_rec++;
277 rec_len++;
278
279 /* Type field length */
280 type_len = *p_cur_rec++;
281 rec_len++;
282
283 /* Payload length - can be 1 or 4 bytes */
284 if (rec_hdr & NDEF_SR_MASK)
285 {
286 payload_len = *p_cur_rec++;
287 rec_len++;
288 }
289 else
290 {
291 BE_STREAM_TO_UINT32 (payload_len, p_cur_rec);
292 rec_len += 4;
293 }
294
295 /* ID field Length */
296 if (rec_hdr & NDEF_IL_MASK)
297 {
298 id_len = *p_cur_rec++;
299 rec_len++;
300 }
301 else
302 id_len = 0;
303
304 /* Total length of record */
305 rec_len += (payload_len + type_len + id_len);
306
307 return (rec_len);
308 }
309
310 /*******************************************************************************
311 **
312 ** Function NDEF_MsgGetNextRec
313 **
314 ** Description This function gets a pointer to the next record in the given
315 ** NDEF message. If the current record pointer is NULL, a pointer
316 ** to the first record is returned.
317 **
318 ** Returns Pointer to the start of the record, or NULL if no more
319 **
320 *******************************************************************************/
NDEF_MsgGetNextRec(UINT8 * p_cur_rec)321 UINT8 *NDEF_MsgGetNextRec (UINT8 *p_cur_rec)
322 {
323 UINT8 rec_hdr, type_len, id_len;
324 UINT32 payload_len;
325
326 /* Get the current record's header */
327 rec_hdr = *p_cur_rec++;
328
329 /* If this is the last record, return NULL */
330 if (rec_hdr & NDEF_ME_MASK)
331 return (NULL);
332
333 /* Type field length */
334 type_len = *p_cur_rec++;
335
336 /* Payload length - can be 1 or 4 bytes */
337 if (rec_hdr & NDEF_SR_MASK)
338 payload_len = *p_cur_rec++;
339 else
340 BE_STREAM_TO_UINT32 (payload_len, p_cur_rec);
341
342 /* ID field Length */
343 if (rec_hdr & NDEF_IL_MASK)
344 id_len = *p_cur_rec++;
345 else
346 id_len = 0;
347
348 /* Point to next record */
349 p_cur_rec += (payload_len + type_len + id_len);
350
351 return (p_cur_rec);
352 }
353
354 /*******************************************************************************
355 **
356 ** Function NDEF_MsgGetRecByIndex
357 **
358 ** Description This function gets a pointer to the record with the given
359 ** index (0-based index) in the given NDEF message.
360 **
361 ** Returns Pointer to the start of the record, or NULL
362 **
363 *******************************************************************************/
NDEF_MsgGetRecByIndex(UINT8 * p_msg,INT32 index)364 UINT8 *NDEF_MsgGetRecByIndex (UINT8 *p_msg, INT32 index)
365 {
366 UINT8 *p_rec = p_msg;
367 UINT8 rec_hdr, type_len, id_len;
368 INT32 count;
369 UINT32 payload_len;
370
371 for (count = 0; ; count++)
372 {
373 if (count == index)
374 return (p_rec);
375
376 rec_hdr = *p_rec++;
377
378 if (rec_hdr & NDEF_ME_MASK)
379 return (NULL);
380
381 /* Type field length */
382 type_len = *p_rec++;
383
384 /* Payload length - can be 1 or 4 bytes */
385 if (rec_hdr & NDEF_SR_MASK)
386 payload_len = *p_rec++;
387 else
388 BE_STREAM_TO_UINT32 (payload_len, p_rec);
389
390 /* ID field Length */
391 if (rec_hdr & NDEF_IL_MASK)
392 id_len = *p_rec++;
393 else
394 id_len = 0;
395
396 /* Point to next record */
397 p_rec += (payload_len + type_len + id_len);
398 }
399
400 /* If here, there is no record of that index */
401 return (NULL);
402 }
403
404
405 /*******************************************************************************
406 **
407 ** Function NDEF_MsgGetLastRecInMsg
408 **
409 ** Description This function gets a pointer to the last record in the
410 ** given NDEF message.
411 **
412 ** Returns Pointer to the start of the last record, or NULL if some problem
413 **
414 *******************************************************************************/
NDEF_MsgGetLastRecInMsg(UINT8 * p_msg)415 UINT8 *NDEF_MsgGetLastRecInMsg (UINT8 *p_msg)
416 {
417 UINT8 *p_rec = p_msg;
418 UINT8 *pRecStart;
419 UINT8 rec_hdr, type_len, id_len;
420 UINT32 payload_len;
421
422 for ( ; ; )
423 {
424 pRecStart = p_rec;
425 rec_hdr = *p_rec++;
426
427 if (rec_hdr & NDEF_ME_MASK)
428 break;
429
430 /* Type field length */
431 type_len = *p_rec++;
432
433 /* Payload length - can be 1 or 4 bytes */
434 if (rec_hdr & NDEF_SR_MASK)
435 payload_len = *p_rec++;
436 else
437 BE_STREAM_TO_UINT32 (payload_len, p_rec);
438
439 /* ID field Length */
440 if (rec_hdr & NDEF_IL_MASK)
441 id_len = *p_rec++;
442 else
443 id_len = 0;
444
445 /* Point to next record */
446 p_rec += (payload_len + type_len + id_len);
447 }
448
449 return (pRecStart);
450 }
451
452
453 /*******************************************************************************
454 **
455 ** Function NDEF_MsgGetFirstRecByType
456 **
457 ** Description This function gets a pointer to the first record with the given
458 ** record type in the given NDEF message.
459 **
460 ** Returns Pointer to the start of the record, or NULL
461 **
462 *******************************************************************************/
NDEF_MsgGetFirstRecByType(UINT8 * p_msg,UINT8 tnf,UINT8 * p_type,UINT8 tlen)463 UINT8 *NDEF_MsgGetFirstRecByType (UINT8 *p_msg, UINT8 tnf, UINT8 *p_type, UINT8 tlen)
464 {
465 UINT8 *p_rec = p_msg;
466 UINT8 *pRecStart;
467 UINT8 rec_hdr, type_len, id_len;
468 UINT32 payload_len;
469
470 for ( ; ; )
471 {
472 pRecStart = p_rec;
473
474 rec_hdr = *p_rec++;
475
476 /* Type field length */
477 type_len = *p_rec++;
478
479 /* Payload length - can be 1 or 4 bytes */
480 if (rec_hdr & NDEF_SR_MASK)
481 payload_len = *p_rec++;
482 else
483 BE_STREAM_TO_UINT32 (payload_len, p_rec);
484
485 /* ID field Length */
486 if (rec_hdr & NDEF_IL_MASK)
487 id_len = *p_rec++;
488 else
489 id_len = 0;
490
491 /* At this point, p_rec points to the start of the type field. We need to */
492 /* compare the type of the type, the length of the type and the data */
493 if ( ((rec_hdr & NDEF_TNF_MASK) == tnf)
494 && (type_len == tlen)
495 && (!memcmp (p_rec, p_type, tlen)) )
496 return (pRecStart);
497
498 /* If this was the last record, return NULL */
499 if (rec_hdr & NDEF_ME_MASK)
500 return (NULL);
501
502 /* Point to next record */
503 p_rec += (payload_len + type_len + id_len);
504 }
505
506 /* If here, there is no record of that type */
507 return (NULL);
508 }
509
510 /*******************************************************************************
511 **
512 ** Function NDEF_MsgGetNextRecByType
513 **
514 ** Description This function gets a pointer to the next record with the given
515 ** record type in the given NDEF message.
516 **
517 ** Returns Pointer to the start of the record, or NULL
518 **
519 *******************************************************************************/
NDEF_MsgGetNextRecByType(UINT8 * p_cur_rec,UINT8 tnf,UINT8 * p_type,UINT8 tlen)520 UINT8 *NDEF_MsgGetNextRecByType (UINT8 *p_cur_rec, UINT8 tnf, UINT8 *p_type, UINT8 tlen)
521 {
522 UINT8 *p_rec;
523 UINT8 *pRecStart;
524 UINT8 rec_hdr, type_len, id_len;
525 UINT32 payload_len;
526
527 /* If this is the last record in the message, return NULL */
528 if ((p_rec = NDEF_MsgGetNextRec (p_cur_rec)) == NULL)
529 return (NULL);
530
531 for ( ; ; )
532 {
533 pRecStart = p_rec;
534
535 rec_hdr = *p_rec++;
536
537 /* Type field length */
538 type_len = *p_rec++;
539
540 /* Payload length - can be 1 or 4 bytes */
541 if (rec_hdr & NDEF_SR_MASK)
542 payload_len = *p_rec++;
543 else
544 BE_STREAM_TO_UINT32 (payload_len, p_rec);
545
546 /* ID field Length */
547 if (rec_hdr & NDEF_IL_MASK)
548 id_len = *p_rec++;
549 else
550 id_len = 0;
551
552 /* At this point, p_rec points to the start of the type field. We need to */
553 /* compare the type of the type, the length of the type and the data */
554 if ( ((rec_hdr & NDEF_TNF_MASK) == tnf)
555 && (type_len == tlen)
556 && (!memcmp (p_rec, p_type, tlen)) )
557 return (pRecStart);
558
559 /* If this was the last record, return NULL */
560 if (rec_hdr & NDEF_ME_MASK)
561 break;
562
563 /* Point to next record */
564 p_rec += (payload_len + type_len + id_len);
565 }
566
567 /* If here, there is no record of that type */
568 return (NULL);
569 }
570
571
572 /*******************************************************************************
573 **
574 ** Function NDEF_MsgGetFirstRecById
575 **
576 ** Description This function gets a pointer to the first record with the given
577 ** record id in the given NDEF message.
578 **
579 ** Returns Pointer to the start of the record, or NULL
580 **
581 *******************************************************************************/
NDEF_MsgGetFirstRecById(UINT8 * p_msg,UINT8 * p_id,UINT8 ilen)582 UINT8 *NDEF_MsgGetFirstRecById (UINT8 *p_msg, UINT8 *p_id, UINT8 ilen)
583 {
584 UINT8 *p_rec = p_msg;
585 UINT8 *pRecStart;
586 UINT8 rec_hdr, type_len, id_len;
587 UINT32 payload_len;
588
589 for ( ; ; )
590 {
591 pRecStart = p_rec;
592
593 rec_hdr = *p_rec++;
594
595 /* Type field length */
596 type_len = *p_rec++;
597
598 /* Payload length - can be 1 or 4 bytes */
599 if (rec_hdr & NDEF_SR_MASK)
600 payload_len = *p_rec++;
601 else
602 BE_STREAM_TO_UINT32 (payload_len, p_rec);
603
604 /* ID field Length */
605 if (rec_hdr & NDEF_IL_MASK)
606 id_len = *p_rec++;
607 else
608 id_len = 0;
609
610 /* At this point, p_rec points to the start of the type field. Skip it */
611 p_rec += type_len;
612
613 /* At this point, p_rec points to the start of the ID field. Compare length and data */
614 if ( (id_len == ilen) && (!memcmp (p_rec, p_id, ilen)) )
615 return (pRecStart);
616
617 /* If this was the last record, return NULL */
618 if (rec_hdr & NDEF_ME_MASK)
619 return (NULL);
620
621 /* Point to next record */
622 p_rec += (id_len + payload_len);
623 }
624
625 /* If here, there is no record of that ID */
626 return (NULL);
627 }
628
629 /*******************************************************************************
630 **
631 ** Function NDEF_MsgGetNextRecById
632 **
633 ** Description This function gets a pointer to the next record with the given
634 ** record id in the given NDEF message.
635 **
636 ** Returns Pointer to the start of the record, or NULL
637 **
638 *******************************************************************************/
NDEF_MsgGetNextRecById(UINT8 * p_cur_rec,UINT8 * p_id,UINT8 ilen)639 UINT8 *NDEF_MsgGetNextRecById (UINT8 *p_cur_rec, UINT8 *p_id, UINT8 ilen)
640 {
641 UINT8 *p_rec;
642 UINT8 *pRecStart;
643 UINT8 rec_hdr, type_len, id_len;
644 UINT32 payload_len;
645
646 /* If this is the last record in the message, return NULL */
647 if ((p_rec = NDEF_MsgGetNextRec (p_cur_rec)) == NULL)
648 return (NULL);
649
650 for ( ; ; )
651 {
652 pRecStart = p_rec;
653
654 rec_hdr = *p_rec++;
655
656 /* Type field length */
657 type_len = *p_rec++;
658
659 /* Payload length - can be 1 or 4 bytes */
660 if (rec_hdr & NDEF_SR_MASK)
661 payload_len = *p_rec++;
662 else
663 BE_STREAM_TO_UINT32 (payload_len, p_rec);
664
665 /* ID field Length */
666 if (rec_hdr & NDEF_IL_MASK)
667 id_len = *p_rec++;
668 else
669 id_len = 0;
670
671 /* At this point, p_rec points to the start of the type field. Skip it */
672 p_rec += type_len;
673
674 /* At this point, p_rec points to the start of the ID field. Compare length and data */
675 if ( (id_len == ilen) && (!memcmp (p_rec, p_id, ilen)) )
676 return (pRecStart);
677
678 /* If this was the last record, return NULL */
679 if (rec_hdr & NDEF_ME_MASK)
680 break;
681
682 /* Point to next record */
683 p_rec += (id_len + payload_len);
684 }
685
686 /* If here, there is no record of that ID */
687 return (NULL);
688 }
689
690 /*******************************************************************************
691 **
692 ** Function NDEF_RecGetType
693 **
694 ** Description This function gets a pointer to the record type for the given NDEF record.
695 **
696 ** Returns Pointer to Type (NULL if none). TNF and len are filled in.
697 **
698 *******************************************************************************/
NDEF_RecGetType(UINT8 * p_rec,UINT8 * p_tnf,UINT8 * p_type_len)699 UINT8 *NDEF_RecGetType (UINT8 *p_rec, UINT8 *p_tnf, UINT8 *p_type_len)
700 {
701 UINT8 rec_hdr, type_len;
702
703 /* First byte is the record header */
704 rec_hdr = *p_rec++;
705
706 /* Next byte is the type field length */
707 type_len = *p_rec++;
708
709 /* Skip the payload length */
710 if (rec_hdr & NDEF_SR_MASK)
711 p_rec += 1;
712 else
713 p_rec += 4;
714
715 /* Skip ID field Length, if present */
716 if (rec_hdr & NDEF_IL_MASK)
717 p_rec++;
718
719 /* At this point, p_rec points to the start of the type field. */
720 *p_type_len = type_len;
721 *p_tnf = rec_hdr & NDEF_TNF_MASK;
722
723 if (type_len == 0)
724 return (NULL);
725 else
726 return (p_rec);
727 }
728
729 /*******************************************************************************
730 **
731 ** Function NDEF_RecGetId
732 **
733 ** Description This function gets a pointer to the record id for the given NDEF record.
734 **
735 ** Returns Pointer to Id (NULL if none). ID Len is filled in.
736 **
737 *******************************************************************************/
NDEF_RecGetId(UINT8 * p_rec,UINT8 * p_id_len)738 UINT8 *NDEF_RecGetId (UINT8 *p_rec, UINT8 *p_id_len)
739 {
740 UINT8 rec_hdr, type_len;
741
742 /* First byte is the record header */
743 rec_hdr = *p_rec++;
744
745 /* Next byte is the type field length */
746 type_len = *p_rec++;
747
748 /* Skip the payload length */
749 if (rec_hdr & NDEF_SR_MASK)
750 p_rec++;
751 else
752 p_rec += 4;
753
754 /* ID field Length */
755 if (rec_hdr & NDEF_IL_MASK)
756 *p_id_len = *p_rec++;
757 else
758 *p_id_len = 0;
759
760 /* p_rec now points to the start of the type field. The ID field follows it */
761 if (*p_id_len == 0)
762 return (NULL);
763 else
764 return (p_rec + type_len);
765 }
766
767
768 /*******************************************************************************
769 **
770 ** Function NDEF_RecGetPayload
771 **
772 ** Description This function gets a pointer to the payload for the given NDEF record.
773 **
774 ** Returns a pointer to the payload (or NULL none). Payload len filled in.
775 **
776 *******************************************************************************/
NDEF_RecGetPayload(UINT8 * p_rec,UINT32 * p_payload_len)777 UINT8 *NDEF_RecGetPayload (UINT8 *p_rec, UINT32 *p_payload_len)
778 {
779 UINT8 rec_hdr, type_len, id_len;
780 UINT32 payload_len;
781
782 /* First byte is the record header */
783 rec_hdr = *p_rec++;
784
785 /* Next byte is the type field length */
786 type_len = *p_rec++;
787
788 /* Next is the payload length (1 or 4 bytes) */
789 if (rec_hdr & NDEF_SR_MASK)
790 payload_len = *p_rec++;
791 else
792 BE_STREAM_TO_UINT32 (payload_len, p_rec);
793
794 *p_payload_len = payload_len;
795
796 /* ID field Length */
797 if (rec_hdr & NDEF_IL_MASK)
798 id_len = *p_rec++;
799 else
800 id_len = 0;
801
802 /* p_rec now points to the start of the type field. The ID field follows it, then the payload */
803 if (payload_len == 0)
804 return (NULL);
805 else
806 return (p_rec + type_len + id_len);
807 }
808
809
810 /*******************************************************************************
811 **
812 ** Function NDEF_MsgInit
813 **
814 ** Description This function initializes an NDEF message.
815 **
816 ** Returns void
817 ** *p_cur_size is initialized to 0
818 **
819 *******************************************************************************/
NDEF_MsgInit(UINT8 * p_msg,UINT32 max_size,UINT32 * p_cur_size)820 void NDEF_MsgInit (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size)
821 {
822 *p_cur_size = 0;
823 memset (p_msg, 0, max_size);
824 }
825
826 /*******************************************************************************
827 **
828 ** Function NDEF_MsgAddRec
829 **
830 ** Description This function adds an NDEF record to the end of an NDEF message.
831 **
832 ** Returns OK, or error if the record did not fit
833 ** *p_cur_size is updated
834 **
835 *******************************************************************************/
NDEF_MsgAddRec(UINT8 * p_msg,UINT32 max_size,UINT32 * p_cur_size,UINT8 tnf,UINT8 * p_type,UINT8 type_len,UINT8 * p_id,UINT8 id_len,UINT8 * p_payload,UINT32 payload_len)836 extern tNDEF_STATUS NDEF_MsgAddRec (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
837 UINT8 tnf, UINT8 *p_type, UINT8 type_len,
838 UINT8 *p_id, UINT8 id_len,
839 UINT8 *p_payload, UINT32 payload_len)
840 {
841 UINT8 *p_rec = p_msg + *p_cur_size;
842 UINT32 recSize;
843 int plen = (payload_len < 256) ? 1 : 4;
844 int ilen = (id_len == 0) ? 0 : 1;
845
846 if (tnf > NDEF_TNF_RESERVED)
847 {
848 tnf = NDEF_TNF_UNKNOWN;
849 type_len = 0;
850 }
851
852 /* First, make sure the record will fit. we need at least 2 bytes for header and type length */
853 recSize = payload_len + 2 + type_len + plen + ilen + id_len;
854
855 if ((*p_cur_size + recSize) > max_size)
856 return (NDEF_MSG_INSUFFICIENT_MEM);
857
858 /* Construct the record header. For the first record, set both begin and end bits */
859 if (*p_cur_size == 0)
860 *p_rec = tnf | NDEF_MB_MASK | NDEF_ME_MASK;
861 else
862 {
863 /* Find the previous last and clear his 'Message End' bit */
864 UINT8 *pLast = NDEF_MsgGetLastRecInMsg (p_msg);
865
866 if (!pLast)
867 return (NDEF_MSG_NO_MSG_END);
868
869 *pLast &= ~NDEF_ME_MASK;
870 *p_rec = tnf | NDEF_ME_MASK;
871 }
872
873 if (plen == 1)
874 *p_rec |= NDEF_SR_MASK;
875
876 if (ilen != 0)
877 *p_rec |= NDEF_IL_MASK;
878
879 p_rec++;
880
881 /* The next byte is the type field length */
882 *p_rec++ = type_len;
883
884 /* Payload length - can be 1 or 4 bytes */
885 if (plen == 1)
886 *p_rec++ = (UINT8)payload_len;
887 else
888 UINT32_TO_BE_STREAM (p_rec, payload_len);
889
890 /* ID field Length (optional) */
891 if (ilen > 0)
892 *p_rec++ = id_len;
893
894 /* Next comes the type */
895 if (type_len)
896 {
897 if (p_type)
898 memcpy (p_rec, p_type, type_len);
899
900 p_rec += type_len;
901 }
902
903 /* Next comes the ID */
904 if (id_len)
905 {
906 if (p_id)
907 memcpy (p_rec, p_id, id_len);
908
909 p_rec += id_len;
910 }
911
912 /* And lastly the payload. If NULL, the app just wants to reserve memory */
913 if (p_payload)
914 memcpy (p_rec, p_payload, payload_len);
915
916 *p_cur_size += recSize;
917
918 return (NDEF_OK);
919 }
920
921 /*******************************************************************************
922 **
923 ** Function NDEF_MsgInsertRec
924 **
925 ** Description This function inserts a record at a specific index into the
926 ** given NDEF message
927 **
928 ** Returns OK, or error if the record did not fit
929 ** *p_cur_size is updated
930 **
931 *******************************************************************************/
NDEF_MsgInsertRec(UINT8 * p_msg,UINT32 max_size,UINT32 * p_cur_size,INT32 index,UINT8 tnf,UINT8 * p_type,UINT8 type_len,UINT8 * p_id,UINT8 id_len,UINT8 * p_payload,UINT32 payload_len)932 extern tNDEF_STATUS NDEF_MsgInsertRec (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size, INT32 index,
933 UINT8 tnf, UINT8 *p_type, UINT8 type_len,
934 UINT8 *p_id, UINT8 id_len,
935 UINT8 *p_payload, UINT32 payload_len)
936 {
937 UINT8 *p_rec;
938 UINT32 recSize;
939 INT32 plen = (payload_len < 256) ? 1 : 4;
940 INT32 ilen = (id_len == 0) ? 0 : 1;
941
942 /* First, make sure the record will fit. we need at least 2 bytes for header and type length */
943 recSize = payload_len + 2 + type_len + plen + ilen + id_len;
944
945 if ((*p_cur_size + recSize) > max_size)
946 return (NDEF_MSG_INSUFFICIENT_MEM);
947
948 /* See where the new record goes. If at the end, call the 'AddRec' function */
949 if ( (index >= NDEF_MsgGetNumRecs (p_msg))
950 || ((p_rec = NDEF_MsgGetRecByIndex(p_msg, index)) == NULL) )
951 {
952 return NDEF_MsgAddRec (p_msg, max_size, p_cur_size, tnf, p_type, type_len,
953 p_id, id_len, p_payload, payload_len);
954 }
955
956 /* If we are inserting at the beginning, remove the MB bit from the current first */
957 if (index == 0)
958 *p_msg &= ~NDEF_MB_MASK;
959
960 /* Make space for the new record */
961 shiftdown (p_rec, (UINT32)(*p_cur_size - (p_rec - p_msg)), recSize);
962
963 /* If adding at the beginning, set begin bit */
964 if (index == 0)
965 *p_rec = tnf | NDEF_MB_MASK;
966 else
967 *p_rec = tnf;
968
969 if (plen == 1)
970 *p_rec |= NDEF_SR_MASK;
971
972 if (ilen != 0)
973 *p_rec |= NDEF_IL_MASK;
974
975 p_rec++;
976
977 /* The next byte is the type field length */
978 *p_rec++ = type_len;
979
980 /* Payload length - can be 1 or 4 bytes */
981 if (plen == 1)
982 *p_rec++ = (UINT8)payload_len;
983 else
984 UINT32_TO_BE_STREAM (p_rec, payload_len);
985
986 /* ID field Length (optional) */
987 if (ilen != 0)
988 *p_rec++ = id_len;
989
990 /* Next comes the type */
991 if (type_len)
992 {
993 if (p_type)
994 memcpy (p_rec, p_type, type_len);
995
996 p_rec += type_len;
997 }
998
999 /* Next comes the ID */
1000 if (ilen != 0)
1001 {
1002 if (p_id)
1003 memcpy (p_rec, p_id, id_len);
1004
1005 p_rec += id_len;
1006 }
1007
1008 /* And lastly the payload. If NULL, the app just wants to reserve memory */
1009 if (p_payload)
1010 memcpy (p_rec, p_payload, payload_len);
1011
1012 *p_cur_size += recSize;
1013
1014 return (NDEF_OK);
1015 }
1016
1017 /*******************************************************************************
1018 **
1019 ** Function NDEF_MsgAppendRec
1020 **
1021 ** Description This function adds NDEF records to the end of an NDEF message.
1022 **
1023 ** Returns OK, or error if the record did not fit
1024 ** *p_cur_size is updated
1025 **
1026 *******************************************************************************/
NDEF_MsgAppendRec(UINT8 * p_msg,UINT32 max_size,UINT32 * p_cur_size,UINT8 * p_new_rec,UINT32 new_rec_len)1027 extern tNDEF_STATUS NDEF_MsgAppendRec (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
1028 UINT8 *p_new_rec, UINT32 new_rec_len)
1029 {
1030 UINT8 *p_rec;
1031 tNDEF_STATUS status;
1032
1033 /* First, validate new records */
1034 if ((status = NDEF_MsgValidate(p_new_rec, new_rec_len, FALSE)) != NDEF_OK)
1035 return (status);
1036
1037 /* First, make sure the record will fit */
1038 if ((*p_cur_size + new_rec_len) > max_size)
1039 return (NDEF_MSG_INSUFFICIENT_MEM);
1040
1041 /* Find where to copy new record */
1042 if (*p_cur_size == 0)
1043 p_rec = p_msg;
1044 else
1045 {
1046 /* Find the previous last and clear his 'Message End' bit */
1047 UINT8 *pLast = NDEF_MsgGetLastRecInMsg (p_msg);
1048
1049 if (!pLast)
1050 return (NDEF_MSG_NO_MSG_END);
1051
1052 *pLast &= ~NDEF_ME_MASK;
1053 p_rec = p_msg + *p_cur_size;
1054
1055 /* clear 'Message Begin' bit of new record */
1056 *p_new_rec &= ~NDEF_MB_MASK;
1057 }
1058
1059 /* append new records */
1060 memcpy (p_rec, p_new_rec, new_rec_len);
1061
1062 *p_cur_size += new_rec_len;
1063
1064 return (NDEF_OK);
1065 }
1066
1067 /*******************************************************************************
1068 **
1069 ** Function NDEF_MsgAppendPayload
1070 **
1071 ** Description This function appends extra payload to a specific record in the
1072 ** given NDEF message
1073 **
1074 ** Returns OK, or error if the extra payload did not fit
1075 ** *p_cur_size is updated
1076 **
1077 *******************************************************************************/
NDEF_MsgAppendPayload(UINT8 * p_msg,UINT32 max_size,UINT32 * p_cur_size,UINT8 * p_rec,UINT8 * p_add_pl,UINT32 add_pl_len)1078 tNDEF_STATUS NDEF_MsgAppendPayload (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
1079 UINT8 *p_rec, UINT8 *p_add_pl, UINT32 add_pl_len)
1080 {
1081 UINT32 prev_paylen, new_paylen;
1082 UINT8 *p_prev_pl, *pp;
1083 UINT8 incr_lenfld = 0;
1084 UINT8 type_len, id_len;
1085
1086 /* Skip header */
1087 pp = p_rec + 1;
1088
1089 /* Next byte is the type field length */
1090 type_len = *pp++;
1091
1092 /* Next is the payload length (1 or 4 bytes) */
1093 if (*p_rec & NDEF_SR_MASK)
1094 prev_paylen = *pp++;
1095 else
1096 BE_STREAM_TO_UINT32 (prev_paylen, pp);
1097
1098 /* ID field Length */
1099 if (*p_rec & NDEF_IL_MASK)
1100 id_len = *pp++;
1101 else
1102 id_len = 0;
1103
1104 p_prev_pl = pp + type_len + id_len;
1105
1106 new_paylen = prev_paylen + add_pl_len;
1107
1108 /* Previous payload may be < 256, and this addition may make it larger than 256 */
1109 /* If that were to happen, the payload length field goes from 1 byte to 4 bytes */
1110 if ( (prev_paylen < 256) && (new_paylen > 255) )
1111 incr_lenfld = 3;
1112
1113 /* Check that it all fits */
1114 if ((*p_cur_size + add_pl_len + incr_lenfld) > max_size)
1115 return (NDEF_MSG_INSUFFICIENT_MEM);
1116
1117 /* Point to payload length field */
1118 pp = p_rec + 2;
1119
1120 /* If we need to increase the length field from 1 to 4 bytes, do it first */
1121 if (incr_lenfld)
1122 {
1123 shiftdown (pp + 1, (UINT32)(*p_cur_size - (pp - p_msg) - 1), 3);
1124 p_prev_pl += 3;
1125 }
1126
1127 /* Store in the new length */
1128 if (new_paylen > 255)
1129 {
1130 *p_rec &= ~NDEF_SR_MASK;
1131 UINT32_TO_BE_STREAM (pp, new_paylen);
1132 }
1133 else
1134 *pp = (UINT8)new_paylen;
1135
1136 /* Point to the end of the previous payload */
1137 pp = p_prev_pl + prev_paylen;
1138
1139 /* If we are not the last record, make space for the extra payload */
1140 if ((*p_rec & NDEF_ME_MASK) == 0)
1141 shiftdown (pp, (UINT32)(*p_cur_size - (pp - p_msg)), add_pl_len);
1142
1143 /* Now copy in the additional payload data */
1144 memcpy (pp, p_add_pl, add_pl_len);
1145
1146 *p_cur_size += add_pl_len + incr_lenfld;
1147
1148 return (NDEF_OK);
1149 }
1150
1151 /*******************************************************************************
1152 **
1153 ** Function NDEF_MsgReplacePayload
1154 **
1155 ** Description This function replaces the payload of a specific record in the
1156 ** given NDEF message
1157 **
1158 ** Returns OK, or error if the new payload did not fit
1159 ** *p_cur_size is updated
1160 **
1161 *******************************************************************************/
NDEF_MsgReplacePayload(UINT8 * p_msg,UINT32 max_size,UINT32 * p_cur_size,UINT8 * p_rec,UINT8 * p_new_pl,UINT32 new_pl_len)1162 tNDEF_STATUS NDEF_MsgReplacePayload (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
1163 UINT8 *p_rec, UINT8 *p_new_pl, UINT32 new_pl_len)
1164 {
1165 UINT32 prev_paylen;
1166 UINT8 *p_prev_pl, *pp;
1167 UINT32 paylen_delta;
1168 UINT8 type_len, id_len;
1169
1170 /* Skip header */
1171 pp = p_rec + 1;
1172
1173 /* Next byte is the type field length */
1174 type_len = *pp++;
1175
1176 /* Next is the payload length (1 or 4 bytes) */
1177 if (*p_rec & NDEF_SR_MASK)
1178 prev_paylen = *pp++;
1179 else
1180 BE_STREAM_TO_UINT32 (prev_paylen, pp);
1181
1182 /* ID field Length */
1183 if (*p_rec & NDEF_IL_MASK)
1184 id_len = *pp++;
1185 else
1186 id_len = 0;
1187
1188 p_prev_pl = pp + type_len + id_len;
1189
1190 /* Point to payload length field again */
1191 pp = p_rec + 2;
1192
1193 if (new_pl_len > prev_paylen)
1194 {
1195 /* New payload is larger than the previous */
1196 paylen_delta = new_pl_len - prev_paylen;
1197
1198 /* If the previous payload length was < 256, and new is > 255 */
1199 /* the payload length field goes from 1 byte to 4 bytes */
1200 if ( (prev_paylen < 256) && (new_pl_len > 255) )
1201 {
1202 if ((*p_cur_size + paylen_delta + 3) > max_size)
1203 return (NDEF_MSG_INSUFFICIENT_MEM);
1204
1205 shiftdown (pp + 1, (UINT32)(*p_cur_size - (pp - p_msg) - 1), 3);
1206 p_prev_pl += 3;
1207 *p_cur_size += 3;
1208 *p_rec &= ~NDEF_SR_MASK;
1209 }
1210 else if ((*p_cur_size + paylen_delta) > max_size)
1211 return (NDEF_MSG_INSUFFICIENT_MEM);
1212
1213 /* Store in the new length */
1214 if (new_pl_len > 255)
1215 {
1216 UINT32_TO_BE_STREAM (pp, new_pl_len);
1217 }
1218 else
1219 *pp = (UINT8)new_pl_len;
1220
1221 /* Point to the end of the previous payload */
1222 pp = p_prev_pl + prev_paylen;
1223
1224 /* If we are not the last record, make space for the extra payload */
1225 if ((*p_rec & NDEF_ME_MASK) == 0)
1226 shiftdown (pp, (UINT32)(*p_cur_size - (pp - p_msg)), paylen_delta);
1227
1228 *p_cur_size += paylen_delta;
1229 }
1230 else if (new_pl_len < prev_paylen)
1231 {
1232 /* New payload is smaller than the previous */
1233 paylen_delta = prev_paylen - new_pl_len;
1234
1235 /* If the previous payload was > 256, and new is less than 256 */
1236 /* the payload length field goes from 4 bytes to 1 byte */
1237 if ( (prev_paylen > 255) && (new_pl_len < 256) )
1238 {
1239 shiftup (pp + 1, pp + 4, (UINT32)(*p_cur_size - (pp - p_msg) - 3));
1240 p_prev_pl -= 3;
1241 *p_cur_size -= 3;
1242 *p_rec |= NDEF_SR_MASK;
1243 }
1244
1245 /* Store in the new length */
1246 if (new_pl_len > 255)
1247 {
1248 UINT32_TO_BE_STREAM (pp, new_pl_len);
1249 }
1250 else
1251 *pp = (UINT8)new_pl_len;
1252
1253 /* Point to the end of the previous payload */
1254 pp = p_prev_pl + prev_paylen;
1255
1256 /* If we are not the last record, remove the extra space from the previous payload */
1257 if ((*p_rec & NDEF_ME_MASK) == 0)
1258 shiftup (pp - paylen_delta, pp, (UINT32)(*p_cur_size - (pp - p_msg)));
1259
1260 *p_cur_size -= paylen_delta;
1261 }
1262
1263 /* Now copy in the new payload data */
1264 if (p_new_pl)
1265 memcpy (p_prev_pl, p_new_pl, new_pl_len);
1266
1267 return (NDEF_OK);
1268 }
1269
1270 /*******************************************************************************
1271 **
1272 ** Function NDEF_MsgReplaceType
1273 **
1274 ** Description This function replaces the type field of a specific record in the
1275 ** given NDEF message
1276 **
1277 ** Returns OK, or error if the new type field did not fit
1278 ** *p_cur_size is updated
1279 **
1280 *******************************************************************************/
NDEF_MsgReplaceType(UINT8 * p_msg,UINT32 max_size,UINT32 * p_cur_size,UINT8 * p_rec,UINT8 * p_new_type,UINT8 new_type_len)1281 tNDEF_STATUS NDEF_MsgReplaceType (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
1282 UINT8 *p_rec, UINT8 *p_new_type, UINT8 new_type_len)
1283 {
1284 UINT8 typelen_delta;
1285 UINT8 *p_prev_type, prev_type_len;
1286 UINT8 *pp;
1287
1288 /* Skip header */
1289 pp = p_rec + 1;
1290
1291 /* Next byte is the type field length */
1292 prev_type_len = *pp++;
1293
1294 /* Skip the payload length */
1295 if (*p_rec & NDEF_SR_MASK)
1296 pp += 1;
1297 else
1298 pp += 4;
1299
1300 if (*p_rec & NDEF_IL_MASK)
1301 pp++;
1302
1303 /* Save pointer to the start of the type field */
1304 p_prev_type = pp;
1305
1306 if (new_type_len > prev_type_len)
1307 {
1308 /* New type is larger than the previous */
1309 typelen_delta = new_type_len - prev_type_len;
1310
1311 if ((*p_cur_size + typelen_delta) > max_size)
1312 return (NDEF_MSG_INSUFFICIENT_MEM);
1313
1314 /* Point to the end of the previous type, and make space for the extra data */
1315 pp = p_prev_type + prev_type_len;
1316 shiftdown (pp, (UINT32)(*p_cur_size - (pp - p_msg)), typelen_delta);
1317
1318 *p_cur_size += typelen_delta;
1319 }
1320 else if (new_type_len < prev_type_len)
1321 {
1322 /* New type field is smaller than the previous */
1323 typelen_delta = prev_type_len - new_type_len;
1324
1325 /* Point to the end of the previous type, and shift up to fill the the unused space */
1326 pp = p_prev_type + prev_type_len;
1327 shiftup (pp - typelen_delta, pp, (UINT32)(*p_cur_size - (pp - p_msg)));
1328
1329 *p_cur_size -= typelen_delta;
1330 }
1331
1332 /* Save in new type length */
1333 p_rec[1] = new_type_len;
1334
1335 /* Now copy in the new type field data */
1336 if (p_new_type)
1337 memcpy (p_prev_type, p_new_type, new_type_len);
1338
1339 return (NDEF_OK);
1340 }
1341
1342 /*******************************************************************************
1343 **
1344 ** Function NDEF_MsgReplaceId
1345 **
1346 ** Description This function replaces the ID field of a specific record in the
1347 ** given NDEF message
1348 **
1349 ** Returns OK, or error if the new ID field did not fit
1350 ** *p_cur_size is updated
1351 **
1352 *******************************************************************************/
NDEF_MsgReplaceId(UINT8 * p_msg,UINT32 max_size,UINT32 * p_cur_size,UINT8 * p_rec,UINT8 * p_new_id,UINT8 new_id_len)1353 tNDEF_STATUS NDEF_MsgReplaceId (UINT8 *p_msg, UINT32 max_size, UINT32 *p_cur_size,
1354 UINT8 *p_rec, UINT8 *p_new_id, UINT8 new_id_len)
1355 {
1356 UINT8 idlen_delta;
1357 UINT8 *p_prev_id, *p_idlen_field;
1358 UINT8 prev_id_len, type_len;
1359 UINT8 *pp;
1360
1361 /* Skip header */
1362 pp = p_rec + 1;
1363
1364 /* Next byte is the type field length */
1365 type_len = *pp++;
1366
1367 /* Skip the payload length */
1368 if (*p_rec & NDEF_SR_MASK)
1369 pp += 1;
1370 else
1371 pp += 4;
1372
1373 p_idlen_field = pp;
1374
1375 if (*p_rec & NDEF_IL_MASK)
1376 prev_id_len = *pp++;
1377 else
1378 prev_id_len = 0;
1379
1380 /* Save pointer to the start of the ID field (right after the type field) */
1381 p_prev_id = pp + type_len;
1382
1383 if (new_id_len > prev_id_len)
1384 {
1385 /* New ID field is larger than the previous */
1386 idlen_delta = new_id_len - prev_id_len;
1387
1388 /* If the previous ID length was 0, we need to add a 1-byte ID length */
1389 if (prev_id_len == 0)
1390 {
1391 if ((*p_cur_size + idlen_delta + 1) > max_size)
1392 return (NDEF_MSG_INSUFFICIENT_MEM);
1393
1394 shiftdown (p_idlen_field, (UINT32)(*p_cur_size - (p_idlen_field - p_msg)), 1);
1395 p_prev_id += 1;
1396 *p_cur_size += 1;
1397 *p_rec |= NDEF_IL_MASK;
1398 }
1399 else if ((*p_cur_size + idlen_delta) > max_size)
1400 return (NDEF_MSG_INSUFFICIENT_MEM);
1401
1402 /* Point to the end of the previous ID field, and make space for the extra data */
1403 pp = p_prev_id + prev_id_len;
1404 shiftdown (pp, (UINT32)(*p_cur_size - (pp - p_msg)), idlen_delta);
1405
1406 *p_cur_size += idlen_delta;
1407 }
1408 else if (new_id_len < prev_id_len)
1409 {
1410 /* New ID field is smaller than the previous */
1411 idlen_delta = prev_id_len - new_id_len;
1412
1413 /* Point to the end of the previous ID, and shift up to fill the the unused space */
1414 pp = p_prev_id + prev_id_len;
1415 shiftup (pp - idlen_delta, pp, (UINT32)(*p_cur_size - (pp - p_msg)));
1416
1417 *p_cur_size -= idlen_delta;
1418
1419 /* If removing the ID, make sure that length field is also removed */
1420 if (new_id_len == 0)
1421 {
1422 shiftup (p_idlen_field, p_idlen_field + 1, (UINT32)(*p_cur_size - (p_idlen_field - p_msg - (UINT32)1)));
1423 *p_rec &= ~NDEF_IL_MASK;
1424 *p_cur_size -= 1;
1425 }
1426 }
1427
1428 /* Save in new ID length and data */
1429 if (new_id_len)
1430 {
1431 *p_idlen_field = new_id_len;
1432
1433 if (p_new_id)
1434 memcpy (p_prev_id, p_new_id, new_id_len);
1435 }
1436
1437 return (NDEF_OK);
1438 }
1439
1440 /*******************************************************************************
1441 **
1442 ** Function NDEF_MsgRemoveRec
1443 **
1444 ** Description This function removes the record at the given
1445 ** index in the given NDEF message.
1446 **
1447 ** Returns TRUE if OK, FALSE if the index was invalid
1448 ** *p_cur_size is updated
1449 **
1450 *******************************************************************************/
NDEF_MsgRemoveRec(UINT8 * p_msg,UINT32 * p_cur_size,INT32 index)1451 tNDEF_STATUS NDEF_MsgRemoveRec (UINT8 *p_msg, UINT32 *p_cur_size, INT32 index)
1452 {
1453 UINT8 *p_rec = NDEF_MsgGetRecByIndex (p_msg, index);
1454 UINT8 *pNext, *pPrev;
1455
1456 if (!p_rec)
1457 return (NDEF_REC_NOT_FOUND);
1458
1459 /* If this is the first record in the message... */
1460 if (*p_rec & NDEF_MB_MASK)
1461 {
1462 /* Find the second record (if any) and set his 'Message Begin' bit */
1463 if ((pNext = NDEF_MsgGetRecByIndex(p_msg, 1)) != NULL)
1464 {
1465 *pNext |= NDEF_MB_MASK;
1466
1467 *p_cur_size -= (UINT32)(pNext - p_msg);
1468
1469 shiftup (p_msg, pNext, *p_cur_size);
1470 }
1471 else
1472 *p_cur_size = 0; /* No more records, lenght must be zero */
1473
1474 return (NDEF_OK);
1475 }
1476
1477 /* If this is the last record in the message... */
1478 if (*p_rec & NDEF_ME_MASK)
1479 {
1480 if (index > 0)
1481 {
1482 /* Find the previous record and set his 'Message End' bit */
1483 if ((pPrev = NDEF_MsgGetRecByIndex(p_msg, index - 1)) == NULL)
1484 return (FALSE);
1485
1486 *pPrev |= NDEF_ME_MASK;
1487 }
1488 *p_cur_size = (UINT32)(p_rec - p_msg);
1489
1490 return (NDEF_OK);
1491 }
1492
1493 /* Not the first or the last... get the address of the next record */
1494 if ((pNext = NDEF_MsgGetNextRec (p_rec)) == NULL)
1495 return (FALSE);
1496
1497 /* We are removing p_rec, so shift from pNext to the end */
1498 shiftup (p_rec, pNext, (UINT32)(*p_cur_size - (pNext - p_msg)));
1499
1500 *p_cur_size -= (UINT32)(pNext - p_rec);
1501
1502 return (NDEF_OK);
1503 }
1504
1505
1506 /*******************************************************************************
1507 **
1508 ** Function NDEF_MsgCopyAndDechunk
1509 **
1510 ** Description This function copies and de-chunks an NDEF message.
1511 ** It is assumed that the destination is at least as large
1512 ** as the source, since the source may not actually contain
1513 ** any chunks.
1514 **
1515 ** Returns The output byte count
1516 **
1517 *******************************************************************************/
NDEF_MsgCopyAndDechunk(UINT8 * p_src,UINT32 src_len,UINT8 * p_dest,UINT32 * p_out_len)1518 tNDEF_STATUS NDEF_MsgCopyAndDechunk (UINT8 *p_src, UINT32 src_len, UINT8 *p_dest, UINT32 *p_out_len)
1519 {
1520 UINT32 out_len, max_out_len;
1521 UINT8 *p_rec;
1522 UINT8 *p_prev_rec = p_dest;
1523 UINT8 *p_type, *p_id, *p_pay;
1524 UINT8 type_len, id_len, tnf;
1525 UINT32 pay_len;
1526 tNDEF_STATUS status;
1527
1528 /* First, validate the source */
1529 if ((status = NDEF_MsgValidate(p_src, src_len, TRUE)) != NDEF_OK)
1530 return (status);
1531
1532 /* The output buffer must be at least as large as the input buffer */
1533 max_out_len = src_len;
1534
1535 /* Initialize output */
1536 NDEF_MsgInit (p_dest, max_out_len, &out_len);
1537
1538 p_rec = p_src;
1539
1540 /* Now, copy record by record */
1541 while ((p_rec != NULL) && (status == NDEF_OK))
1542 {
1543 p_type = NDEF_RecGetType (p_rec, &tnf, &type_len);
1544 p_id = NDEF_RecGetId (p_rec, &id_len);
1545 p_pay = NDEF_RecGetPayload (p_rec, &pay_len);
1546
1547 /* If this is the continuation of a chunk, append the payload to the previous */
1548 if (tnf == NDEF_TNF_UNCHANGED)
1549 {
1550 if (p_pay)
1551 {
1552 status = NDEF_MsgAppendPayload (p_dest, max_out_len, &out_len, p_prev_rec, p_pay, pay_len);
1553 }
1554 }
1555 else
1556 {
1557 p_prev_rec = p_dest + out_len;
1558
1559 status = NDEF_MsgAddRec (p_dest, max_out_len, &out_len, tnf, p_type, type_len,
1560 p_id, id_len, p_pay, pay_len);
1561 }
1562
1563 p_rec = NDEF_MsgGetNextRec (p_rec);
1564 }
1565
1566 *p_out_len = out_len;
1567
1568 return (status);
1569 }
1570
1571