Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/intl/icu/source/common/ucnv_cb.cpp
Line
Count
Source (jump to first uncovered line)
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
**********************************************************************
5
*   Copyright (C) 2000-2006, International Business Machines
6
*   Corporation and others.  All Rights Reserved.
7
**********************************************************************
8
 *  ucnv_cb.c:
9
 *  External APIs for the ICU's codeset conversion library
10
 *  Helena Shih
11
 *
12
 * Modification History:
13
 *
14
 *   Date        Name        Description
15
 *   7/28/2000   srl         Implementation
16
 */
17
18
/**
19
 * @name Character Conversion C API
20
 *
21
 */
22
23
#include "unicode/utypes.h"
24
25
#if !UCONFIG_NO_CONVERSION
26
27
#include "unicode/ucnv_cb.h"
28
#include "ucnv_bld.h"
29
#include "ucnv_cnv.h"
30
#include "cmemory.h"
31
32
/* need to update the offsets when the target moves. */
33
/* Note: Recursion may occur in the cb functions, be sure to update the offsets correctly
34
if you don't use ucnv_cbXXX functions.  Make sure you don't use the same callback within
35
the same call stack if the complexity arises. */
36
U_CAPI void  U_EXPORT2
37
ucnv_cbFromUWriteBytes (UConverterFromUnicodeArgs *args,
38
                       const char* source,
39
                       int32_t length,
40
                       int32_t offsetIndex,
41
                       UErrorCode * err)
42
0
{
43
0
    if(U_FAILURE(*err)) {
44
0
        return;
45
0
    }
46
0
47
0
    ucnv_fromUWriteBytes(
48
0
        args->converter,
49
0
        source, length,
50
0
        &args->target, args->targetLimit,
51
0
        &args->offsets, offsetIndex,
52
0
        err);
53
0
}
54
55
U_CAPI void  U_EXPORT2
56
ucnv_cbFromUWriteUChars(UConverterFromUnicodeArgs *args,
57
                             const UChar** source,
58
                             const UChar*  sourceLimit,
59
                             int32_t offsetIndex,
60
                             UErrorCode * err)
61
0
{
62
0
    /*
63
0
    This is a fun one.  Recursion can occur - we're basically going to
64
0
    just retry shoving data through the same converter. Note, if you got
65
0
    here through some kind of invalid sequence, you maybe should emit a
66
0
    reset sequence of some kind and/or call ucnv_reset().  Since this
67
0
    IS an actual conversion, take care that you've changed the callback
68
0
    or the data, or you'll get an infinite loop.
69
0
70
0
    Please set the err value to something reasonable before calling
71
0
    into this.
72
0
    */
73
0
74
0
    char *oldTarget;
75
0
76
0
    if(U_FAILURE(*err))
77
0
    {
78
0
        return;
79
0
    }
80
0
81
0
    oldTarget = args->target;
82
0
83
0
    ucnv_fromUnicode(args->converter,
84
0
        &args->target,
85
0
        args->targetLimit,
86
0
        source,
87
0
        sourceLimit,
88
0
        NULL, /* no offsets */
89
0
        FALSE, /* no flush */
90
0
        err);
91
0
92
0
    if(args->offsets)
93
0
    {
94
0
        while (args->target != oldTarget)  /* if it moved at all.. */
95
0
        {
96
0
            *(args->offsets)++ = offsetIndex;
97
0
            oldTarget++;
98
0
        }
99
0
    }
100
0
101
0
    /*
102
0
    Note, if you did something like used a Stop subcallback, things would get interesting.
103
0
    In fact, here's where we want to return the partially consumed in-source!
104
0
    */
105
0
    if(*err == U_BUFFER_OVERFLOW_ERROR)
106
0
    /* && (*source < sourceLimit && args->target >= args->targetLimit)
107
0
    -- S. Hrcek */
108
0
    {
109
0
        /* Overflowed the target.  Now, we'll write into the charErrorBuffer.
110
0
        It's a fixed size. If we overflow it... Hmm */
111
0
        char *newTarget;
112
0
        const char *newTargetLimit;
113
0
        UErrorCode err2 = U_ZERO_ERROR;
114
0
115
0
        int8_t errBuffLen;
116
0
117
0
        errBuffLen  = args->converter->charErrorBufferLength;
118
0
119
0
        /* start the new target at the first free slot in the errbuff.. */
120
0
        newTarget = (char *)(args->converter->charErrorBuffer + errBuffLen);
121
0
122
0
        newTargetLimit = (char *)(args->converter->charErrorBuffer +
123
0
            sizeof(args->converter->charErrorBuffer));
124
0
125
0
        if(newTarget >= newTargetLimit)
126
0
        {
127
0
            *err = U_INTERNAL_PROGRAM_ERROR;
128
0
            return;
129
0
        }
130
0
131
0
        /* We're going to tell the converter that the errbuff len is empty.
132
0
        This prevents the existing errbuff from being 'flushed' out onto
133
0
        itself.  If the errbuff is needed by the converter this time,
134
0
        we're hosed - we're out of space! */
135
0
136
0
        args->converter->charErrorBufferLength = 0;
137
0
138
0
        ucnv_fromUnicode(args->converter,
139
0
                         &newTarget,
140
0
                         newTargetLimit,
141
0
                         source,
142
0
                         sourceLimit,
143
0
                         NULL,
144
0
                         FALSE,
145
0
                         &err2);
146
0
147
0
        /* We can go ahead and overwrite the  length here. We know just how
148
0
        to recalculate it. */
149
0
150
0
        args->converter->charErrorBufferLength = (int8_t)(
151
0
            newTarget - (char*)args->converter->charErrorBuffer);
152
0
153
0
        if((newTarget >= newTargetLimit) || (err2 == U_BUFFER_OVERFLOW_ERROR))
154
0
        {
155
0
            /* now we're REALLY in trouble.
156
0
            Internal program error - callback shouldn't have written this much
157
0
            data!
158
0
            */
159
0
            *err = U_INTERNAL_PROGRAM_ERROR;
160
0
            return;
161
0
        }
162
0
        /*else {*/
163
0
            /* sub errs could be invalid/truncated/illegal chars or w/e.
164
0
            These might want to be passed on up.. But the problem is, we already
165
0
            need to pass U_BUFFER_OVERFLOW_ERROR. That has to override these
166
0
            other errs.. */
167
0
168
0
            /*
169
0
            if(U_FAILURE(err2))
170
0
            ??
171
0
            */
172
0
        /*}*/
173
0
    }
174
0
}
175
176
U_CAPI void  U_EXPORT2
177
ucnv_cbFromUWriteSub (UConverterFromUnicodeArgs *args,
178
                           int32_t offsetIndex,
179
                           UErrorCode * err)
