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
flagCB_fromU_openContext()16 U_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
flagCB_fromU(const void * context,UConverterFromUnicodeArgs * fromUArgs,const UChar * codeUnits,int32_t length,UChar32 codePoint,UConverterCallbackReason reason,UErrorCode * err)29 U_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
debugCB_nextSerial()133 static uint32_t debugCB_nextSerial()
134 {
135 static uint32_t n = 1;
136
137 return (n++);
138 }
139
debugCB_print_log(debugCBContext * q,const char * name)140 static 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
debugCB_clone(debugCBContext * ctx)154 static 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
debugCB_fromU(const void * context,UConverterFromUnicodeArgs * fromUArgs,const UChar * codeUnits,int32_t length,UChar32 codePoint,UConverterCallbackReason reason,UErrorCode * err)172 void 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
debugCB_openContext()268 debugCBContext *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