home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libi18n / autocvt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  10.4 KB  |  337 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*    autodetect.c    */
  19.  
  20. /*
  21.  * CODESET    1st Byte        2nd Byte    3rd Byte
  22.  * JIS        0x21-0x7E        0x21-0x7E    n/a
  23.  * SJIS        0xA1-0xDF        n/a            n/a
  24.  *            0x81-0x9F        0x40-0xFC    n/a
  25.  *            0xE0-0xEF        0x40-0xFC    n/a
  26.  * EUCJP    0x8E (SS2)        0xA1-0xDF    n/a
  27.  *            0xA1-0xFE        0xA1-0xFE    n/a
  28.  *            0x8F (SS3)        0xA1-0xFE    0xA1-0xFE
  29.  * Invalid    7F,80,A0,FF
  30.  */
  31.             
  32. #include "intlpriv.h"
  33.  
  34. #define ALLOW_NBSP 1
  35.  
  36. /*
  37.  *      JIS X 0201-Roman            ESC ( J
  38.  *      Half-width Katakana         ESC ( I
  39.  *      JIS X 0208-1978             ESC $ @
  40.  *      JIS X 0208-1983             ESC $ B
  41.  *      JIS X 0212-1990             ESC $ ( D
  42.  */
  43. #define IsJISEscSeq(cp, len)                                                \
  44.     ((cp[0] == ESC) && ((len) > 2) && (                                        \
  45.         ((cp[1] == '$') && (cp[2] == 'B')) ||                                \
  46.         ((cp[1] == '$') && (cp[2] == '@')) ||                                \
  47.         ((cp[1] == '(') && (cp[2] == 'J')) ||                                \
  48.         ((cp[1] == '(') && (cp[2] == 'I')) ||                                \
  49.         (((len) > 3) && (cp[1] == '$') && (cp[2] == '(') && (cp[3] == 'D')) ) )
  50.  
  51. #define IsRoman(c)            ((c) < 0x80)
  52. #define IsSJIS2ndByte(c)    (((c) > 0x3F) && ((c) < 0xFD))
  53. #define IsLoSJIS2ndByte(c)    (((c) > 0x3F) && ((c) < 0xA1))
  54. #define IsHiSJIS2ndByte(c)    (((c) > 0xA0) && ((c) < 0xFD))
  55. #define IsEUCJPKana(b1)        (((b1) > 0xA0) && ((b1) < 0xE0))
  56. #define IsEUCJPKanji(b1or2)    (((b1or2) > 0xA0) && ((b1or2) < 0xFF))
  57.  
  58. #define    YES        1
  59. #define NO        0
  60. #define    MAYBE    -1
  61.  
  62. PRIVATE int
  63. isSJIS(const unsigned char *cp, int32 len)
  64. {
  65.     while (len) {
  66.         if (IsRoman(*cp)) {
  67.             cp++, len--;
  68.         } else if (*cp == 0x80) {        /* illegal SJIS 1st byte            */
  69.             return NO;
  70.         } else if ((*cp < 0xA0)) {        /* byte 1 of 2byte SJIS 1st range    */
  71.             if (len > 1) {
  72.                 if (IsSJIS2ndByte(cp[1])) {
  73.                     if ((*cp != 0x8E && *cp != 0x8F) || (*(cp+1) <= 0xA0))
  74.                         return YES;
  75.                     cp += 2, len -= 2;    /* valid 2 byte SJIS                */
  76.                 } else {
  77.                     return NO;            /* invalid SJIS    2nd byte            */
  78.                 }
  79.             } else
  80.                 break;                        /* buffer ended w/1of2 byte SJIS */
  81.         } else if (*cp == 0xA0) {            /* illegal EUCJP byte        */
  82. #if ALLOW_NBSP
  83.             cp++, len--; /* allow nbsp */
  84. #endif
  85.         } else if (*cp < 0xE0) {        /* SJIS half-width kana                */
  86.             cp++, len--;
  87.         } else if (*cp < 0xF0) {        /* byte 1 of 2byte SJIS     2nd range    */
  88.             if (len > 1) {
  89.                 if (IsSJIS2ndByte(cp[1])) {
  90.                     cp += 2, len -= 2;    /* valid 2 byte SJIS                */
  91.                 } else {
  92.                     return NO;            /* invalid SJIS                        */
  93.                 }
  94.             } else
  95.                 break;                    /* buffer ended w/1of2 byte SJIS    */
  96.         } else {
  97.             return NO;                    /* invalid SJIS 1st byte            */
  98.         }
  99.     }
  100.     return MAYBE;                        /* No illegal SJIS values found        */
  101. }
  102.  
  103. PRIVATE int
  104. isEUCJP(const unsigned char *cp, int32 len)
  105. {
  106.     while (len) {
  107.         if (IsRoman(*cp)) {            /* Roman                        */
  108.             cp++, len--;
  109.         } else if (*cp == SS2) {        /* EUCJP JIS201 half-width kana */
  110.             if (len > 1) {
  111.                 if (IsEUCJPKana(cp[1]))
  112.                     cp += 2, len -= 2;        /* valid half-width kana */
  113.                 else
  114.                     return NO;                /* invalid 2of3 byte EUC */ 
  115.             } else
  116.                 break;                        /* buffer ended w/1of2 byte EUC    */
  117.         } else if (*cp == SS3) {            /* EUCJP JIS212                    */
  118.              if (len > 1) {
  119.                  if (IsEUCJPKanji(cp[1])) {
  120.                      if (len > 2) {
  121.                          if (IsEUCJPKanji(cp[2]))
  122.                             cp += 2, len -= 2;    /* valid 3 byte EUCJP        */
  123.                         else
  124.                             return NO;        /* invalid 3of3 byte EUCJP    */
  125.                     } else
  126.                         break;                /* buffer ended w/2of3 byte EUCJP */
  127.                 } else
  128.                     return NO;                /* invalid 2of3 byte EUCJP    */
  129.             } else
  130.                 break;                        /* buffer ended w/1of3 byte EUCJP */
  131.         } else if (*cp == 0xA0) {            /* illegal EUCJP byte        */
  132. #if ALLOW_NBSP
  133.             cp++, len--; /* allow nbsp */
  134. #else
  135.             return NO;
  136. #endif
  137.         } else if (*cp < 0xF0) {        /* EUCJP JIS208 (overlaps SJIS)        */
  138.             if (len > 1) {
  139.                  if (IsEUCJPKanji(cp[1]))
  140.                     cp += 2, len -= 2;        /* valid 2 byte EUCJP        */
  141.                 else
  142.                     return NO;                /* invalid 2of2 byte EUCJP    */
  143.             } else
  144.                 break;                        /* buffer ended w/1of2 byte EUCJP */
  145.         } else if (*cp < 0xFF) {        /* EUCJP JIS208 only:            */
  146.             if (len > 1) {
  147.                  if (IsEUCJPKanji(cp[1]))
  148.                     return YES;            /* valid 2 byte EUCJP, invalid SJIS    */
  149.                 else
  150.                     return NO;                /* invalid 2of2 byte EUCJP    */
  151.             } else
  152.                 break;                        /* buffer ended w/1of2 byte EUCJP */
  153.         } else {
  154.             return NO;                    /* invalid EUCJP 1st byte: 0xFF    */
  155.         }
  156.     }
  157.     return MAYBE;
  158. }
  159.  
  160. MODULE_PRIVATE int16
  161. intl_detect_JCSID (uint16 defaultCSID, const unsigned char *buf, int32 len)
  162. {
  163.     register const unsigned char    *cp = buf;
  164.     int        sjisFlag;
  165.     int        eucjpFlag;
  166.  
  167.     /* JIS is 7bit. Scan to end of 7bit data or legitimate JIS ESC sequence. */
  168.     while (len && (IsRoman(*cp) || (*cp == 0xA0))) { /* allow nbsp */
  169.         if (IsJISEscSeq(cp, len))
  170.             return CS_JIS;
  171.         cp++, len--;
  172.     }
  173.  
  174.     /* If len > 0, must be either SJIS or EUC because there's 8bit data */
  175.     while (len) {
  176.         if (*cp == 0x80) {
  177.             return CS_DEFAULT;/* illegal byte1 (SJIS & EUCJP) */
  178.         }
  179.         if (*cp < 0x8E)
  180.             return CS_SJIS;        /* Illegal EUCJP 1st byte    */
  181.         if (*cp == 0xA0) {
  182. #if ALLOW_NBSP
  183.             cp++; len--;
  184.             continue; /* allow nbsp */
  185. #else
  186.             return CS_DEFAULT;/* illegal byte1 (SJIS & EUCJP) */
  187. #endif
  188.         }
  189.         if ( (*cp > 0xEF) && (*cp < 0xFF) )    /* illegal SJIS 1st byte    */
  190.             return CS_EUCJP;
  191.         if (*cp == 0xFF) {
  192.             return CS_DEFAULT;/* illegal byte1 (SJIS & EUCJP) */
  193.         }
  194.         
  195.         /* At this point. 1st byte is 0x8E, 0x8F, or 0xA1-0xEF.                */
  196.         /* If 1st Byte is 0xE0-0xEF inclusive, then it's 2byte SJIS or EUC    */
  197.         if ((*cp > 0xDF) && (*cp < 0xF0)) {
  198.             if (len > 1) {
  199.                 if (cp[1] < 0x41) {            /* illegal byte2 (SJIS & EUCJP) */
  200.                     return CS_DEFAULT;
  201.                 }
  202.                 if (cp[1] < 0xA1)
  203.                     return CS_SJIS;            /* Illegal EUCJP 2nd byte */
  204.                 if (cp[1] > 0xFC)
  205.                     return CS_EUCJP;        /* illegal SJIS 2nd byte */
  206.                 cp += 2, len -= 2;            /* Skip 2 byte character */
  207.  
  208.                 /* Gobble up single byte characters and continue outer loop    */
  209.                 while (len && IsRoman(*cp)) {
  210.                         cp++, len--;
  211.                 }
  212.                 continue;
  213.             } else {
  214.                 len = 0;
  215.                 break;                        /* No more chars in buffer         */
  216.             }
  217.         }
  218.         /* 1st Byte is 0xA1-DF inclusive:
  219.          * 1byte SJIS kana or 1of2 byte SJIS or EUC
  220.          */
  221.         break;                            /* break and handle ambiguous cases    */
  222.     }
  223.  
  224.     if (len) {
  225.         eucjpFlag = isEUCJP(cp, len);
  226.         if (YES == eucjpFlag)
  227.             return CS_EUCJP;
  228.  
  229.         sjisFlag = isSJIS(cp, len);
  230.         if (YES == sjisFlag)
  231.             return CS_SJIS;
  232.  
  233.         /* Neither one is YES, look at NO : MAYBE Pair */
  234.         if ((NO == eucjpFlag) && (MAYBE == sjisFlag))
  235.             return CS_SJIS;
  236.         if ((MAYBE == eucjpFlag) && (NO == sjisFlag))
  237.             return CS_EUCJP;
  238.     }
  239.  
  240.     /* Some servers relied upon the previous Nav3.0 default for ambiguous SJIS/EUC encoding. */
  241. #define USE_ACKBAR_LOGIC 1
  242.  
  243.     /* Now, both are NO or both are MAYBE, look at default */
  244.     if (len) {                        /* Must be ambiguous -- EUC or SJIS        */
  245. #if USE_ACKBAR_LOGIC
  246.  
  247. #ifdef XP_MAC
  248.         defaultCSID = CS_SJIS_AUTO;                     /* simulate Akbar old charset hints */
  249. #else
  250.         defaultCSID = CS_JIS;
  251. #endif
  252.         if (defaultCSID == CS_SJIS) {
  253.             eucjpFlag = isEUCJP(cp, len);
  254.             if (eucjpFlag == YES)
  255.                 return CS_EUCJP;
  256.             else
  257.                 return CS_SJIS;
  258.         } else if (defaultCSID == CS_EUCJP) {
  259.             sjisFlag = isSJIS(cp, len);
  260.             if (sjisFlag == YES)
  261.                 return CS_SJIS;
  262.             else
  263.                 return CS_EUCJP;
  264.         } else {                            /* default is JIS */
  265.             sjisFlag = isSJIS(cp, len);
  266.             if (sjisFlag == YES)
  267.                 return CS_SJIS;
  268.             eucjpFlag = isEUCJP(cp, len);
  269.             if (eucjpFlag == YES)
  270.                 return CS_EUCJP;
  271.             if (sjisFlag == NO) {
  272.                 if (eucjpFlag != NO)        /* SJIS-NO, EUCJP-MAYBE */
  273.                     return CS_EUCJP;
  274.             } else {
  275.                 if (eucjpFlag == NO)        /* SJIS-MAYBE, EUCJP-NO */
  276.                     return CS_SJIS;
  277.                 else {                      /* both MAYBE */
  278.                     return CS_EUCJP;        /* have to pick one... */
  279.                 }
  280.             }
  281.         }
  282. #else
  283.         if (CS_SJIS == defaultCSID) {
  284.             if (MAYBE == sjisFlag)
  285.                 return CS_SJIS;
  286.         } else if (CS_EUCJP == defaultCSID) {
  287.             if (MAYBE == eucjpFlag)
  288.                 return CS_EUCJP;
  289.         } else {                            /* default is JIS */
  290.             if ((MAYBE == eucjpFlag) && (MAYBE == sjisFlag))        /* pick one- EUC */
  291.                 return CS_EUCJP;
  292.         }
  293. #endif
  294.     }
  295.     return CS_ASCII;                /* Could be any of the 3... */
  296. }
  297.  
  298.     /* Auto Detect Japanese Char Code Conversion    */
  299. MODULE_PRIVATE unsigned char *
  300. autoJCCC (CCCDataObject obj, const unsigned char *s, int32 l)
  301. {
  302.     int16 doc_csid = 0;
  303.     uint16 detected_doc_csid;
  304.  
  305.     /* try to determine doc Japanese CSID.    */
  306.     doc_csid = intl_detect_JCSID((uint16)(INTL_GetCCCDefaultCSID(obj)&~CS_AUTO),
  307.                                             (const unsigned char *) s,l);
  308.     if (doc_csid == CS_ASCII) {    /* return s unconverted and                */
  309.         INTL_SetCCCLen(obj, l);
  310.         return (unsigned char *)s;    /* autodetect next block of stream data    */
  311.     }
  312.     if (doc_csid == CS_DEFAULT) { /* found unexpected chars */
  313.         doc_csid = INTL_GetCCCDefaultCSID(obj) & ~CS_AUTO;
  314.         detected_doc_csid = CS_DEFAULT;
  315.     } else {
  316.         detected_doc_csid = doc_csid | CS_AUTO;
  317.     }
  318.     /* Setup converter function for success streams data blocks    */
  319.     (void) INTL_GetCharCodeConverter(doc_csid, INTL_GetCCCToCSID(obj), obj);
  320.     INTL_CallCCCReportAutoDetect(obj, detected_doc_csid);
  321.  
  322.     /* If no conversion needed, change put_block module for successive
  323.      * data blocks.  For current data block, return unmodified buffer.
  324.      */
  325.     if (INTL_GetCCCCvtfunc(obj) == NULL) {
  326.         INTL_SetCCCLen(obj, l);
  327.         return((unsigned char *) s);
  328.     }
  329.     /* For initial block, must call converter directly.  Success calls
  330.      * to the converter will be called directly from net_CharCodeConv()
  331.      */
  332.     return (unsigned char *)(INTL_GetCCCCvtfunc(obj)) (obj, (const unsigned char    *)s, l);
  333. }
  334.  
  335.  
  336.  
  337.