summaryrefslogtreecommitdiffstats
path: root/generic/tclEncoding.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclEncoding.c')
-rw-r--r--generic/tclEncoding.c515
1 files changed, 339 insertions, 176 deletions
diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c
index 9e1d262..cf738ed 100644
--- a/generic/tclEncoding.c
+++ b/generic/tclEncoding.c
@@ -18,7 +18,7 @@ typedef size_t (LengthProc)(const char *src);
* convert between various character sets and UTF-8.
*/
-typedef struct Encoding {
+typedef struct {
char *name; /* Name of encoding. Malloced because (1) hash
* table entry that owns this encoding may be
* freed prior to this encoding being freed,
@@ -46,7 +46,7 @@ typedef struct Encoding {
* nullSize is 2, this is a function that
* returns the number of bytes in a 0x0000
* terminated string. */
- int refCount; /* Number of uses of this structure. */
+ size_t refCount; /* Number of uses of this structure. */
Tcl_HashEntry *hPtr; /* Hash table entry that owns this encoding. */
} Encoding;
@@ -57,7 +57,7 @@ typedef struct Encoding {
* encoding.
*/
-typedef struct TableEncodingData {
+typedef struct {
int fallback; /* Character (in this encoding) to substitute
* when this encoding cannot represent a UTF-8
* character. */
@@ -83,7 +83,7 @@ typedef struct TableEncodingData {
} TableEncodingData;
/*
- * The following structures is the clientData for a dynamically-loaded,
+ * Each of the following structures is the clientData for a dynamically-loaded
* escape-driven encoding that is itself comprised of other simpler encodings.
* An example is "iso-2022-jp", which uses escape sequences to switch between
* ascii, jis0208, jis0212, gb2312, and ksc5601. Note that "escape-driven"
@@ -91,7 +91,7 @@ typedef struct TableEncodingData {
* for switching character sets.
*/
-typedef struct EscapeSubTable {
+typedef struct {
unsigned sequenceLen; /* Length of following string. */
char sequence[16]; /* Escape code that marks this encoding. */
char name[32]; /* Name for encoding. */
@@ -100,7 +100,7 @@ typedef struct EscapeSubTable {
* yet. */
} EscapeSubTable;
-typedef struct EscapeEncodingData {
+typedef struct {
int fallback; /* Character (in this encoding) to substitute
* when this encoding cannot represent a UTF-8
* character. */
@@ -117,8 +117,8 @@ typedef struct EscapeEncodingData {
* 0. */
int numSubTables; /* Length of following array. */
EscapeSubTable subTables[1];/* Information about each EscapeSubTable used
- * by this encoding type. The actual size will
- * be as large as necessary to hold all
+ * by this encoding type. The actual size is
+ * as large as necessary to hold all
* EscapeSubTables. */
} EscapeEncodingData;
@@ -156,7 +156,7 @@ static ProcessGlobalValue encodingFileMap = {
* A list of directories making up the "library path". Historically this
* search path has served many uses, but the only one remaining is a base for
* the encodingSearchPath above. If the application does not explicitly set
- * the encodingSearchPath, then it will be initialized by appending /encoding
+ * the encodingSearchPath, then it is initialized by appending /encoding
* to each directory in this "libraryPath".
*/
@@ -177,7 +177,7 @@ TCL_DECLARE_MUTEX(encodingMutex)
/*
* The following are used to hold the default and current system encodings.
* If NULL is passed to one of the conversion routines, the current setting of
- * the system encoding will be used to perform the conversion.
+ * the system encoding is used to perform the conversion.
*/
static Tcl_Encoding defaultEncoding = NULL;
@@ -234,12 +234,17 @@ static int TableToUtfProc(ClientData clientData, const char *src,
char *dst, int dstLen, int *srcReadPtr,
int *dstWrotePtr, int *dstCharsPtr);
static size_t unilen(const char *src);
-static int UnicodeToUtfProc(ClientData clientData,
+static int Utf16ToUtfProc(ClientData clientData,
const char *src, int srcLen, int flags,
Tcl_EncodingState *statePtr, char *dst, int dstLen,
int *srcReadPtr, int *dstWrotePtr,
int *dstCharsPtr);
-static int UtfToUnicodeProc(ClientData clientData,
+static int UtfToUtf16Proc(ClientData clientData,
+ const char *src, int srcLen, int flags,
+ Tcl_EncodingState *statePtr, char *dst, int dstLen,
+ int *srcReadPtr, int *dstWrotePtr,
+ int *dstCharsPtr);
+static int UtfToUcs2Proc(ClientData clientData,
const char *src, int srcLen, int flags,
Tcl_EncodingState *statePtr, char *dst, int dstLen,
int *srcReadPtr, int *dstWrotePtr,
@@ -279,6 +284,21 @@ static int Iso88591ToUtfProc(ClientData clientData,
static const Tcl_ObjType encodingType = {
"encoding", FreeEncodingIntRep, DupEncodingIntRep, NULL, NULL
};
+#define EncodingSetIntRep(objPtr, encoding) \
+ do { \
+ Tcl_ObjIntRep ir; \
+ ir.twoPtrValue.ptr1 = (encoding); \
+ ir.twoPtrValue.ptr2 = NULL; \
+ Tcl_StoreIntRep((objPtr), &encodingType, &ir); \
+ } while (0)
+
+#define EncodingGetIntRep(objPtr, encoding) \
+ do { \
+ const Tcl_ObjIntRep *irPtr; \
+ irPtr = TclFetchIntRep ((objPtr), &encodingType); \
+ (encoding) = irPtr ? irPtr->twoPtrValue.ptr1 : NULL; \
+ } while (0)
+
/*
*----------------------------------------------------------------------
@@ -305,17 +325,16 @@ Tcl_GetEncodingFromObj(
Tcl_Obj *objPtr,
Tcl_Encoding *encodingPtr)
{
+ Tcl_Encoding encoding;
const char *name = TclGetString(objPtr);
- if (objPtr->typePtr != &encodingType) {
- Tcl_Encoding encoding = Tcl_GetEncoding(interp, name);
-
+ EncodingGetIntRep(objPtr, encoding);
+ if (encoding == NULL) {
+ encoding = Tcl_GetEncoding(interp, name);
if (encoding == NULL) {
return TCL_ERROR;
}
- TclFreeIntRep(objPtr);
- objPtr->internalRep.twoPtrValue.ptr1 = encoding;
- objPtr->typePtr = &encodingType;
+ EncodingSetIntRep(objPtr, encoding);
}
*encodingPtr = Tcl_GetEncoding(NULL, name);
return TCL_OK;
@@ -335,8 +354,10 @@ static void
FreeEncodingIntRep(
Tcl_Obj *objPtr)
{
- Tcl_FreeEncoding(objPtr->internalRep.twoPtrValue.ptr1);
- objPtr->typePtr = NULL;
+ Tcl_Encoding encoding;
+
+ EncodingGetIntRep(objPtr, encoding);
+ Tcl_FreeEncoding(encoding);
}
/*
@@ -354,7 +375,8 @@ DupEncodingIntRep(
Tcl_Obj *srcPtr,
Tcl_Obj *dupPtr)
{
- dupPtr->internalRep.twoPtrValue.ptr1 = Tcl_GetEncoding(NULL, srcPtr->bytes);
+ Tcl_Encoding encoding = Tcl_GetEncoding(NULL, TclGetString(srcPtr));
+ EncodingSetIntRep(dupPtr, encoding);
}
/*
@@ -429,9 +451,8 @@ TclGetLibraryPath(void)
* Keeps the per-thread copy of the library path current with changes to
* the global copy.
*
- * NOTE: this routine returns void, so there's no way to report the error
- * that searchPath is not a valid list. In that case, this routine will
- * silently do nothing.
+ * Since the result of this routine is void, if searchPath is not a valid
+ * list this routine silently does nothing.
*
*----------------------------------------------------------------------
*/
@@ -453,17 +474,16 @@ TclSetLibraryPath(
*
* FillEncodingFileMap --
*
- * Called to bring the encoding file map in sync with the current value
+ * Called to update the encoding file map with the current value
* of the encoding search path.
*
- * Scan the directories on the encoding search path, find the *.enc
- * files, and store the found pathnames in a map associated with the
- * encoding name.
+ * Finds *.end files in the directories on the encoding search path and
+ * stores the found pathnames in a map associated with the encoding name.
*
- * In particular, if $dir is on the encoding search path, and the file
- * $dir/foo.enc is found, then store a "foo" -> $dir entry in the map.
- * Later, any need for the "foo" encoding will quickly * be able to
- * construct the $dir/foo.enc pathname for reading the encoding data.
+ * If $dir is on the encoding search path and the file $dir/foo.enc is
+ * found, stores a "foo" -> $dir entry in the map. if the "foo" encoding
+ * is needed later, the $dir/foo.enc name can be quickly constructed in
+ * order to read the encoding data.
*
* Results:
* None.
@@ -547,22 +567,27 @@ TclInitEncodingSubsystem(void)
TableEncodingData *dataPtr;
unsigned size;
unsigned short i;
+ union {
+ char c;
+ short s;
+ } isLe;
if (encodingsInitialized) {
return;
}
+ isLe.s = 1;
Tcl_MutexLock(&encodingMutex);
Tcl_InitHashTable(&encodingTable, TCL_STRING_KEYS);
Tcl_MutexUnlock(&encodingMutex);
/*
- * Create a few initial encodings. Note that the UTF-8 to UTF-8
- * translation is not a no-op, because it will turn a stream of improperly
- * formed UTF-8 into a properly formed stream.
+ * Create a few initial encodings. UTF-8 to UTF-8 translation is not a
+ * no-op because it turns a stream of improperly formed UTF-8 into a
+ * properly formed stream.
*/
- type.encodingName = "identity";
+ type.encodingName = NULL;
type.toUtfProc = BinaryProc;
type.fromUtfProc = BinaryProc;
type.freeProc = NULL;
@@ -578,14 +603,39 @@ TclInitEncodingSubsystem(void)
type.clientData = NULL;
Tcl_CreateEncoding(&type);
- type.encodingName = "unicode";
- type.toUtfProc = UnicodeToUtfProc;
- type.fromUtfProc = UtfToUnicodeProc;
+ type.toUtfProc = Utf16ToUtfProc;
+ type.fromUtfProc = UtfToUcs2Proc;
type.freeProc = NULL;
type.nullSize = 2;
- type.clientData = NULL;
+ type.encodingName = "ucs-2le";
+ type.clientData = INT2PTR(1);
+ Tcl_CreateEncoding(&type);
+ type.encodingName = "ucs-2be";
+ type.clientData = INT2PTR(0);
+ Tcl_CreateEncoding(&type);
+ type.encodingName = "ucs-2";
+ type.clientData = INT2PTR(isLe.c);
Tcl_CreateEncoding(&type);
+ type.toUtfProc = Utf16ToUtfProc;
+ type.fromUtfProc = UtfToUtf16Proc;
+ type.freeProc = NULL;
+ type.nullSize = 2;
+ type.encodingName = "utf-16le";
+ type.clientData = INT2PTR(1);;
+ Tcl_CreateEncoding(&type);
+ type.encodingName = "utf-16be";
+ type.clientData = INT2PTR(0);
+ Tcl_CreateEncoding(&type);
+ type.encodingName = "utf-16";
+ type.clientData = INT2PTR(isLe.c);;
+ Tcl_CreateEncoding(&type);
+
+#ifndef TCL_NO_DEPRECATED
+ type.encodingName = "unicode";
+ Tcl_CreateEncoding(&type);
+#endif
+
/*
* Need the iso8859-1 encoding in order to process binary data, so force
* it to always be embedded. Note that this encoding *must* be a proper
@@ -692,6 +742,7 @@ TclFinalizeEncodingSubsystem(void)
*-------------------------------------------------------------------------
*/
+#if !defined(TCL_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9
const char *
Tcl_GetDefaultEncodingDir(void)
{
@@ -735,6 +786,7 @@ Tcl_SetDefaultEncodingDir(
Tcl_ListObjReplace(NULL, searchPath, 0, 0, 1, &directory);
Tcl_SetEncodingSearchPath(searchPath);
}
+#endif
/*
*-------------------------------------------------------------------------
@@ -752,11 +804,7 @@ Tcl_SetDefaultEncodingDir(
* interp was NULL.
*
* Side effects:
- * The new encoding type is entered into a table visible to all
- * interpreters, keyed off the encoding's name. For each call to this
- * function, there should eventually be a call to Tcl_FreeEncoding, so
- * that the database can be cleaned up when encodings aren't needed
- * anymore.
+ * LoadEncodingFile is called if necessary.
*
*-------------------------------------------------------------------------
*/
@@ -794,15 +842,15 @@ Tcl_GetEncoding(
*
* Tcl_FreeEncoding --
*
- * This function is called to release an encoding allocated by
- * Tcl_CreateEncoding() or Tcl_GetEncoding().
+ * Releases an encoding allocated by Tcl_CreateEncoding() or
+ * Tcl_GetEncoding().
*
* Results:
* None.
*
* Side effects:
* The reference count associated with the encoding is decremented and
- * the encoding may be deleted if nothing is using it anymore.
+ * the encoding is deleted if nothing is using it anymore.
*
*---------------------------------------------------------------------------
*/
@@ -821,13 +869,14 @@ Tcl_FreeEncoding(
*
* FreeEncoding --
*
- * This function is called to release an encoding by functions that
- * already have the encodingMutex.
+ * Decrements the reference count of an encoding. The caller must hold
+ * encodingMutes.
*
* Results:
* None.
*
* Side effects:
+ * Releases the resource for an encoding if it is now unused.
* The reference count associated with the encoding is decremented and
* the encoding may be deleted if nothing is using it anymore.
*
@@ -843,18 +892,16 @@ FreeEncoding(
if (encodingPtr == NULL) {
return;
}
- if (encodingPtr->refCount<=0) {
- Tcl_Panic("FreeEncoding: refcount problem !!!");
- }
- encodingPtr->refCount--;
- if (encodingPtr->refCount == 0) {
+ if (encodingPtr->refCount-- <= 1) {
if (encodingPtr->freeProc != NULL) {
encodingPtr->freeProc(encodingPtr->clientData);
}
if (encodingPtr->hPtr != NULL) {
Tcl_DeleteHashEntry(encodingPtr->hPtr);
}
- ckfree(encodingPtr->name);
+ if (encodingPtr->name) {
+ ckfree(encodingPtr->name);
+ }
ckfree(encodingPtr);
}
}
@@ -1017,23 +1064,22 @@ Tcl_SetSystemEncoding(
*
* Tcl_CreateEncoding --
*
- * This function is called to define a new encoding and the functions
- * that are used to convert between the specified encoding and Unicode.
+ * Defines a new encoding, along with the functions that are used to
+ * convert to and from Unicode.
*
* Results:
* Returns a token that represents the encoding. If an encoding with the
* same name already existed, the old encoding token remains valid and
- * continues to behave as it used to, and will eventually be garbage
- * collected when the last reference to it goes away. Any subsequent
- * calls to Tcl_GetEncoding with the specified name will retrieve the
- * most recent encoding token.
+ * continues to behave as it used to, and is eventually garbage collected
+ * when the last reference to it goes away. Any subsequent calls to
+ * Tcl_GetEncoding with the specified name retrieve the most recent
+ * encoding token.
*
* Side effects:
- * The new encoding type is entered into a table visible to all
- * interpreters, keyed off the encoding's name. For each call to this
- * function, there should eventually be a call to Tcl_FreeEncoding, so
- * that the database can be cleaned up when encodings aren't needed
- * anymore.
+ * A new record having the name of the encoding is entered into a table of
+ * encodings visible to all interpreters. For each call to this function,
+ * there should eventually be a call to Tcl_FreeEncoding, which cleans
+ * deletes the record in the table when an encoding is no longer needed.
*
*---------------------------------------------------------------------------
*/
@@ -1043,9 +1089,24 @@ Tcl_CreateEncoding(
const Tcl_EncodingType *typePtr)
/* The encoding type. */
{
+ Encoding *encodingPtr = ckalloc(sizeof(Encoding));
+ encodingPtr->name = NULL;
+ encodingPtr->toUtfProc = typePtr->toUtfProc;
+ encodingPtr->fromUtfProc = typePtr->fromUtfProc;
+ encodingPtr->freeProc = typePtr->freeProc;
+ encodingPtr->nullSize = typePtr->nullSize;
+ encodingPtr->clientData = typePtr->clientData;
+ if (typePtr->nullSize == 1) {
+ encodingPtr->lengthProc = (LengthProc *) strlen;
+ } else {
+ encodingPtr->lengthProc = (LengthProc *) unilen;
+ }
+ encodingPtr->refCount = 1;
+ encodingPtr->hPtr = NULL;
+
+ if (typePtr->encodingName) {
Tcl_HashEntry *hPtr;
int isNew;
- Encoding *encodingPtr;
char *name;
Tcl_MutexLock(&encodingMutex);
@@ -1056,30 +1117,17 @@ Tcl_CreateEncoding(
* reference goes away.
*/
- encodingPtr = Tcl_GetHashValue(hPtr);
- encodingPtr->hPtr = NULL;
+ Encoding *replaceMe = Tcl_GetHashValue(hPtr);
+ replaceMe->hPtr = NULL;
}
name = ckalloc(strlen(typePtr->encodingName) + 1);
-
- encodingPtr = ckalloc(sizeof(Encoding));
encodingPtr->name = strcpy(name, typePtr->encodingName);
- encodingPtr->toUtfProc = typePtr->toUtfProc;
- encodingPtr->fromUtfProc = typePtr->fromUtfProc;
- encodingPtr->freeProc = typePtr->freeProc;
- encodingPtr->nullSize = typePtr->nullSize;
- encodingPtr->clientData = typePtr->clientData;
- if (typePtr->nullSize == 1) {
- encodingPtr->lengthProc = (LengthProc *) strlen;
- } else {
- encodingPtr->lengthProc = (LengthProc *) unilen;
- }
- encodingPtr->refCount = 1;
encodingPtr->hPtr = hPtr;
Tcl_SetHashValue(hPtr, encodingPtr);
Tcl_MutexUnlock(&encodingMutex);
-
+ }
return (Tcl_Encoding) encodingPtr;
}
@@ -1278,10 +1326,9 @@ Tcl_ExternalToUtf(
*
* Tcl_UtfToExternalDString --
*
- * Convert a source buffer from UTF-8 into the specified encoding. If any
+ * Convert a source buffer from UTF-8 to the specified encoding. If any
* of the bytes in the source buffer are invalid or cannot be represented
- * in the target encoding, a default fallback character will be
- * substituted.
+ * in the target encoding, a default fallback character is substituted.
*
* Results:
* The converted bytes are stored in the DString, which is then NULL
@@ -1461,7 +1508,7 @@ Tcl_FindExecutable(
const char *argv0) /* The value of the application's argv[0]
* (native). */
{
- TclInitSubsystems();
+ Tcl_InitSubsystems();
TclpSetInitialEncodings();
TclpFindExecutable(argv0);
}
@@ -1592,13 +1639,13 @@ OpenEncodingFileChannel(
* the data.
*
* Results:
- * The return value is the newly loaded Encoding, or NULL if the file
- * didn't exist of was in the incorrect format. If NULL was returned, an
- * error message is left in interp's result object, unless interp was
- * NULL.
+ * The return value is the newly loaded Tcl_Encoding or NULL if the file
+ * didn't exist or could not be processed. If NULL is returned and interp
+ * is not NULL, an error message is left in interp's result object.
*
* Side effects:
- * File read from disk.
+ * A corresponding encoding file might be read from persistent storage, in
+ * which case LoadTableEncoding is called.
*
*---------------------------------------------------------------------------
*/
@@ -1606,8 +1653,8 @@ OpenEncodingFileChannel(
static Tcl_Encoding
LoadEncodingFile(
Tcl_Interp *interp, /* Interp for error reporting, if not NULL. */
- const char *name) /* The name of the encoding file on disk and
- * also the name for new encoding. */
+ const char *name) /* The name of both the encoding file
+ * and the new encoding. */
{
Tcl_Channel chan = NULL;
Tcl_Encoding encoding = NULL;
@@ -1661,27 +1708,27 @@ LoadEncodingFile(
*
* LoadTableEncoding --
*
- * Helper function for LoadEncodingTable(). Loads a table to that
- * converts between Unicode and some other encoding and creates an
- * encoding (using a TableEncoding structure) from that information.
+ * Helper function for LoadEncodingFile(). Creates a Tcl_EncodingType
+ * structure along with its corresponding TableEncodingData structure, and
+ * passes it to Tcl_Createncoding.
*
- * File contains binary data, but begins with a marker to indicate
- * byte-ordering, so that same binary file can be read on either endian
- * platforms.
+ * The file contains binary data but begins with a marker to indicate
+ * byte-ordering so a single binary file can be read on big or
+ * little-endian systems.
*
* Results:
- * The return value is the new encoding, or NULL if the encoding could
- * not be created (because the file contained invalid data).
+ * Returns the new Tcl_Encoding, or NULL if it could could
+ * not be created because the file contained invalid data.
*
* Side effects:
- * None.
+ * See Tcl_CreateEncoding().
*
*-------------------------------------------------------------------------
*/
static Tcl_Encoding
LoadTableEncoding(
- const char *name, /* Name for new encoding. */
+ const char *name, /* Name of the new encoding. */
int type, /* Type of encoding (ENCODING_?????). */
Tcl_Channel chan) /* File containing new encoding. */
{
@@ -1720,7 +1767,7 @@ LoadTableEncoding(
};
Tcl_DStringInit(&lineString);
- if (Tcl_Gets(chan, &lineString) == -1) {
+ if (Tcl_Gets(chan, &lineString) == TCL_IO_FAILURE) {
return NULL;
}
line = Tcl_DStringValue(&lineString);
@@ -1798,10 +1845,10 @@ LoadTableEncoding(
}
/*
- * Invert toUnicode array to produce the fromUnicode array. Performs a
+ * Invert the toUnicode array to produce the fromUnicode array. Performs a
* single malloc to get the memory for the array and all the pages needed
- * by the array. While reading in the toUnicode array, we remembered what
- * pages that would be needed for the fromUnicode array.
+ * by the array. While reading in the toUnicode array remember what
+ * pages are needed for the fromUnicode array.
*/
if (symbol) {
@@ -1840,8 +1887,8 @@ LoadTableEncoding(
if (type == ENCODING_MULTIBYTE) {
/*
* If multibyte encodings don't have a backslash character, define
- * one. Otherwise, on Windows, native file names won't work because
- * the backslash in the file name will map to the unknown character
+ * one. Otherwise, on Windows, native file names don't work because
+ * the backslash in the file name maps to the unknown character
* (question mark) when converting from UTF-8 to external encoding.
*/
@@ -1853,13 +1900,13 @@ LoadTableEncoding(
}
if (symbol) {
/*
- * Make a special symbol encoding that not only maps the symbol
- * characters from their Unicode code points down into page 0, but
- * also ensure that the characters on page 0 map to themselves. This
- * is so that a symbol font can be used to display a simple string
- * like "abcd" and have alpha, beta, chi, delta show up, rather than
- * have "unknown" chars show up because strictly speaking the symbol
- * font doesn't have glyphs for those low ASCII chars.
+ * Make a special symbol encoding that maps each symbol character from
+ * its Unicode code point down into page 0, and also ensure that each
+ * characters on page 0 maps to itself so that a symbol font can be
+ * used to display a simple string like "abcd" and have alpha, beta,
+ * chi, delta show up, rather than have "unknown" chars show up because
+ * strictly speaking the symbol font doesn't have glyphs for those low
+ * ASCII chars.
*/
page = dataPtr->fromUnicode[0];
@@ -1906,7 +1953,7 @@ LoadTableEncoding(
}
/*
- * Read lines from the encoding until EOF.
+ * Read lines until EOF.
*/
for (TclDStringClear(&lineString);
@@ -1983,7 +2030,7 @@ LoadTableEncoding(
static Tcl_Encoding
LoadEscapeEncoding(
- const char *name, /* Name for new encoding. */
+ const char *name, /* Name of the new encoding. */
Tcl_Channel chan) /* File containing new encoding. */
{
int i;
@@ -2319,7 +2366,7 @@ UtfToUtfProc(
}
dstStart = dst;
- dstEnd = dst + dstLen - ((pureNullMode == 1) ? 4 : TCL_UTF_MAX);
+ dstEnd = dst + dstLen - TCL_UTF_MAX;
for (numChars = 0; src < srcEnd && numChars <= charLimit; numChars++) {
if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
@@ -2365,21 +2412,14 @@ UtfToUtfProc(
if ((*chPtr & 0xFC00) == 0xD800) {
/* A high surrogate character is detected, handle especially */
Tcl_UniChar low = *chPtr;
- size_t len = (src <= srcEnd-3) ? Tcl_UtfToUniChar(src, &low) : 0;
+ if (src <= srcEnd-3) {
+ Tcl_UtfToUniChar(src, &low);
+ }
if ((low & 0xFC00) != 0xDC00) {
*dst++ = (char) (((*chPtr >> 12) | 0xE0) & 0xEF);
*dst++ = (char) (((*chPtr >> 6) | 0x80) & 0xBF);
*dst++ = (char) ((*chPtr | 0x80) & 0xBF);
continue;
- } else if (pureNullMode == 1) {
- int full = (((*chPtr & 0x3FF) << 10) | (low & 0x3FF)) + 0x10000;
- *dst++ = (char) (((full >> 18) | 0xF0) & 0xF7);
- *dst++ = (char) (((full >> 12) | 0x80) & 0xBF);
- *dst++ = (char) (((full >> 6) | 0x80) & 0xBF);
- *dst++ = (char) ((full | 0x80) & 0xBF);
- *chPtr = 0;
- src += len;
- continue;
}
}
dst += Tcl_UniCharToUtf(*chPtr, dst);
@@ -2395,9 +2435,9 @@ UtfToUtfProc(
/*
*-------------------------------------------------------------------------
*
- * UnicodeToUtfProc --
+ * Utf16ToUtfProc --
*
- * Convert from Unicode to UTF-8.
+ * Convert from UTF-16 to UTF-8.
*
* Results:
* Returns TCL_OK if conversion was successful.
@@ -2409,8 +2449,8 @@ UtfToUtfProc(
*/
static int
-UnicodeToUtfProc(
- ClientData clientData, /* Not used. */
+Utf16ToUtfProc(
+ ClientData clientData, /* != NULL means LE, == NUL means BE */
const char *src, /* Source string in Unicode. */
int srcLen, /* Source string length in bytes. */
int flags, /* Conversion control flags. */
@@ -2438,16 +2478,22 @@ UnicodeToUtfProc(
const char *srcStart, *srcEnd;
const char *dstEnd, *dstStart;
int result, numChars, charLimit = INT_MAX;
- Tcl_UniChar ch;
+ unsigned short ch;
if (flags & TCL_ENCODING_CHAR_LIMIT) {
charLimit = *dstCharsPtr;
}
result = TCL_OK;
- if ((srcLen % sizeof(Tcl_UniChar)) != 0) {
+
+ /* check alignment with utf-16 (2 == sizeof(UTF-16)) */
+ if ((srcLen % 2) != 0) {
+ result = TCL_CONVERT_MULTIBYTE;
+ srcLen--;
+ }
+ /* If last code point is a high surrogate, we cannot handle that yet */
+ if ((srcLen >= 2) && ((src[srcLen - (clientData?1:2)] & 0xFC) == 0xD8)) {
result = TCL_CONVERT_MULTIBYTE;
- srcLen /= sizeof(Tcl_UniChar);
- srcLen *= sizeof(Tcl_UniChar);
+ srcLen-= 2;
}
srcStart = src;
@@ -2462,18 +2508,21 @@ UnicodeToUtfProc(
break;
}
+ if (clientData) {
+ ch = (src[1] & 0xFF) << 8 | (src[0] & 0xFF);
+ } else {
+ ch = (src[0] & 0xFF) << 8 | (src[1] & 0xFF);
+ }
/*
* Special case for 1-byte utf chars for speed. Make sure we work with
- * Tcl_UniChar-size data.
+ * unsigned short-size data.
*/
-
- ch = *(Tcl_UniChar *)src;
if (ch && ch < 0x80) {
*dst++ = (ch & 0xFF);
} else {
dst += Tcl_UniCharToUtf(ch, dst);
}
- src += sizeof(Tcl_UniChar);
+ src += sizeof(unsigned short);
}
*srcReadPtr = src - srcStart;
@@ -2485,9 +2534,9 @@ UnicodeToUtfProc(
/*
*-------------------------------------------------------------------------
*
- * UtfToUnicodeProc --
+ * UtfToUtf16Proc --
*
- * Convert from UTF-8 to Unicode.
+ * Convert from UTF-8 to UTF-16.
*
* Results:
* Returns TCL_OK if conversion was successful.
@@ -2499,9 +2548,8 @@ UnicodeToUtfProc(
*/
static int
-UtfToUnicodeProc(
- ClientData clientData, /* TableEncodingData that specifies
- * encoding. */
+UtfToUtf16Proc(
+ ClientData clientData, /* != NULL means LE, == NUL means BE */
const char *src, /* Source string in UTF-8. */
int srcLen, /* Source string length in bytes. */
int flags, /* Conversion control flags. */
@@ -2565,27 +2613,37 @@ UtfToUnicodeProc(
* casting dst to a Tcl_UniChar. [Bug 1122671]
*/
-#ifdef WORDS_BIGENDIAN
+ if (clientData) {
#if TCL_UTF_MAX > 4
- *dst++ = (*chPtr >> 24);
- *dst++ = ((*chPtr >> 16) & 0xFF);
- *dst++ = ((*chPtr >> 8) & 0xFF);
- *dst++ = (*chPtr & 0xFF);
+ if (*chPtr <= 0xFFFF) {
+ *dst++ = (*chPtr & 0xFF);
+ *dst++ = (*chPtr >> 8);
+ } else {
+ *dst++ = (((*chPtr - 0x10000) >> 10) & 0xFF);
+ *dst++ = (((*chPtr - 0x10000) >> 18) & 0x3) | 0xD8;
+ *dst++ = (*chPtr & 0xFF);
+ *dst++ = ((*chPtr & 0x3) >> 8) | 0xDC;
+ }
#else
- *dst++ = (*chPtr >> 8);
- *dst++ = (*chPtr & 0xFF);
+ *dst++ = (*chPtr & 0xFF);
+ *dst++ = (*chPtr >> 8);
#endif
-#else
+ } else {
#if TCL_UTF_MAX > 4
- *dst++ = (*chPtr & 0xFF);
- *dst++ = ((*chPtr >> 8) & 0xFF);
- *dst++ = ((*chPtr >> 16) & 0xFF);
- *dst++ = (*chPtr >> 24);
+ if (*chPtr <= 0xFFFF) {
+ *dst++ = (*chPtr >> 8);
+ *dst++ = (*chPtr & 0xFF);
+ } else {
+ *dst++ = ((*chPtr & 0x3) >> 8) | 0xDC;
+ *dst++ = (*chPtr & 0xFF);
+ *dst++ = (((*chPtr - 0x10000) >> 18) & 0x3) | 0xD8;
+ *dst++ = (((*chPtr - 0x10000) >> 10) & 0xFF);
+ }
#else
- *dst++ = (*chPtr & 0xFF);
- *dst++ = (*chPtr >> 8);
-#endif
+ *dst++ = (*chPtr >> 8);
+ *dst++ = (*chPtr & 0xFF);
#endif
+ }
}
*srcReadPtr = src - srcStart;
*dstWrotePtr = dst - dstStart;
@@ -2596,6 +2654,113 @@ UtfToUnicodeProc(
/*
*-------------------------------------------------------------------------
*
+ * UtfToUcs2Proc --
+ *
+ * Convert from UTF-8 to UCS-2.
+ *
+ * Results:
+ * Returns TCL_OK if conversion was successful.
+ *
+ * Side effects:
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static int
+UtfToUcs2Proc(
+ ClientData clientData, /* != NULL means LE, == NUL means BE */
+ const char *src, /* Source string in UTF-8. */
+ int srcLen, /* Source string length in bytes. */
+ int flags, /* Conversion control flags. */
+ Tcl_EncodingState *statePtr,/* Place for conversion routine to store state
+ * information used during a piecewise
+ * conversion. Contents of statePtr are
+ * initialized and/or reset by conversion
+ * routine under control of flags argument. */
+ char *dst, /* Output buffer in which converted string is
+ * stored. */
+ int dstLen, /* The maximum length of output buffer in
+ * bytes. */
+ int *srcReadPtr, /* Filled with the number of bytes from the
+ * source string that were converted. This may
+ * be less than the original source length if
+ * there was a problem converting some source
+ * characters. */
+ int *dstWrotePtr, /* Filled with the number of bytes that were
+ * stored in the output buffer as a result of
+ * the conversion. */
+ int *dstCharsPtr) /* Filled with the number of characters that
+ * correspond to the bytes stored in the
+ * output buffer. */
+{
+ const char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd;
+ int result, numChars;
+#if TCL_UTF_MAX <= 4
+ int len;
+#endif
+ Tcl_UniChar ch = 0;
+
+ srcStart = src;
+ srcEnd = src + srcLen;
+ srcClose = srcEnd;
+ if ((flags & TCL_ENCODING_END) == 0) {
+ srcClose -= TCL_UTF_MAX;
+ }
+
+ dstStart = dst;
+ dstEnd = dst + dstLen - sizeof(Tcl_UniChar);
+
+ result = TCL_OK;
+ for (numChars = 0; src < srcEnd; numChars++) {
+ if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
+ /*
+ * If there is more string to follow, this will ensure that the
+ * last UTF-8 character in the source buffer hasn't been cut off.
+ */
+
+ result = TCL_CONVERT_MULTIBYTE;
+ break;
+ }
+ if (dst > dstEnd) {
+ result = TCL_CONVERT_NOSPACE;
+ break;
+ }
+#if TCL_UTF_MAX <= 4
+ src += (len = TclUtfToUniChar(src, &ch));
+ if ((ch >= 0xD800) && (len < 3)) {
+ src += TclUtfToUniChar(src, &ch);
+ ch = 0xFFFD;
+ }
+#else
+ src += TclUtfToUniChar(src, &ch);
+ if (ch > 0xFFFF) {
+ ch = 0xFFFD;
+ }
+#endif
+
+ /*
+ * Need to handle this in a way that won't cause misalignment by
+ * casting dst to a Tcl_UniChar. [Bug 1122671]
+ */
+
+ if (clientData) {
+ *dst++ = (ch & 0xFF);
+ *dst++ = (ch >> 8);
+ } else {
+ *dst++ = (ch >> 8);
+ *dst++ = (ch & 0xFF);
+ }
+ }
+ *srcReadPtr = src - srcStart;
+ *dstWrotePtr = dst - dstStart;
+ *dstCharsPtr = numChars;
+ return result;
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
* TableToUtfProc --
*
* Convert from the encoding specified by the TableEncodingData into
@@ -2794,7 +2959,7 @@ TableFromUtfProc(
if (ch & 0xffff0000) {
word = 0;
} else
-#elif TCL_UTF_MAX == 4
+#else
if (!len) {
word = 0;
} else
@@ -2996,7 +3161,7 @@ Iso88591FromUtfProc(
*/
if (ch > 0xff
-#if TCL_UTF_MAX == 4
+#if TCL_UTF_MAX <= 4
|| ((ch >= 0xD800) && (len < 3))
#endif
) {
@@ -3004,10 +3169,9 @@ Iso88591FromUtfProc(
result = TCL_CONVERT_UNKNOWN;
break;
}
-#if TCL_UTF_MAX == 4
+#if TCL_UTF_MAX <= 4
if ((ch >= 0xD800) && (len < 3)) len = 4;
#endif
-
/*
* Plunge on, using '?' as a fallback character.
*/
@@ -3496,14 +3660,13 @@ EscapeFromUtfProc(
*
* EscapeFreeProc --
*
- * This function is invoked when an EscapeEncodingData encoding is
- * deleted. It deletes the memory used by the encoding.
+ * Frees resources used by the encoding.
*
* Results:
* None.
*
* Side effects:
- * Memory freed.
+ * Memory is freed.
*
*---------------------------------------------------------------------------
*/
@@ -3641,11 +3804,11 @@ unilen(
static void
InitializeEncodingSearchPath(
char **valuePtr,
- int *lengthPtr,
+ unsigned int *lengthPtr,
Tcl_Encoding *encodingPtr)
{
const char *bytes;
- int i, numDirs, numBytes;
+ int i, numDirs;
Tcl_Obj *libPathObj, *encodingObj, *searchPathObj;
TclNewLiteralStringObj(encodingObj, "encoding");
@@ -3675,11 +3838,11 @@ InitializeEncodingSearchPath(
if (*encodingPtr) {
((Encoding *)(*encodingPtr))->refCount++;
}
- bytes = Tcl_GetStringFromObj(searchPathObj, &numBytes);
+ bytes = TclGetString(searchPathObj);
- *lengthPtr = numBytes;
- *valuePtr = ckalloc(numBytes + 1);
- memcpy(*valuePtr, bytes, (size_t) numBytes + 1);
+ *lengthPtr = searchPathObj->length;
+ *valuePtr = ckalloc(*lengthPtr + 1);
+ memcpy(*valuePtr, bytes, *lengthPtr + 1);
Tcl_DecrRefCount(searchPathObj);
}