]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | /************************************************************************** |
2 | * © 2016 and later: Unicode, Inc. and others. | |
3 | * License & terms of use: http://www.unicode.org/copyright.html#License | |
4 | ************************************************************************** | |
5 | ************************************************************************** | |
b75a7d8f | 6 | * COPYRIGHT: |
46f4442e | 7 | * Copyright (c) 1999-2007, International Business Machines Corporation and |
b75a7d8f | 8 | * others. All Rights Reserved. |
f3c0d7a5 | 9 | **************************************************************************/ |
b75a7d8f A |
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; | |
46f4442e | 52 | const void *saveContext; |
b75a7d8f A |
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; | |
46f4442e | 200 | const void *saveContext; |
b75a7d8f A |
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 | } |