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