在Windows的控制台界面下输出BMPString的内容

在解析X.509格式的数字证书时,有时候从证书中提取出的 commonName、countryName 等项的值类型是 BMPString,特别当这些值是中文的时候。此时如果在 Windows 的控制台下使用使用 wprintf() 输出这些值,显示的结果是乱码。

为了搞清楚产生乱码的原因,找到一张证书,查看其中的 countryName,对应的 ASN.1 编码类型是BMPString,编码是:0x1E, 0x4, 0x4E, 0x2D, 0x56, 0xFD,对应值为“中国”。在网上查询了”中国“对应的 Unicode 编码是 {0x4E, 0x2D, 0x56, 0xFD},0x4E, 0x2D 对应字符“中”,0x56, 0xFD 对应字符“国” 。将字符 0x4E, 0x2D, 0x56, 0xFD 顺序放入一个字符数组,依次调用 setlocale() 、wprintf()
函数,输出为乱码。

在网上查了一下,对于BMPString 的 ASN.1 编码,其负载部分采用 Unicode 编码中的 UTF-16 编码方式,一个字符的编码占两个字节。但是这两个字节中哪一个用来存放编码的高 8 位、哪一个用来存放编码的低 8 位,在不同的地方有不同处理方式。在 ASN.1 编码中,一般对于负载部分的编码都采用 big-endian 顺序,所以从数字证书中提取出来的“中国”对应的编码为 {0x4E, 0x2D, 0x56, 0xFD},其顺序是 Big-endian 顺序。在 Intel
的 CPU 上通常使用 little-endian 字节顺序,Windows 中处理数据也采用 little-endian 顺序,所以在 Windows 中试图输出Big-endian 顺序编码的字符,当然会产生乱码。(顺便说一句,对于 UniversalString 的ASN.1 编码,其负载部分采用Unicode 编码中的 UTF-32 编码方式,一个字符的编码占四个字节。)

要解决输出乱码的问题,方法是在输出前,先将 Big-endian 顺序编码的字符转换为 little-endian 顺序编码的字符,然后再输出,就不会产生乱码了。下面给出一个示例程序:

/**************************************************
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: Oct 30th, 2014
* Description: demonstrate how to print BMPString
  on Windows console
**************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>

/**************************************************
*函数名称:InterchangeEndianOrder
*功能: 颠倒 BMPString 编码中每一个 UTF-16字符 的 endian 顺序
*参数:
    BMPString     [in]
    BMPString_len [in]   BMPString 的长度,以字节为单位
*返回值:
    0   成功
	-1  失败
*备注:
  BMPString 通常由 UTF-16 字符组成,UTF-16 字符有时采用 big-endian 顺序,
  有时采用 little-endian 顺序,本函数的功能是颠倒 endian 顺序
**************************************************/
int InterchangeEndianOrder(unsigned char *BMPString, unsigned int BMPString_len)
{
  int i;
  unsigned char *p, temp;

  if ( (BMPString_len % 2) != 0 )
  {
#ifdef _DEBUG
	printf("Invalid BMPString byte length: %d.\n", BMPString_len);
	printf("BMPString byte length must be multiple of 2!\n");
#endif
	return (-1);
  }

  p = BMPString;
  for (i=0; i < (int)( BMPString_len/2); i++)
  {
	temp=*p;
	*p=*(p+1);
	*(p+1)=temp;
	p+=2;
  }
  return 0;
}

/**************************************************
*函数名称:PrintBMPString
*功能: 在 Windows 控制台界面下输出 BMPString
*参数:
    BMPString     [in]
    BMPString_len [in]   BMPString 的长度,以字节为单位
*返回值:
    0   成功
	-1  失败
**************************************************/
int PrintBMPString(unsigned char *BMPString, unsigned int BMPString_len)
{
  unsigned char *buffer;
  unsigned int buffer_len;

  buffer_len = BMPString_len +2; /* 缓冲区大小比 BMPString 的字节长度多出两个字节,
                                    这两个字节用来存放 UTF-16 编码的字符串结束符 \0,
                                    其对应编码是 0x0, 0x0 */
  if ( !(buffer=(unsigned char *)malloc(buffer_len)) )
  {
#ifdef _DEBUG
	printf("malloc() function failed!\n");
#endif
	return (-1);
  }
  memset(buffer, 0, buffer_len);
  memcpy(buffer, BMPString, BMPString_len);
  setlocale(LC_ALL, "chs");
  InterchangeEndianOrder(buffer, BMPString_len);
  wprintf(L"BMPString: %ls\n", (wchar_t *)buffer);

  free(buffer);
  return 0;
}

int main(void)
{
  int error_code;
  unsigned char BMPString_data1[]={0x4e, 0x2d, 0x56, 0xfd};  /* 中文字符串"中国"对应的 Unicode 编码 */
  unsigned char BMPString_data2[]={0x0, 0x55, 0x0, 0x73, 0x0, 0x65, 0x0, 0x72};  /* 英文字符串"User"对应的 Unicode 编码 */
  wchar_t str[]=L"中国";
  unsigned char *p;
  int i;

  if ( error_code = PrintBMPString(BMPString_data1, sizeof(BMPString_data1)) )
  {
	printf("Print BMPstring on Windows console failed!\n");
	return (-1);
  }
  if ( error_code = PrintBMPString(BMPString_data2, sizeof(BMPString_data2)) )
  {
	printf("Print BMPstring on Windows console failed!\n");
	return (-1);
  }

/* 下面给出了说明 unicode 编码的字符在 Windows 中是如何存放的一个例子,
   从显示结果可以看出每一个 UTF-16 字符都是以 little-endian 顺序存放 */
  printf("\n");
  setlocale(LC_ALL, "chs");
  wprintf(L"%ls\n", (wchar_t *)str);
  p=(unsigned char *)str;
  printf("Wide character length is: %d\n", wcslen(str));
  printf("Unicode encode on Windows platform: ");
  for (i=0; i < (int)(wcslen(str)*2); i++)
  {
	printf("0x%x  ", *p);
	p++;
  }
  printf("\n");

  system("pause");
  return 0;
}

