/*
 *  utility.c
 *      ユーティリティ関数群
 *      written by H.Tsujimura    16 Sep 2004 / 10 Sep 2008
 *
 *      Copyright (c) 2004, 2005, 2006, 2007, 2008 by H.Tsujimura (tsupo@na.rim.or.jp)
 *      All Rights Reserved.
 *
 *  元々、xmlRPC.dll 内に用意してあった関数を抽出したもの
 *
 * History:
 * $Log: /makeRSS/carot/utility.c $
 * 
 * 1     08/09/10 18:21 Tsujimura543
 * getCategoryIDbyName(), getCategoryIDs() を xmlRPC.dll から移管
 */

#include "xmlRPC.h"
#include "utility.h"

#ifndef	lint
static char	*rcs_id =
"$Header: /makeRSS/carot/utility.c 1     08/09/10 18:21 Tsujimura543 $";
#endif

/*
 *  ユーティリティ関数群
 */

/* Unicode(UCS-2BE) (%uXXXX or &#XXXXX;) → UTF-8 (xxyyzz) 変換 */
char    *
convUnicode( unsigned long code )
{
    unsigned short  a, b, c, d;
    static char     codeStr[6];

    if ( code < 0x0080 ) {
        a = (unsigned short)code;
        codeStr[0] = (char)(a & 0xFF);
        codeStr[1] = NUL;
    }
    else if ( code < 0x0800 ) {
        a = (unsigned short)(((code & 0x07C0) >> 6) | 0xC0);
        b = (unsigned short)(( code & 0x003F)       | 0x80);
        codeStr[0] = (char)(a & 0xFF);
        codeStr[1] = (char)(b & 0xFF);
        codeStr[2] = NUL;
    }
    else if ( code < 0x010000 ) {
        a = (unsigned short)(((code & 0xF000) >> 12) | 0xE0);
        b = (unsigned short)(((code & 0x0FC0) >>  6) | 0x80);
        c = (unsigned short)(( code & 0x003F)        | 0x80);
        codeStr[0] = (char)(a & 0xFF);
        codeStr[1] = (char)(b & 0xFF);
        codeStr[2] = (char)(c & 0xFF);
        codeStr[3] = NUL;
    }
    else {
        a = (unsigned short)(((code & 0x001C0000) >> 18) | 0xF0);
        b = (unsigned short)(((code & 0x0003F000) >> 12) | 0x80);
        c = (unsigned short)(((code & 0x00000FC0) >>  6) | 0x80);
        d = (unsigned short)(( code & 0x0000003F)        | 0x80);
        codeStr[0] = (char)(a & 0xFF);
        codeStr[1] = (char)(b & 0xFF);
        codeStr[2] = (char)(c & 0xFF);
        codeStr[3] = (char)(d & 0xFF);
        codeStr[4] = NUL;
    }

    return ( codeStr );
}

char    *
decodeNumericReference( char *src )
{
    char    *p    = src;
    char    *temp = (char *)malloc( strlen( src ) + 1 );

    if ( temp ) {
        unsigned long   l;

        temp[0] = NUL;
        while ( *p ) {
            if ( (*p == '&') && (*(p + 1) == '#') ) {
                l = atol( p + 2 );
                strcat( temp, convUnicode( l ) );
                p = strchr( p + 2, ';' ) + 1;
            }
            else {
                l = temp[0] ? strlen( temp ) : 0;
                temp[l]     = *p;
                temp[l + 1] = NUL;
                p++;
            }
        }
        strcpy( src, temp );

        free( temp );
    }

    return ( src );
}


