Imported Upstream version 58.1
[platform/upstream/icu.git] / source / samples / ucnv / flagcb.c
1 /**************************************************************************
2  * Copyright (C) 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
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;
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
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;
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
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 }