【问题标题】:Why is a bitmask (0x1F) commonly ANDed to the character encoding bytes of NFC tag NDEF payloads?为什么位掩码 (0x1F) 通常与 NFC 标签 NDEF 有效负载的字符编码字节进行“与”运算?
【发布时间】:2017-09-18 21:08:51
【问题描述】:

我正在编写一个 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 &amp; 0x1F)); 部分。 0x1F 位掩码是怎么回事?起初我以为规范只允许 5 位来描述编码的长度,但这没有意义,因为我们无论如何都要写一个完整的字节。

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

我错过了什么吗?

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

【问题讨论】:

    标签: android format nfc specifications ndef


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 感谢您的回答。不是5位吗? 0x1F11111。您可以为您提供的信息添加来源吗?
    • 我找到了a source,这与您所说的一致,但这似乎暗示0x1F 是错误的掩码,而应该是0x3F
    • 没错,0x1F 是匹配规范的错误掩码。尽管该代码的开发人员可能已经想到语言代码不应超过 31 个字节(实际上它们只有几个字节)。然而,同样的想法应用于解析传入数据会大错特错。无论如何,我必须更新答案。
    【解决方案2】:

    感谢代码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 &amp; 0x1F) 的建议似乎是不正确的,至少出于以下原因:

    1. 这个值应该代表一个标签号,而不是字符编码。
    2. 假设每个标签都是universal classprimitive data
    3. 如果低 5 位全为 1(即:值为 31),则格式不正确,因为下一个字节应描述数字。

    由于我已经回答了自己的问题,并且我不完全确定我是否正确,如果其他人可以提供更好的解释或更深入的了解,我将选择您的答案。

    【讨论】:

      猜你喜欢
      • 2013-09-10
      • 1970-01-01
      • 2023-03-09
      • 2016-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-15
      相关资源
      最近更新 更多