NDEF Decoding and Encoding¶
NDEF (NFC Data Exchange Format), specified by the NFC Forum, is a binary message format used to encapsulate application-defined payloads exchanged between NFC Devices and Tags. Each payload is encoded as an NDEF Record with fields that specify the payload size, payload type, an optional payload identifier, and flags for indicating the first and last record of an NDEF Message or tagging record chunks. An NDEF Message is simply a sequence of one or more NDEF Records where the first and last record are marked by the Message Begin and End flags.
ndef package interface for decoding and encoding of NDEF Messages
consists of the
that both return generators for decoding octets into
instances or encoding
ndef.Record instances into octets. Known
record types are decoded into instances of their implementation
class and can be directly encoded as part of a message.
message_decoder(stream_or_bytes, errors='strict', known_records=Record._known_types)¶
Returns a generator function that decodes NDEF Records from a file-like, byte-oriented stream or a bytes object given by the stream_or_bytes argument. When the errors argument is set to ‘strict’ (the default), the decoder expects a valid NDEF Message with Message Begin and End flags set for the first and last record and decoding of known record types will fail for any format errors. Minor format errors are accepted when errors is set to ‘relax’. With errors set to ‘ignore’ the decoder silently stops when a non-correctable error is encountered. The known_records argument provides the mapping of record type strings to class implementations. It defaults to all global records implemented by
ndeflibor additionally registered from user code. It’s main use would probably be to force decoding into only generic records with
ndef.DecodeError – for data format errors (unless errors is set to ‘ignore’)
>>> import ndef >>> octets = bytearray.fromhex('910303414243616263 5903030144454630646566') >>> decoder = ndef.message_decoder(octets) >>> next(decoder) ndef.record.Record('urn:nfc:wkt:ABC', '', bytearray(b'abc')) >>> next(decoder) ndef.record.Record('urn:nfc:wkt:DEF', '0', bytearray(b'def')) >>> next(decoder) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>> message = list(ndef.message_decoder(octets)) >>> len(message) 2
Returns a generator function that encodes
ndef.Recordobjects into an NDEF Message octet sequence. The message argument is either an iterable of records or None, if message is None the records must be sequentially send to the encoder (as for any generator the first send value must be None, specific to the message encoder is that octets are generated for the previous record and a final None value must be send for the last record octets). The stream argument controls the output of the generator function. If stream is None, the generator yields a bytes object for each encoded record. Otherwise, it must be a file-like, byte-oriented stream that receives the encoded octets and the generator yields the number of octets written per record.
ndef.EncodeError – for invalid record parameter values or types
>>> import ndef >>> record1 = ndef.Record('urn:nfc:wkt:ABC', '1', b'abc') >>> record2 = ndef.Record('urn:nfc:wkt:DEF', '2', b'def') >>> encoder = ndef.message_encoder() >>> encoder.send(None) >>> encoder.send(record1) >>> encoder.send(record2) b'\x99\x03\x03\x01ABC1abc' >>> encoder.send(None) b'Y\x03\x03\x01DEF2def' >>> message = [record1, record2] >>> b''.join((ndef.message_encoder(message))) b'\x99\x03\x03\x01ABC1abcY\x03\x03\x01DEF2def' >>> list((ndef.message_encoder(message, open('/dev/null', 'wb')))) [11, 11]
Record(type='', name='', data=b'')¶
This class implements generic decoding and encoding of an NDEF Record and is the base for all specialized record type classes. The NDEF Record Payload Type encoded by the TNF (Type Name Format) and TYPE field is represented by a single type string argument:
Empty (TNF 0)An Empty record has no TYPE, ID, and PAYLOAD fields. This is set if the type argument is absent, None, or an empty string. Encoding ignores whatever is set as name and data, producing just the short length record
NFC Forum Well Known Type (TNF 1)An NFC Forum Well Known Type is a URN (RFC 2141) with namespace identifier (NID)
nfcand the namespace specific string (NSS) prefixed with
wkt:. When encoding, the type is written as a relative-URI (cf. RFC 3986), omitting the NID and the prefix. For example, the type
urn:nfc:wkt:Tis encoded as TNF 1, TYPE
Media-type as defined in RFC 2046 (TNF 2)A media-type follows the media-type grammar defined in RFC 2046. Records that carry a payload with an existing, registered media type should use this record type. Note that the record type indicates the type of the payload; it does not refer to a MIME message that contains an entity of the given type. For example, the media type ‘image/jpeg’ indicates that the payload is an image in JPEG format using JFIF encoding as defined by RFC 2046.
Absolute URI as defined in RFC 3986 (TNF 3)An absolute-URI follows the absolute-URI BNF construct defined by RFC 3986. This type can be used for payloads that are defined by URIs. For example, records that carry a payload with an XML-based message type may use the XML namespace identifier of the root element as the record type, like a SOAP/1.1 message may be
NFC Forum External Type (TNF 4)An NFC Forum External Type is a URN (RFC 2141) with namespace identifier (NID)
nfcand the namespace specific string (NSS) prefixed with
ext:. When encoding, the type is written as a relative-URI (cf. RFC 3986), omitting the NID and the prefix. For example, the type
urn:nfc:ext:nfcpy.org:Twill be encoded as TNF 4, TYPE
Unknown (TNF 5)The Unknown record type indicates that the type of the payload is unknown, similar to the
application/octet-streammedia type. It is set with the type argument
unknownand encoded with an empty TYPE field.
Unchanged (TNF 6)The Unchanged record type is used for all except the first record in a chunked payload. It is set with the type argument
unchangedand encoded with an empty TYPE field.
The type argument sets the final value of the
typeattribute, which provides the value only for reading. The name and data argument set the initial values of the
dataattributes. They can both be changed later.
The record type is a read-only text string set either by decoding or through initialization.
The record name is a text string that corresponds to the NDEF Record ID field. The maximum capacity is 255 8-bit characters, converted in and out as latin-1.
The record data is a bytearray with the sequence of octets that correspond to the NDEF Record PAYLOAD field. The attribute itself is readonly but the bytearray content can be changed. Note that for derived record classes this becomes a read-only bytes object with the content encoded from the record’s attributes.
This is a class data attribute that restricts the decodable and encodable maximum NDEF Record PAYLOAD size from the theoretical value of up to 4GB to 1MB. If needed, a different value can be assigned to the record class:
ndef.Record.MAX_PAYLOAD_SIZE = 100*1024