Home | History | Annotate | Download | only in ucnv
      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 
     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;
     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 
    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;
    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 
    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