blob: 46007b730069198b99a0eee75b2402f5c74af65f [file] [log] [blame]
//========================================================================
//
// UTF.h
//
// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
// Copyright (C) 2008 Koji Otani <sho@bbr.jp>
// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================
#include "goo/gmem.h"
#include "PDFDocEncoding.h"
#include "UTF.h"
bool UnicodeIsValid(Unicode ucs4)
{
return (ucs4 < 0x110000) &&
((ucs4 & 0xfffff800) != 0xd800) &&
(ucs4 < 0xfdd0 || ucs4 > 0xfdef) &&
((ucs4 & 0xfffe) != 0xfffe);
}
int UTF16toUCS4(const Unicode *utf16, int utf16Len, Unicode **ucs4)
{
int i, n, len;
Unicode *u;
// count characters
len = 0;
for (i = 0; i < utf16Len; i++) {
if (utf16[i] >= 0xd800 && utf16[i] < 0xdc00 && i + 1 < utf16Len &&
utf16[i+1] >= 0xdc00 && utf16[i+1] < 0xe000) {
i++; /* surrogate pair */
}
len++;
}
if (ucs4 == NULL)
return len;
u = (Unicode*)gmallocn(len, sizeof(Unicode));
n = 0;
// convert string
for (i = 0; i < utf16Len; i++) {
if (utf16[i] >= 0xd800 && utf16[i] < 0xdc00) { /* surrogate pair */
if (i + 1 < utf16Len && utf16[i+1] >= 0xdc00 && utf16[i+1] < 0xe000) {
/* next code is a low surrogate */
u[n] = (((utf16[i] & 0x3ff) << 10) | (utf16[i+1] & 0x3ff)) + 0x10000;
++i;
} else {
/* missing low surrogate
replace it with REPLACEMENT CHARACTER (U+FFFD) */
u[n] = 0xfffd;
}
} else if (utf16[i] >= 0xdc00 && utf16[i] < 0xe000) {
/* invalid low surrogate
replace it with REPLACEMENT CHARACTER (U+FFFD) */
u[n] = 0xfffd;
} else {
u[n] = utf16[i];
}
if (!UnicodeIsValid(u[n])) {
u[n] = 0xfffd;
}
n++;
}
*ucs4 = u;
return len;
}
int TextStringToUCS4(GooString *textStr, Unicode **ucs4)
{
int i, len;
const char *s;
Unicode *u;
len = textStr->getLength();
s = textStr->getCString();
if (len == 0)
return 0;
if (textStr->hasUnicodeMarker()) {
Unicode *utf16;
len = len/2 - 1;
if (len > 0) {
utf16 = new Unicode[len];
for (i = 0 ; i < len; i++) {
utf16[i] = (s[2 + i*2] & 0xff) << 8 | (s[3 + i*2] & 0xff);
}
len = UTF16toUCS4(utf16, len, &u);
delete[] utf16;
} else {
u = NULL;
}
} else {
u = (Unicode*)gmallocn(len, sizeof(Unicode));
for (i = 0 ; i < len; i++) {
u[i] = pdfDocEncoding[s[i] & 0xff];
}
}
*ucs4 = u;
return len;
}