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