[47] [DFN[符号化]]は、[[文字列]]を[[バイト列]]に変換する操作です。
[DFN[復号]]は、[[バイト列]]を[[文字列]]に変換する操作です。

* 仕様書

[REFS[
- [15] [CITE@en-US[Encoding Standard]] ([TIME[2016-07-29 16:12:31 +09:00]]) <https://encoding.spec.whatwg.org/#encodings>
- [1] [CITE@en-US[Encoding Standard]] ([TIME[2016-07-29 16:12:31 +09:00]]) <https://encoding.spec.whatwg.org/#specification-hooks>
- [56] [CITE@en-US[Encoding Standard]] ([TIME[2016-07-29 16:12:31 +09:00]]) <https://encoding.spec.whatwg.org/#textdecoder>
]REFS]

* 符号化

[45] [[符号化][符号化 (動詞)]]は、[[文字列]]を何らかの[[バイト列]]に変換する操作です。

[40] [DFN[[RUBYB[符号化]@en[encode]]]]は、
[[符号位置]]の[[ストリーム]][VAR[ストリーム]]と[[文字符号化]][VAR[符号化]]について、
次のようにします [SRC[>>1]]。
[FIG(steps)[
= [41] [VAR[出力]]を、[[バイトストリーム]]に設定します。
= [42] [VAR[符号化]]の[F[符号化器クラス]]を[[走らせ][走らせる]]ます。
[VAR[入力]]を[VAR[ストリーム]]、[VAR[出力]]を[VAR[出力]]とし、
[VAR[[[誤りモード]]]]は [CODE[html]] とします。
= [43] [VAR[出力]]を返します。
]FIG]

;; [44] [[replacement]]、[[UTF-16BE]]、[[UTF-16LE]] を[VAR[符号化]]とすることはできません
[SRC[>>1]]。

[53] [[符号化]]操作が使われる場面は、 [[Webにおける文字コード]]を参照。

[46] この操作は、 [CITE[Encoding Standard]] の規定する任意の[[文字符号化]]への[[符号化][符号化 (動詞)]]が必要な場合に使います。
これは[[後方互換性]]のため必要な場面に限定されています。
新しい文脈では [[UTF-8符号化]]などを用いるのが望ましいと考えられています [SRC[>>1]]。

* 復号

[33] [[復号][復号 (符号化)]]は、何らかの[[バイト列]]を[[文字列]]に変換する操作です。


[3] [DFN[[RUBYB[復号]@en[decode]]][復号 (符号化)]]は、
[[バイトストリーム]][VAR[ストリーム]]と[[符号化][文字符号化]][VAR[符号化]]について、
次のようにします [SRC[>>1]]。

[FIG(steps)[
= [4] [VAR[バッファー]]を、空の[[バイト列]]に設定します。
= [6] 繰り返し、[VAR[ストリーム]]を[[読み][読む (ストリーム)]]、
[VAR[バッファー]]の末尾に追加します。[VAR[バッファー]]が3[[バイト]]となるか、
[[end-of-stream]] が得られた時点でやめます。
= [7] [VAR[バッファー]]の最初の3バイトが [CODE[0xEF 0xBB 0xBF]] なら、
== [8] [VAR[符号化]]を、 [[UTF-8]] に設定します。
= [10] それ以外で、[VAR[バッファー]]の最初の2バイトが [CODE[0xFE 0xFF]] なら、
== [11] [VAR[符号化]]を、 [[UTF-16BE]] に設定します。
== [5] [VAR[バッファー]]が3バイトなら、
=== [9] [VAR[バッファー]]の最後の[[バイト]]を、[VAR[ストリーム]]に[[prepend][prepend (ストリーム)]]します。
= [13] それ以外で、[VAR[バッファー]]の最初の2バイトが [CODE[0xFF 0xFE]] なら、
== [14] [VAR[符号化]]を、 [[UTF-16LE]] に設定します。
== [35] [VAR[バッファー]]が3バイトなら、
=== [36] [VAR[バッファー]]の最後の[[バイト]]を、[VAR[ストリーム]]に[[prepend][prepend (ストリーム)]]します。
= [34] それ以外なら、
== [32] [VAR[バッファー]]を、[VAR[ストリーム]]に[[prepend][prepend (ストリーム)]]します。
= [12] [VAR[出力]]を、[[符号位置]]の[[ストリーム]]に設定します。
= [16] [VAR[符号化]]の[F[復号器クラス]]を[[走らせ][走らせる (符号化)]]ます。
[VAR[入力]]は[VAR[ストリーム]]、[VAR[出力]]は[VAR[出力]]とします。
= [17] [VAR[出力]]を返します。
]FIG]

