00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032 #ifdef HAVE_CONFIG_H
00033 #include "autoconfig.h"
00034 #endif
00035
00036 #include "string_converter.h"
00037 #include "config_manager.h"
00038
00039 using namespace zmm;
00040
00041 StringConverter::StringConverter(String from, String to) : Object()
00042 {
00043 dirty = false;
00044
00045 cd = iconv_open(to.c_str(), from.c_str());
00046 if (cd == (iconv_t)(-1))
00047 {
00048 cd = (iconv_t)(0);
00049 throw _Exception(_("iconv: ") + strerror(errno));
00050 }
00051 }
00052
00053 StringConverter::~StringConverter()
00054 {
00055 if (cd != (iconv_t)(0))
00056 iconv_close(cd);
00057 }
00058
00059 zmm::String StringConverter::convert(String str, bool validate)
00060 {
00061 size_t stoppedAt = 0;
00062 String ret;
00063
00064 if (!string_ok(str))
00065 return str;
00066
00067 do
00068 {
00069 ret = ret + _convert(str, validate, &stoppedAt);
00070 if ((ret.length() > 0) && (stoppedAt == 0))
00071 break;
00072
00073 ret = ret + "?";
00074 if ((stoppedAt + 1) < (size_t)str.length())
00075 str = str.substring(stoppedAt+1);
00076 else
00077 break;
00078
00079 stoppedAt = 0;
00080 } while (true);
00081
00082 return ret;
00083 }
00084
00085 bool StringConverter::validate(String str)
00086 {
00087 try
00088 {
00089 _convert(str, true);
00090 return true;
00091 }
00092 catch (Exception e)
00093 {
00094 return false;
00095 }
00096 }
00097
00098 zmm::String StringConverter::_convert(String str, bool validate,
00099 size_t *stoppedAt)
00100 {
00101 String ret_str;
00102
00103 int buf_size = str.length() * 4;
00104
00105 char *input = str.c_str();
00106 char *output = (char *)MALLOC(buf_size);
00107 if (!output)
00108 {
00109 log_debug("Could not allocate memory for string conversion!\n");
00110 throw _Exception(_("Could not allocate memory for string conversion!"));
00111 }
00112
00113 char *input_copy = input;
00114 char *output_copy = output;
00115
00116 char **input_ptr = &input_copy;
00117 char **output_ptr = &output_copy;
00118
00119 size_t input_bytes = (size_t)str.length();
00120 size_t output_bytes = (size_t)buf_size;
00121
00122 int ret;
00123
00124
00125 if (dirty)
00126 {
00127 iconv(cd, NULL, 0, NULL, 0);
00128 dirty = false;
00129 }
00130
00131
00132
00133 #if defined(ICONV_CONST) || defined(SOLARIS)
00134 ret = iconv(cd, (const char**)input_ptr, &input_bytes,
00135 output_ptr, &output_bytes);
00136 #else
00137 ret = iconv(cd, input_ptr, &input_bytes,
00138 output_ptr, &output_bytes);
00139 #endif
00140
00141 if (ret == -1)
00142 {
00143 log_error("iconv: %s\n", strerror(errno));
00144 String err;
00145 switch (errno)
00146 {
00147 case EILSEQ:
00148 case EINVAL:
00149 if (errno == EILSEQ)
00150 log_error("iconv: %s could not be converted to new encoding: invalid character sequence!\n", str.c_str());
00151 else
00152 log_error("iconv: Incomplete multibyte sequence\n");
00153 if (validate)
00154 throw _Exception(err);
00155
00156 if (stoppedAt)
00157 *stoppedAt = (size_t)str.length()-input_bytes;
00158 ret_str = String(output, output_copy - output);
00159 dirty = true;
00160 *output_copy = 0;
00161 FREE(output);
00162 return ret_str;
00163 break;
00164 case E2BIG:
00166 err = _("iconv: Insufficient space in output buffer");
00167 break;
00168 default:
00169 err = _("iconv: ") + strerror(errno);
00170 break;
00171 }
00172 *output_copy = 0;
00173 log_error("%s\n", err.c_str());
00174
00175
00176 dirty = true;
00177 if (output)
00178 FREE(output);
00179 throw _Exception(err);
00180 }
00181
00182
00183
00184
00185
00186 ret_str = String(output, output_copy - output);
00187 FREE(output);
00188 if (stoppedAt)
00189 *stoppedAt = 0;
00190 return ret_str;
00191 }
00192
00194 Ref<StringConverter> StringConverter::i2f()
00195 {
00196 Ref<StringConverter> conv(new StringConverter(
00197 _(DEFAULT_INTERNAL_CHARSET), ConfigManager::getInstance()->getOption(CFG_IMPORT_FILESYSTEM_CHARSET)));
00198
00199 return conv;
00200 }
00201 Ref<StringConverter> StringConverter::f2i()
00202 {
00203 Ref<StringConverter> conv(new StringConverter(
00204 ConfigManager::getInstance()->getOption(CFG_IMPORT_FILESYSTEM_CHARSET), _(DEFAULT_INTERNAL_CHARSET)));
00205 return conv;
00206 }
00207 Ref<StringConverter> StringConverter::m2i()
00208 {
00209 Ref<StringConverter> conv(new StringConverter(
00210 ConfigManager::getInstance()->getOption(CFG_IMPORT_METADATA_CHARSET),
00211 _(DEFAULT_INTERNAL_CHARSET)));
00212 return conv;
00213 }
00214
00215 #ifdef HAVE_JS
00216 Ref<StringConverter> StringConverter::j2i()
00217 {
00218 Ref<StringConverter> conv(new StringConverter(
00219 ConfigManager::getInstance()->getOption(CFG_IMPORT_SCRIPTING_CHARSET),
00220 _(DEFAULT_INTERNAL_CHARSET)));
00221 return conv;
00222 }
00223
00224 Ref<StringConverter> StringConverter::p2i()
00225 {
00226 Ref<StringConverter> conv(new StringConverter(
00227 ConfigManager::getInstance()->getOption(CFG_IMPORT_PLAYLIST_CHARSET),
00228 _(DEFAULT_INTERNAL_CHARSET)));
00229 return conv;
00230 }
00231 #endif
00232
00233 #if defined (HAVE_JS) || defined(HAVE_TAGLIB) || defined(YOUTUBE) || defined(HAVE_LIBEXTRACTOR) || defined(HAVE_LIBMP4V2)
00234
00235 Ref<StringConverter> StringConverter::i2i()
00236 {
00237 Ref<StringConverter> conv(new StringConverter(_(DEFAULT_INTERNAL_CHARSET),
00238 _(DEFAULT_INTERNAL_CHARSET)));
00239 return conv;
00240 }
00241
00242 #endif