1 /**************************************************************************
2 * © 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
flagCB_fromU_openContext()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
flagCB_fromU(const void * context,UConverterFromUnicodeArgs * fromUArgs,const UChar * codeUnits,int32_t length,UChar32 codePoint,UConverterCallbackReason reason,UErrorCode * err)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
debugCB_nextSerial()137 static uint32_t debugCB_nextSerial()
138 {
139 static uint32_t n = 1;
140
141 return (n++);
142 }
143
debugCB_print_log(debugCBContext * q,const char * name)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
debugCB_clone(debugCBContext * ctx)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
debugCB_fromU(const void * context,UConverterFromUnicodeArgs * fromUArgs,const UChar * codeUnits,int32_t length,UChar32 codePoint,UConverterCallbackReason reason,UErrorCode * err)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
debugCB_openContext()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