为什么位掩码(0x1F)通常与NFC标签NDEF有效负载的字符编码字节进行AND运算?

时间:2017-09-18 21:08:52

标签: android format nfc specifications ndef

我正在编写一个Android应用程序来编写NFC标签,我一直看到这样的例子:

private NdefRecord createTextRecord(String content){
    try {
        byte[] language;
        language = Locale.getDefault().getLanguage().getBytes("UTF-8");

        final byte[] text = content.getBytes("UTF-8");
        final int languageSize = language.length;
        final int textLength = text.length;
        final ByteArrayOutputStream payload = new ByteArrayOutputStream(1 + languageSize + textLength);

        payload.write((byte) (languageSize & 0x1F)); // <----- LOOK HERE
        payload.write(language, 0, languageSize);
        payload.write(text, 0, textLength);

        return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload.toByteArray());
    }
    catch (UnsupportedEncodingException e){
        Log.e("createNdefMessage",e.getMessage());
    }
    return null;
}

请注意payload.write((byte) (languageSize & 0x1F));部分。那个0x1F位掩码怎么了?起初我认为规范只允许5位来描述编码的长度,但这没有意义,因为我们总是编写一个完整的字节。

有关NDEF规范的示例,请参阅herehere。有关使用此神秘0x1F掩码的更多示例,请参阅herehere

我错过了什么吗?

编辑:由于我已经回答了我自己的问题,而且我不完全确定我是否正确,如果其他人可以提供更好的解释或更多的见解,我会选择你的答案。

2 个答案:

答案 0 :(得分:2)

NDEF文本记录是通用NDEF记录结构的一个版本,其特征在于类型名称格式(TNF字段)代码1(由NFC论坛分配的众所周知的记录类型名称)和类型名称(TYPE)字段)“T”(0x54)。

对于NFC论坛众所周知的类型名称“T”,NDEF记录PAYLOAD的结构由“NFC论坛文本记录类型定义”规范给出。

文本记录有效负载由状态字节,后跟可变长度语言代码和实际的UTF-8或UTF-16编码文本内容组成。状态字节的最高有效位对于UTF-8为0,对于UTF-16编码为1。下一位是保留的。 6个最低有效位表示语言代码占用的字节数。位掩码0x1F对应于字节的5个最低有效位,与规范文本不匹配。此外,后续行写入languageSize个字节而不应用相同的掩码,因此可能会创建一个错误的NDEF文本记录,其中语言代码的尾部成为文本内容的一部分。

作为示例有效负载,字节序列02656e48656c6c6f20576f726c64以状态字节0x02开头,用于2字节语言代码“en”(0x65,0x6e),后跟UTF-8编码文本“Hello World”。

答案 1 :(得分:0)

感谢代码here中的评论......

byte MASK = (byte) 0x1F;
if ((tagFirstOctet & MASK) == MASK) { // EMV book 3, Page 178 or Annex B1 (EMV4.3)

...我能够在page 156 of EMV 4.3 Book 3上找到我问题的部分答案。

似乎低5位描述编码,用于tag number,前3位用于描述classobject,因此:

b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | Meaning
---------------------------------------------------------------
 0 |  0 |    |    |    |    |    |    | Universal class
 0 |  1 |    |    |    |    |    |    | Application class
 1 |  0 |    |    |    |    |    |    | Context-specific class
 1 |  1 |    |    |    |    |    |    | Private class
   |    |  0 |    |    |    |    |    | Primitive data object
   |    |  1 |    |    |    |    |    | Constructed data object
   |    |    |  1 |  1 |  1 |  1 |  1 | See subsequent bytes
   |    |    |   Any other value <31  | Tag number

According to ISO/IEC 8825, Table 36 defines the coding rules of the 
subsequent bytes of a BER-TLV tag when tag numbers ≥ 31 are used
(that is, bits b5 - b1 of the first byte equal '11111').

b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | Meaning
---------------------------------------------------------------
 1 |    |    |    |    |    |    |    | Another byte follows
 0 |    |    |    |    |    |    |    | Last tag byte
   |           Any value > 0          | (Part of) tag number

因此,似乎使用(languageSize & 0x1F)的建议不正确,至少出于以下原因:

  1. 此值应表示标签号,而不是字符编码。
  2. 假设每个代码都是universal classprimitive data
  3. 如果低5位全部为1(即:值为31),格式将不正确,因为下一个字节应描述该数字。
  4. 由于我已经回答了我自己的问题,而且我不完全确定我是否正确,如果其他人可以提供更好的解释或更多的见解,我会选择你的答案。