[31] [[仕様書]]にはありませんが、[VAR[符号化]]も返す必要があります。

[57] [CODE(DOMi)@en[TextDecoder]] [[インターフェイス]]の
[CODE(DOMa)@en[decode][TextDecoder]] [[メソッド]] [SRC[>>56]]
は、その[[復号][復号 (符号化)]]の処理の部分について、引数として
[FIG(list members)[
: [VAR[復号器オブジェクト]] : [[復号器オブジェクト]]
: [VAR[ストリーム]] : [[ストリーム]]
: [VAR[誤りモード]] : [[誤りモード]] ([CODE[replacement][replacement (符号化)]] または [CODE[fatal][fatal (符号化)]])
: [VAR[do not flush flag]] : [[フラグ]]
: [VAR[BOM無視フラグ]] : [[フラグ]]
]FIG]
... を受け取り、次のようにします。
[FIG(steps)[
= [58] [VAR[出力]]を、新しい[[ストリーム]]に設定します。
= [59] 繰り返し、
== [60] [VAR[字句]]を、[VAR[ストリーム]]を[[読ん][読む]]だ結果に設定します。
== [61] [VAR[字句]]が [[end-of-stream]] で、 [VAR[do not flush flag]] が[[真]]なら、
=== [63] 繰り返しをここで脱出します。
== [62] それ以外なら、
=== [64] [VAR[結果]]を、[VAR[復号器オブジェクト]]の[[処理][処理 (符号化)]]の結果に設定します。
[VAR[入力]]は[VAR[ストリーム]]、[VAR[出力]]を[VAR[出力]]、
[VAR[誤りモード]]を[VAR[誤りモード]]とします。
=== [65] [VAR[結果]]により、
[FIG(switch)[
: [[終了済み][終了済み (符号化)]] : 繰り返しをここで脱出します。
: [[誤り][誤り (符号化)]] : [CODE(DOMe)@en[TypeError]] を[[投げ]]、ここで停止します。
]FIG]
= [67] [DFN[[RUBYB[ストリームの直列化]@en[serialize stream]]]]、すなわち、
== [66] [VAR[ストリーム]]を、 [[end-of-stream]] が得られるまで[[読み][読む]]続けます。
[VAR[結果]]を、得られた[[符号位置]]を順に連結したものに設定します。
== [68] [VAR[復号器オブジェクト]]が [[UTF-8]]、[[UTF-16BE]]、[[UTF-16LE]] のいずれかで、
[VAR[BOM無視フラグ]]が[[偽]]なら、
=== [69] [VAR[結果]]の先頭が [CODE(char)[U+FEFF]] なら、これを除去します。
== [70] [VAR[結果]]を返します。
]FIG]

[71] この操作は、[[文字列]]の境界以外で分割されているかもしれない複数の[[バイト列]]を連続する1つの[[文字列]]として処理することや、
[[BOM]] の扱いを[[著者]]が指示することを想定し、他での処理よりも複雑となっています。

[84] 実際には、[[復号][復号 (符号化)]]操作や[[UTF-8復号]]および関連各操作も、
入出力が1つの[[バイト列]]・[[文字列]]ではなく[[ストリーム]]となる場合があり、
この操作と同じような形で実装することになると思われます。

