uniconv.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:14k
源码类别:

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 2002 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: uniconv.cpp,v 1.1 2002/11/22 14:57:06 tng Exp $
  58.  */
  59. #include <stdlib.h>
  60. #include <stdio.h>
  61. #include <string.h>
  62. #include <errno.h>
  63. #include <ctype.h>
  64. #include <cunhc.h>
  65. #include "ccsid.h"
  66. #include "uniconv.h"
  67. XERCES_CPP_NAMESPACE_BEGIN
  68. #define WORK_BUFFER_SIZE 16*1024
  69. #define DDA_NEEDED CUNBCPRM_DDA_REQ
  70. #define RETRY_THRESHOLD 10000
  71. // This is utility routine which strips '-', '_' and spaces from the name and
  72. // also upper cases the name. It also returns the length of the string.
  73. static int stripNameCopy(const char *s,char *d,int max)
  74. {
  75.    int si=0;
  76.    int di=0;
  77.    while ( (s[si] != '') && (di < max) ) {
  78.       if ( (s[si] == ' ') || (s[si] == '_') || (s[si] == '-') )
  79.          si++;
  80.       else {
  81.          d[di] = toupper(s[si]);
  82.          si++;di++;
  83.       }
  84.    }
  85.    d[di] = 0;
  86.    if (s[si] != '')
  87.       return -1;
  88.    return si;
  89. }
  90. // This takes a name and does a lookup into the ccsid table (from ccsid.h)
  91. // to find the corresponding ccsid. It also checks if the string ends in s390
  92. // and returns that information to the caller.
  93. // The lookup into the table is done via a binary search since we know that the
  94. // table was nicely sorted for us.
  95. static int getccsid(const char *s,int * is390)
  96. {
  97.    char tmpstr[_AE_MAX_CODESET_NAME_LENGTH];
  98.    int start;
  99.    int limit;
  100.    int index;
  101.    int result;
  102.    int thelen;
  103.    // Clean up the name....
  104.    if (s == NULL)
  105.       return -1;
  106.    if ((thelen = stripNameCopy(s,tmpstr,_AE_MAX_CODESET_NAME_LENGTH-1)) == -1)
  107.       return -1;
  108.    // Check for the S390 string in the name
  109.    *is390 = 0;
  110.    if ( (strstr((char *)tmpstr, "S390")) != NULL )
  111.       *is390 = 1;
  112.    // Now lookup the name via a binary search
  113.    start = 0;
  114.    limit = _AE_NUM_OF_CODESETS;
  115.    index = limit/2;
  116.    while ( ((result=strcoll(tmpstr, CCSID_MAPPING[index].NAME)) != 0) &&
  117.             (start < limit-1) ) {
  118.       if (result < 0)
  119.          limit = index;
  120.       else
  121.           start = index;
  122.       index = (start+limit)/2;
  123.    }
  124.    if (result != 0 && start >= limit-1)
  125.       return -1;
  126.    return CCSID_MAPPING[index].CCSID;
  127. }
  128. // **********************************************************************
  129. // These are the character conversion services
  130. // **********************************************************************
  131. // "Open" the conversion. Allocate memory to hold the handle which
  132. // unicode services requires. Call unicode services with a 0 length
  133. // so that it can initialize it's handle.
  134. // Note that unicode services must always be called in a loop since
  135. // it could be busy reloading its tables.
  136. uniconv_t uniconv_open(const char *destenc, const char *srcenc) {
  137.    CUNBCPRM  defparms = {CUNBCPRM_DEFAULT};
  138.    CUNBCPRM * tmpp;
  139.    void * handle_area;
  140.    char *cptr;
  141.    int srcis390;
  142.    int destis390;
  143.    errno = 0;
  144.    handle_area = malloc (sizeof(CUNBCPRM)+DDA_NEEDED+WORK_BUFFER_SIZE);
  145.    tmpp = (CUNBCPRM *) handle_area;
  146.    if (tmpp==NULL)
  147.       return (uniconv_t)-1;
  148.    // initialize the parm area with defaults, then start filling it
  149.    // in with our values.
  150.    memcpy(tmpp,&defparms,sizeof(defparms));
  151.    tmpp->Src_Buf_Len= 0;
  152.    // get the ccsids.
  153.    if ( ((tmpp->Src_CCSID=getccsid(srcenc,&srcis390)) == -1) ||
  154.         ((tmpp->Targ_CCSID=getccsid(destenc,&destis390)) == -1) ) {
  155.       errno=ENOENT;
  156.       free(handle_area);
  157.       return (uniconv_t)-1;
  158.    }
  159.    tmpp->Wrk_Buf_Ptr=(void*) (((unsigned int) handle_area) + sizeof(CUNBCPRM)+DDA_NEEDED);
  160.    tmpp->Wrk_Buf_Len=WORK_BUFFER_SIZE;
  161.    tmpp->DDA_Buf_Ptr=(void*) ((unsigned int) handle_area + sizeof(CUNBCPRM));
  162.    tmpp->DDA_Buf_Len=DDA_NEEDED;
  163.    // This flag tells the services to automatically refresh the handle if it
  164.    // becomes invalid.
  165.    tmpp->Flag1|=CUNBCPRM_REFRESH_AT_INV_HANDLE_START;
  166.    tmpp->Flag1|=CUNBCPRM_SUB_ACTION_SUBSTITUTE;
  167.    /* Determine which technique to use */
  168.    if ( (srcis390) || (destis390) )
  169.       // This technique causes it to swap LF and NL.
  170.       memcpy(tmpp->Technique,"L       ",8);
  171.    else
  172.       memcpy(tmpp->Technique,"        ",8);
  173.    // Retry if the services are busy reloading their tables.
  174.    int retry_count = 0;
  175.    while (retry_count < RETRY_THRESHOLD) {
  176.       CUNLCNV(tmpp);
  177.       if (tmpp->Return_Code == CUN_RC_OK)
  178.          break;
  179.       else if ( (tmpp->Return_Code == CUN_RC_WARN) &&
  180.                 ( (tmpp->Reason_Code == CUN_RS_NO_HANDLE) ||
  181.                   (tmpp->Reason_Code == CUN_RS_INV_HANDLE_NOSET) ||
  182.                   (tmpp->Reason_Code == CUN_RS_INV_HANDLE_SET) ) )
  183.          // Let it loop around again
  184.          retry_count++;
  185.       else
  186.          break;
  187.    }
  188.    if (tmpp->Return_Code != CUN_RC_OK) {
  189. // printf("uniconv_open() Error!!! rc=%d rs=%dn",tmpp->Return_Code,tmpp->Reason_Code);   // remove this after function test
  190.       free(handle_area);
  191.       errno=EINVAL;
  192.       handle_area = (uniconv_t)-1;
  193.    }
  194.    return handle_area;
  195. }
  196. // All that is required for close is to free the handle buffer.
  197. int uniconv_close(uniconv_t handle_area) {
  198.    errno = 0;
  199.    if (((int)handle_area) <= 0) {
  200.       errno=EBADF;
  201.       return -1;
  202.    }
  203.    free(handle_area);
  204.    return 0;
  205. }
  206. // This does the real conversion.
  207. // Note that unicode services must always be called in a loop since
  208. // it could be busy reloading its tables.
  209. int uniconv(uniconv_t cd, char **inbuf,  size_t *inbytesleft,
  210.                           char **outbuf, size_t *outbytesleft) {
  211.    CUNBCPRM * tmpp;
  212.    size_t startinlen = *inbytesleft;
  213.    size_t startoutlen = *outbytesleft;
  214.    errno = 0;
  215.    if (((int)cd) <= 0) {
  216.       errno=EBADF;
  217.       return -1;
  218.    }
  219.    // Fill in the parameter area with current values
  220.    tmpp = (CUNBCPRM *) cd;
  221.    tmpp->Src_Buf_Ptr = *inbuf;
  222.    tmpp->Src_Buf_Len = *inbytesleft;
  223.    tmpp->Targ_Buf_Ptr = *outbuf;
  224.    tmpp->Targ_Buf_Len = *outbytesleft;
  225.    // Retry if the services are busy reloading their tables.
  226.    int retry_count = 0;
  227.    while (retry_count < RETRY_THRESHOLD) {
  228.       CUNLCNV(tmpp);
  229.       if (tmpp->Return_Code == CUN_RC_OK)
  230.          break;
  231.       else if ( (tmpp->Return_Code == CUN_RC_WARN) &&
  232.                 ( (tmpp->Reason_Code == CUN_RS_NO_HANDLE) ||
  233.                   (tmpp->Reason_Code == CUN_RS_INV_HANDLE_NOSET) ||
  234.                   (tmpp->Reason_Code == CUN_RS_INV_HANDLE_SET) ) )
  235.          // Let it loop around again
  236.          retry_count++;
  237.       else
  238.          break;
  239.    }
  240.    *inbuf        = (char *)tmpp->Src_Buf_Ptr;
  241.    *inbytesleft  = tmpp->Src_Buf_Len;
  242.    *outbuf       = (char *)tmpp->Targ_Buf_Ptr;
  243.    *outbytesleft = tmpp->Targ_Buf_Len;
  244.    if (tmpp->Return_Code != CUN_RC_OK) {
  245.       if (tmpp->Reason_Code == CUN_RS_TRG_EXH)
  246.          errno=E2BIG;
  247.       else if (tmpp->Reason_Code == CUN_RS_MBC_INCOMPLETE)
  248.          errno=EINVAL;
  249.       else {
  250.  printf("uniconv() Error!!! rc=%d rs=%dn",tmpp->Return_Code,tmpp->Reason_Code); // remove after function test
  251.          errno=EBADF;
  252.          return -1;
  253.       }
  254.    }
  255.    return (startinlen-*inbytesleft);
  256. }
  257. // **********************************************************************
  258. // These are the case conversion services.
  259. // **********************************************************************
  260. // This "opens" the case conversion. It allocates the parameter area
  261. // then does a dummy call to unicode services so that it can set up
  262. // the handle.
  263. // Note that unicode services must always be called in a loop since
  264. // it could be busy reloading its tables.
  265. static inline uniconv_t uniconv_case_open(unsigned char direction) {
  266. CUNBAPRM  defparms = {CUNBAPRM_DEFAULT};
  267. CUNBAPRM * tmpp;
  268. void * handle_area;
  269.    errno = 0;
  270.    handle_area = malloc (sizeof(CUNBAPRM)+CUNBAPRM_DDA_REQ);
  271.    tmpp = (CUNBAPRM *) handle_area;
  272.    if (tmpp==NULL)
  273.       return (uniconv_t)-1;
  274.    // initialize the parm area with defaults, then start filling it
  275.    // in with our values.
  276.    memcpy(tmpp,&defparms,sizeof(defparms));
  277.    tmpp->DDA_Buf_Ptr=(void*) ((unsigned int) handle_area + sizeof(CUNBAPRM));
  278.    tmpp->DDA_Buf_Len=CUNBAPRM_DDA_REQ;
  279.    // This flag tells the services to automatically refresh the handle if it
  280.    // becomes invalid.
  281.    tmpp->Flag1|=CUNBAPRM_REFRESH_AT_INV_HANDLE_START;
  282.    unichar_t inchar = 0x61;
  283.    unichar_t outchar;
  284.    tmpp->Src_Buf_Ptr=&inchar;
  285.    tmpp->Targ_Buf_Ptr=&outchar;
  286.    tmpp->Targ_Buf_Len=sizeof(unichar_t);
  287.    tmpp->Src_Buf_Len=sizeof(unichar_t);
  288.    tmpp->Conv_Type=direction;
  289.    // Retry if the services are busy reloading their tables.
  290.    int retry_count = 0;
  291.    while (true) {
  292.       CUNLASE ( tmpp );
  293.       if (tmpp->Return_Code == CUN_RC_OK) {
  294.          break;
  295.       } else if ( (tmpp->Return_Code == CUN_RC_WARN) &&
  296.                   ( (tmpp->Reason_Code == CUN_RS_NO_HANDLE) ||
  297.                     (tmpp->Reason_Code == CUN_RS_INV_HANDLE_NOSET) ||
  298.                     (tmpp->Reason_Code == CUN_RS_INV_HANDLE_SET) ) ) {
  299.          // Let it loop around again
  300.          retry_count++;
  301.          if (retry_count > RETRY_THRESHOLD) {
  302.             errno = ENOSYS;
  303.             break;
  304.          }
  305.       } else {
  306. // printf("CUNLASE: Unicode Services is a Failure!n");
  307. // printf("CUNLASE rc=%d rs=%dn",tmpp->Return_Code,tmpp->Reason_Code);
  308.          errno = ENOSYS;
  309.          break;
  310.       }
  311.    }
  312.    if (tmpp->Return_Code != CUN_RC_OK) {
  313. // printf("uniconv_case_open() Error!!! rc=%d rs=%dn",tmpp->Return_Code,tmpp->Reason_Code); // remove after function test.
  314.       free(handle_area);
  315.       errno=EINVAL;
  316.       handle_area = (uniconv_t)-1;
  317.    }
  318.    return handle_area;
  319. }
  320. // These are the actual external interfaces for the open function
  321. uniconv_t uniconv_toupper_open() {
  322.    return uniconv_case_open(CUNBAPRM_TO_UPPER);
  323. }
  324. uniconv_t uniconv_tolower_open() {
  325.    return uniconv_case_open(CUNBAPRM_TO_LOWER);
  326. }
  327. // This closes the case conversion. All it does is free the handle buffer.
  328. int _uniconv_case_close(uniconv_t handle_area) {
  329.    errno = 0;
  330.    if (((int)handle_area) <= 0) {
  331.       errno=EBADF;
  332.       return -1;
  333.    }
  334.    free(handle_area);
  335.    return 0;
  336. }
  337. // This does the actual case conversion. The direction is already
  338. // stored in the handle buffer.
  339. // Note that unicode services must always be called in a loop since
  340. // it could be busy reloading its tables.
  341. unichar_t uniconv_caseit (uniconv_t cd,unichar_t inchar) {
  342.    unichar_t outchar;
  343.    CUNBAPRM * tmpp;
  344.    errno = 0;
  345.    if (((int)cd) <= 0) {
  346.       errno=EBADF;
  347.       return -1;
  348.    }
  349.    tmpp = (CUNBAPRM *) cd;
  350.    tmpp->Src_Buf_Ptr=&inchar;
  351.    tmpp->Targ_Buf_Ptr=&outchar;
  352.    tmpp->Targ_Buf_Len=sizeof(unichar_t);
  353.    tmpp->Src_Buf_Len=sizeof(unichar_t);
  354.    // Retry if the services are busy reloading their tables.
  355.    int retry_count = 0;
  356.    while (true) {
  357.       CUNLASE ( tmpp );
  358.       if (tmpp->Return_Code == CUN_RC_OK) {
  359.          break;
  360.       }
  361.       else if ( (tmpp->Return_Code == CUN_RC_WARN) &&
  362.                 ( (tmpp->Reason_Code == CUN_RS_NO_HANDLE) ||
  363.                   (tmpp->Reason_Code == CUN_RS_INV_HANDLE_NOSET) ||
  364.                   (tmpp->Reason_Code == CUN_RS_INV_HANDLE_SET) ) ) {
  365.          // Let it loop around again
  366.          retry_count++;
  367.          if (retry_count > RETRY_THRESHOLD) {
  368.             errno = ENOSYS;
  369.             break;
  370.          }
  371.       } else {
  372. // printf("CUNLASE: Unicode Services is a Failure!n");
  373. // printf("CUNLASE rc=%d rs=%dn",tmpp->Return_Code,tmpp->Reason_Code);
  374.          errno = ENOSYS;
  375.          break;
  376.       }
  377.    }
  378.    return outchar;
  379. }
  380. XERCES_CPP_NAMESPACE_END