"Fossies" - the Fresh Open Source Software Archive

Member "jpilot-2_0_1/otherconv.c" (3 Apr 2021, 9129 Bytes) of package /linux/privat/jpilot-2_0_1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*******************************************************************************
    2  * otherconv.c
    3  * A module of J-Pilot http://jpilot.org
    4  *
    5  * Copyright (C) 2004 by Amit Aronovitch 
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; version 2 of the License.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License
   17  * along with this program; if not, write to the Free Software
   18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   19  ******************************************************************************/
   20 
   21 /*
   22  * General charset conversion library (using gconv)
   23  * Convert Palm  <-> Unix:
   24  * Palm : Any - according to the "other-pda-charset" setup option.
   25  * Unix : UTF-8
   26  */
   27 
   28 /********************************* Includes ***********************************/
   29 #include "config.h"
   30 #include <stdlib.h>
   31 #include <stdio.h>
   32 #include <string.h>
   33 #include <errno.h>
   34 #include <glib.h>
   35 
   36 #include "otherconv.h"
   37 #include "i18n.h"
   38 #include "prefs.h"
   39 #include "log.h"
   40 
   41 /********************************* Constants **********************************/
   42 #define HOST_CS "UTF-8"
   43 
   44 #define min(a,b) (((a) < (b)) ? (a) : (b))
   45 
   46 /* You can't do #ifndef __FUNCTION__ */
   47 #if !defined(__GNUC__) && !defined(__IBMC__)
   48 #define __FUNCTION__ ""
   49 #endif
   50 
   51 #define OC_FREE_ICONV(conv) oc_free_iconv(__FUNCTION__, conv,#conv)
   52 
   53 /* #define OTHERCONV_DEBUG */
   54 
   55 /******************************* Global vars **********************************/
   56 static GIConv glob_topda = NULL;
   57 static GIConv glob_frompda = NULL;
   58 
   59 /****************************** Main Code *************************************/
   60 /*
   61  * strnlen is not ANSI.
   62  * To avoid conflicting declarations, it is reimplemented as a thin
   63  * inline function over the library function strlen
   64  */
   65 static inline size_t oc_strnlen(const char *s, size_t maxlen) 
   66 {
   67    return min(strlen(s), maxlen); 
   68 }
   69 
   70 static void oc_free_iconv(const char *funcname, GIConv conv, char *convname) 
   71 {
   72    if (conv != NULL) {
   73       if (g_iconv_close(conv) != 0) {
   74          jp_logf(JP_LOG_WARN, _("%s: error exit from g_iconv_close(%s)\n"),
   75             funcname,convname);
   76       }
   77    }
   78 }
   79 
   80 /*
   81  * Convert char_set integer code to iconv charset text string
   82  */
   83 static const char *char_set_to_text(int char_set)
   84 {
   85    switch (char_set) {
   86     case CHAR_SET_1250_UTF:
   87       return "CP1250";
   88 
   89     case CHAR_SET_1253_UTF:
   90       return "CP1253";
   91 
   92     case CHAR_SET_ISO8859_2_UTF:
   93       return "ISO8859-2";
   94 
   95     case CHAR_SET_KOI8_R_UTF:
   96       return "KOI8-R";
   97 
   98     case CHAR_SET_1251_UTF:
   99       return "CP1251";
  100 
  101     case CHAR_SET_GBK_UTF:
  102       return "GBK";
  103 
  104     case CHAR_SET_BIG5_UTF:
  105       return "BIG-5";
  106 
  107     case CHAR_SET_SJIS_UTF:
  108       return "SJIS";
  109 
  110     case CHAR_SET_1255_UTF:
  111       return "CP1255";
  112 
  113     case CHAR_SET_949_UTF:
  114       return "CP949";
  115 
  116     case CHAR_SET_1252_UTF:
  117     default:
  118       return "CP1252";
  119    }
  120 }
  121 
  122 /*
  123  * Module initialization function
  124  *  Call this before any conversion routine.
  125  *  Can also be used if you want to reread the 'charset' option
  126  *
  127  * Returns 0 if OK, -1 if iconv could not be initialized
  128  *  (probably because of bad charset string)
  129  */
  130 int otherconv_init(void) 
  131 {
  132    long char_set;
  133  
  134    get_pref(PREF_CHAR_SET, &char_set, NULL);
  135  
  136    /* (re)open the "to" iconv */
  137    OC_FREE_ICONV(glob_topda);
  138    glob_topda = g_iconv_open(char_set_to_text(char_set), HOST_CS);
  139    if (glob_topda == (GIConv)(-1))
  140       return EXIT_FAILURE;
  141  
  142    /* (re)open the "from" iconv */
  143    OC_FREE_ICONV(glob_frompda);
  144    glob_frompda = g_iconv_open(HOST_CS, char_set_to_text(char_set));
  145    if (glob_frompda == (GIConv)(-1)) {
  146       OC_FREE_ICONV(glob_topda);
  147       return EXIT_FAILURE;
  148    }
  149    return EXIT_SUCCESS;
  150 }
  151 
  152 /*
  153  * Module finalization function
  154  * closes the iconvs
  155  */
  156 void otherconv_free(void) 
  157 {
  158    OC_FREE_ICONV(glob_topda);
  159    OC_FREE_ICONV(glob_frompda);
  160 }
  161 
  162 /*
  163  *           Conversion to UTF using g_convert_with_iconv
  164  *     A new buffer is now allocated and the old one remains unchanged
  165  */
  166 char *other_to_UTF(const char *buf, int buf_len)
  167 {
  168    char *outbuf;
  169    gsize bytes_read;
  170    GError *err = NULL;
  171    size_t str_len;
  172  
  173 #ifdef OTHERCONV_DEBUG
  174    jp_logf(JP_LOG_DEBUG, "%s:%s reset iconv state...\n", __FILE__, __FUNCTION__);
  175 #endif
  176    g_iconv(glob_frompda, NULL, NULL, NULL, NULL);
  177 #ifdef OTHERCONV_DEBUG
  178    jp_logf(JP_LOG_DEBUG, "%s:%s converting   [%s]\n", __FILE__, __FUNCTION__, buf);
  179 #endif
  180  
  181    if (buf_len == -1) {
  182       str_len = -1;
  183    } else {
  184       str_len = oc_strnlen(buf, buf_len-1);  // -1 leaves room for \0 terminator
  185    }
  186  
  187    outbuf = (char *)g_convert_with_iconv((gchar *)buf,
  188             str_len, glob_frompda, &bytes_read, NULL, &err);
  189  
  190    if (err != NULL) {
  191       char c;
  192       char *head, *tail;
  193       int  outbuf_len;
  194       char *tmp_buf = (char *)buf;
  195       static int call_depth = 0;
  196       printf("ERROR HAPPENED\n");
  197       if (0 == call_depth)
  198          jp_logf(JP_LOG_WARN, _("%s:%s g_convert_with_iconv error: %s, buff: %s\n"),
  199                               __FILE__, __FUNCTION__, 
  200                               err ? err->message : _("last char truncated"),
  201                               buf);
  202       if (err != NULL)
  203          g_error_free(err);
  204       else
  205          g_free(outbuf);
  206  
  207       if (buf_len == -1) {
  208          buf_len = strlen(buf); 
  209       }
  210  
  211       /* convert the head, skip the problematic char, convert the tail */
  212       c = tmp_buf[bytes_read];
  213       tmp_buf[bytes_read] = '\0';
  214       head = g_convert_with_iconv(tmp_buf, 
  215                                   oc_strnlen(tmp_buf, buf_len),
  216                                   glob_frompda, 
  217                                   &bytes_read, 
  218                                   NULL, NULL);
  219       tmp_buf[bytes_read] = c;
  220  
  221       call_depth++;
  222       tail = other_to_UTF(tmp_buf + bytes_read +1, buf_len - bytes_read - 1);
  223       call_depth--;
  224  
  225       outbuf_len = strlen(head) +4 + strlen(tail)+1;
  226       outbuf = g_malloc(outbuf_len);
  227       g_snprintf(outbuf, outbuf_len, "%s\\%02X%s", head, (unsigned char)c, tail);
  228  
  229       g_free(head);
  230       g_free(tail);
  231    }
  232  
  233 #ifdef OTHERCONV_DEBUG
  234    jp_logf(JP_LOG_DEBUG, "%s:%s converted to [%s]\n", __FILE__, __FUNCTION__, outbuf);
  235 #endif
  236    /*
  237     * Note: outbuf was allocated by glib, so should be freed with g_free
  238     * To be 100% safe, I should have done strncpy to a new malloc-allocated 
  239     * string. (at least under an 'if (!g_mem_is_system_malloc())' test)
  240     *
  241     * However, unless you replace the default GMemVTable, freeing with C free
  242     * should be fine so I decided this is not worth the overhead.
  243     * -- Amit Aronovitch
  244     */
  245    return outbuf;
  246 }
  247 
  248 /*
  249  *           Conversion to pda encoding using g_iconv
  250  */
  251 void UTF_to_other(char *const buf, int buf_len)
  252 {
  253    gsize inleft,outleft;
  254    gchar *inptr, *outptr;
  255    size_t rc;
  256    char *errstr = NULL;
  257    char buf_out[1000];
  258    char *buf_out_ptr = NULL;
  259    int failed = FALSE;
  260 
  261 #ifdef OTHERCONV_DEBUG
  262    jp_logf(JP_LOG_DEBUG, "%s:%s reset iconv state...\n", __FILE__, __FUNCTION__);
  263 #endif
  264    rc = g_iconv(glob_topda, NULL, NULL, NULL, NULL);
  265 #ifdef OTHERCONV_DEBUG
  266    jp_logf(JP_LOG_DEBUG, "%s:%s converting   [%s]\n", __FILE__, __FUNCTION__, buf);
  267 #endif
  268 
  269    inleft = oc_strnlen(buf, buf_len);
  270    outleft = buf_len-1;
  271    inptr = buf;
  272 
  273   /* Most strings can be converted without recourse to malloc */
  274    if (buf_len > sizeof(buf_out)) {
  275       buf_out_ptr = malloc(buf_len);
  276       if (NULL == buf_out_ptr) {
  277          jp_logf(JP_LOG_WARN, _("UTF_to_other: %s\n"), _("Out of memory"));
  278          return;
  279       }
  280       outptr = buf_out_ptr;
  281    } else {
  282       outptr = buf_out;
  283    }
  284 
  285    rc = g_iconv(glob_topda, &inptr, &inleft, &outptr, &outleft);
  286    *outptr = 0; /* NULL terminate whatever fraction was converted */
  287  
  288    if ((size_t)(-1) == rc) {
  289       switch (errno) {
  290        case EILSEQ:
  291          errstr = _("iconv: unconvertible sequence at place %d in \'%s\'\n");
  292          failed = TRUE;
  293          break;
  294        case EINVAL:
  295          errstr = _("iconv: incomplete UTF-8 sequence at place %d in \'%s\'\n");
  296          break;
  297        case E2BIG:
  298          errstr = _("iconv: buffer filled. stopped at place %d in \'%s\'\n");
  299         break;
  300        default:
  301          errstr = _("iconv: unexpected error at place %d in \'%s\'\n");
  302       }
  303    }
  304 
  305    if (buf_out_ptr) {
  306       g_strlcpy(buf, buf_out_ptr, buf_len);
  307       free(buf_out_ptr);
  308    } else {
  309       g_strlcpy(buf, buf_out, buf_len);
  310    }
  311 
  312    if ((size_t)(-1) == rc)
  313       jp_logf(JP_LOG_WARN, errstr, inptr - buf, buf);
  314 
  315    if (failed)
  316    {
  317       /* convert the end of the string */
  318       int l = inptr - buf;
  319 
  320       buf[l] = '?';
  321       UTF_to_other(inptr+1, buf_len-l-1);
  322       memmove(buf+l+1, inptr+1, buf_len-l-1);
  323    }
  324 
  325 #ifdef OTHERCONV_DEBUG
  326    jp_logf(JP_LOG_DEBUG, "%s:%s converted to [%s]\n", __FILE__, __FUNCTION__, buf);
  327 #endif
  328 }
  329