1 /**************************************************************************
2 * Copyright (C) 2016 and later: Unicode, Inc. and others.
3 * License & terms of use: http://www.unicode.org/copyright.html#License
4 **************************************************************************
5 **************************************************************************
7 * Copyright (c) 1999-2007, International Business Machines Corporation and
8 * others. All Rights Reserved.
9 **************************************************************************/
11 #include "unicode/utypes.h"
12 #include "unicode/ucnv.h"
18 #define DEBUG_TMI 0 /* set to 1 for Too Much Information (TMI) */
20 U_CAPI FromUFLAGContext* U_EXPORT2 flagCB_fromU_openContext()
22 FromUFLAGContext *ctx;
24 ctx = (FromUFLAGContext*) malloc(sizeof(FromUFLAGContext));
26 ctx->subCallback = NULL;
27 ctx->subContext = NULL;
33 U_CAPI void U_EXPORT2 flagCB_fromU(
35 UConverterFromUnicodeArgs *fromUArgs,
36 const UChar* codeUnits,
39 UConverterCallbackReason reason,
42 /* First step - based on the reason code, take action */
44 if(reason == UCNV_UNASSIGNED) { /* whatever set should be trapped here */
45 ((FromUFLAGContext*)context)->flag = TRUE;
48 if(reason == UCNV_CLONE) {
49 /* The following is the recommended way to implement UCNV_CLONE
51 UConverterFromUCallback saveCallback;
52 const void *saveContext;
53 FromUFLAGContext *old, *cloned;
54 UErrorCode subErr = U_ZERO_ERROR;
57 printf("*** FLAGCB: cloning %p ***\n", context);
59 old = (FromUFLAGContext*)context;
60 cloned = flagCB_fromU_openContext();
62 memcpy(cloned, old, sizeof(FromUFLAGContext));
65 printf("%p: my subcb=%p:%p\n", old, old->subCallback,
67 printf("%p: cloned subcb=%p:%p\n", cloned, cloned->subCallback,
71 /* We need to get the sub CB to handle cloning,
72 * so we have to set up the following, temporarily:
74 * - Set the callback+context to the sub of this (flag) cb
75 * - preserve the current cb+context, it could be anything
78 * CNV -> FLAG -> subcb -> ...
83 * The chain from 'something' on is saved, and will be restored
84 * at the end of this block.
88 ucnv_setFromUCallBack(fromUArgs->converter,
95 if( cloned->subCallback != NULL ) {
96 /* Now, call the sub callback if present */
97 cloned->subCallback(cloned->subContext, fromUArgs, codeUnits,
98 length, codePoint, reason, err);
101 ucnv_setFromUCallBack(fromUArgs->converter,
102 saveCallback, /* Us */
103 cloned, /* new context */
104 &cloned->subCallback, /* IMPORTANT! Accept any change in CB or context */
108 if(U_FAILURE(subErr)) {
113 /* process other reasons here if need be */
115 /* Always call the subCallback if present */
116 if(((FromUFLAGContext*)context)->subCallback != NULL &&
117 reason != UCNV_CLONE) {
118 ((FromUFLAGContext*)context)->subCallback( ((FromUFLAGContext*)context)->subContext,
127 /* cleanup - free the memory AFTER calling the sub CB */
128 if(reason == UCNV_CLOSE) {
129 free((void*)context);
133 /* Debugging callback, just outputs what happens */
135 /* Test safe clone callback */
137 static uint32_t debugCB_nextSerial()
139 static uint32_t n = 1;
144 static void debugCB_print_log(debugCBContext *q, const char *name)
147 printf("debugCBontext: %s is NULL!!\n", name);
149 if(q->magic != 0xC0FFEE) {
150 fprintf(stderr, "debugCBContext: %p:%d's magic is %x, supposed to be 0xC0FFEE\n",
151 q,q->serial, q->magic);
153 printf("debugCBContext %p:%d=%s - magic %x\n",
154 q, q->serial, name, q->magic);
158 static debugCBContext *debugCB_clone(debugCBContext *ctx)
160 debugCBContext *newCtx;
161 newCtx = malloc(sizeof(debugCBContext));
163 newCtx->serial = debugCB_nextSerial();
164 newCtx->magic = 0xC0FFEE;
166 newCtx->subCallback = ctx->subCallback;
167 newCtx->subContext = ctx->subContext;
170 printf("debugCB_clone: %p:%d -> new context %p:%d\n", ctx, ctx->serial, newCtx, newCtx->serial);
176 void debugCB_fromU(const void *context,
177 UConverterFromUnicodeArgs *fromUArgs,
178 const UChar* codeUnits,
181 UConverterCallbackReason reason,
184 debugCBContext *ctx = (debugCBContext*)context;
185 /*UConverterFromUCallback junkFrom;*/
188 printf("debugCB_fromU: Context %p:%d called, reason %d on cnv %p [err=%s]\n", ctx, ctx->serial, reason, fromUArgs->converter, u_errorName(*err));
191 if(ctx->magic != 0xC0FFEE) {
192 fprintf(stderr, "debugCB_fromU: Context %p:%d magic is 0x%x should be 0xC0FFEE.\n", ctx,ctx->serial, ctx->magic);
196 if(reason == UCNV_CLONE) {
197 /* see comments in above flagCB clone code */
199 UConverterFromUCallback saveCallback;
200 const void *saveContext;
201 debugCBContext *cloned;
202 UErrorCode subErr = U_ZERO_ERROR;
206 printf("debugCB_fromU: cloning..\n");
208 cloned = debugCB_clone(ctx);
211 fprintf(stderr, "debugCB_fromU: internal clone failed on %p\n", ctx);
212 *err = U_MEMORY_ALLOCATION_ERROR;
216 ucnv_setFromUCallBack(fromUArgs->converter,
223 if( cloned->subCallback != NULL) {
225 printf("debugCB_fromU:%p calling subCB %p\n", ctx, cloned->subCallback);
227 /* call subCB if present */
228 cloned->subCallback(cloned->subContext, fromUArgs, codeUnits,
229 length, codePoint, reason, err);
231 printf("debugCB_fromU:%p, NOT calling subCB, it's NULL\n", ctx);
234 /* set back callback */
235 ucnv_setFromUCallBack(fromUArgs->converter,
236 saveCallback, /* Us */
237 cloned, /* new context */
238 &cloned->subCallback, /* IMPORTANT! Accept any change in CB or context */
242 if(U_FAILURE(subErr)) {
247 /* process other reasons here */
249 /* always call subcb if present */
250 if(ctx->subCallback != NULL && reason != UCNV_CLONE) {
251 ctx->subCallback(ctx->subContext,
260 if(reason == UCNV_CLOSE) {
262 printf("debugCB_fromU: Context %p:%d closing\n", ctx, ctx->serial);
268 printf("debugCB_fromU: leaving cnv %p, ctx %p: err %s\n", fromUArgs->converter, ctx, u_errorName(*err));
272 debugCBContext *debugCB_openContext()
276 ctx = malloc(sizeof(debugCBContext));
279 ctx->magic = 0xC0FFEE;
280 ctx->serial = debugCB_nextSerial();
281 ctx->subCallback = NULL;
282 ctx->subContext = NULL;
285 fprintf(stderr, "debugCB:openContext opened[%p] = serial #%d\n", ctx, ctx->serial);