1/******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1999-2007, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ********************************************************************/ 6 7#include "unicode/utypes.h" 8#include "unicode/ucnv.h" 9#include "flagcb.h" 10#include <string.h> 11#include <stdlib.h> 12#include <stdio.h> 13 14#define DEBUG_TMI 0 /* set to 1 for Too Much Information (TMI) */ 15 16U_CAPI FromUFLAGContext* U_EXPORT2 flagCB_fromU_openContext() 17{ 18 FromUFLAGContext *ctx; 19 20 ctx = (FromUFLAGContext*) malloc(sizeof(FromUFLAGContext)); 21 22 ctx->subCallback = NULL; 23 ctx->subContext = NULL; 24 ctx->flag = FALSE; 25 26 return ctx; 27} 28 29U_CAPI void U_EXPORT2 flagCB_fromU( 30 const void *context, 31 UConverterFromUnicodeArgs *fromUArgs, 32 const UChar* codeUnits, 33 int32_t length, 34 UChar32 codePoint, 35 UConverterCallbackReason reason, 36 UErrorCode * err) 37{ 38 /* First step - based on the reason code, take action */ 39 40 if(reason == UCNV_UNASSIGNED) { /* whatever set should be trapped here */ 41 ((FromUFLAGContext*)context)->flag = TRUE; 42 } 43 44 if(reason == UCNV_CLONE) { 45 /* The following is the recommended way to implement UCNV_CLONE 46 in a callback. */ 47 UConverterFromUCallback saveCallback; 48 const void *saveContext; 49 FromUFLAGContext *old, *cloned; 50 UErrorCode subErr = U_ZERO_ERROR; 51 52#if DEBUG_TMI 53 printf("*** FLAGCB: cloning %p ***\n", context); 54#endif 55 old = (FromUFLAGContext*)context; 56 cloned = flagCB_fromU_openContext(); 57 58 memcpy(cloned, old, sizeof(FromUFLAGContext)); 59 60#if DEBUG_TMI 61 printf("%p: my subcb=%p:%p\n", old, old->subCallback, 62 old->subContext); 63 printf("%p: cloned subcb=%p:%p\n", cloned, cloned->subCallback, 64 cloned->subContext); 65#endif 66 67 /* We need to get the sub CB to handle cloning, 68 * so we have to set up the following, temporarily: 69 * 70 * - Set the callback+context to the sub of this (flag) cb 71 * - preserve the current cb+context, it could be anything 72 * 73 * Before: 74 * CNV -> FLAG -> subcb -> ... 75 * 76 * After: 77 * CNV -> subcb -> ... 78 * 79 * The chain from 'something' on is saved, and will be restored 80 * at the end of this block. 81 * 82 */ 83 84 ucnv_setFromUCallBack(fromUArgs->converter, 85 cloned->subCallback, 86 cloned->subContext, 87 &saveCallback, 88 &saveContext, 89 &subErr); 90 91 if( cloned->subCallback != NULL ) { 92 /* Now, call the sub callback if present */ 93 cloned->subCallback(cloned->subContext, fromUArgs, codeUnits, 94 length, codePoint, reason, err); 95 } 96 97 ucnv_setFromUCallBack(fromUArgs->converter, 98 saveCallback, /* Us */ 99 cloned, /* new context */ 100 &cloned->subCallback, /* IMPORTANT! Accept any change in CB or context */ 101 &cloned->subContext, 102 &subErr); 103 104 if(U_FAILURE(subErr)) { 105 *err = subErr; 106 } 107 } 108 109 /* process other reasons here if need be */ 110 111 /* Always call the subCallback if present */ 112 if(((FromUFLAGContext*)context)->subCallback != NULL && 113 reason != UCNV_CLONE) { 114 ((FromUFLAGContext*)context)->subCallback( ((FromUFLAGContext*)context)->subContext, 115 fromUArgs, 116 codeUnits, 117 length, 118 codePoint, 119 reason, 120 err); 121 } 122 123 /* cleanup - free the memory AFTER calling the sub CB */ 124 if(reason == UCNV_CLOSE) { 125 free((void*)context); 126 } 127} 128 129/* Debugging callback, just outputs what happens */ 130 131/* Test safe clone callback */ 132 133static uint32_t debugCB_nextSerial() 134{ 135 static uint32_t n = 1; 136 137 return (n++); 138} 139 140static void debugCB_print_log(debugCBContext *q, const char *name) 141{ 142 if(q==NULL) { 143 printf("debugCBontext: %s is NULL!!\n", name); 144 } else { 145 if(q->magic != 0xC0FFEE) { 146 fprintf(stderr, "debugCBContext: %p:%d's magic is %x, supposed to be 0xC0FFEE\n", 147 q,q->serial, q->magic); 148 } 149 printf("debugCBContext %p:%d=%s - magic %x\n", 150 q, q->serial, name, q->magic); 151 } 152} 153 154static debugCBContext *debugCB_clone(debugCBContext *ctx) 155{ 156 debugCBContext *newCtx; 157 newCtx = malloc(sizeof(debugCBContext)); 158 159 newCtx->serial = debugCB_nextSerial(); 160 newCtx->magic = 0xC0FFEE; 161 162 newCtx->subCallback = ctx->subCallback; 163 newCtx->subContext = ctx->subContext; 164 165#if DEBUG_TMI 166 printf("debugCB_clone: %p:%d -> new context %p:%d\n", ctx, ctx->serial, newCtx, newCtx->serial); 167#endif 168 169 return newCtx; 170} 171 172void debugCB_fromU(const void *context, 173 UConverterFromUnicodeArgs *fromUArgs, 174 const UChar* codeUnits, 175 int32_t length, 176 UChar32 codePoint, 177 UConverterCallbackReason reason, 178 UErrorCode * err) 179{ 180 debugCBContext *ctx = (debugCBContext*)context; 181 /*UConverterFromUCallback junkFrom;*/ 182 183#if DEBUG_TMI 184 printf("debugCB_fromU: Context %p:%d called, reason %d on cnv %p [err=%s]\n", ctx, ctx->serial, reason, fromUArgs->converter, u_errorName(*err)); 185#endif 186 187 if(ctx->magic != 0xC0FFEE) { 188 fprintf(stderr, "debugCB_fromU: Context %p:%d magic is 0x%x should be 0xC0FFEE.\n", ctx,ctx->serial, ctx->magic); 189 return; 190 } 191 192 if(reason == UCNV_CLONE) { 193 /* see comments in above flagCB clone code */ 194 195 UConverterFromUCallback saveCallback; 196 const void *saveContext; 197 debugCBContext *cloned; 198 UErrorCode subErr = U_ZERO_ERROR; 199 200 /* "recreate" it */ 201#if DEBUG_TMI 202 printf("debugCB_fromU: cloning..\n"); 203#endif 204 cloned = debugCB_clone(ctx); 205 206 if(cloned == NULL) { 207 fprintf(stderr, "debugCB_fromU: internal clone failed on %p\n", ctx); 208 *err = U_MEMORY_ALLOCATION_ERROR; 209 return; 210 } 211 212 ucnv_setFromUCallBack(fromUArgs->converter, 213 cloned->subCallback, 214 cloned->subContext, 215 &saveCallback, 216 &saveContext, 217 &subErr); 218 219 if( cloned->subCallback != NULL) { 220#if DEBUG_TMI 221 printf("debugCB_fromU:%p calling subCB %p\n", ctx, cloned->subCallback); 222#endif 223 /* call subCB if present */ 224 cloned->subCallback(cloned->subContext, fromUArgs, codeUnits, 225 length, codePoint, reason, err); 226 } else { 227 printf("debugCB_fromU:%p, NOT calling subCB, it's NULL\n", ctx); 228 } 229 230 /* set back callback */ 231 ucnv_setFromUCallBack(fromUArgs->converter, 232 saveCallback, /* Us */ 233 cloned, /* new context */ 234 &cloned->subCallback, /* IMPORTANT! Accept any change in CB or context */ 235 &cloned->subContext, 236 &subErr); 237 238 if(U_FAILURE(subErr)) { 239 *err = subErr; 240 } 241 } 242 243 /* process other reasons here */ 244 245 /* always call subcb if present */ 246 if(ctx->subCallback != NULL && reason != UCNV_CLONE) { 247 ctx->subCallback(ctx->subContext, 248 fromUArgs, 249 codeUnits, 250 length, 251 codePoint, 252 reason, 253 err); 254 } 255 256 if(reason == UCNV_CLOSE) { 257#if DEBUG_TMI 258 printf("debugCB_fromU: Context %p:%d closing\n", ctx, ctx->serial); 259#endif 260 free(ctx); 261 } 262 263#if DEBUG_TMI 264 printf("debugCB_fromU: leaving cnv %p, ctx %p: err %s\n", fromUArgs->converter, ctx, u_errorName(*err)); 265#endif 266} 267 268debugCBContext *debugCB_openContext() 269{ 270 debugCBContext *ctx; 271 272 ctx = malloc(sizeof(debugCBContext)); 273 274 if(ctx != NULL) { 275 ctx->magic = 0xC0FFEE; 276 ctx->serial = debugCB_nextSerial(); 277 ctx->subCallback = NULL; 278 ctx->subContext = NULL; 279 280#if DEBUG_TMI 281 fprintf(stderr, "debugCB:openContext opened[%p] = serial #%d\n", ctx, ctx->serial); 282#endif 283 284 } 285 286 287 return ctx; 288} 289