-*-*-

[72] [[復号][復号 (符号化)]]操作が使われる場面は、
[[Webにおける文字コード]]参照。

[43] 
[[復号][復号 (符号化)]]操作は、 [CITE[Encoding Standard]] の任意の[[文字符号化]]からの[[復号][復号 (符号化)]]のために使えます。
これは[[後方互換性]]のため必要な場面に限られます。
新しい文脈では [[UTF-8復号]]を用いるのが望ましいと考えられています [SRC[>>1]]。

;; [81] [[UTF-8復号]]は、[[復号][復号 (符号化)]]操作を呼び出さず、
直接[[復号器]]を呼び出しています。


[37] [[復号][復号 (符号化)]]の操作は、引数として[[文字符号化]]を引き渡すことができます。
しかし入力に [[BOM]] が含まれていれば、そちらが優先されます ([DFN[BOM sniffing]])。

;; [73] 他の [[charset sniffing]] との関係については、
[[Webにおける文字コード]]を参照。

[NOTE[

[39] この操作はしばしば [[HTTP]] で転送されたデータに適用されます。
[SEE[ [[Webにおける文字コード]] ]]

[38] [[HTTP]] 仕様上は [CODE(MIME)@en[charset]] [[引数]]の[[文字符号化]]の指定が
[[BOM]] より優先されることになっていますが、現実にはそれでは[[相互運用性]]に問題があります。
これは[[意図的違反]]です [SRC[>>1]]。

[83] なお、
[CODE(MIME)@en[charset]] [[引数]]で指定されるのは[[符号化ラベル]]であり、
呼び出し側で適切な[[文字符号化]]に変換してから本操作を呼び出す必要があります。

]NOTE]


* 符号化器と復号器

[49] [[Encoding Standard]] は、[[符号化器]]と[[復号器]]を、
[[文字符号化]]ごとに定義される[[クラス]]的なものと、
その[[実現値]]たる個別の[[オブジェクト]]的なものの両方の意味で使っています。

[52] [[符号化器クラス]]や[[復号器クラス]]には、
[[走らせる][走らせる (符号化)]]処理と[F[取扱器][取扱器 (符号化)]]が定義されています。
また[[復号器クラス]]の[F[BOMを持つ]]は、当該[[復号器]]の[[文字符号化]]が
[[UTF-8]]、[[UTF-16BE]]、[[UTF-16LE]] のいずれかなら[[真]]で、それ以外なら[[偽]]です。

[2] [[符号化器オブジェクト]]や[[復号器オブジェクト]]は、
いくつかの[[文字符号化]]依存の状態を持ちます。
また、[[処理][処理 (符号化)]]演算が定義されています。

[50] 更に、 [[Web IDLインターフェイス]]として [CODE(DOMi)@en[TextEncoder]]
と [CODE(DOMi)@en[TextDecoder]] があり、それぞれ (通常の [[Web IDL]]
の[[インターフェイス]]同様に) [[インターフェイスオブジェクト]] (≒ [[クラス]]) 
と[[オブジェクト]]が存在しています。

[51] [CODE(DOMi)@en[TextEncoder]] や [CODE(DOMi)@en[TextDecoder]] の[[オブジェクト]]は、
いくつかの状態を持ちます。それには[[符号化器オブジェクト]]や[[復号器オブジェクト]]も含まれます。
同時には1つの[[オブジェクト]]だけを持ちますが、時に新しい[[オブジェクト]]に差し替えられることがあります。

