Skip to content
Wireshark Wiki 中文翻译整理专题首页原始页面

平台字符串编码

Wireshark 所使用的系统和 C 语言 API 提供或接收的文件名、命令行参数、环境变量以及其他字符串可能使用的各种字符编码会相当令人困惑;请参见 “Character Encodings”,了解这些字符串中可能使用的编码。

UN*X

在 UN*X 系统(Linux、macOS、BSD 系统、Solaris 等)中,Wireshark 当前假定所有此类字符串都以 UTF-8 编码,并且 locale 使用 UTF-8 作为其编码;所有 Wireshark 程序都会在 main routine 早期通过调用 setlocale(LC_ALL, ""),将 C 语言 locale 初始化为默认值。

我目前不知道在所有(尤其是较旧的)*nix 版本上编码转换是否都被正确完成。- UlfLamping

Windows

在 Windows 中,大多数系统和 C 语言 API 都有两个变体,其中一个接受或提供当前 “ANSI code page” 中的字符串,另一个接受或提供 UTF-16 编码的 Unicode 字符串。Wireshark 会尽可能尝试使用 UTF-16 变体,并通过 wrapper routines 在 Wireshark 内部使用的 UTF-8 字符串与 API 中使用的 UTF-16 字符串之间进行转换,从而完整支持 Unicode。

C 语言 locale

所有 Wireshark 程序都会在 main routine 早期通过调用 setlocale(LC_ALL, ".UTF-8"),将 C 语言 locale 初始化为使用 UTF-8。请参见 Microsoft 文档中 Visual C 的 setlocale() routine 的 “UTF-8 Support” 部分。这会使 C runtime support 中所有 routines 的 “ANSI code page” 版本接受并提供以 UTF-8 编码的字符串。

该更改最初是为了修复 bug 16649。

我们不会把 “ANSI code page” 改为 UTF-8(code page 65001),因为这会导致更多 /? 在 Windows 7 上失败;UTF-8 code page 在较旧版本的 Windows 上支持得不好。较新版本的 Windows 10 中的支持相较早期 Windows 版本有所改进。

程序参数

对于命令行程序,main() 函数会接收当前 “ANSI code page” 中的参数字符串,这意味着,如果当前 “ANSI code page” 不是 UTF-8 code page:

  • argv[] 值不是 UTF-8,必须转换为 UTF-8 才能在 Wireshark 内部使用;
  • 并非所有 Unicode 字符串都能表示为 argv[] 值,因此,例如,无法用当前 “ANSI code page” 表示的文件名不能作为参数提供给这些程序。

将 C 语言 locale 改为使用 UTF-8 并不会把 argv[] 值改为 UTF-8,因此我们必须自己进行转换。这通过以下方式完成:

  • 让包含 main() 函数的源文件 include “cli_main.h”,它会将 main 重新定义为 real_main,因此该源文件定义一个名为 real_main() 的函数,其代码就是 main function code;
  • 将程序与 cli_main.c 链接,cli_main.c 定义了一个 wmain() 函数,该函数接收 UTF-16 中的参数字符串,将它们全部转换为 UTF-8,并将参数数量和参数列表数组传递给 real_main();

这样 main function 就会收到 UTF-8 参数字符串。

对于 GUI 程序,我们使用 Qt。Qt 定义了一个 WinMain() 函数,它是 Windows 上 GUI 程序的 main function,并接收一个当前 “ANSI code page” 中的单个字符串,其中包含命令行参数,形式是一个包含命令行的单个字符串。Qt 的 WinMain() 调用 GetCommandLineW() 获取命令行字符串的 UTF-16 版本,将其传递给 CommandLineToArgvW(),将其解析为 argv[] 风格的 UTF-16 字符串列表,把这些字符串转换为当前 “ANSI code page”,并将参数数量和这些字符串数组传递给 main()。这意味着,诸如 Wireshark 这样的 GUI 程序的 main function 会遇到与诸如 TShark 这样的命令行程序中的 main() 函数相同的问题。

处理方式是让 Wireshark main() 函数调用 GetCommandLineW() 获取参数字符串,将其传递给 CommandLineToArgvW(),将其解析为 argv[] 风格的 UTF-16 字符串列表,把这些字符串转换为 UTF-8,并使用该数组作为参数字符串数组。

环境变量

值中可能包含非 ASCII 字符的环境变量应使用 g_getenv() 而不是 getenv() 获取,因为 g_getenv() 在 Windows 上会获取环境变量的 UTF-16 值并将其转换为 UTF-8。

(注意:既然我们正在将 C-library locale 设置为使用 UTF-8,这可能不再必要。)

文件访问

C library 的 _open()、fopen()、_stat() 等 routines 期望 pathnames 使用当前 “ANSI code page”。为了处理 UTF-8 pathnames,我们有诸如 ws_open()、ws_fopen()、ws_stat64() 等 wrappers,它们会将 pathnames 从 UTF-8 转换为 UTF-16,并调用 C library routines 的 “wide character” 版本。

(注意:既然我们正在将 C-library locale 设置为使用 UTF-8,这可能不再必要。)

Imported from https://wiki.wireshark.org/Development/FilenameEncoding on 2020-08-11 23:12:48 UTC

相关 Wireshark Wiki 页面

网络分析技术档案