• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   *
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