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