]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /******************************************************************** |
2 | * COPYRIGHT: | |
46f4442e | 3 | * Copyright (c) 1999-2007, International Business Machines Corporation and |
b75a7d8f A |
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 | ||
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 | ||
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; | |
46f4442e | 48 | const void *saveContext; |
b75a7d8f A |
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 | ||
133 | static uint32_t debugCB_nextSerial() | |
134 | { | |
135 | static uint32_t n = 1; | |
136 | ||
137 | return (n++); | |
138 | } | |
139 | ||
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 | ||
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 | ||
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; | |
46f4442e | 196 | const void *saveContext; |
b75a7d8f A |
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 | ||
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 | } |