"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. For more information about "otherconv.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.8.2_vs_2_0_1.

    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