/* カテゴリ名を元にカテゴリIDを取得する */
char    *
getCategoryIDbyName(
        char       *catID,          /* (O) カテゴリID (文字列)      */
        const char *categoryName,   /* (I) カテゴリ名 (Shift_JIS)   */
        const char *htmlSrcCode,    /* (I) 管理画面htmlソースコード */
        const char *beginSelect,    /* (I) <select>                 */
        const char *endSelect,      /* (I) </select>                */
        const char *beginOption,    /* (I) <option>                 */
        const char *endOption,      /* (I) </option>                */
        int        charSet          /* (I) 文字コード               */
    )
{
    char    *p, *q, *r;
    char    temp[MAX_CATNAMELENGTH], *pp;
    char    value[MAX_CATNAMELENGTH];
    BOOL    done  = FALSE;
 // int     len11 = strlen( beginSelect );
    int     len12 = strlen( endSelect );
    int     len21 = strlen( beginOption );
    int     len22 = strlen( endOption );

    p = strstr( htmlSrcCode, beginSelect );
    if ( p ) {
        p += strlen( beginSelect );
        do {
            while ( *p &&
                    ((*p == '\r') || (*p == '\n') ||
                     (*p == ' ')  || (*p == '\t')    ) )
                p++;
            if ( !(*p) || !strncmp( p, endSelect, len12 ) )
                break;

            p = strstr( p, beginOption );
            if ( p ) {
                p += len21;
                q = strchr( p, '>' );
                if ( q && *++q ) {
                    r = strstr( p, "value=\"" );    /* for JUGEM */
                    if ( r && (r < q) )             /* for JUGEM */
                        p = r + 7;                  /* for JUGEM */
                    strncpy( value, p, (q - 1) - p );
                    value[(q - 1) - p] = NUL;
                    if ( value[strlen(value) - 1] == '"' )
                        value[strlen(value) - 1] = NUL;

                    r = strchr( q, '<' );
                    if ( r ) {
                        strncpy( temp, q, r - q );
                        temp[r - q] = '\0';

                        switch ( charSet ) {
                        case CHARSET_EUCJP:
                            pp = euc2sjis( temp );
                            break;
                        case CHARSET_ISO2022JP:
                            pp = jis2sjis( temp );
                            break;
                        case CHARSET_UTF8:
                            pp = utf2sjis( decodeNumericReference( temp ) );
                            break;
                        case CHARSET_SHIFTJIS:
                        default:
                            pp = temp;
                            break;
                        }

                        if ( pp )
                            break;

                        while ( (pp[strlen(pp) - 1] == '\r') ||
                                (pp[strlen(pp) - 1] == '\n') ||
                                (pp[strlen(pp) - 1] == '\t') ||
                                (pp[strlen(pp) - 1] == ' ')     )
                            pp[strlen(pp) - 1] = NUL;

                        if ( !strcmp( pp, categoryName ) ) {
                            strcpy( catID, value );
                            done = TRUE;
                            break;
                        }
                    }
                }

                p = strstr( p, endOption );
                if ( p )
                    p += len22;
            }
            else
                break;
        } while ( !done );
    }

    return ( catID );
}


/* カテゴリ一覧の取得 */
int
getCategoryIDs(
        long         *numOfCategories,  /* (I) 取得するカテゴリの数     */
                                        /* (O) 取得したカテゴリの数     */
        CATLISTINF_t categories,        /* (O) 取得したカテゴリ情報     */
        const char   *htmlSrcCode,      /* (I) 管理画面htmlソースコード */
        const char   *beginSelect,      /* (I) <select>                 */
        const char   *endSelect,        /* (I) </select>                */
        const char   *beginOption,      /* (I) <option>                 */
        const char   *endOption,        /* (I) </option>                */
        int          charSet            /* (I) 文字コード               */
    )
{
    int     numOfCats = 0;
    char    *p, *q, *r;
    char    temp[MAX_CATNAMELENGTH], *pp;
    BOOL    done  = FALSE;
 // int     len11 = strlen( beginSelect );
    int     len12 = strlen( endSelect );
    int     len21 = strlen( beginOption );
    int     len22 = strlen( endOption );

    p = strstr( htmlSrcCode, beginSelect );
    if ( p ) {
        p += strlen( beginSelect );
        do {
            while ( *p &&
                    ((*p == '\r') || (*p == '\n') ||
                     (*p == ' ')  || (*p == '\t')    ) )
                p++;
            if ( !(*p) || !strncmp( p, endSelect, len12 ) )
                break;
            if ( !(*p) != '<' ) {
                q = strchr( p, '<' );
                if ( q && (endSelect[0] == '<')      &&
                     !strncmp( q, endSelect, len12 )    )
                    break;
            }

            p = strstr( p, beginOption );
            if ( p ) {
                p += len21;
                q = strchr( p, '>' );
                if ( q && *++q ) {
                    r = strchr( q, '<' );
                    if ( r ) {
                        strncpy( temp, q, r - q );
                        temp[r - q] = '\0';

                        switch ( charSet ) {
                        case CHARSET_EUCJP:
                            pp = euc2sjis( temp );
                            break;
                        case CHARSET_ISO2022JP:
                            pp = jis2sjis( temp );
                            break;
                        case CHARSET_UTF8:
                            pp = utf2sjis( decodeNumericReference( temp ) );
                            break;
                        case CHARSET_SHIFTJIS:
                        default:
                            pp = temp;
                            break;
                        }

                        if ( pp )
                            break;

                        while ( (pp[strlen(pp) - 1] == '\r') ||
                                (pp[strlen(pp) - 1] == '\n') ||
                                (pp[strlen(pp) - 1] == '\t') ||
                                (pp[strlen(pp) - 1] == ' ')     )
                            pp[strlen(pp) - 1] = NUL;

                        sprintf( categories[numOfCats].categoryId, "%08d", numOfCats );
                        strcpy( categories[numOfCats].categoryName, pp );
                        numOfCats++;
                        if ( numOfCats >= *numOfCategories )
                            break;
                    }
                }

                p = strstr( p, endOption );
                if ( p )
                    p += len22;
            }
            else
                break;
        } while ( !done );
    }

    *numOfCategories = numOfCats;
    return ( numOfCats );
}

