Fixed bug in IConverter that saved end of string instead of beginning
[barry.git] / src / iconv.cc
blob714545114d89d205651d2936dfbe99c0cbf4933b
1 ///
2 /// \file iconv.cc
3 /// iconv wrapper class, and pluggable interface for records
4 ///
6 /*
7 Copyright (C) 2008, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "iconv.h"
23 #include "common.h"
24 #include "error.h"
25 #include <errno.h>
27 namespace Barry {
29 IConverter::IConverter(const char *tocode, bool throw_on_conv_err)
30 : m_throw_on_conv_err(throw_on_conv_err)
32 m_from = iconv_open(tocode, BLACKBERRY_CHARSET);
33 if( m_from == (iconv_t)(-1) ) {
34 throw ErrnoError("iconv_open failed (from)", errno);
37 m_to = iconv_open(BLACKBERRY_CHARSET, tocode);
38 if( m_to == (iconv_t)(-1) ) {
39 ErrnoError err("iconv_open failed (to)", errno);
40 iconv_close(m_from);
41 throw err;
45 IConverter::~IConverter()
47 iconv_close(m_from);
48 iconv_close(m_to);
51 std::string IConverter::Convert(iconv_t cd, const std::string &str) const
53 size_t target = str.size() * 2;
54 char *out = 0, *outstart = 0;
55 size_t outbytesleft = 0;
56 std::string ret;
58 // this loop is for the very odd case that the output string
59 // needs more than twice the input size
60 for( int tries = 0; ; tries++ ) {
62 const char *in = str.data();
63 size_t inbytesleft = str.size();
64 out = outstart = (char*) m_buffer.GetBuffer(target);
65 outbytesleft = m_buffer.GetBufSize();
67 iconv(cd, NULL, NULL, NULL, NULL); // reset cd's state
68 size_t status = iconv(cd, (char**)&in, &inbytesleft, &out, &outbytesleft);
70 if( status == (size_t)(-1) ) {
71 if( errno == E2BIG && tries < 2 ) {
72 target += inbytesleft * 2;
73 // try again with more memory...
74 continue;
77 // should never happen :-)
78 // but if it does, and we get here, check
79 // whether the user wants to be notified by
80 // exception... if not, just fall through and
81 // store as much converted data as possible
82 if( m_throw_on_conv_err ) {
83 throw ErrnoError("iconv failed", errno);
86 else {
87 // success
88 break;
92 // store any available converted data
93 ret.assign(outstart, out - outstart);
94 return ret;
97 std::string IConverter::FromBB(const std::string &str) const
99 return Convert(m_from, str);
102 std::string IConverter::ToBB(const std::string &str) const
104 return Convert(m_to, str);
107 } // namespace Barry