金庆的专栏

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  423 随笔 :: 0 文章 :: 454 评论 :: 0 Trackbacks
log4cxx中文输出错误补丁

(金庆的专栏)

已提交Bug:https://issues.apache.org/jira/browse/LOGCXX-399

log4cxx_0.10.0及主干代码,Windows下输出中文,发现有多余输出。

void main()
{
    setlocale(LC_ALL, "");
     LOG4CXX_INFO(pLog, "一二");  // log 2 chinese characters.
}

输出为:一二二。

错误在 MbstowcsCharsetDecoder::decode().

   size_t converted = mbsrtowcs(...
   if (converted == (size_t) -1) {
       ...
   } else {
       stat = append(out, buf);
       in.position(in.position() + converted);  // ERROR!
   }

mbsrtowcs()返回的是汉字的字数,而输入缓冲区in的position是按字节计数的,
对于汉字,position应该增加2*converted,而不是converted.
因为position少增加了一半,所以后半部分字符串会重复解码。

可如下更改:

   if (converted == (size_t) -1) {
       ...
   } else {
       stat = append(out, buf);
       // in.position(in.position() + converted);  // ERROR!
       if (src)
           in.position(src - in.data());
       else  // mbsrtowcs() set src to NULL.
           in.position(in.position() + strnlen(in.current(), in.remaining()));
   }

此处的in是个二进制块,其中可能会有0,而mbsrtowcs()的输入应该是0结尾的字符串。
碰到0时,mbsrtowcs()认为已经成功转换到串尾,并将src重设为NULL。
代码中已经有对0的处理。

有可能mbsrtowcs()会越过输入缓冲区的尾部一直读取,最多为256字节,仍有可能出现垃圾字符。
但是现在的std::string实现有0结尾,所有才没有出错。若要更正这个错误,就需要在输入缓冲区尾部添0。
posted on 2012-11-19 20:29 金庆 阅读(1444) 评论(3)  编辑 收藏 引用 所属分类: 1. C/C++

评论

# re: log4cxx中文输出错误补丁 2014-03-06 17:00 bigbad
很有帮助, 顶。

不过最后应该写为:
in.position(in.position() + strnlen(src, in.remaining()));

否则只转255个wchar_t

  回复  更多评论
  

# re: log4cxx中文输出错误补丁 2014-03-06 17:37 bigbad
汗, 上面错了。 最后更新position,应该这样写
if(src ==NULL)
{
in.position(in.limit());
}
else
{
in.position(in.position() + src - in.current());
}
  回复  更多评论
  

# re: log4cxx中文输出错误补丁 2014-05-13 21:15 金庆
@bigbad
src不为空时,position到新的src处,这2种计算相同:
in.position(in.position() + src - in.current());
in.position(src - in.data());

src为空时,2种计算不相同:
in.position(in.limit());
in.position(in.position() + strnlen(in.current(), in.remaining()));
当in中间有'\0'时,in.limit()会跳过剩余的输入串。

  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理