Newer
Older
Import / applications / MakePDF / 3rdParty / libharu-with-PRs / src / hpdf_string.c
/*
 * << Haru Free PDF Library >> -- hpdf_string.c
 *
 * URL: http://libharu.org
 *
 * Copyright (c) 1999-2006 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
 * Copyright (c) 2007-2009 Antony Dovgal <tony@daylessday.org>
 *
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 * It is provided "as is" without express or implied warranty.
 *
 */

#include <string.h>
#include "hpdf_conf.h"
#include "hpdf_utils.h"
#include "hpdf_objects.h"

static const HPDF_BYTE UNICODE_HEADER[] = {
    0xFE, 0xFF
};


HPDF_String
HPDF_String_New  (HPDF_MMgr        mmgr,
                  const char  *value,
                  HPDF_Encoder     encoder)
{
    HPDF_String obj;

    HPDF_PTRACE((" HPDF_String_New\n"));

    obj = (HPDF_String)HPDF_GetMem (mmgr, sizeof(HPDF_String_Rec));
    if (obj) {
        HPDF_MemSet (&obj->header, 0, sizeof(HPDF_Obj_Header));
        obj->header.obj_class = HPDF_OCLASS_STRING;

        obj->mmgr = mmgr;
        obj->error = mmgr->error;
        obj->encoder = encoder;
        obj->value = NULL;
        obj->len = 0;

        if (HPDF_String_SetValue (obj, value) != HPDF_OK) {
            HPDF_FreeMem (obj->mmgr, obj);
            return NULL;
        }
    }

    return obj;
}


HPDF_STATUS
HPDF_String_SetValue  (HPDF_String      obj,
                       const char  *value)
{
    HPDF_UINT len;
    HPDF_STATUS ret = HPDF_OK;

    HPDF_PTRACE((" HPDF_String_SetValue\n"));

    if (obj->value) {
        HPDF_FreeMem (obj->mmgr, obj->value);
        obj->len = 0;
    }

    if (obj->encoder == NULL) {
        len = HPDF_StrLen(value, HPDF_LIMIT_MAX_STRING_LEN + 1);

        if (len > HPDF_LIMIT_MAX_STRING_LEN)
            return HPDF_SetError (obj->error, HPDF_STRING_OUT_OF_RANGE, 0);

        obj->value = HPDF_GetMem (obj->mmgr, len + 1);
        if (!obj->value)
            return HPDF_Error_GetCode (obj->error);

        HPDF_StrCpy ((char *)obj->value, value, (char *)obj->value + len);
    } else {
        len = HPDF_Encoder_StrLen(obj->encoder, value, HPDF_LIMIT_MAX_STRING_LEN + 1);

        if (len > HPDF_LIMIT_MAX_STRING_LEN)
            return HPDF_SetError (obj->error, HPDF_STRING_OUT_OF_RANGE, 0);

        obj->value = HPDF_GetMem (obj->mmgr, len);
        if (!obj->value)
            return HPDF_Error_GetCode (obj->error);

        HPDF_MemCpy (obj->value, (const HPDF_BYTE *)value, len);
    }
    obj->len = len;

    return ret;
}

void
HPDF_String_Free  (HPDF_String  obj)
{
    if (!obj)
        return;

    HPDF_PTRACE((" HPDF_String_Free\n"));

    HPDF_FreeMem (obj->mmgr, obj->value);
    HPDF_FreeMem (obj->mmgr, obj);
}


HPDF_STATUS
HPDF_String_Write  (HPDF_String   obj,
                    HPDF_Stream   stream,
                    HPDF_Encrypt  e)
{
    HPDF_STATUS ret;

    /*
     *  When encoder is not NULL, text is changed to unicode using encoder,
     *  and it outputs by HPDF_write_binary method.
     */

    HPDF_PTRACE((" HPDF_String_Write\n"));

    if (e)
        HPDF_Encrypt_Reset (e);

    if (obj->encoder == NULL) {
        if (e) {
            if ((ret = HPDF_Stream_WriteChar (stream, '<')) != HPDF_OK)
                return ret;

            if ((ret = HPDF_Stream_WriteBinary (stream, obj->value,
                    HPDF_StrLen ((char *)obj->value, -1), e, NULL)) != HPDF_OK)
                return ret;

            return HPDF_Stream_WriteChar (stream, '>');
        } else {
            return HPDF_Stream_WriteEscapeText (stream, (char *)obj->value);
        }
    } else {
        HPDF_BYTE* src = obj->value;
        HPDF_BYTE buf[HPDF_TEXT_DEFAULT_LEN * 2];
        HPDF_UINT tmp_len = 0;
        HPDF_BYTE* pbuf = buf;
        HPDF_INT32 len = obj->len;
        HPDF_ParseText_Rec  parse_state;
        HPDF_UINT i;
        HPDF_BYTE tmp_utf16[4] = {0xFF, 0xFF, 0xFF, 0xFF,};

        if ((ret = HPDF_Stream_WriteChar (stream, '<')) != HPDF_OK)
           return ret;

        if ((ret = HPDF_Stream_WriteBinary (stream, UNICODE_HEADER,
                2, e, NULL)) != HPDF_OK)
            return ret;

        HPDF_Encoder_SetParseText (obj->encoder, &parse_state, src, len);

        for (i = 0; (HPDF_INT32)i < len; i++) {
            HPDF_BYTE b = src[i];
            HPDF_UINT bytes;
            HPDF_ByteType btype = HPDF_Encoder_ByteType (obj->encoder,
                    &parse_state, &bytes);

            if (tmp_len >= HPDF_TEXT_DEFAULT_LEN - 1) {
                if ((ret = HPDF_Stream_WriteBinary (stream, buf,
                        tmp_len * 2, e, NULL)) != HPDF_OK)
                    return ret;

                tmp_len = 0;
                pbuf = buf;
            }

            if (btype != HPDF_BYTE_TYPE_TRIAL)
                if (HPDF_Ucs4ToUTF16BE (tmp_utf16,
                      HPDF_Encoder_ToUcs4 (obj->encoder, src + i, bytes)) <= 2)
                    tmp_utf16[2] = 0;
            if (tmp_utf16[2] < 0xFF) {
                if (btype != HPDF_BYTE_TYPE_TRIAL) {
                    *pbuf++ = tmp_utf16[0];
                    *pbuf++ = tmp_utf16[1];
                    if (tmp_utf16[2] == 0)
                        tmp_utf16[2] = 0xFF;
                } else {
                    *pbuf++ = tmp_utf16[2];
                    *pbuf++ = tmp_utf16[3];
                    tmp_utf16[2] = 0xFF;
                }
                tmp_len++;
            }
        }

        if (tmp_len > 0) {
            if ((ret = HPDF_Stream_WriteBinary (stream, buf, 
                    tmp_len * 2, e, NULL)) != HPDF_OK)
                return ret;
        }

        if ((ret = HPDF_Stream_WriteChar (stream, '>')) != HPDF_OK)
            return ret;
    }

    return HPDF_OK;
}


HPDF_INT32
HPDF_String_Cmp  (HPDF_String s1,
                  HPDF_String s2)
{
    if (s1->len < s2->len) return -1;
    if (s1->len > s2->len) return +1;
    return memcmp(s1->value, s2->value, s1->len);
}