You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
9.0 KiB
293 lines
9.0 KiB
/**************************************************************************
|
|
* © 2016 and later: Unicode, Inc. and others.
|
|
* License & terms of use: http://www.unicode.org/copyright.html
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* COPYRIGHT:
|
|
* Copyright (c) 1999-2007, International Business Machines Corporation and
|
|
* others. All Rights Reserved.
|
|
**************************************************************************/
|
|
|
|
#include "unicode/utypes.h"
|
|
#include "unicode/ucnv.h"
|
|
#include "flagcb.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#define DEBUG_TMI 0 /* set to 1 for Too Much Information (TMI) */
|
|
|
|
U_CAPI FromUFLAGContext* U_EXPORT2 flagCB_fromU_openContext()
|
|
{
|
|
FromUFLAGContext *ctx;
|
|
|
|
ctx = (FromUFLAGContext*) malloc(sizeof(FromUFLAGContext));
|
|
|
|
ctx->subCallback = NULL;
|
|
ctx->subContext = NULL;
|
|
ctx->flag = false;
|
|
|
|
return ctx;
|
|
}
|
|
|
|
U_CAPI void U_EXPORT2 flagCB_fromU(
|
|
const void *context,
|
|
UConverterFromUnicodeArgs *fromUArgs,
|
|
const UChar* codeUnits,
|
|
int32_t length,
|
|
UChar32 codePoint,
|
|
UConverterCallbackReason reason,
|
|
UErrorCode * err)
|
|
{
|
|
/* First step - based on the reason code, take action */
|
|
|
|
if(reason == UCNV_UNASSIGNED) { /* whatever set should be trapped here */
|
|
((FromUFLAGContext*)context)->flag = true;
|
|
}
|
|
|
|
if(reason == UCNV_CLONE) {
|
|
/* The following is the recommended way to implement UCNV_CLONE
|
|
in a callback. */
|
|
UConverterFromUCallback saveCallback;
|
|
const void *saveContext;
|
|
FromUFLAGContext *old, *cloned;
|
|
UErrorCode subErr = U_ZERO_ERROR;
|
|
|
|
#if DEBUG_TMI
|
|
printf("*** FLAGCB: cloning %p ***\n", context);
|
|
#endif
|
|
old = (FromUFLAGContext*)context;
|
|
cloned = flagCB_fromU_openContext();
|
|
|
|
memcpy(cloned, old, sizeof(FromUFLAGContext));
|
|
|
|
#if DEBUG_TMI
|
|
printf("%p: my subcb=%p:%p\n", old, old->subCallback,
|
|
old->subContext);
|
|
printf("%p: cloned subcb=%p:%p\n", cloned, cloned->subCallback,
|
|
cloned->subContext);
|
|
#endif
|
|
|
|
/* We need to get the sub CB to handle cloning,
|
|
* so we have to set up the following, temporarily:
|
|
*
|
|
* - Set the callback+context to the sub of this (flag) cb
|
|
* - preserve the current cb+context, it could be anything
|
|
*
|
|
* Before:
|
|
* CNV -> FLAG -> subcb -> ...
|
|
*
|
|
* After:
|
|
* CNV -> subcb -> ...
|
|
*
|
|
* The chain from 'something' on is saved, and will be restored
|
|
* at the end of this block.
|
|
*
|
|
*/
|
|
|
|
ucnv_setFromUCallBack(fromUArgs->converter,
|
|
cloned->subCallback,
|
|
cloned->subContext,
|
|
&saveCallback,
|
|
&saveContext,
|
|
&subErr);
|
|
|
|
if( cloned->subCallback != NULL ) {
|
|
/* Now, call the sub callback if present */
|
|
cloned->subCallback(cloned->subContext, fromUArgs, codeUnits,
|
|
length, codePoint, reason, err);
|
|
}
|
|
|
|
ucnv_setFromUCallBack(fromUArgs->converter,
|
|
saveCallback, /* Us */
|
|
cloned, /* new context */
|
|
&cloned->subCallback, /* IMPORTANT! Accept any change in CB or context */
|
|
&cloned->subContext,
|
|
&subErr);
|
|
|
|
if(U_FAILURE(subErr)) {
|
|
*err = subErr;
|
|
}
|
|
}
|
|
|
|
/* process other reasons here if need be */
|
|
|
|
/* Always call the subCallback if present */
|
|
if(((FromUFLAGContext*)context)->subCallback != NULL &&
|
|
reason != UCNV_CLONE) {
|
|
((FromUFLAGContext*)context)->subCallback( ((FromUFLAGContext*)context)->subContext,
|
|
fromUArgs,
|
|
codeUnits,
|
|
length,
|
|
codePoint,
|
|
reason,
|
|
err);
|
|
}
|
|
|
|
/* cleanup - free the memory AFTER calling the sub CB */
|
|
if(reason == UCNV_CLOSE) {
|
|
free((void*)context);
|
|
}
|
|
}
|
|
|
|
/* Debugging callback, just outputs what happens */
|
|
|
|
/* Test safe clone callback */
|
|
|
|
static uint32_t debugCB_nextSerial()
|
|
{
|
|
static uint32_t n = 1;
|
|
|
|
return (n++);
|
|
}
|
|
|
|
static void debugCB_print_log(debugCBContext *q, const char *name)
|
|
{
|
|
if(q==NULL) {
|
|
printf("debugCBontext: %s is NULL!!\n", name);
|
|
} else {
|
|
if(q->magic != 0xC0FFEE) {
|
|
fprintf(stderr, "debugCBContext: %p:%d's magic is %x, supposed to be 0xC0FFEE\n",
|
|
q,q->serial, q->magic);
|
|
}
|
|
printf("debugCBContext %p:%d=%s - magic %x\n",
|
|
q, q->serial, name, q->magic);
|
|
}
|
|
}
|
|
|
|
static debugCBContext *debugCB_clone(debugCBContext *ctx)
|
|
{
|
|
debugCBContext *newCtx;
|
|
newCtx = malloc(sizeof(debugCBContext));
|
|
|
|
newCtx->serial = debugCB_nextSerial();
|
|
newCtx->magic = 0xC0FFEE;
|
|
|
|
newCtx->subCallback = ctx->subCallback;
|
|
newCtx->subContext = ctx->subContext;
|
|
|
|
#if DEBUG_TMI
|
|
printf("debugCB_clone: %p:%d -> new context %p:%d\n", ctx, ctx->serial, newCtx, newCtx->serial);
|
|
#endif
|
|
|
|
return newCtx;
|
|
}
|
|
|
|
void debugCB_fromU(const void *context,
|
|
UConverterFromUnicodeArgs *fromUArgs,
|
|
const UChar* codeUnits,
|
|
int32_t length,
|
|
UChar32 codePoint,
|
|
UConverterCallbackReason reason,
|
|
UErrorCode * err)
|
|
{
|
|
debugCBContext *ctx = (debugCBContext*)context;
|
|
/*UConverterFromUCallback junkFrom;*/
|
|
|
|
#if DEBUG_TMI
|
|
printf("debugCB_fromU: Context %p:%d called, reason %d on cnv %p [err=%s]\n", ctx, ctx->serial, reason, fromUArgs->converter, u_errorName(*err));
|
|
#endif
|
|
|
|
if(ctx->magic != 0xC0FFEE) {
|
|
fprintf(stderr, "debugCB_fromU: Context %p:%d magic is 0x%x should be 0xC0FFEE.\n", ctx,ctx->serial, ctx->magic);
|
|
return;
|
|
}
|
|
|
|
if(reason == UCNV_CLONE) {
|
|
/* see comments in above flagCB clone code */
|
|
|
|
UConverterFromUCallback saveCallback;
|
|
const void *saveContext;
|
|
debugCBContext *cloned;
|
|
UErrorCode subErr = U_ZERO_ERROR;
|
|
|
|
/* "recreate" it */
|
|
#if DEBUG_TMI
|
|
printf("debugCB_fromU: cloning..\n");
|
|
#endif
|
|
cloned = debugCB_clone(ctx);
|
|
|
|
if(cloned == NULL) {
|
|
fprintf(stderr, "debugCB_fromU: internal clone failed on %p\n", ctx);
|
|
*err = U_MEMORY_ALLOCATION_ERROR;
|
|
return;
|
|
}
|
|
|
|
ucnv_setFromUCallBack(fromUArgs->converter,
|
|
cloned->subCallback,
|
|
cloned->subContext,
|
|
&saveCallback,
|
|
&saveContext,
|
|
&subErr);
|
|
|
|
if( cloned->subCallback != NULL) {
|
|
#if DEBUG_TMI
|
|
printf("debugCB_fromU:%p calling subCB %p\n", ctx, cloned->subCallback);
|
|
#endif
|
|
/* call subCB if present */
|
|
cloned->subCallback(cloned->subContext, fromUArgs, codeUnits,
|
|
length, codePoint, reason, err);
|
|
} else {
|
|
printf("debugCB_fromU:%p, NOT calling subCB, it's NULL\n", ctx);
|
|
}
|
|
|
|
/* set back callback */
|
|
ucnv_setFromUCallBack(fromUArgs->converter,
|
|
saveCallback, /* Us */
|
|
cloned, /* new context */
|
|
&cloned->subCallback, /* IMPORTANT! Accept any change in CB or context */
|
|
&cloned->subContext,
|
|
&subErr);
|
|
|
|
if(U_FAILURE(subErr)) {
|
|
*err = subErr;
|
|
}
|
|
}
|
|
|
|
/* process other reasons here */
|
|
|
|
/* always call subcb if present */
|
|
if(ctx->subCallback != NULL && reason != UCNV_CLONE) {
|
|
ctx->subCallback(ctx->subContext,
|
|
fromUArgs,
|
|
codeUnits,
|
|
length,
|
|
codePoint,
|
|
reason,
|
|
err);
|
|
}
|
|
|
|
if(reason == UCNV_CLOSE) {
|
|
#if DEBUG_TMI
|
|
printf("debugCB_fromU: Context %p:%d closing\n", ctx, ctx->serial);
|
|
#endif
|
|
free(ctx);
|
|
}
|
|
|
|
#if DEBUG_TMI
|
|
printf("debugCB_fromU: leaving cnv %p, ctx %p: err %s\n", fromUArgs->converter, ctx, u_errorName(*err));
|
|
#endif
|
|
}
|
|
|
|
debugCBContext *debugCB_openContext()
|
|
{
|
|
debugCBContext *ctx;
|
|
|
|
ctx = malloc(sizeof(debugCBContext));
|
|
|
|
if(ctx != NULL) {
|
|
ctx->magic = 0xC0FFEE;
|
|
ctx->serial = debugCB_nextSerial();
|
|
ctx->subCallback = NULL;
|
|
ctx->subContext = NULL;
|
|
|
|
#if DEBUG_TMI
|
|
fprintf(stderr, "debugCB:openContext opened[%p] = serial #%d\n", ctx, ctx->serial);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
return ctx;
|
|
}
|