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