180
0
{
181
0
    UConverter *converter;
182
0
    int32_t length;
183
0
184
0
    if(U_FAILURE(*err)) {
185
0
        return;
186
0
    }
187
0
    converter = args->converter;
188
0
    length = converter->subCharLen;
189
0
190
0
    if(length == 0) {
191
0
        return;
192
0
    }
193
0
194
0
    if(length < 0) {
195
0
        /*
196
0
         * Write/convert the substitution string. Its real length is -length.
197
0
         * Unlike the escape callback, we need not change the converter's
198
0
         * callback function because ucnv_setSubstString() verified that
199
0
         * the string can be converted, so we will not get a conversion error
200
0
         * and will not recurse.
201
0
         * At worst we should get a U_BUFFER_OVERFLOW_ERROR.
202
0
         */
203
0
        const UChar *source = (const UChar *)converter->subChars;
204
0
        ucnv_cbFromUWriteUChars(args, &source, source - length, offsetIndex, err);
205
0
        return;
206
0
    }
207
0
208
0
    if(converter->sharedData->impl->writeSub!=NULL) {
209
0
        converter->sharedData->impl->writeSub(args, offsetIndex, err);
210
0
    }
211
0
    else if(converter->subChar1!=0 && (uint16_t)converter->invalidUCharBuffer[0]<=(uint16_t)0xffu) {
212
0
        /*
213
0
        TODO: Is this untestable because the MBCS converter has a writeSub function to call
214
0
        and the other converters don't use subChar1?
215
0
        */
216
0
        ucnv_cbFromUWriteBytes(args,
217
0
                               (const char *)&converter->subChar1, 1,
218
0
                               offsetIndex, err);
219
0
    }
220
0
    else {
221
0
        ucnv_cbFromUWriteBytes(args,
222
0
                               (const char *)converter->subChars, length,
223
0
                               offsetIndex, err);
224
0
    }
225
0
}
226
227
U_CAPI void  U_EXPORT2
228
ucnv_cbToUWriteUChars (UConverterToUnicodeArgs *args,
229
                            const UChar* source,
230
                            int32_t length,
231
                            int32_t offsetIndex,
232
                            UErrorCode * err)
233
0
{
234
0
    if(U_FAILURE(*err)) {
235
0
        return;
236
0
    }
237
0
238
0
    ucnv_toUWriteUChars(
239
0
        args->converter,
240
0
        source, length,
241
0
        &args->target, args->targetLimit,
242
0
        &args->offsets, offsetIndex,
243
0
        err);
244
0
}
245
246
U_CAPI void  U_EXPORT2
247
ucnv_cbToUWriteSub (UConverterToUnicodeArgs *args,
248
                         int32_t offsetIndex,
249
                       UErrorCode * err)
250
0
{
251
0
    static const UChar kSubstituteChar1 = 0x1A, kSubstituteChar = 0xFFFD;
252
0
253
0
    /* could optimize this case, just one uchar */
254
0
    if(args->converter->invalidCharLength == 1 && args->converter->subChar1 != 0) {
255
0
        ucnv_cbToUWriteUChars(args, &kSubstituteChar1, 1, offsetIndex, err);
256
0
    } else {
257
0
        ucnv_cbToUWriteUChars(args, &kSubstituteChar, 1, offsetIndex, err);
258
0
    }
259
0
}
260
261
#endif