1. 前言
UTF-8 编码是交换 Unicode(通用编码字符集)最合适的编码。因此,对于新协议和格式,以及在新环境中部署的现有格式,本规范要求(并定义)使用 UTF-8 编码。
其他(旧)编码在过去某种程度上已经被定义。然而,用户代理并未始终以相同的方式实现它们,也未始终使用相同的标签,并且在处理编码的未定义和以前的专有区域时经常有所不同。本规范解决了这些差距,使得新的用户代理无需逆向工程编码实现,而现有的用户代理可以趋于一致。
特别是,本规范定义了所有这些编码、从字节到标量值及其返回的算法、它们的规范名称和识别标签。本规范还定义了一个 API,用于向 JavaScript 暴露部分编码算法。
用户代理在标签方面也显著偏离了 IANA 字符集注册表中列出的内容。为了阻止进一步传播旧编码,本规范对上述细节进行了详尽的定义,因此不需要注册表。特别是,本规范不提供扩展编码任何方面的机制。
2. 安全背景
当生产者和消费者对使用的编码或对给定编码的实现方式未达成一致时,会出现一系列编码安全问题。例如,2011 年报告了一次攻击,其中 Shift_JIS 的前导字节 0x82 被用来“掩盖” JSON 资源中某字段的尾随字节 0x22,该字段由攻击者控制。生产者未发现问题,尽管这是一个非法字节组合。消费者将其解码为单个 U+FFFD(�),因此改变了整体解释,因为 U+0022(")是一个重要的分隔符。现在,使用多个字节表示标量值的编码的解码器要求,在非法字节组合的情况下,范围 U+0000 到 U+007F(含)的标量值不能被“掩盖”。对于上述序列,输出将是 U+FFFD U+0022。(作为一个不幸的例外,gb18030 解码器将在 队列末尾最多“掩盖”一个这样的字节。)
对于将任何 ASCII 字节映射到非 ASCII 代码点的编码(当没有前导字节存在时),这是一个更大的问题。这些是“ASCII 不兼容”编码,除了由于已部署内容而必须支持的 ISO-2022-JP 和 UTF-16BE/LE,它们不被支持。(正在 调查是否可以将更多此类编码的标签映射到 替代编码,而不是未知编码回退。)一个示例攻击是向资源注入精心设计的内容,然后鼓励用户覆盖编码,从而导致例如脚本执行。
HTML 和 HTML 表单功能中使用的 URL 编码器在使用无法表示所有标量值的编码时也可能导致轻微的信息丢失。例如,当资源使用 windows-1252 编码时,服务器将无法区分最终用户在表单中输入“💩”和“💩”。
当仅使用 UTF-8 时,这里概述的问题将消失,这也是现在所有事物必须使用 UTF-8 编码的众多原因之一。
另请参阅 浏览器 UI章节。
3. 术语
本规范依赖于 Infra 标准。[INFRA]
十六进制数字以 "0x" 为前缀。
在公式中,所有数字均为整数,加法用 "+" 表示,减法用 "−" 表示,乘法用 "×" 表示,整数除法用 "/" 表示(返回商),取模用 "%" 表示(返回整数除法的余数),逻辑左移用 "<<" 表示,逻辑右移用 ">>" 表示,按位与用 "&" 表示,按位或用 "|" 表示。
对于逻辑右移,操作数必须至少具有 21 位精度。
I/O 队列 是一种 列表,其 项具有特定类型(例如 字节或 标量值)。队列末尾 是一种特殊的 项,可以存在于任何类型的 I/O 队列中,表示队列中没有更多的 项。
使用 I/O 队列有两种方式:即时模式,用于表示存储在内存中的 I/O 数据;流模式,用于表示来自网络的数据。即时队列的最后一项是 队列末尾,而流队列不需要有它,因此它们的 读取操作可能会阻塞。
预计流式 I/O 队列将被创建为空,并且随着数据从网络进入,会将新的 项 推入队列。当底层网络流关闭时,应将一个 队列末尾项 推入队列。
要从 I/O 队列 ioQueue 读取一个 项,按以下步骤执行:
-
如果 ioQueue[0] 是 队列结尾(end-of-queue),则返回 队列结尾。
-
移除 ioQueue[0] 并返回它。
要从 ioQueue 中读取 number 个 项,请执行以下步骤:
向 I/O 队列 ioQueue 推送一系列项,是指按照给定顺序,将序列中的每一项依次推送到 ioQueue 中。
将一个 项(非 队列结尾(end-of-queue))恢复到 I/O 队列中,即执行 列表的 前插(prepend)操作。将一个不含 队列结尾 的项列表恢复到 I/O 队列中,则按给定顺序将这些项插入到队列的第一个项之前。
如果向 I/O 队列 « 0x92 0xA9, 队列结尾 » 插入字节 « 0xF0, 0x9F », 则结果为 I/O 队列 « 0xF0, 0x9F, 0x92 0xA9, 队列结尾 »。下一个要读取的项是 0xF0。
Infra 标准预计将定义一些关于类型转换的基础设施。详见 whatwg/infra issue #319。[INFRA]
I/O 队列被定义为列表,而非队列,因为它们包含 恢复操作。然而,这一恢复操作仅是本规范算法的内部细节,不应被其他标准使用。实现可以采用其他方式来实现此类算法,细节见实现注意事项。
要从代理对中获取一个 标量值,给定一个 前导代理 leading 和一个 尾随代理 trailing,返回 0x10000 + ((leading − 0xD800) << 10) + (trailing − 0xDC00)。
要创建一个
Uint8Array
对象,给定一个 I/O 队列 ioQueue 和 realm realm:
-
令 bytes 为将 ioQueue 转换为字节序列的结果。
-
返回在 realm 中用 bytes 创建
Uint8Array
对象的结果。
4. 编码
编码定义了从标量值序列到字节序列(及其反向)的映射。每个编码都有一个名称,以及一个或多个标签。
本规范定义了三个与 Unicode 标准中定义的编码方案同名的编码:UTF-8、UTF-16LE和UTF-16BE。这些编码与编码方案的不同之处在于字节顺序标记(也称为 BOM)的处理不是编码本身的一部分,而是本规范中包装算法的一部分,而字节顺序标记处理是 Unicode 标准中编码方案定义的一部分。UTF-8与UTF-8 解码算法一起使用时,与同名的编码方案匹配。本规范不提供与UTF-16LE和UTF-16BE结合以匹配类似名称的编码方案的包装算法。[UNICODE]
4.1. 编码器和解码器
每个编码都有一个关联的解码器,并且大多数都有一个关联的编码器。解码器和编码器的实例具有一个处理器算法,并可能具有状态。处理器算法接受一个输入I/O 队列和一个项,并返回完成、一个或多个项、错误(可选地带有一个代码点),或继续。
错误模式在以下使用中,对于解码器是"replacement
"或"fatal
",对于编码器是"fatal
"或"html
"。
由于 HTML 表单需要一个非终止的旧编码器,"html
"作为错误模式存在。"html
"错误模式会导致发出一个无法与合法输入区分的序列,因此可能导致静默的数据丢失。强烈建议开发人员使用UTF-8编码以防止这种情况发生。[HTML]
要处理一个项,给定一个项item、一个编码的编码器或解码器实例encoderDecoder、I/O 队列input、I/O 队列output和错误模式mode:
4.2. 名称和标签
下表列出了所有编码及其标签,用户代理必须支持这些编码和标签。用户代理不得支持任何其他编码或标签。
对于每个编码,对其ASCII 小写化的名称会生成其一个标签。
作者必须使用UTF-8编码,并且必须使用其(ASCII
大小写不敏感)"utf-8
"标签来标识它。
新协议和格式,以及在新环境中部署的现有格式,必须仅使用UTF-8编码。如果这些协议和格式需要公开编码的名称或标签,它们必须将其公开为"utf-8
"。
要从字符串label获取编码,请执行以下步骤:
-
移除label中的任何前导和尾随ASCII 空白。
-
如果label与下表中列出的任何标签ASCII 大小写不敏感匹配,则返回对应的编码;否则返回失败。
这是一个比Unicode 技术标准第 22 号第 1.4 节规定的更基本和更严格的将标签映射到编码的算法,因为这是与已部署内容兼容所必需的。
名称 | 标签 |
---|---|
编码 | |
UTF-8 | "unicode-1-1-utf-8 " |
"unicode11utf8 " |
|
"unicode20utf8 " |
|
"utf-8 " |
|
"utf8 " |
|
"x-unicode20utf8 " |
|
旧单字节编码 | |
IBM866 | "866 " |
"cp866 " |
|
"csibm866 " |
|
"ibm866 " |
|
ISO-8859-2 | "csisolatin2 " |
"iso-8859-2 " |
|
"iso-ir-101 " |
|
"iso8859-2 " |
|
"iso88592 " |
|
"iso_8859-2 " |
|
"iso_8859-2:1987 " |
|
"l2 " |
|
"latin2 "
| |
ISO-8859-3 | "csisolatin3 "
|
"iso-8859-3 "
| |
"iso-ir-109 "
| |
"iso8859-3 "
| |
"iso88593 "
| |
"iso_8859-3 "
| |
"iso_8859-3:1988 "
| |
"l3 "
| |
"latin3 "
| |
ISO-8859-4 | "csisolatin4 "
|
"iso-8859-4 "
| |
"iso-ir-110 "
| |
"iso8859-4 "
| |
"iso88594 "
| |
"iso_8859-4 "
| |
"iso_8859-4:1988 "
| |
"l4 "
| |
"latin4 "
| |
ISO-8859-5 | "csisolatincyrillic "
|
"cyrillic "
| |
"iso-8859-5 "
| |
"iso-ir-144 "
| |
"iso8859-5 "
| |
"iso88595 "
| |
"iso_8859-5 "
| |
"iso_8859-5:1988 "
| |
ISO-8859-6 | "arabic "
|
"asmo-708 "
| |
"csiso88596e "
| |
"csiso88596i "
| |
"csisolatinarabic "
| |
"ecma-114 "
| |
"iso-8859-6 "
| |
"iso-8859-6-e "
| |
"iso-8859-6-i "
| |
"iso-ir-127 "
| |
"iso8859-6 "
| |
"iso88596 "
| |
"iso_8859-6 "
| |
"iso_8859-6:1987 "
| |
ISO-8859-7 | "csisolatingreek "
|
"ecma-118 "
| |
"elot_928 "
| |
"greek "
| |
"greek8 "
| |
"iso-8859-7 "
| |
"iso-ir-126 "
| |
"iso8859-7 "
| |
"iso88597 "
| |
"iso_8859-7 "
| |
"iso_8859-7:1987 "
| |
"sun_eu_greek "
| |
ISO-8859-8 | "csiso88598e "
|
"csisolatinhebrew "
| |
"hebrew "
| |
"iso-8859-8 "
| |
"iso-8859-8-e "
| |
"iso-ir-138 "
| |
"iso8859-8 "
| |
"iso88598 "
| |
"iso_8859-8 "
| |
"iso_8859-8:1988 "
| |
"visual "
| |
ISO-8859-8-I | "csiso88598i "
|
"iso-8859-8-i "
| |
"logical "
| |
ISO-8859-10 | "csisolatin6 "
|
"iso-8859-10 "
| |
"iso-ir-157 "
| |
"iso8859-10 "
| |
"iso885910 "
| |
"l6 "
| |
"latin6 "
| |
ISO-8859-13 | "iso-8859-13 "
|
"iso8859-13 "
| |
"iso885913 "
| |
ISO-8859-14 | "iso-8859-14 "
|
"iso8859-14 "
| |
"iso885914 "
| |
ISO-8859-15 | "csisolatin9 "
|
"iso-8859-15 "
| |
"iso8859-15 "
| |
"iso885915 "
| |
"iso_8859-15 "
| |
"l9 "
| |
ISO-8859-16 | "iso-8859-16 "
|
KOI8-R | "cskoi8r "
|
"koi "
| |
"koi8 "
| |
"koi8-r "
| |
"koi8_r "
| |
KOI8-U | "koi8-ru "
|
"koi8-u "
| |
macintosh | "csmacintosh "
|
"mac "
| |
"macintosh "
| |
"x-mac-roman "
| |
windows-874 | "dos-874 "
|
"iso-8859-11 "
| |
"iso8859-11 "
| |
"iso885911 "
| |
"tis-620 "
| |
"windows-874 "
| |
windows-1250 | "cp1250 "
|
"windows-1250 "
| |
"x-cp1250 "
| |
windows-1251 | "cp1251 "
|
"windows-1251 "
| |
"x-cp1251 "
| |
windows-1252
参见下文了解与历史上的“Latin1”和“ASCII”概念的关系。 | "ansi_x3.4-1968 "
|
"ascii "
| |
"cp1252 "
| |
"cp819 "
| |
"csisolatin1 "
| |
"ibm819 "
| |
"iso-8859-1 "
| |
"iso-ir-100 "
| |
"iso8859-1 "
| |
"iso88591 "
| |
"iso_8859-1 "
| |
"iso_8859-1:1987 "
| |
"l1 "
| |
"latin1 "
| |
"us-ascii "
| |
"windows-1252 "
| |
"x-cp1252 "
| |
windows-1253 | "cp1253 "
|
"windows-1253 "
| |
"x-cp1253 "
| |
windows-1254 | "cp1254 "
|
"csisolatin5 "
| |
"iso-8859-9 "
| |
"iso-ir-148 "
| |
"iso8859-9 "
| |
"iso88599 "
| |
"iso_8859-9 "
| |
"iso_8859-9:1989 "
| |
"l5 "
| |
"latin5 "
| |
"windows-1254 "
| |
"x-cp1254 "
| |
windows-1255 | "cp1255 "
|
"windows-1255 "
| |
"x-cp1255 "
| |
windows-1256 | "cp1256 "
|
"windows-1256 "
| |
"x-cp1256 "
| |
windows-1257 | "cp1257 "
|
"windows-1257 "
| |
"x-cp1257 "
| |
windows-1258 | "cp1258 "
|
"windows-1258 "
| |
"x-cp1258 "
| |
x-mac-cyrillic | "x-mac-cyrillic "
|
"x-mac-ukrainian "
| |
旧多字节中文(简体)编码 | |
GBK | "chinese "
|
"csgb2312 "
| |
"csiso58gb231280 "
| |
"gb2312 "
| |
"gb_2312 "
| |
"gb_2312-80 "
| |
"gbk "
| |
"iso-ir-58 "
| |
"x-gbk "
| |
gb18030 | "gb18030 "
|
旧多字节中文(繁体)编码 | |
Big5 | "big5 "
|
"big5-hkscs "
| |
"cn-big5 "
| |
"csbig5 "
| |
"x-x-big5 "
| |
旧多字节日语编码 | |
EUC-JP | "cseucpkdfmtjapanese "
|
"euc-jp "
| |
"x-euc-jp "
| |
ISO-2022-JP | "csiso2022jp "
|
"iso-2022-jp "
| |
Shift_JIS | "csshiftjis "
|
"ms932 "
| |
"ms_kanji "
| |
"shift-jis "
| |
"shift_jis "
| |
"sjis "
| |
"windows-31j "
| |
"x-sjis "
| |
旧多字节韩语编码 | |
EUC-KR | "cseuckr "
|
"csksc56011987 "
| |
"euc-kr "
| |
"iso-ir-149 "
| |
"korean "
| |
"ks_c_5601-1987 "
| |
"ks_c_5601-1989 "
| |
"ksc5601 "
| |
"ksc_5601 "
| |
"windows-949 "
| |
旧杂项编码 | |
replacement | "csiso2022kr "
|
"hz-gb-2312 "
| |
"iso-2022-cn "
| |
"iso-2022-cn-ext "
| |
"iso-2022-kr "
| |
"replacement "
| |
UTF-16BE | "unicodefffe "
|
"utf-16be "
| |
UTF-16LE | "csunicode "
|
"iso-10646-ucs-2 "
| |
"ucs-2 "
| |
"unicode "
| |
"unicodefeff "
| |
"utf-16 "
| |
"utf-16le "
| |
x-user-defined | "x-user-defined "
|
所有编码及其标签也可以作为非规范性的encodings.json资源获取。
支持的编码集主要基于本标准开发开始时主要浏览器引擎支持的编码集的交集,同时移除了那些很少被合法使用但可能被用于攻击的编码。从现有 Web 内容的使用水平的零散证据来看,某些编码的包含是值得怀疑的。也就是说,虽然这些编码被浏览器广泛支持,但尚不清楚它们是否被 Web 内容广泛使用。然而,并未积极移除那些被浏览器广泛支持或属于 ISO 8859 系列的单字节编码。特别是,IBM866、macintosh、x-mac-cyrillic、ISO-8859-3、ISO-8859-10、ISO-8859-14和ISO-8859-16的必要性对于支持现有内容来说是值得怀疑的,但目前没有移除这些编码的计划。
windows-1252编码有多个标签,例如"latin1
"、"iso-8859-1
"和"ascii
",这些标签在历史上对开发人员来说一直很困惑。在
Web 上以及任何希望通过实现本标准与 Web 兼容的软件中,这些标签是同义词:"latin1
"和"ascii
"只是windows-1252的标签,任何遵循本标准的软件,例如,在请求“Latin1”或“ASCII”解码该字节时,会将 0x80 解码为
U+20AC (€)。
不遵循本标准的软件并不总是给出相同的答案。这一问题的根源在于最初指定 Latin1 的文档(ISO/IEC 8859-1)未为字节范围 0x00 到 0x1F 或 0x7F 到 0x9F 提供任何映射。同样,最初指定 ASCII 的文档(ISO/IEC 646 等)未为字节范围 0x80 到 0xFF 提供任何映射。这意味着在请求使用 Latin1 或 ASCII 编码时,不同的软件为这些字节选择了不同的代码点映射。Web 浏览器和与浏览器兼容的软件选择根据windows-1252映射这些字节,windows-1252 是两者的超集,这一选择已在本标准中被规范化。其他软件会抛出错误,或使用同构解码或其他映射。[ISO8859-1][ISO646]
因此,实施者和开发人员在使用以“Latin1”或“ASCII”为术语的 API 的库时需要格外小心。如果这些库为原始规范中未定义的字节选择了其他行为,则它们很可能不会给出符合本标准的答案。
4.3. 输出编码
要从编码encoding获取输出编码,请执行以下步骤:
-
如果encoding是替代或UTF-16BE/LE,则返回UTF-8。
-
返回encoding。
获取输出编码算法对于 URL 解析和 HTML 表单提交非常有用,因为两者都需要完全符合此算法。
5. 索引
大多数旧的编码都使用索引。一个索引是一个有序的条目列表,每个条目由一个指针和一个对应的代码点组成。在一个索引中,指针是唯一的,而代码点可以重复。
一个高效的实现可能为每个编码提供两个索引。一个针对其解码器优化,另一个针对其编码器优化。
要在一个索引中找到指针及其对应的代码点,请执行以下步骤:令lines为将资源内容按 U+000A LF 分割的结果。然后移除lines中为空字符串或以 U+0023 (#) 开头的每一项。然后通过将lines中的每一项按 U+0009 TAB 分割来找到指针及其对应的代码点。第一个子项是指针(作为十进制数),第二个是对应的代码点(作为十六进制数)。其他子项不相关。
为了表示变化,一个索引包括一个标识符和一个日期。如果标识符发生变化,则索引也发生变化。
索引代码点是index中pointer对应的代码点,如果pointer不在index中,则为 null。
索引指针是index中codePoint对应的第一个指针,如果codePoint不在index中,则为 null。
除了GB18030 范围索引和ISO-2022-JP 片假名索引外,每个索引都有一个非规范性的可视化。JIS0208 索引也有一个替代的Shift_JIS可视化。此外,除了GB18030 范围索引和ISO-2022-JP 片假名索引外,每个索引的基本多语言平面覆盖范围也有可视化。
可视化的图例如下:
- 未映射
- UTF-8 中的两个字节
- UTF-8 中的两个字节,代码点紧接前一个指针的代码点
- UTF-8 中的三个字节(非 PUA)
- UTF-8 中的三个字节(非 PUA),代码点紧接前一个指针的代码点
- 专用使用
- 专用使用,代码点紧接前一个指针的代码点
- UTF-8 中的四个字节
- UTF-8 中的四个字节,代码点紧接前一个指针的代码点
- 重复代码点已在较早的索引中映射
- CJK 兼容表意文字
- CJK 统一表意文字扩展 A
以下是本规范定义的索引,不包括单字节索引,后者有自己的表格:
索引 | 备注 | |||
---|---|---|---|---|
Big5 索引 | index-big5.txt | Big5 索引可视化 | Big5 索引 BMP 覆盖范围 | 与 Big5 标准结合香港补充字符集及其他常见扩展相匹配。 |
EUC-KR 索引 | index-euc-kr.txt | EUC-KR 索引可视化 | EUC-KR 索引 BMP 覆盖范围 | 与 KS X 1001 标准和统一韩文代码(通常称为 Windows 代码页 949)相匹配。完全覆盖 Unicode 的韩文音节块。可视化中左上角位于指针 9026 的韩文块按 Unicode 顺序排列。单独来看,此索引中的其余韩文音节也按 Unicode 顺序排列。 |
GB18030 索引 | index-gb18030.txt | GB18030 索引可视化 | GB18030 索引 BMP 覆盖范围 | 与 GB18030-2022 标准中编码为两个字节的代码点相匹配,但 0xA3 0xA0 映射到 U+3000 IDEOGRAPHIC SPACE 以与已部署内容兼容。此索引完全覆盖 Unicode 的 CJK 统一表意文字块。可视化中位于(第一个)U+3000 上方或左侧的该块中的条目按 Unicode 顺序排列。 |
GB18030 范围索引 | index-gb18030-ranges.txt | 此索引的工作方式与其他所有索引不同。列出所有代码点将导致超过一百万个条目,而它们可以整齐地表示为 207 个范围,并结合简单的限制检查。因此,它仅在表面上与 GB18030-2000 标准中编码为四个字节的代码点相匹配。GB18030-2005 修订版的更改由伴随此索引的下文GB18030 范围索引代码点和GB18030 范围索引指针算法内联处理。而 GB18030-2022 修订版的更改则再次以不同方式处理,以避免进一步增加映射到专用使用代码点的字节序列数量。相关的专用使用代码点在GB18030 编码器中通过一个旁表直接映射,以保持与它们之前映射方式的兼容性。 | ||
JIS0208 索引 | index-jis0208.txt | JIS0208 索引可视化, Shift_JIS 可视化 | JIS0208 索引 BMP 覆盖范围 | 这是 JIS X 0208 标准,包括以前来自 IBM 和 NEC 的专有扩展。 |
JIS0212 索引 | index-jis0212.txt | JIS0212 索引可视化 | JIS0212 索引 BMP 覆盖范围 | 这是 JIS X 0212 标准。由于在其他地方缺乏广泛支持,它仅由EUC-JP 解码器使用。 |
ISO-2022-JP 片假名索引 | index-iso-2022-jp-katakana.txt | 根据 Unicode 规范化形式 KC,这将半角片假名映射到全角片假名,但 U+FF9E (゙) 和 U+FF9F (゚) 映射到 U+309B (゛) 和 U+309C (゜),而不是 U+3099 (◌゙) 和 U+309A (◌゚)。它仅由ISO-2022-JP 编码器使用。[UNICODE] |
GB18030 范围索引代码点是针对pointer的以下步骤的返回值:
-
如果pointer大于 39419 且小于 189000,或者pointer大于 1237575,则返回 null。
-
如果pointer是 7457,则返回代码点 U+E7C7。
-
令offset为GB18030 范围索引中小于或等于pointer的最后一个指针,并令codePointOffset为其对应的代码点。
-
返回一个代码点,其值为codePointOffset + pointer − offset。
GB18030 范围索引指针是针对codePoint的以下步骤的返回值:
-
如果codePoint是 U+E7C7,则返回指针 7457。
-
令offset为GB18030 范围索引中小于或等于codePoint的最后一个代码点,并令pointerOffset为其对应的指针。
-
返回一个指针,其值为pointerOffset + codePoint − offset。
Shift_JIS 索引指针是针对codePoint的以下步骤的返回值:
-
令index为JIS0208 索引,排除所有指针在 8272 到 8835(含)范围内的条目。
JIS0208 索引包含重复的代码点,因此排除这些条目会导致使用后面的代码点。
-
返回index中codePoint的索引指针。
Big5 索引指针是针对codePoint的以下步骤的返回值:
所有索引也可以作为非规范性的indexes.json资源获取。(GB18030 范围索引在此处采用稍有不同的格式,以便表示范围。)
6. 为标准提供的挂钩
下面定义的算法(UTF-8 解码、不带 BOM 的 UTF-8 解码、不带 BOM 或失败的 UTF-8 解码以及UTF-8 编码)旨在供其他标准使用。
对于解码,新格式应使用UTF-8 解码。对于格式或协议中的标识符或字节序列,请使用不带 BOM 的 UTF-8 解码或不带 BOM 或失败的 UTF-8 解码。
对于编码,应使用UTF-8 编码。
标准应确保它们传递给UTF-8 编码(以及旧的编码)的输入 I/O 队列实际上是标量值的 I/O 队列,即它们不包含代理项。
这些挂钩(以及解码和编码)将阻塞,直到输入 I/O 队列被完全消耗。为了在使用输出令牌时将其推入流中,调用者应使用空的输出 I/O 队列调用挂钩,并并行地从中读取。请注意,在使用不带 BOM 或失败的 UTF-8 解码时需要小心,因为在解码过程中发现的任何错误都将阻止队列末尾项被推入输出 I/O 队列。
要对字节的 I/O 队列ioQueue进行UTF-8 解码,给定一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:
要对字节的 I/O 队列ioQueue进行不带 BOM 的 UTF-8 解码,给定一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:
要对字节的 I/O 队列ioQueue进行不带 BOM 或失败的 UTF-8 解码,给定一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:
6.1. 为标准提供的旧版挂钩
强烈建议标准不要使用解码、BOM 嗅探和编码,除非为了兼容性需要。需要这些旧版挂钩的标准很可能还需要使用获取编码(将标签转换为编码)和获取输出编码(将一个编码转换为适合传递给编码的另一个编码)。
对于 URL 百分号编码这种极其特殊的情况,需要自定义编码器错误处理。应使用获取编码器和编码或失败算法。其他算法不应直接使用。
要对字节的 I/O 队列ioQueue进行解码,给定一个备用编码encoding和一个可选的标量值 I/O 队列output(默认为 « »),请执行以下步骤:
要对字节的 I/O 队列ioQueue进行BOM 嗅探,请执行以下步骤:
-
令BOM为从ioQueue窥视 3 个字节并转换为字节序列的结果。
-
对于下表中的每一行,从第一行开始向下,如果BOM以第一列中给出的字节开头,则返回该行第二列单元格中给出的编码。否则,返回 null。
字节顺序标记 编码 0xEF 0xBB 0xBF UTF-8 0xFE 0xFF UTF-16BE 0xFF 0xFE UTF-16LE
此挂钩是一个变通方法,因为解码无法向调用者传达它已找到字节顺序标记,因此未使用提供的编码。此挂钩应在解码之前调用,它将返回与找到的字节顺序标记对应的编码,否则返回 null。
要对标量值的 I/O 队列ioQueue进行编码,给定一个编码encoding和一个可选的字节 I/O 队列output(默认为 « »),请执行以下步骤:
要从编码encoding获取编码器:
-
断言:encoding不是替代或UTF-16BE/LE。
-
返回encoding的编码器实例。
要对标量值的 I/O 队列ioQueue进行编码或失败,给定一个编码器实例encoder和一个字节 I/O 队列output,请执行以下步骤:
-
令potentialError为使用encoder、ioQueue、output和"
fatal
"处理队列的结果。 -
返回 null。
这是 URL 百分号编码的旧版挂钩。调用者必须保持一个编码器实例的活动状态,因为ISO-2022-JP 编码器在返回错误时可能处于两种不同状态之一。这也意味着,如果调用者以某种方式发出字节来编码错误,这些字节必须在 0x00 到 0x7F(含)的范围内,不包括 0x0E、0x0F、0x1B、0x5C 和 0x7E。[URL]
特别是,如果在返回错误时,ISO-2022-JP 编码器处于罗马状态,调用者不能输出 0x5C (\),因为它不会被解码为 U+005C (\)。因此,将编码或失败用于非预期目的的应用程序应注意防止将ISO-2022-JP 编码器与替换方案(例如
JavaScript 和 CSS 的替换方案)结合使用,这些方案使用 U+005C (\) 作为替换语法的一部分(例如,\u2603
),或者确保将替换语法通过编码器传递(与
URL 百分号编码相反)。
返回值要么是表示无法编码的代码点的数字,要么是 null(如果没有错误)。当它返回非 null 时,调用者将必须再次调用它,提供相同的编码器实例和一个新的输出 I/O 队列。
7. API
本节使用 Web IDL 的术语。浏览器用户代理必须支持此 API。JavaScript 实现应支持此 API。鼓励其他用户代理或编程语言使用适合其需求的 API,可能不是这一个。[WEBIDL]
以下示例使用 TextEncoder
对象将字符串数组编码为 ArrayBuffer
。结果是一个
Uint8Array
,其中包含字符串的数量(作为
Uint32Array
),后跟第一个字符串的长度(作为
Uint32Array
)、UTF-8 编码的字符串数据、第二个字符串的长度(作为 Uint32Array
)、字符串数据,依此类推。
function encodeArrayOfStrings( strings) {
var encoder, encoded, len, bytes, view, offset;
encoder = new TextEncoder();
encoded = [];
len = Uint32Array. BYTES_PER_ELEMENT;
for ( var i = 0 ; i < strings. length; i++ ) {
len += Uint32Array. BYTES_PER_ELEMENT;
encoded[ i] = encoder. encode( strings[ i]);
len += encoded[ i]. byteLength;
}
bytes = new Uint8Array( len);
view = new DataView( bytes. buffer);
offset = 0 ;
view. setUint32( offset, strings. length);
offset += Uint32Array. BYTES_PER_ELEMENT;
for ( var i = 0 ; i < encoded. length; i += 1 ) {
len = encoded[ i]. byteLength;
view. setUint32( offset, len);
offset += Uint32Array. BYTES_PER_ELEMENT;
bytes. set( encoded[ i], offset);
offset += len;
}
return bytes. buffer;
}
以下示例将包含由前一个示例生成的格式编码的数据的 ArrayBuffer
(或用于非
UTF-8 编码的等效算法)解码回字符串数组。
function decodeArrayOfStrings( buffer, encoding) {
var decoder, view, offset, num_strings, strings, len;
decoder = new TextDecoder( encoding);
view = new DataView( buffer);
offset = 0 ;
strings = [];
num_strings = view. getUint32( offset);
offset += Uint32Array. BYTES_PER_ELEMENT;
for ( var i = 0 ; i < num_strings; i++ ) {
len = view. getUint32( offset);
offset += Uint32Array. BYTES_PER_ELEMENT;
strings[ i] = decoder. decode(
new DataView( view. buffer, offset, len));
offset += len;
}
return strings;
}
7.1.
接口混入 TextDecoderCommon
interface mixin {
TextDecoderCommon readonly attribute DOMString encoding ;readonly attribute boolean fatal ;readonly attribute boolean ignoreBOM ; };
TextDecoderCommon
接口混入定义了 TextDecoder
和 TextDecoderStream
对象共享的通用 getter。这些对象有关联的:
- 编码
- 一个编码。
- 解码器
- 一个解码器实例。
- I/O 队列
- 一个字节的I/O 队列。
- 忽略 BOM
- 一个布尔值,初始为 false。
- 已见 BOM
- 一个布尔值,初始为 false。
- 错误模式
- 一个错误模式,初始为
"
replacement
"。
序列化 I/O
队列算法,给定一个 TextDecoderCommon
decoder 和一个标量值的I/O 队列 ioQueue,运行以下步骤:
-
令 output 为空字符串。
-
当为真时:
该算法在 BOM 处理方面与平台其余部分使用的解码算法故意不同,以便为 API 用户提供更多控制。
7.2. 接口 TextDecoder
dictionary {
TextDecoderOptions boolean =
fatal false ;boolean =
ignoreBOM false ; };dictionary {
TextDecodeOptions boolean =
stream false ; }; [Exposed=*]interface {
TextDecoder constructor (optional DOMString = "utf-8",
label optional TextDecoderOptions = {});
options USVString decode (optional AllowSharedBufferSource ,
input optional TextDecodeOptions = {}); };
options TextDecoder includes TextDecoderCommon ;
一个 TextDecoder
对象拥有一个关联的不刷新标志(do not flush flag),它是一个布尔值,
初始为 false。
decoder = new TextDecoder([label = "utf-8" [, options]])
-
返回一个新的
TextDecoder
对象。如果 label 不是一个有效的标签,或者是用于 replacement 的标签,则抛出一个
RangeError
。 decoder . encoding
decoder . fatal
-
如果错误模式是 "
fatal
",则返回 true;否则返回 false。 decoder . ignoreBOM
-
返回忽略 BOM 标志的值。
decoder . decode([input [, options]])
-
返回运行编码的解码器的结果。 该方法可以被多次调用,并将 options 的
stream
属性设置为 true,然后最后一次调用时不再设置 options 的stream
(或设为 false),以处理分段的输入。如果最后一次调用(`stream` 未设置或为 false)时没有 input,最清晰的做法是省略这两个参数。var string= "" , decoder= new TextDecoder( encoding), buffer; while ( buffer= next_chunk()) { string+= decoder. decode( buffer, { stream: true }); } string+= decoder. decode(); // 队列末尾
new TextDecoder(label, options)
构造函数的步骤如下:
decode(input, options)
方法的步骤如下:
-
如果当前对象的不刷新标志为 false,则设置当前对象的 解码器为一个新的当前对象的 编码的解码器实例,当前对象的 I/O 队列为字节的I/O 队列 « 队列末尾 », 以及当前对象的BOM 已见标志为 false。
-
如果给定了 input,则将 input 的一个副本 推入到当前对象的 I/O 队列中。
强烈建议实现者采用 避免此次复制的实现策略。这样做时,必须确保对 input 的更改 不会影响未来对
decode()
的调用。 -
循环执行:
7.3.
接口混入 TextEncoderCommon
interface mixin {
TextEncoderCommon readonly attribute DOMString encoding ; };
TextEncoderCommon
接口混入定义了
TextEncoder
和 TextEncoderStream
对象共享的通用 getter。
encoding
getter 的步骤是返回 "utf-8
"。
7.4. 接口 TextEncoder
dictionary {
TextEncoderEncodeIntoResult unsigned long long ;
read unsigned long long ; }; [Exposed=*]
written interface {
TextEncoder constructor (); [NewObject ]Uint8Array encode (optional USVString = "");
input TextEncoderEncodeIntoResult encodeInto (USVString , [
source AllowShared ]Uint8Array ); };
destination TextEncoder includes TextEncoderCommon ;
一个 TextEncoder
对象不提供 label 参数,因为它只支持 UTF-8。它也不提供
stream
选项,因为没有编码器需要缓冲标量值。
encoder = new TextEncoder()
-
返回一个新的
TextEncoder
对象。 encoder . encoding
-
返回 "
utf-8
"。 encoder . encode([input = ""])
encoder . encodeInto(source, destination)
-
在 source 上运行UTF-8 编码器,将该操作的结果存入 destination,并以一个对象的形式返回进度,其中
read
是 source 中已转换的代码单元数,而written
是 destination 中已修改的字节数。
new TextEncoder()
构造函数的步骤是:不执行任何操作。
encode(input)
方法的步骤如下:
encodeInto(source, destination)
方法的步骤如下:
-
令 read 为 0。
-
令 written 为 0。
-
令 encoder 为一个UTF-8 编码器的实例。
-
循环执行:
encodeInto() 方法可用于将字符串编码到一个已存在的 ArrayBuffer
对象中。以下示例中的一些细节留给读者作为练习,但它展示了使用此方法的一种可行方式:
function convertString( buffer, input, callback) {
let bufferSize = 256 ,
bufferStart = malloc( buffer, bufferSize),
writeOffset = 0 ,
readOffset = 0 ;
while ( true ) {
const view = new Uint8Array( buffer, bufferStart + writeOffset, bufferSize - writeOffset),
{ read, written} = cachedEncoder. encodeInto( input. substring( readOffset), view);
readOffset += read;
writeOffset += written;
if ( readOffset === input. length) {
callback( bufferStart, writeOffset);
free( buffer, bufferStart);
return ;
}
bufferSize *= 2 ;
bufferStart = realloc( buffer, bufferStart, bufferSize);
}
}
7.5.
接口 TextDecoderStream
[Exposed=*]interface {
TextDecoderStream constructor (optional DOMString = "utf-8",
label optional TextDecoderOptions = {}); };
options TextDecoderStream includes TextDecoderCommon ;TextDecoderStream includes GenericTransformStream ;
decoder = new TextDecoderStream([label = "utf-8" [, options]])
-
返回一个新的
TextDecoderStream
对象。如果 label 不是一个有效的标签,或者是用于replacement的标签,则抛出一个
RangeError
。 decoder . encoding
decoder . fatal
-
如果错误模式是 "
fatal
",则返回 true,否则返回 false。 decoder . ignoreBOM
-
返回忽略 BOM 标志的值。
decoder . readable
decoder . writable
-
返回一个可写流,它接受
AllowSharedBufferSource
块,并通过编码的解码器运行它们,然后才使它们对readable
可用。通常这将通过在一个
ReadableStream
源上使用pipeThrough()
方法来完成。var decoder= new TextDecoderStream( encoding); byteReadable. pipeThrough( decoder) . pipeTo( textWritable); 如果错误模式是 "
fatal
" 并且编码的解码器返回错误,那么readable
和writable
都将因一个TypeError
而出错。
new TextDecoderStream(label, options)
构造函数的步骤如下:
-
令 encoding 为从 label 获取编码的结果。
-
如果 encoding 是 failure 或 replacement,则抛出一个
RangeError
。 -
令 transformAlgorithm 为一个接受 chunk 参数的算法,并使用当前对象和 chunk 运行解码并入队一个块算法。
-
令 transformStream 为一个新的
TransformStream
。 -
设置 transformStream, transformAlgorithm 设为 transformAlgorithm, flushAlgorithm 设为 flushAlgorithm。
解码并入队一个块算法,给定一个 TextDecoderStream
对象
decoder 和一个 chunk,运行以下步骤:
-
令 bufferSource 为将 chunk 转换为
AllowSharedBufferSource
的结果。 -
循环执行:
刷新并入队算法,用于处理来自输入
ReadableStream
对象的数据结束,给定一个 TextDecoderStream
对象 decoder,运行以下步骤:
-
循环执行:
7.6.
接口 TextEncoderStream
[Exposed=*]interface {
TextEncoderStream constructor (); };TextEncoderStream includes TextEncoderCommon ;TextEncoderStream includes GenericTransformStream ;
一个 TextEncoderStream
对象拥有一个关联的:
- 编码器(encoder)
- 一个编码器实例。
- 前导代理项(leading surrogate)
- null 或一个前导代理项,初始为 null。
一个 TextEncoderStream
对象不提供 label 参数,因为它只支持 UTF-8。
encoder = new TextEncoderStream()
-
返回一个新的
TextEncoderStream
对象。 encoder . encoding
-
返回 "
utf-8
"。 encoder . readable
encoder . writable
-
返回一个可写流,它接受字符串块,并通过 UTF-8 的编码器运行它们,然后才使它们对
readable
可用。通常这将通过在一个
ReadableStream
源上使用pipeThrough()
方法来完成。textReadable
. pipeThrough( new TextEncoderStream()) . pipeTo( byteWritable);
new TextEncoderStream()
构造函数的步骤如下:
-
令 transformAlgorithm 为一个接受 chunk 参数的算法,并使用当前对象和 chunk 运行编码并入队一个块算法。
-
令 transformStream 为一个新的
TransformStream
。 -
设置 transformStream, transformAlgorithm 设为 transformAlgorithm, flushAlgorithm 设为 flushAlgorithm。
编码并入队一个块算法,给定一个 TextEncoderStream
对象
encoder 和 chunk,运行以下步骤:
将代码单元转换为标量值算法,给定一个
TextEncoderStream
对象
encoder、一个代码单元 item 和一个代码单元的I/O 队列
input,运行以下步骤:
-
如果 encoder 的前导代理项非空:
-
令 leadingSurrogate 为 encoder 的 前导代理项。
-
设置 encoder 的前导代理项为 null。
-
如果 item 是一个后尾代理项,则返回一个根据 leadingSurrogate 和 item 从代理对得到的标量值。
-
将 item 恢复到 input。
-
返回 U+FFFD ()。
-
-
如果 item 是一个后尾代理项,则返回 U+FFFD ()。
-
返回 item。
这相当于 Infra 标准中的“将一个字符串转换为一个 标量值字符串”算法,但允许 代理对在字符串之间被分割。 [INFRA]
编码并刷新算法,给定一个 TextEncoderStream
对象
encoder,运行以下步骤:
8. 编码
8.1. UTF-8
8.1.1. UTF-8 解码器
字节顺序标记(BOM)的优先级高于标签,因为在已部署的内容中发现它更为准确。因此,它不属于 UTF-8 解码器算法的一部分,而是属于 decode 和 UTF-8 decode 算法。
- UTF-8 码点
- 已见 UTF-8 字节数
- 所需 UTF-8 字节数
- 已见 UTF-8 字节数
- 均为数字,初始为 0。
- UTF-8 下界
- 一个字节,初始为 0x80。
- UTF-8 上界
- 一个字节,初始为 0xBF。
UTF-8 解码器的处理程序,给定 ioQueue 和 byte,运行以下步骤:
-
如果 byte 是队列末尾且所需 UTF-8 字节数不为 0,则将 所需 UTF-8 字节数设为 0 并返回错误。
-
如果所需 UTF-8 字节数为 0,则根据 byte:
- 0x00 到 0x7F
-
返回一个码点,其值为 byte。
- 0xC2 到 0xDF
-
-
将所需 UTF-8 字节数设为 1。
-
将UTF-8 码点设为 byte & 0x1F。
byte 的最低五位。
-
- 0xE0 到 0xEF
-
-
如果 byte 是 0xE0,则将UTF-8 下界设为 0xA0。
-
如果 byte 是 0xED,则将UTF-8 上界设为 0x9F。
-
将所需 UTF-8 字节数设为 2。
-
将UTF-8 码点设为 byte & 0xF。
byte 的最低四位。
-
- 0xF0 到 0xF4
-
-
如果 byte 是 0xF0,则将UTF-8 下界设为 0x90。
-
如果 byte 是 0xF4,则将UTF-8 上界设为 0x8F。
-
将所需 UTF-8 字节数设为 3。
-
将UTF-8 码点设为 byte & 0x7。
byte 的最低三位。
-
- 其他情况
-
返回错误。
返回继续。
-
如果 byte 不在UTF-8 下界到 UTF-8 上界(含)的范围内:
-
将UTF-8 码点、 所需 UTF-8 字节数和已见 UTF-8 字节数设为 0, 将UTF-8 下界设为 0x80,并将 UTF-8 上界设为 0xBF。
-
将 byte 恢复到 ioQueue。
-
返回错误。
-
-
将UTF-8 码点设为 (UTF-8 码点 << 6) | (byte & 0x3F)
将UTF-8 码点的现有位左移六位,并将新空出的最低六位设置为 byte 的最低六位。
-
将已见 UTF-8 字节数增加一。
-
如果已见 UTF-8 字节数不等于所需 UTF-8 字节数,则返回 继续。
-
令 codePoint 为UTF-8 码点。
-
将UTF-8 码点、 所需 UTF-8 字节数和已见 UTF-8 字节数设为 0。
-
返回一个码点,其值为 codePoint。
上述UTF-8 解码器中的约束与 Unicode 标准中的“使用 U+FFFD 的最佳实践”相匹配。根据编码标准,不允许有其他行为(实现相同结果的其他算法是允许的,甚至是被鼓励的)。 [UNICODE]
8.1.2. UTF-8 编码器
UTF-8 的编码器的处理程序,给定 unused 和 codePoint,执行以下步骤:
-
如果 codePoint 是一个ASCII 码点,则返回一个值为 codePoint 的字节。
-
根据 codePoint 所在的范围设置 count 和 offset:
- U+0080 到 U+07FF(含)
- 1 和 0xC0
- U+0800 到 U+FFFF(含)
- 2 和 0xE0
- U+10000 到 U+10FFFF(含)
- 3 和 0xF0
-
令 bytes 为一个字节序列,其第一个字节是 (codePoint >> (6 × count)) + offset。
-
当 count 大于 0 时:
-
将 temp 设置为 codePoint >> (6 × (count − 1))。
-
向 bytes 追加 0x80 | (temp & 0x3F)。
-
将 count 减一。
-
-
按顺序返回字节序列 bytes。
该算法的结果与 Unicode 标准中描述的算法相同。 此处包含它是为了完整性。[UNICODE]
9. 旧式单字节编码
一个编码,其中每个字节要么是一个单独的码点,要么什么都不是,这就是单字节编码。 单字节编码共享 解码器和编码器。单字节索引,由单字节解码器和 单字节编码器引用,由下表定义,并取决于所使用的单字节编码。除了两种 单字节编码外,所有单字节编码都有一个唯一的索引。
ISO-8859-8 和ISO-8859-8-I是 不同的编码名称,因为 ISO-8859-8 会影响布局方向。尽管 历史上ISO-8859-6和 “ISO-8859-6-I”也可能存在这种情况,但现在已不再如此。
9.1. 单字节解码器
单字节编码的解码器的处理程序,给定 unused 和 byte,执行以下步骤:
9.2. 单字节编码器
单字节编码的编码器的处理程序,给定 unused 和 codePoint,执行以下步骤:
-
如果 codePoint 是一个ASCII 码点,则返回一个值为 codePoint 的字节。
-
如果 pointer 为 null,则返回带 codePoint 的错误。
-
返回一个值为 pointer + 0x80 的字节。
10. 旧式多字节简体中文编码
10.1. GBK
10.1.1. GBK 解码器
10.1.2. GBK 编码器
GBK 的编码器是 gb18030 的编码器,并将其 is GBK 标志设置为 true。
不将 GBK 与 gb18030 完全别名化是一种保守的做法,旨在减少破坏使用 GBK 编码器生成的旧式服务器和其他内容消费者的可能性。
10.2. gb18030
10.2.1. gb18030 解码器
- gb18030 第一个字节
- gb18030 第二个字节
- gb18030 第三个字节
- gb18030 第二个字节
- 均为字节,初始值为 0x00。
gb18030 的解码器的处理程序,给定 ioQueue 和 byte,执行以下步骤:
-
如果 byte 是队列末尾,并且gb18030 第一个字节、gb18030 第二个字节和 gb18030 第三个字节均为 0x00,则返回完成。
-
如果 byte 是队列末尾,并且gb18030 第一个字节、gb18030 第二个字节或 gb18030 第三个字节不为 0x00,则将gb18030 第一个字节、gb18030 第二个字节和 gb18030 第三个字节设为 0x00,并返回错误。
-
如果gb18030 第三个字节不为 0x00:
-
如果 byte 不在 0x30 到 0x39(含)的范围内:
-
将 « gb18030 第二个字节, gb18030 第三个字节, byte » 恢复到 ioQueue。
-
将gb18030 第一个字节、gb18030 第二个字节和gb18030 第三个字节设为 0x00。
-
返回错误。
-
-
令 codePoint 为 ((gb18030 第一个字节 − 0x81) × (10 × 126 × 10)) + ((gb18030 第二个字节 − 0x30) × (10 × 126)) + ((gb18030 第三个字节 − 0x81) × 10) + byte − 0x30 对应的gb18030 范围索引码点。
-
将gb18030 第一个字节、gb18030 第二个字节和gb18030 第三个字节设为 0x00。
-
如果 codePoint 为 null,则返回错误。
-
返回一个值为 codePoint 的码点。
-
-
如果gb18030 第二个字节不为 0x00:
-
如果 byte 在 0x81 到 0xFE(含)的范围内,则将gb18030 第三个字节设为 byte 并返回继续。
-
将 « gb18030 第二个字节, byte » 恢复到 ioQueue,将 gb18030 第一个字节和gb18030 第二个字节设为 0x00,并返回错误。
-
-
如果gb18030 第一个字节不为 0x00:
-
如果 byte 在 0x30 到 0x39(含)的范围内,则将gb18030 第二个字节设为 byte 并返回继续。
-
令 leading 为gb18030 第一个字节。
-
将gb18030 第一个字节设为 0x00。
-
令 pointer 为 null。
-
如果 byte 小于 0x7F,则令 offset 为 0x40;否则为 0x41。
-
如果 byte 在 0x40 到 0x7E(含)或 0x80 到 0xFE(含)的范围内, 则将 pointer 设为 (leading − 0x81) × 190 + (byte − offset)。
-
如果 pointer 为 null,则令 codePoint 为 null;否则为gb18030 索引中 pointer 对应的 索引码点。
-
如果 codePoint 不为 null,则返回一个值为 codePoint 的码点。
-
返回错误。
-
-
如果 byte 是一个ASCII 字节,则返回一个值为 byte 的码点。
-
如果 byte 是 0x80,则返回码点 U+20AC (€)。
-
如果 byte 在 0x81 到 0xFE(含)的范围内,则将gb18030 第一个字节设为 byte 并返回继续。
-
返回错误。
10.2.2. gb18030 编码器
gb18030 的编码器有一个关联的 is GBK 标志,它是一个布尔值, 初始为 false。
gb18030 的编码器的处理程序,给定 unused 和 codePoint,执行以下步骤:
-
如果 codePoint 是一个ASCII 码点,则返回一个值为 codePoint 的字节。
-
如果 codePoint 是 U+E5E5,则返回带 codePoint 的错误。
gb18030 索引将 0xA3 0xA0 映射到 U+3000 表意空格,而不是 U+E5E5, 以兼容已部署的内容。因此它不能往返。
-
如果is GBK为 true 且 codePoint 是 U+20AC (€),则返回字节 0x80。
-
如果下表中有某行的第一列是 codePoint,则返回该行第二列中列出的两个字节:
码点 字节 U+E78D 0xA6 0xD9 U+E78E 0xA6 0xDA U+E78F 0xA6 0xDB U+E790 0xA6 0xDC U+E791 0xA6 0xDD U+E792 0xA6 0xDE U+E793 0xA6 0xDF U+E794 0xA6 0xEC U+E795 0xA6 0xED U+E796 0xA6 0xF3 U+E81E 0xFE 0x59 U+E826 0xFE 0x61 U+E82B 0xFE 0x66 U+E82C 0xFE 0x67 U+E832 0xFE 0x6D U+E843 0xFE 0x7E U+E854 0xFE 0x90 U+E864 0xFE 0xA0 这个不对称的编码器表保留了与 GB18030-2005 标准的兼容性。另请参见gb18030 范围索引处的解释。
-
令 pointer 为gb18030 索引中 codePoint 对应的索引指针。
-
如果 pointer 不为 null:
-
令 leading 为 pointer / 190 + 0x81。
-
令 trailing 为 pointer % 190。
-
如果 trailing 小于 0x3F,则令 offset 为 0x40, 否则为 0x41。
-
返回两个字节,其值分别为 leading 和 trailing + offset。
-
-
将 pointer 设为 codePoint 对应的gb18030 范围索引指针。
-
令 byte1 为 pointer / (10 × 126 × 10)。
-
将 pointer 设为 pointer % (10 × 126 × 10)。
-
令 byte2 为 pointer / (10 × 126)。
-
将 pointer 设为 pointer % (10 × 126)。
-
令 byte3 为 pointer / 10。
-
令 byte4 为 pointer % 10。
-
返回四个字节,其值分别为 byte1 + 0x81、 byte2 + 0x30、byte3 + 0x81、 byte4 + 0x30。
11. 旧式多字节繁体中文编码
11.1. Big5
11.1.1. Big5 解码器
Big5 的解码器有一个关联的 Big5 前导字节,它是一个字节,初始值为 0x00。
Big5 的解码器的处理程序,给定 ioQueue 和 byte,执行以下步骤:
-
如果Big5 前导字节不为 0x00:
-
令 leading 为Big5 前导字节。
-
将Big5 前导字节设为 0x00。
-
令 pointer 为 null。
-
如果 byte 小于 0x7F,则令 offset 为 0x40;否则为 0x62。
-
如果 byte 在 0x40 到 0x7E(含)或 0xA1 到 0xFE(含)的范围内, 则将 pointer 设为 (leading − 0x81) × 157 + (byte − offset)。
-
如果下表中存在第一列为 pointer 的行,则返回其第二列中列出的两个码点(第三列无关):
指针 码点 备注 1133 U+00CA U+0304 Ê̄ (带扬抑符和长音符的拉丁大写字母 E) 1135 U+00CA U+030C Ê̌ (带扬抑符和抑扬符的拉丁大写字母 E) 1164 U+00EA U+0304 ê̄ (带扬抑符和长音符的拉丁小写字母 e) 1166 U+00EA U+030C ê̌ (带扬抑符和抑扬符的拉丁小写字母 e) 由于索引仅限于 单个码点,因此对这些指针使用此表。
-
如果 pointer 为 null,则令 codePoint 为 null;否则为Big5 索引中 pointer 对应的 索引码点。
-
如果 codePoint 不为 null,则返回一个值为 codePoint 的码点。
-
返回错误。
-
-
如果 byte 是一个ASCII 字节,则返回一个值为 byte 的码点。
-
返回错误。
11.1.2. Big5 编码器
Big5 的编码器的处理程序,给定 unused 和 codePoint,执行以下步骤:
-
如果 codePoint 是一个ASCII 码点,则返回一个值为 codePoint 的字节。
-
令 pointer 为 codePoint 对应的Big5 索引指针。
-
如果 pointer 为 null,则返回带 codePoint 的错误。
-
令 leading 为 pointer / 157 + 0x81。
-
令 trailing 为 pointer % 157。
-
如果 trailing 小于 0x3F,则令 offset 为 0x40, 否则为 0x62。
-
返回两个字节,其值分别为 leading 和 trailing + offset。
12. 旧式多字节日文编码
12.1. EUC-JP
12.1.1. EUC-JP 解码器
- EUC-JP jis0212
- 一个布尔值,初始为 false。
- EUC-JP 前导字节
- 一个字节,初始为 0x00。
EUC-JP 的解码器的处理程序,给定 ioQueue 和 byte,执行以下步骤:
-
如果 byte 是队列末尾且EUC-JP 前导字节不为 0x00,则将 EUC-JP 前导字节设为 0x00 并返回错误。
-
如果 byte 是队列末尾且EUC-JP 前导字节为 0x00,则返回 完成。
-
如果EUC-JP 前导字节为 0x8E 且 byte 在 0xA1 到 0xDF(含)的范围内,则将EUC-JP 前导字节设为 0x00 并返回一个值为 0xFF61 − 0xA1 + byte 的码点。
-
如果EUC-JP 前导字节为 0x8F 且 byte 在 0xA1 到 0xFE(含)的范围内,则将EUC-JP jis0212 设为 true,将EUC-JP 前导字节设为 byte, 并返回继续。
-
如果EUC-JP 前导字节不为 0x00:
-
令 leading 为EUC-JP 前导字节。
-
将EUC-JP 前导字节设为 0x00。
-
令 codePoint 为 null。
-
如果 leading 和 byte 都在 0xA1 到 0xFE(含)的范围内,则 如果EUC-JP jis0212为 false,则将 codePoint 设为jis0208 索引中 (leading − 0xA1) × 94 + byte − 0xA1 对应的索引码点;否则设为jis0212 索引中对应的码点。
-
将EUC-JP jis0212 设为 false。
-
如果 codePoint 不为 null,则返回一个值为 codePoint 的码点。
-
返回错误。
-
-
如果 byte 是一个ASCII 字节,则返回一个值为 byte 的码点。
-
如果 byte 是 0x8E、0x8F 或在 0xA1 到 0xFE(含)的范围内,则将 EUC-JP 前导字节设为 byte 并返回继续。
-
返回错误。
12.1.2. EUC-JP 编码器
EUC-JP 的编码器的处理程序,给定 unused 和 codePoint,执行以下步骤:
-
如果 codePoint 是一个ASCII 码点,则返回一个值为 codePoint 的字节。
-
如果 codePoint 是 U+00A5 (¥),则返回字节 0x5C。
-
如果 codePoint 是 U+203E (‾),则返回字节 0x7E。
-
如果 codePoint 在 U+FF61 (。) 到 U+FF9F (゚)(含)的范围内,则返回两个 字节,其值分别为 0x8E 和 codePoint − 0xFF61 + 0xA1。
-
如果 codePoint 是 U+2212 (−),则将其设为 U+FF0D (-)。
-
令 pointer 为jis0208 索引中 codePoint 对应的索引指针。
如果 pointer 不为 null,则由于 jis0208 索引和 索引指针 操作的性质,它将小于 8836。
-
如果 pointer 为 null,则返回带 codePoint 的错误。
-
令 leading 为 pointer / 94 + 0xA1。
-
令 trailing 为 pointer % 94 + 0xA1。
-
返回两个字节,其值分别为 leading 和 trailing。
12.2. ISO-2022-JP
12.2.1. ISO-2022-JP 解码器
ISO-2022-JP 的解码器有一个关联的:
- ISO-2022-JP 解码器状态
- 一个状态,初始为ASCII。
- ISO-2022-JP 解码器输出状态
- 一个状态,初始为ASCII。
- ISO-2022-JP 前导字节
- 一个字节,初始为 0x00。
- ISO-2022-JP 输出标志
- 一个布尔值,初始为 false。
ISO-2022-JP 的解码器的处理程序,给定 ioQueue 和 byte,根据 ISO-2022-JP 解码器状态执行以下步骤:
- ASCII
-
根据 byte:
- 0x1B
-
将ISO-2022-JP 解码器状态设为 转义开始并返回 继续。
- 0x00 到 0x7F,不包括 0x0E、0x0F 和 0x1B
-
将ISO-2022-JP 输出标志设为 false 并返回一个值为 byte 的码点。
- 队列末尾
-
返回完成。
- 其他情况
-
将ISO-2022-JP 输出标志设为 false 并返回错误。
- 罗马字
-
根据 byte:
- 0x1B
-
将ISO-2022-JP 解码器状态设为 转义开始并返回 继续。
- 0x5C
-
将ISO-2022-JP 输出标志设为 false 并返回码点 U+00A5 (¥)。
- 0x7E
-
将ISO-2022-JP 输出标志设为 false 并返回码点 U+203E (‾)。
- 0x00 到 0x7F,不包括 0x0E、0x0F、0x1B、0x5C 和 0x7E
-
将ISO-2022-JP 输出标志设为 false 并返回一个值为 byte 的码点。
- 队列末尾
-
返回完成。
- 其他情况
-
将ISO-2022-JP 输出标志设为 false 并返回错误。
- 片假名
-
根据 byte:
- 0x1B
-
将ISO-2022-JP 解码器状态设为 转义开始并返回 继续。
- 0x21 到 0x5F
-
将ISO-2022-JP 输出标志设为 false 并返回一个值为 0xFF61 − 0x21 + byte 的码点。
- 队列末尾
-
返回完成。
- 其他情况
-
将ISO-2022-JP 输出标志设为 false 并返回错误。
- 前导字节
-
根据 byte:
- 0x1B
-
将ISO-2022-JP 解码器状态设为 转义开始并返回 继续。
- 0x21 到 0x7E
-
将ISO-2022-JP 输出标志设为 false,将ISO-2022-JP 前导字节设为 byte, 将ISO-2022-JP 解码器状态设为尾随字节, 并返回继续。
- 队列末尾
-
返回完成。
- 其他情况
-
将ISO-2022-JP 输出标志设为 false 并返回错误。
- 尾随字节
-
根据 byte:
- 0x1B
-
将ISO-2022-JP 解码器状态设为 转义开始并返回错误。
- 0x21 到 0x7E
-
-
令 pointer 为 (ISO-2022-JP 前导字节 − 0x21) × 94 + byte − 0x21。
-
令 codePoint 为jis0208 索引中 pointer 对应的 索引码点。
-
如果 codePoint 为 null,则返回错误。
-
返回一个值为 codePoint 的码点。
- 队列末尾
-
将ISO-2022-JP 解码器状态设为 前导字节并返回错误。
- 其他情况
-
将ISO-2022-JP 解码器状态设为 前导字节并返回 错误。
- 转义开始
-
-
如果 byte 是 0x24 或 0x28,则将 ISO-2022-JP 前导字节设为 byte,将ISO-2022-JP 解码器状态设为 转义,并返回继续。
-
将ISO-2022-JP 输出标志设为 false,将ISO-2022-JP 解码器状态设为 ISO-2022-JP 解码器输出状态,并返回错误。
-
- 转义
-
-
令 leading 为ISO-2022-JP 前导字节并设 ISO-2022-JP 前导字节为 0x00。
-
令 state 为 null。
-
如果 leading 是 0x28 且 byte 是 0x42,则将 state 设为ASCII。
-
如果 leading 是 0x28 且 byte 是 0x4A,则将 state 设为罗马字。
-
如果 leading 是 0x28 且 byte 是 0x49,则将 state 设为片假名。
-
如果 leading 是 0x24 且 byte 是 0x40 或 0x42, 则将 state 设为前导字节。
-
如果 state 不为 null:
-
将ISO-2022-JP 解码器状态和 ISO-2022-JP 解码器输出状态设为 state。
-
令 output 为ISO-2022-JP 输出标志的值。
-
将ISO-2022-JP 输出标志设为 true。
-
-
如果 byte 是队列末尾,则将 leading 恢复到 ioQueue;否则,将 « leading, byte » 恢复到 ioQueue。
-
将ISO-2022-JP 输出标志设为 false, 将ISO-2022-JP 解码器状态设为ISO-2022-JP 解码器输出状态 并返回错误。
-
12.2.2. ISO-2022-JP 编码器
ISO-2022-JP 编码器是唯一一个当多个输出连接起来并通过相应的解码器运行时可能导致错误的编码器。
编码 U+00A5 (¥) 会得到 0x1B 0x28 0x4A 0x5C 0x1B 0x28 0x42。执行两次,连接结果,然后解码会得到 U+00A5 U+FFFD U+00A5。
ISO-2022-JP 的编码器有一个关联的 ISO-2022-JP 编码器状态,可以是ASCII、 罗马字或 jis0208,初始为 ASCII。
ISO-2022-JP 的编码器的处理程序,给定 ioQueue 和 codePoint,执行以下步骤:
-
如果 codePoint 是队列末尾且ISO-2022-JP 编码器状态不为 ASCII,则将ISO-2022-JP 编码器状态设为 ASCII 并返回三个字节 0x1B 0x28 0x42。
-
如果 codePoint 是队列末尾且ISO-2022-JP 编码器状态为 ASCII,则返回完成。
-
如果ISO-2022-JP 编码器状态为ASCII或 罗马字,且 codePoint 为 U+000E、U+000F 或 U+001B,则返回带 U+FFFD () 的错误。
这里返回 U+FFFD () 而不是 codePoint 是为了防止攻击。
-
如果ISO-2022-JP 编码器状态为ASCII且 codePoint 是一个ASCII 码点,则返回一个值为 codePoint 的字节。
-
如果ISO-2022-JP 编码器状态为罗马字且 codePoint 是一个ASCII 码点(不包括 U+005C (\) 和 U+007E (~)),或者是 U+00A5 (¥) 或 U+203E (‾):
-
如果 codePoint 是一个ASCII 码点,则返回一个值为 codePoint 的字节。
-
如果 codePoint 是 U+00A5 (¥),则返回字节 0x5C。
-
如果 codePoint 是 U+203E (‾),则返回字节 0x7E。
-
-
如果 codePoint 是一个ASCII 码点,且ISO-2022-JP 编码器状态不为ASCII,则将 codePoint 恢复到 ioQueue,将ISO-2022-JP 编码器状态设为 ASCII,并返回三个字节 0x1B 0x28 0x42。
-
如果 codePoint 是 U+00A5 (¥) 或 U+203E (‾),且 ISO-2022-JP 编码器状态不为罗马字,则将 codePoint 恢复到 ioQueue, 将ISO-2022-JP 编码器状态设为 罗马字,并返回三个字节 0x1B 0x28 0x4A。
-
如果 codePoint 是 U+2212 (−),则将其设为 U+FF0D (-)。
-
如果 codePoint 在 U+FF61 (。) 到 U+FF9F (゚)(含)的范围内,则将其设为 ISO-2022-JP 片假名索引中 codePoint − 0xFF61 对应的索引码点。
-
令 pointer 为jis0208 索引中 codePoint 对应的索引指针。
如果 pointer 不为 null,则由于 jis0208 索引和 索引指针 操作的性质,它将小于 8836。
-
如果 pointer 为 null:
-
如果ISO-2022-JP 编码器状态为jis0208, 则将 codePoint 恢复到 ioQueue,将 ISO-2022-JP 编码器状态设为ASCII,并返回三个 字节 0x1B 0x28 0x42。
-
返回带 codePoint 的错误。
-
-
如果ISO-2022-JP 编码器状态不为jis0208, 则将 codePoint 恢复到 ioQueue, 将 ISO-2022-JP 编码器状态设为jis0208,并返回 三个字节 0x1B 0x24 0x42。
-
令 leading 为 pointer / 94 + 0x21。
-
令 trailing 为 pointer % 94 + 0x21。
-
返回两个字节,其值分别为 leading 和 trailing。
12.3. Shift_JIS
12.3.1. Shift_JIS 解码器
Shift_JIS 的解码器有一个关联的 Shift_JIS 前导字节,它是一个字节,初始值为 0x00。
Shift_JIS 的解码器的处理程序,给定 ioQueue 和 byte,执行以下步骤:
-
如果 byte 是队列末尾且Shift_JIS 前导字节不为 0x00,则将 Shift_JIS 前导字节设为 0x00 并返回错误。
-
如果 byte 是队列末尾且Shift_JIS 前导字节为 0x00,则返回 完成。
-
如果Shift_JIS 前导字节不为 0x00:
-
令 leading 为Shift_JIS 前导字节。
-
将Shift_JIS 前导字节设为 0x00。
-
令 pointer 为 null。
-
如果 byte 小于 0x7F,则令 offset 为 0x40;否则为 0x41。
-
如果 leading 小于 0xA0,则令 leadingOffset 为 0x81;否则为 0xC1。
-
如果 byte 在 0x40 到 0x7E(含)或 0x80 到 0xFC(含)的范围内, 则将 pointer 设为 (leading − leadingOffset) × 188 + byte − offset。
-
如果 pointer 在 8836 到 10715(含)的范围内,则返回一个值为 0xE000 − 8836 + pointer 的码点。
这是来自 Windows 的可互操作的旧式传统,称为 EUDC。
-
如果 pointer 为 null,则令 codePoint 为 null;否则为jis0208 索引中 pointer 对应的 索引码点。
-
如果 codePoint 不为 null,则返回一个值为 codePoint 的码点。
-
返回错误。
-
-
如果 byte 是一个ASCII 字节或 0x80,则返回一个值为 byte 的码点。
-
如果 byte 在 0xA1 到 0xDF(含)的范围内,则返回一个值为 0xFF61 − 0xA1 + byte 的码点。
-
如果 byte 在 0x81 到 0x9F(含)或 0xE0 到 0xFC(含)的范围内,则 将Shift_JIS 前导字节设为 byte 并返回继续。
-
返回错误。
12.3.2. Shift_JIS 编码器
Shift_JIS 的编码器的处理程序,给定 unused 和 codePoint,执行以下步骤:
-
如果 codePoint 是一个ASCII 码点或 U+0080,则返回一个值为 codePoint 的字节。
-
如果 codePoint 是 U+00A5 (¥),则返回字节 0x5C。
-
如果 codePoint 是 U+203E (‾),则返回字节 0x7E。
-
如果 codePoint 在 U+FF61 (。) 到 U+FF9F (゚)(含)的范围内,则返回一个 值为 codePoint − 0xFF61 + 0xA1 的字节。
-
如果 codePoint 是 U+2212 (−),则将其设为 U+FF0D (-)。
-
令 pointer 为 codePoint 对应的Shift_JIS 索引指针。
-
如果 pointer 为 null,则返回带 codePoint 的错误。
-
令 leading 为 pointer / 188。
-
如果 leading 小于 0x1F,则令 leadingOffset 为 0x81;否则为 0xC1。
-
令 trailing 为 pointer % 188。
-
如果 trailing 小于 0x3F,则令 offset 为 0x40;否则为 0x41。
-
返回两个字节,其值分别为 leading + leadingOffset 和 trailing + offset。
13. 旧版多字节韩文编码
13.1. EUC-KR
13.1.1. EUC-KR 解码器
EUC-KR 的解码器有一个关联的 EUC-KR 前导字节,它是一个字节,初始值为 0x00。
EUC-KR 的解码器的处理程序,给定 ioQueue 和 byte,执行以下步骤:
-
如果 byte 是队列末尾且EUC-KR 前导字节不为 0x00,则将 EUC-KR 前导字节设为 0x00 并返回错误。
-
如果 byte 是队列末尾且EUC-KR 前导字节为 0x00,则返回 完成。
-
如果EUC-KR 前导字节不为 0x00:
-
令 leading 为EUC-KR 前导字节。
-
将EUC-KR 前导字节设为 0x00。
-
令 pointer 为 null。
-
如果 byte 在 0x41 到 0xFE(含)的范围内,则将 pointer 设为 (leading − 0x81) × 190 + (byte − 0x41)。
-
如果 pointer 为 null,则令 codePoint 为 null;否则为EUC-KR 索引中 pointer 对应的 索引码点。
-
如果 codePoint 不为 null,则返回一个值为 codePoint 的码点。
-
返回错误。
-
-
如果 byte 是一个ASCII 字节,则返回一个值为 byte 的码点。
-
如果 byte 在 0x81 到 0xFE(含)的范围内,则将EUC-KR 前导字节设为 byte 并返回继续。
-
返回错误。
13.1.2. EUC-KR 编码器
EUC-KR 的编码器的处理程序,给定 unused 和 codePoint,执行以下步骤:
-
如果 codePoint 是一个ASCII 码点,则返回一个值为 codePoint 的字节。
-
如果 pointer 为 null,则返回带 codePoint 的错误。
-
令 leading 为 pointer / 190 + 0x81。
-
令 trailing 为 pointer % 190 + 0x41。
-
返回两个字节,其值分别为 leading 和 trailing。
14. 旧式杂项编码
14.1. replacement
replacement 编码的存在是为了防止滥用服务器与客户端支持的 编码不一致造成的某些攻击。
14.1.1. replacement 解码器
replacement 的解码器有一个关联的 replacement error returned,它是一个布尔值,初始为 false。
replacement 的解码器的处理程序,给定 unused 和 byte,执行以下步骤:
-
如果 replacement error returned 为 false,则将 replacement error returned 设为 true,并返回错误。
-
返回完成。
14.2. UTF-16BE/LE 的通用基础设施
UTF-16BE/LE 是 UTF-16BE 或 UTF-16LE。
14.2.1. 共享 UTF-16 解码器
字节顺序标记优先于标签,因为在实际内容中它被发现更为准确。因此它不是共享 UTF-16 解码器算法的一部分,而属于解码算法。
共享 UTF-16 解码器有一个关联的:
- UTF-16 前导字节
- 为空或一个字节,初始为 null。
- UTF-16 前导代理项
- 为空或前导代理项,初始为 null。
- 是否 UTF-16BE 解码器
- 布尔值,初始为 false。
共享 UTF-16 解码器的处理程序,给定 ioQueue 和 byte,执行以下步骤:
-
如果 byte 是队列末尾,且 UTF-16 前导字节 或 UTF-16 前导代理项非空,则将 UTF-16 前导字节和 UTF-16 前导代理项设为 null,并返回错误。
-
如果 byte 是队列末尾,且UTF-16 前导字节和 UTF-16 前导代理项均为空,则返回完成。
-
如果UTF-16 前导字节为空,则将UTF-16 前导字节设为 byte,并返回继续。
-
令 codeUnit 为以下结果之一:
- 是否 UTF-16BE 解码器为 true
-
(UTF-16 前导字节 << 8) + byte。
- 是否 UTF-16BE 解码器为 false
-
(byte << 8) + UTF-16 前导字节。
-
将UTF-16 前导字节设为 null。
-
如果UTF-16 前导代理项非空:
-
令 leadingSurrogate 为UTF-16 前导代理项。
-
将UTF-16 前导代理项设为 null。
-
如果 codeUnit 是尾随代理项,则返回由代理项组成的标量值,参数为 leadingSurrogate 和 codeUnit。
-
令 byte1 为 codeUnit >> 8。
-
令 byte2 为 codeUnit & 0x00FF。
-
若是否 UTF-16BE 解码器为 true,则 bytes 为 [byte1, byte2],否则为 [byte2, byte1]。
-
-
如果 codeUnit 是前导代理项,则将UTF-16 前导代理项设为 codeUnit 并返回继续。
-
返回码点 codeUnit。
14.3. UTF-16BE
14.3.1. UTF-16BE 解码器
UTF-16BE 的解码器是共享 UTF-16 解码器,其 是否 UTF-16BE 解码器 设为 true。
14.4. UTF-16LE
"utf-16
" 是 UTF-16LE 的标签,用于兼容已部署的内容。
14.4.1. UTF-16LE 解码器
14.5. x-user-defined
虽然技术上这是单字节编码,但它被单独定义,因为它可以算法化实现。
14.5.1. x-user-defined 解码器
x-user-defined 的解码器的处理程序,给定 unused 和 byte,执行以下步骤:
14.5.2. x-user-defined 编码器
x-user-defined 的编码器的处理程序,给定 unused 和 codePoint,执行以下步骤:
-
如果 codePoint 是一个ASCII 码点,则返回一个值为 codePoint 的字节。
-
如果 codePoint 在 U+F780 到 U+F7FF(含)的范围内,则返回一个值为 codePoint − 0xF780 + 0x80 的字节。
-
返回带 codePoint 的错误。
15. 浏览器 UI
建议浏览器不要启用覆盖资源编码的选项。如果此功能仍然存在,浏览器不应将 UTF-16BE/LE 作为选项提供,因为上述安全问题。若资源已用 UTF-16BE/LE 解码,浏览器也应该禁用该功能。
实现注意事项
对于本标准中的编码,其解码器可以用如下方式实现,无需支持具有任意I/O 队列和任意恢复:
-
能够反读当前字节。
-
为 gb18030(一个 ASCII 字节)和 ISO-2022-JP(0x24 或 0x28)提供单字节缓冲区。
对于 gb18030,当 gb18030 third 不为 0x00 时遇到非法字节,可以将 gb18030 second 移入单字节缓冲区,作为下一个字节返回,并将 gb18030 third 作为新的 gb18030 first,在单字节缓冲区被返回并清空后检查其是否不为 0x00。因为 gb18030 的第一个字节和第三个字节的取值范围是相同的,所以这是可行的。
ISO-2022-JP 编码器需要 ISO-2022-JP 编码器状态 作为额外状态,但除此之外,本标准中其他编码的编码器不需要额外状态或缓冲区。