[21] [[符号化][文字符号化]]の[F[符号化器クラス]]または[F[復号器クラス]][VAR[器]]を、
[[ストリーム]][VAR[入力]]、[[ストリーム]][VAR[出力]]、
[[誤りモード]][VAR[モード]]について[DFN[[RUBYB[走らせる]@en[run]]]]には、
次のようにします [SRC[>>15]]。
[FIG(steps)[
= [22] [VAR[オブジェクト]]を、[VAR[器]]の新しい[[実現値]]オブジェクトに設定します。
= [23] 繰り返し、
== [24] [VAR[結果]]を、[[処理][処理 (符号化)]]の結果に設定します。
[FIG(list members middle)[
: [VAR[オブジェクト]] : [VAR[オブジェクト]]
: [VAR[字句]] : [VAR[入力]]を[[読んだ][読む (ストリーム)]]結果
: [VAR[入力]] : [VAR[入力]]
: [VAR[出力]] : [VAR[出力]]
: [VAR[モード]] : [VAR[モード]]
]FIG]
== [25] [VAR[結果]]が[[継続][継続 (符号化)]]以外なら、
=== [26] [VAR[結果]]を返し、ここで停止します。
]FIG]

;; [55] [[走らせる][走らせる (符号化)]]は、[[符号化][符号化 (動詞)]]、
[[復号][復号 (符号化)]]の他に、
[[UTF-8復号]]、[[BOMなしUTF-8復号]]、[[BOMなしUTF-8復号または失敗]]から呼び出されます。