输出结果如下图:

时间: 2024-10-08 22:26:07

在Windows的控制台界面下输出BMPString的内容的相关文章

在Linux的终端中显示BMPString的内容

在上一篇博文中,介绍了怎样在 Windows 的控制台界面下输出 BMPString 的内容,可是那里的方法在 Linux 下不适用.假设将那里的演示样例代码放到 Linux 下运行.输出的结果为乱码.产生乱码的原因在于 wchar_t 类型的变量在 Windows 下和 Linux 下的字节长度不同. 下面 C 程序在 Windows 和 Linux 下都可以运行: #include <stdio.h> #include <wchar.h> #if defined(_WIN32)

windows API之控制台界面

windows API之控制台界面 tkorays ([email protected]) 在windows里面,用户界面包括控制台(Console)形式的和窗口(Window)形式的.控制台形式的界面我们也是经常接触的,不就是那个黑色的框框吗?但是我们并没有直接使用Windows API,通常我们调用printf来输出.scanf来输入.实际上,这个c语言函数也是通过Windows API来实现的.不信的话,可以打开crtdll.dll查看里面的字符串. 关于Console的API不是很多,主

双缓冲解决控制台应用程序输出“闪屏”(C/C++,Windows)

使用 C 语言编写游戏的小伙伴们想必起初都要遇到这样的问题,在不断清屏输出数据的过程中,控制台中的输出内容会不断地闪屏.出现这个问题的原因是程序对数据处理花掉的时间影响到了数据显示,或许你可以使用局部覆盖更新方法(减少更新数据量)来缓解闪屏,但是这种方法并不适用于所有场合,尤其是更新数据本身就非常大的场合. 本文将讲述解决控制台应用程序输出闪屏的终级解决方法——双缓冲. 问题呈现 下面的代码演示了在高速不断清屏输出数据的过程的闪屏问题,特邀您一试: 1 2 3 4 5 6 7 8 9 10 11

终于解决了用JAVA写窗口程序在不同的windows界面下的显示保持一致。

好像是两三年前的时候发现这个问题. 由于在windows经典界面与windows xp界面下,窗口的标题栏的高度是不一样的. 所以我们在用Java写GUI程序的时候,会遇到一个问题. 当我把一个JFrame显式的设为setSize(300,200);并且这个Container的Layout是null的时候,在windows经典界面和windows xp界面显示的时候是有差别的.因为windows xp界面下的标题栏比windows经典界面下的标题栏高了7个象素. 今天我终于找到了一个办法,可以不

Windows和Linux环境下Memcached安装与配置(转)

一.memcached安装配置 windows平台安装 1.memcached-1.2.6-win32-bin.zip下载地址: http://code.jellycan.com/memcached/,执行memcached.exe -d install 安装. 2.守护进程方式启动:memcached.exe -m 512 -d start-d为守护进程启动,不能指定端口 默认端口11211-m为指定内存大小 3.指定端口启动:memcached.exe –p 33000 -m 512可以启动

windows visual studio 2012下MPI并行环境搭建

因为课程作业的缘故需要编写并行计算的程序,准备写一下MPI程序,MPI的全称是Message Passing Interface即标准消息传递界面,可以用于并行计算.MPI的具体实现一般采用MPICH.下面介绍如何在Windows 8系统下visual studio 2012中搭建MPI环境来编写MPI程序. 安装MPI实现库 MPICH官网上给出了windows下的下载地址.可以看出链接到了微软的官网,根据我的版本下载并安装了HPC Pack 2012 SDK.然而在网上查找资料发现都是关于M

Linux终端和win32控制台文本颜色输出

在使用putty.secureCRT.XShell等终端仿真器连接linux系统时,ls.vim等工具的输出都含有各种颜色,这些颜色的输出大大地增强了文本的可读性. 通常我们可以使用echo命令加-e选项输出各种颜色的文本,例如:echo -e "\033[31mRed Text\033[0m",可以输出红色的字体“Red Text”.其中:"\033[31m"和"\033[0m"是ANSI转义序列(ANSI escape code/sequen

HoloLens开发手记 - 使用Windows设备控制台 Using Windows Device Portal

Windows设备控制台允许你通过Wi-Fi或USB来远程控制你的HoloLens设备.设备控制台是HoloLens上的一个Web Server,你可以通过PC的浏览器来连接到它.设备控制台包含了很多帮助你管理.调试和优化HoloLens设备的工具. 设置HoloLens以使用Windows设备控制台 Setting up HoloLens to use Windows Device Portal 打开HoloLens,并穿戴上 使用绽开手势打开开始菜单 选中设置应用,在你放置它以后会自动启动

在DOS界面下快速进入目录的技巧

在DOS界面如果想进入某一目录还是比较困难的,尤其是有长目录名和中文目录名的时候. 比如:要进入“D:/工具箱/杀毒软件”这个目录. 1.在Windows下进入这个目录. 2.在地址栏输入 C:/WINDOWS/system32/cmd.exe ,回车就直接进入DOS界面相应的目录了. 技巧:在地址栏输入路径其实也有一个小技巧,Windows可以将当前目录下的文件夹和文件列出来,只要输入前面几位字母就可以方便的选择啦 :-)