From 13e8c527ca95e11218e1944ff5f594b2c3b41651 Mon Sep 17 00:00:00 2001 From: Masayuki Yamamoto Date: Fri, 8 Feb 2019 01:05:49 +0900 Subject: [PATCH] Sanitize numeric character reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit サロゲートペアなど数値文字参照としてはエラーになる値をチェックして かわりに規定の値を返すよう修正する。 参考文献 : Numeric character reference end state (HTML 5.3) https://www.w3.org/TR/html53/syntax.html#numeric-character-reference-end-state --- src/jdlib/miscutil.cpp | 83 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/jdlib/miscutil.cpp b/src/jdlib/miscutil.cpp index 242a9b73b..1fdf50474 100644 --- a/src/jdlib/miscutil.cpp +++ b/src/jdlib/miscutil.cpp @@ -1305,6 +1305,87 @@ int MISC::spchar_number_ln( const char* in_char, int& offset ) } +// 特定の変換が必要なコードポイントをチェックする +static int transform_7f_9f( int raw_point ) +{ + switch( raw_point ) { + case 0x80: return 0x20AC; // EURO SIGN (€) + case 0x82: return 0x201A; // SINGLE LOW-9 QUOTATION MARK (‚) + case 0x83: return 0x0192; // LATIN SMALL LETTER F WITH HOOK (ƒ) + case 0x84: return 0x201E; // DOUBLE LOW-9 QUOTATION MARK („) + case 0x85: return 0x2026; // HORIZONTAL ELLIPSIS (…) + case 0x86: return 0x2020; // DAGGER (†) + case 0x87: return 0x2021; // DOUBLE DAGGER (‡) + case 0x88: return 0x02C6; // MODIFIER LETTER CIRCUMFLEX ACCENT (ˆ) + case 0x89: return 0x2030; // PER MILLE SIGN (‰) + case 0x8A: return 0x0160; // LATIN CAPITAL LETTER S WITH CARON (Š) + case 0x8B: return 0x2039; // SINGLE LEFT-POINTING ANGLE QUOTATION MARK (‹) + case 0x8C: return 0x0152; // LATIN CAPITAL LIGATURE OE (Œ) + case 0x8E: return 0x017D; // LATIN CAPITAL LETTER Z WITH CARON (Ž) + case 0x91: return 0x2018; // LEFT SINGLE QUOTATION MARK (‘) + case 0x92: return 0x2019; // RIGHT SINGLE QUOTATION MARK (’) + case 0x93: return 0x201C; // LEFT DOUBLE QUOTATION MARK (“) + case 0x94: return 0x201D; // RIGHT DOUBLE QUOTATION MARK (”) + case 0x95: return 0x2022; // BULLET (•) + case 0x96: return 0x2013; // EN DASH (–) + case 0x97: return 0x2014; // EM DASH (—) + case 0x98: return 0x02DC; // SMALL TILDE (˜) + case 0x99: return 0x2122; // TRADE MARK SIGN (™) + case 0x9A: return 0x0161; // LATIN SMALL LETTER S WITH CARON (š) + case 0x9B: return 0x203A; // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (›) + case 0x9C: return 0x0153; // LATIN SMALL LIGATURE OE (œ) + case 0x9E: return 0x017E; // LATIN SMALL LETTER Z WITH CARON (ž) + case 0x9F: return 0x0178; // LATIN CAPITAL LETTER Y WITH DIAERESIS (Ÿ) + default: + return 0xFFFD; // REPLACEMENT CHARACTER + } +} + +// +// コードポイントが数値文字参照としてはエラーなら規定の値へ変換する +// 例えばサロゲートペアは'REPLACEMENT CHARACTER' (U+FFFD)を返す +// +// 参考文献 : Numeric character reference end state (HTML 5.3) +// https://www.w3.org/TR/html53/syntax.html#numeric-character-reference-end-state +// +static int sanitize_numeric_character_reference( int raw_point ) +{ + // NOTE: 記号や絵文字を速やかに処理できるよう順番が組まれている + + bool parse_error = false; + + // 基本多言語面(BMP)をおおまかにチェック + if( 0x009F < raw_point && raw_point < 0xD800 ) return raw_point; + // 特定のbitパターンの非文字と符号空間の範囲をチェック + else if( ( raw_point & 0xFFFE ) == 0xFFFE || raw_point > 0x10FFFF ) parse_error = true; + // bitパターンを除いたらBMPの一部と追加多言語面(SMP)以降をチェック + else if( 0xFDEF < raw_point ) return raw_point; + // サロゲートペアはエラー + else if( 0xD800 <= raw_point && raw_point <= 0xDFFF ) parse_error = true; + + // 基本ラテン文字をチェック + else if( 0x001F < raw_point && raw_point < 0x007F ) return raw_point; + // 特定の変換が必要なコードポイントをチェック + else if( 0x007F <= raw_point && raw_point <= 0x009F ) return transform_7f_9f( raw_point ); + // 最後に制御文字と非文字をチェック + // サロゲートペアは他の値より入力される可能性が高いので処理を優先している + else if( raw_point <= 0x0008 // Control character + || raw_point == 0x000B // Control character (Vertical tab) + || ( 0x000D <= raw_point && raw_point <= 0x001F ) // Control character + || ( 0xFDD0 <= raw_point && raw_point <= 0xFDEF ) // Noncharacters + ) { + parse_error = true; + } + + if( parse_error ) { +#ifdef _DEBUG + std::cout << "Parse error for numeric character reference... " << raw_point << std::endl; +#endif + return 0xFFFD; // REPLACEMENT CHARACTER + } + return raw_point; +} + // // 「&#数字;」形式の数字参照文字列を数字(int)に変換する // @@ -1331,7 +1412,7 @@ int MISC::decode_spchar_number( const char* in_char, const int offset, const int if( offset == 2 ) num = atoi( str_num ); else num = strtol( str_num, NULL, 16 ); - return num; + return sanitize_numeric_character_reference( num ); }