[27] [[符号化器オブジェクト]]または[[復号器オブジェクト]][VAR[オブジェクト]]を、
[[字句][字句 (文字コード)]][VAR[字句]]、
[[ストリーム]][VAR[入力]]、[[ストリーム]][VAR[出力]]、
[[誤りモード]][VAR[モード]]について[DFN[[RUBYB[処理]@en[process]]]]するには、
次のようにします [SRC[>>15]]。
[FIG(steps)[
= [28] [VAR[結果]]を、[VAR[入力]]と[VAR[字句]]について[VAR[オブジェクト]]の[F[クラス]]の[F[取扱器][取扱器 (符号化)]]を実行した結果に設定します。
= [29] [VAR[結果]]により、
[FIG(switch)[
: [[継続][継続 (符号化)]]、[[終了済み][終了済み (符号化)]] : [VAR[結果]]を返し、ここで停止します。
: 1つ[[以上]]の[[字句]] : [VAR[結果]]を[VAR[出力]]に[[push][push (ストリーム)]]します。
: [[誤り][誤り (符号化)]] : [VAR[モード]]により、
[FIG(switch)[
: [CODE[replacement][replacement (符号化)]] : [CODE[U+FFFD]] を[VAR[出力]]に[[push][push (ストリーム)]]します。
: [CODE[html][html (符号化)]] :
[CODE[&#]]、[VAR[結果]]の[F[符号位置]]を[[十進数]]で[[ASCII数字]]で最短で表現したもの、
[CODE[;]] を連結したものを''[VAR[入力]]''に[[prepend][prepend (ストリーム)]]します。
: [CODE[fatal][fatal (符号化)]] : [[誤り][誤り (符号化)]]を返し、ここで停止します。
]FIG]
]FIG]
= [30] [[継続][継続 (符号化)]]を返します。
]FIG]

;; [54] [[処理][処理 (符号化)]]は、[[走らせる][走らせる (符号化)]]の他に、
[CODE(DOMi)@en[TextEncoder]] の [CODE(DOMm)@en[encode][TextEncoder]]
[[メソッド]]でも呼びだされます。しかし[[UTF-8符号化]]
(間接的に[[走らせる][走らせる (符号化)]]を呼び出します。) と実質的に等価です。

[19] [[符号化器]]や[[復号器]]の[DFN[[F[[RUBYB[[[取扱器][取扱器 (符号化)]]]@en[handler]]]]]]は、
[[ストリーム]]と[[字句]]を入力とします。
次のいずれかを返します。 [SRC[>>15]]
[FIG(list middle)[
- [DFN[[RUBYB[[[終了済み][終了済み (符号化)]]]@en[finished]]]]
- 1つ[[以上]]の[[字句][字句 (文字コード)]]
- [DFN[[RUBYB[[[誤り][誤り (符号化)]]]@en[error]]]]と省略可能な[[符号位置]]
- [DFN[[RUBYB[[[継続][継続 (符号化)]]]@en[continue]]]]
]FIG]

[48] 具体的な[[アルゴリズム]]は、[[文字符号化]]ごとに規定されています。

;; 各[[文字符号化]]の項を参照。

* 文脈

[18] [[符号化]]は、[DFN[[F[[RUBYB[[[符号化器]]]@en[encoder]]クラス]]]]と[DFN[[F[[RUBYB[[[復号器]]]@en[decoder]]クラス]]]]を持ちます
[SRC[>>15]]。

;; ただし[[置換]]、[[UTF-16BE]]、[[UTF-16LE]]は[F[[[符号化器]]クラス]]を持ちません [SRC[>>15]]。

* 誤りモード

[20] [DFN[[RUBYB[誤りモード]@en[error mode]]]]は、次のいずれかです [SRC[>>15]]。
[FIG(list)[
: [DFN[[CODE[replacement][replacement (符号化)]]]] ([[復号器]]、[[既定値]]) :
不正な入力を [CODE(char)[U+FFFD]] に置換することを指定するものです。
: [DFN[[CODE[fatal][fatal (符号化)]]]] ([[復号器]] / [[符号化器]]、[[既定値]]) :
不正な入力の時[[エラー]]を報告して停止するべきことを指定するものです。
: [DFN[[CODE[html][html (符号化)]]]] ([[符号化器]]) :
出力の[[文字符号化]]で表現できない時 [[HTML]] の[[十進文字参照]]に置換することを指定するものです。
]FIG]

[75] [CODE[fatal][fatal (符号化)]] は、 [[XML構文解析器]] [SRC[>>15]]、
[[BOMなしUTF-8復号または失敗]]、 [CODE(DOMi)@en[TextDecoder]] [CODE(DOMa)@en[fatal][fatal (符号化)]]
で使われます。

[78] [CODE[replacement]] はその他の[[復号]]が必要な場面で使われます。
例えば[[HTML構文解析器]]が該当します。

[74] [[符号化器]]では実際には [CODE[html][html (符号化)]] しか使われません。
かつては [CODE(DOMi)@en[TextEncoder]] で [[UTF-8]] 以外かつ [CODE(DOMa)@en[fatal][fatal (符号化)]]
が指定される可能性があったようですが、現在では [[UTF-8]] しか指定できません。
また [[UTF-8]] はすべての[[Unicodeスカラー値]]を[[誤り][誤り (符号化)]]なく[[符号化][符号化 (動詞)]]できます。

;; [[サロゲート]]は [[Web IDL]] [CODE(IDL)@en[USVString]] への変換の時点で置換されます。

* 歴史

[76] [CITE@en[Define 'continue' and 'break' statements]]
([[mikewest]]著, [TIME[2016-11-22 03:27:37 +09:00]])
<https://github.com/whatwg/infra/commit/8fbf990dcdb5f7ee80a85b569cba61a056fe1cc5>

[77] [CITE@en[Parse application/x-www-form-urlencoded using UTF-8 only]]
([[annevk]]著, [TIME[2017-01-17 19:11:02 +09:00]])
<https://github.com/whatwg/url/commit/3fe969679f78c92c353047661b0c4b6797f099f6>

[90] [CITE@en[Give clearer advice on hooks for standards]]
([[annevk]]著, [TIME[2018-04-25 21:22:45 +09:00]])
<https://github.com/whatwg/encoding/commit/b579018b406d7752f8b7a3aa9c2bc800519c6f1a>

[92] [CITE@en[Use UTF-8 decode without BOM for multipart/form-data]]
([[annevk]], [TIME[2019-11-04 23:23:54 +09:00]], [TIME[2021-03-06T02:54:19.000Z]])
<https://github.com/whatwg/fetch/commit/7db8ac52245d6f0abaaeec6ae1cd96553c30b737>