1/*
2*******************************************************************************
3*
4*   Copyright (C) 2005-2010, International Business Machines
5*   Corporation and others.  All Rights Reserved.
6*
7*******************************************************************************
8*   file name:  swapimpl.cpp
9*   encoding:   US-ASCII
10*   tab size:   8 (not used)
11*   indentation:4
12*
13*   created on: 2005may05
14*   created by: Markus W. Scherer
15*
16*   Data file swapping functions moved here from the common library
17*   because some data is hardcoded in ICU4C and needs not be swapped any more.
18*   Moving the functions here simplifies testing (for code coverage) because
19*   we need not jump through hoops (like adding snapshots of these files
20*   to testdata).
21*
22*   The declarations for these functions remain in the internal header files
23*   in icu/source/common/
24*/
25
26#include "unicode/utypes.h"
27#include "unicode/putil.h"
28#include "unicode/udata.h"
29
30/* Explicit include statement for std_string.h is needed
31 * for compilation on certain platforms. (e.g. AIX/VACPP)
32 */
33#include "unicode/std_string.h"
34
35#include "cmemory.h"
36#include "cstring.h"
37#include "uinvchar.h"
38#include "uassert.h"
39#include "uarrsort.h"
40#include "ucmndata.h"
41#include "udataswp.h"
42
43/* swapping implementations in common */
44
45#include "uresdata.h"
46#include "ucnv_io.h"
47#include "uprops.h"
48#include "ucase.h"
49#include "ubidi_props.h"
50#include "ucol_swp.h"
51#include "ucnv_bld.h"
52#include "unormimp.h"
53#include "normalizer2impl.h"
54#include "sprpimpl.h"
55#include "propname.h"
56#include "rbbidata.h"
57#include "triedict.h"
58#include "utrie2.h"
59
60/* swapping implementations in i18n */
61
62#if !UCONFIG_NO_NORMALIZATION
63#include "uspoof_impl.h"
64#endif
65
66
67/* definitions */
68
69#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
70
71/* Unicode properties data swapping ----------------------------------------- */
72
73U_CAPI int32_t U_EXPORT2
74uprops_swap(const UDataSwapper *ds,
75            const void *inData, int32_t length, void *outData,
76            UErrorCode *pErrorCode) {
77    const UDataInfo *pInfo;
78    int32_t headerSize, i;
79
80    int32_t dataIndexes[UPROPS_INDEX_COUNT];
81    const int32_t *inData32;
82
83    /* udata_swapDataHeader checks the arguments */
84    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
85    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
86        return 0;
87    }
88
89    /* check data format and format version */
90    pInfo=(const UDataInfo *)((const char *)inData+4);
91    if(!(
92        pInfo->dataFormat[0]==0x55 &&   /* dataFormat="UPro" */
93        pInfo->dataFormat[1]==0x50 &&
94        pInfo->dataFormat[2]==0x72 &&
95        pInfo->dataFormat[3]==0x6f &&
96        (3<=pInfo->formatVersion[0] && pInfo->formatVersion[0]<=7) &&
97        (pInfo->formatVersion[0]>=7 ||
98            (pInfo->formatVersion[2]==UTRIE_SHIFT &&
99             pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT))
100    )) {
101        udata_printError(ds, "uprops_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not a Unicode properties file\n",
102                         pInfo->dataFormat[0], pInfo->dataFormat[1],
103                         pInfo->dataFormat[2], pInfo->dataFormat[3],
104                         pInfo->formatVersion[0]);
105        *pErrorCode=U_UNSUPPORTED_ERROR;
106        return 0;
107    }
108
109    /* the properties file must contain at least the indexes array */
110    if(length>=0 && (length-headerSize)<(int32_t)sizeof(dataIndexes)) {
111        udata_printError(ds, "uprops_swap(): too few bytes (%d after header) for a Unicode properties file\n",
112                         length-headerSize);
113        *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
114        return 0;
115    }
116
117    /* read the indexes */
118    inData32=(const int32_t *)((const char *)inData+headerSize);
119    for(i=0; i<UPROPS_INDEX_COUNT; ++i) {
120        dataIndexes[i]=udata_readInt32(ds, inData32[i]);
121    }
122
123    /*
124     * comments are copied from the data format description in genprops/store.c
125     * indexes[] constants are in uprops.h
126     */
127    int32_t dataTop;
128    if(length>=0) {
129        int32_t *outData32;
130
131        /*
132         * In formatVersion 7, UPROPS_DATA_TOP_INDEX has the post-header data size.
133         * In earlier formatVersions, it is 0 and a lower dataIndexes entry
134         * has the top of the last item.
135         */
136        for(i=UPROPS_DATA_TOP_INDEX; i>0 && (dataTop=dataIndexes[i])==0; --i) {}
137
138        if((length-headerSize)<(4*dataTop)) {
139            udata_printError(ds, "uprops_swap(): too few bytes (%d after header) for a Unicode properties file\n",
140                             length-headerSize);
141            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
142            return 0;
143        }
144
145        outData32=(int32_t *)((char *)outData+headerSize);
146
147        /* copy everything for inaccessible data (padding) */
148        if(inData32!=outData32) {
149            uprv_memcpy(outData32, inData32, 4*dataTop);
150        }
151
152        /* swap the indexes[16] */
153        ds->swapArray32(ds, inData32, 4*UPROPS_INDEX_COUNT, outData32, pErrorCode);
154
155        /*
156         * swap the main properties UTrie
157         * PT serialized properties trie, see utrie.h (byte size: 4*(i0-16))
158         */
159        utrie2_swapAnyVersion(ds,
160            inData32+UPROPS_INDEX_COUNT,
161            4*(dataIndexes[UPROPS_PROPS32_INDEX]-UPROPS_INDEX_COUNT),
162            outData32+UPROPS_INDEX_COUNT,
163            pErrorCode);
164
165        /*
166         * swap the properties and exceptions words
167         * P  const uint32_t props32[i1-i0];
168         * E  const uint32_t exceptions[i2-i1];
169         */
170        ds->swapArray32(ds,
171            inData32+dataIndexes[UPROPS_PROPS32_INDEX],
172            4*(dataIndexes[UPROPS_EXCEPTIONS_TOP_INDEX]-dataIndexes[UPROPS_PROPS32_INDEX]),
173            outData32+dataIndexes[UPROPS_PROPS32_INDEX],
174            pErrorCode);
175
176        /*
177         * swap the UChars
178         * U  const UChar uchars[2*(i3-i2)];
179         */
180        ds->swapArray16(ds,
181            inData32+dataIndexes[UPROPS_EXCEPTIONS_TOP_INDEX],
182            4*(dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX]-dataIndexes[UPROPS_EXCEPTIONS_TOP_INDEX]),
183            outData32+dataIndexes[UPROPS_EXCEPTIONS_TOP_INDEX],
184            pErrorCode);
185
186        /*
187         * swap the additional UTrie
188         * i3 additionalTrieIndex; -- 32-bit unit index to the additional trie for more properties
189         */
190        utrie2_swapAnyVersion(ds,
191            inData32+dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX],
192            4*(dataIndexes[UPROPS_ADDITIONAL_VECTORS_INDEX]-dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX]),
193            outData32+dataIndexes[UPROPS_ADDITIONAL_TRIE_INDEX],
194            pErrorCode);
195
196        /*
197         * swap the properties vectors
198         * PV const uint32_t propsVectors[(i6-i4)/i5][i5]==uint32_t propsVectors[i6-i4];
199         */
200        ds->swapArray32(ds,
201            inData32+dataIndexes[UPROPS_ADDITIONAL_VECTORS_INDEX],
202            4*(dataIndexes[UPROPS_SCRIPT_EXTENSIONS_INDEX]-dataIndexes[UPROPS_ADDITIONAL_VECTORS_INDEX]),
203            outData32+dataIndexes[UPROPS_ADDITIONAL_VECTORS_INDEX],
204            pErrorCode);
205
206        // swap the Script_Extensions data
207        // SCX const uint16_t scriptExtensions[2*(i7-i6)];
208        ds->swapArray16(ds,
209            inData32+dataIndexes[UPROPS_SCRIPT_EXTENSIONS_INDEX],
210            4*(dataIndexes[UPROPS_RESERVED_INDEX_7]-dataIndexes[UPROPS_SCRIPT_EXTENSIONS_INDEX]),
211            outData32+dataIndexes[UPROPS_SCRIPT_EXTENSIONS_INDEX],
212            pErrorCode);
213    }
214
215    /* i7 reservedIndex7; -- 32-bit unit index to the top of the Script_Extensions data */
216    return headerSize+4*dataIndexes[UPROPS_RESERVED_INDEX_7];
217}
218
219/* Unicode case mapping data swapping --------------------------------------- */
220
221U_CAPI int32_t U_EXPORT2
222ucase_swap(const UDataSwapper *ds,
223           const void *inData, int32_t length, void *outData,
224           UErrorCode *pErrorCode) {
225    const UDataInfo *pInfo;
226    int32_t headerSize;
227
228    const uint8_t *inBytes;
229    uint8_t *outBytes;
230
231    const int32_t *inIndexes;
232    int32_t indexes[16];
233
234    int32_t i, offset, count, size;
235
236    /* udata_swapDataHeader checks the arguments */
237    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
238    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
239        return 0;
240    }
241
242    /* check data format and format version */
243    pInfo=(const UDataInfo *)((const char *)inData+4);
244    if(!(
245        pInfo->dataFormat[0]==UCASE_FMT_0 &&    /* dataFormat="cAsE" */
246        pInfo->dataFormat[1]==UCASE_FMT_1 &&
247        pInfo->dataFormat[2]==UCASE_FMT_2 &&
248        pInfo->dataFormat[3]==UCASE_FMT_3 &&
249        ((pInfo->formatVersion[0]==1 &&
250          pInfo->formatVersion[2]==UTRIE_SHIFT &&
251          pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT) ||
252         pInfo->formatVersion[0]==2)
253    )) {
254        udata_printError(ds, "ucase_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as case mapping data\n",
255                         pInfo->dataFormat[0], pInfo->dataFormat[1],
256                         pInfo->dataFormat[2], pInfo->dataFormat[3],
257                         pInfo->formatVersion[0]);
258        *pErrorCode=U_UNSUPPORTED_ERROR;
259        return 0;
260    }
261
262    inBytes=(const uint8_t *)inData+headerSize;
263    outBytes=(uint8_t *)outData+headerSize;
264
265    inIndexes=(const int32_t *)inBytes;
266
267    if(length>=0) {
268        length-=headerSize;
269        if(length<16*4) {
270            udata_printError(ds, "ucase_swap(): too few bytes (%d after header) for case mapping data\n",
271                             length);
272            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
273            return 0;
274        }
275    }
276
277    /* read the first 16 indexes (ICU 3.2/format version 1: UCASE_IX_TOP==16, might grow) */
278    for(i=0; i<16; ++i) {
279        indexes[i]=udata_readInt32(ds, inIndexes[i]);
280    }
281
282    /* get the total length of the data */
283    size=indexes[UCASE_IX_LENGTH];
284
285    if(length>=0) {
286        if(length<size) {
287            udata_printError(ds, "ucase_swap(): too few bytes (%d after header) for all of case mapping data\n",
288                             length);
289            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
290            return 0;
291        }
292
293        /* copy the data for inaccessible bytes */
294        if(inBytes!=outBytes) {
295            uprv_memcpy(outBytes, inBytes, size);
296        }
297
298        offset=0;
299
300        /* swap the int32_t indexes[] */
301        count=indexes[UCASE_IX_INDEX_TOP]*4;
302        ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
303        offset+=count;
304
305        /* swap the UTrie */
306        count=indexes[UCASE_IX_TRIE_SIZE];
307        utrie2_swapAnyVersion(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
308        offset+=count;
309
310        /* swap the uint16_t exceptions[] and unfold[] */
311        count=(indexes[UCASE_IX_EXC_LENGTH]+indexes[UCASE_IX_UNFOLD_LENGTH])*2;
312        ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
313        offset+=count;
314
315        U_ASSERT(offset==size);
316    }
317
318    return headerSize+size;
319}
320
321/* Unicode bidi/shaping data swapping --------------------------------------- */
322
323U_CAPI int32_t U_EXPORT2
324ubidi_swap(const UDataSwapper *ds,
325           const void *inData, int32_t length, void *outData,
326           UErrorCode *pErrorCode) {
327    const UDataInfo *pInfo;
328    int32_t headerSize;
329
330    const uint8_t *inBytes;
331    uint8_t *outBytes;
332
333    const int32_t *inIndexes;
334    int32_t indexes[16];
335
336    int32_t i, offset, count, size;
337
338    /* udata_swapDataHeader checks the arguments */
339    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
340    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
341        return 0;
342    }
343
344    /* check data format and format version */
345    pInfo=(const UDataInfo *)((const char *)inData+4);
346    if(!(
347        pInfo->dataFormat[0]==UBIDI_FMT_0 &&    /* dataFormat="BiDi" */
348        pInfo->dataFormat[1]==UBIDI_FMT_1 &&
349        pInfo->dataFormat[2]==UBIDI_FMT_2 &&
350        pInfo->dataFormat[3]==UBIDI_FMT_3 &&
351        ((pInfo->formatVersion[0]==1 &&
352          pInfo->formatVersion[2]==UTRIE_SHIFT &&
353          pInfo->formatVersion[3]==UTRIE_INDEX_SHIFT) ||
354         pInfo->formatVersion[0]==2)
355    )) {
356        udata_printError(ds, "ubidi_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as bidi/shaping data\n",
357                         pInfo->dataFormat[0], pInfo->dataFormat[1],
358                         pInfo->dataFormat[2], pInfo->dataFormat[3],
359                         pInfo->formatVersion[0]);
360        *pErrorCode=U_UNSUPPORTED_ERROR;
361        return 0;
362    }
363
364    inBytes=(const uint8_t *)inData+headerSize;
365    outBytes=(uint8_t *)outData+headerSize;
366
367    inIndexes=(const int32_t *)inBytes;
368
369    if(length>=0) {
370        length-=headerSize;
371        if(length<16*4) {
372            udata_printError(ds, "ubidi_swap(): too few bytes (%d after header) for bidi/shaping data\n",
373                             length);
374            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
375            return 0;
376        }
377    }
378
379    /* read the first 16 indexes (ICU 3.4/format version 1: UBIDI_IX_TOP==16, might grow) */
380    for(i=0; i<16; ++i) {
381        indexes[i]=udata_readInt32(ds, inIndexes[i]);
382    }
383
384    /* get the total length of the data */
385    size=indexes[UBIDI_IX_LENGTH];
386
387    if(length>=0) {
388        if(length<size) {
389            udata_printError(ds, "ubidi_swap(): too few bytes (%d after header) for all of bidi/shaping data\n",
390                             length);
391            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
392            return 0;
393        }
394
395        /* copy the data for inaccessible bytes */
396        if(inBytes!=outBytes) {
397            uprv_memcpy(outBytes, inBytes, size);
398        }
399
400        offset=0;
401
402        /* swap the int32_t indexes[] */
403        count=indexes[UBIDI_IX_INDEX_TOP]*4;
404        ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
405        offset+=count;
406
407        /* swap the UTrie */
408        count=indexes[UBIDI_IX_TRIE_SIZE];
409        utrie2_swapAnyVersion(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
410        offset+=count;
411
412        /* swap the uint32_t mirrors[] */
413        count=indexes[UBIDI_IX_MIRROR_LENGTH]*4;
414        ds->swapArray32(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
415        offset+=count;
416
417        /* just skip the uint8_t jgArray[] */
418        count=indexes[UBIDI_IX_JG_LIMIT]-indexes[UBIDI_IX_JG_START];
419        offset+=count;
420
421        U_ASSERT(offset==size);
422    }
423
424    return headerSize+size;
425}
426
427/* Unicode normalization data swapping -------------------------------------- */
428
429#if !UCONFIG_NO_NORMALIZATION
430
431U_CAPI int32_t U_EXPORT2
432unorm_swap(const UDataSwapper *ds,
433           const void *inData, int32_t length, void *outData,
434           UErrorCode *pErrorCode) {
435    const UDataInfo *pInfo;
436    int32_t headerSize;
437
438    const uint8_t *inBytes;
439    uint8_t *outBytes;
440
441    const int32_t *inIndexes;
442    int32_t indexes[32];
443
444    int32_t i, offset, count, size;
445
446    /* udata_swapDataHeader checks the arguments */
447    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
448    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
449        return 0;
450    }
451
452    /* check data format and format version */
453    pInfo=(const UDataInfo *)((const char *)inData+4);
454    if(!(
455        pInfo->dataFormat[0]==0x4e &&   /* dataFormat="Norm" */
456        pInfo->dataFormat[1]==0x6f &&
457        pInfo->dataFormat[2]==0x72 &&
458        pInfo->dataFormat[3]==0x6d &&
459        pInfo->formatVersion[0]==2
460    )) {
461        udata_printError(ds, "unorm_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as unorm.icu\n",
462                         pInfo->dataFormat[0], pInfo->dataFormat[1],
463                         pInfo->dataFormat[2], pInfo->dataFormat[3],
464                         pInfo->formatVersion[0]);
465        *pErrorCode=U_UNSUPPORTED_ERROR;
466        return 0;
467    }
468
469    inBytes=(const uint8_t *)inData+headerSize;
470    outBytes=(uint8_t *)outData+headerSize;
471
472    inIndexes=(const int32_t *)inBytes;
473
474    if(length>=0) {
475        length-=headerSize;
476        if(length<32*4) {
477            udata_printError(ds, "unorm_swap(): too few bytes (%d after header) for unorm.icu\n",
478                             length);
479            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
480            return 0;
481        }
482    }
483
484    /* read the first 32 indexes (ICU 2.8/format version 2.2: _NORM_INDEX_TOP==32, might grow) */
485    for(i=0; i<32; ++i) {
486        indexes[i]=udata_readInt32(ds, inIndexes[i]);
487    }
488
489    /* calculate the total length of the data */
490    size=
491        32*4+ /* size of indexes[] */
492        indexes[_NORM_INDEX_TRIE_SIZE]+
493        indexes[_NORM_INDEX_UCHAR_COUNT]*2+
494        indexes[_NORM_INDEX_COMBINE_DATA_COUNT]*2+
495        indexes[_NORM_INDEX_FCD_TRIE_SIZE]+
496        indexes[_NORM_INDEX_AUX_TRIE_SIZE]+
497        indexes[_NORM_INDEX_CANON_SET_COUNT]*2;
498
499    if(length>=0) {
500        if(length<size) {
501            udata_printError(ds, "unorm_swap(): too few bytes (%d after header) for all of unorm.icu\n",
502                             length);
503            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
504            return 0;
505        }
506
507        /* copy the data for inaccessible bytes */
508        if(inBytes!=outBytes) {
509            uprv_memcpy(outBytes, inBytes, size);
510        }
511
512        offset=0;
513
514        /* swap the indexes[] */
515        count=32*4;
516        ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
517        offset+=count;
518
519        /* swap the main UTrie */
520        count=indexes[_NORM_INDEX_TRIE_SIZE];
521        utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
522        offset+=count;
523
524        /* swap the uint16_t extraData[] and the uint16_t combiningTable[] */
525        count=(indexes[_NORM_INDEX_UCHAR_COUNT]+indexes[_NORM_INDEX_COMBINE_DATA_COUNT])*2;
526        ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
527        offset+=count;
528
529        /* swap the FCD UTrie */
530        count=indexes[_NORM_INDEX_FCD_TRIE_SIZE];
531        if(count!=0) {
532            utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
533            offset+=count;
534        }
535
536        /* swap the aux UTrie */
537        count=indexes[_NORM_INDEX_AUX_TRIE_SIZE];
538        if(count!=0) {
539            utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
540            offset+=count;
541        }
542
543        /* swap the uint16_t combiningTable[] */
544        count=indexes[_NORM_INDEX_CANON_SET_COUNT]*2;
545        ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
546        offset+=count;
547    }
548
549    return headerSize+size;
550}
551
552#endif
553
554/* Swap 'Test' data from gentest */
555U_CAPI int32_t U_EXPORT2
556test_swap(const UDataSwapper *ds,
557           const void *inData, int32_t length, void *outData,
558           UErrorCode *pErrorCode) {
559    const UDataInfo *pInfo;
560    int32_t headerSize;
561
562    const uint8_t *inBytes;
563    uint8_t *outBytes;
564
565    int32_t offset;
566
567    /* udata_swapDataHeader checks the arguments */
568    headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
569    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
570        udata_printError(ds, "test_swap(): data header swap failed %s\n", u_errorName(*pErrorCode));
571        return 0;
572    }
573
574    /* check data format and format version */
575    pInfo=(const UDataInfo *)((const char *)inData+4);
576    if(!(
577        pInfo->dataFormat[0]==0x54 &&   /* dataFormat="Norm" */
578        pInfo->dataFormat[1]==0x65 &&
579        pInfo->dataFormat[2]==0x73 &&
580        pInfo->dataFormat[3]==0x74 &&
581        pInfo->formatVersion[0]==1
582    )) {
583        udata_printError(ds, "test_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as testdata\n",
584                         pInfo->dataFormat[0], pInfo->dataFormat[1],
585                         pInfo->dataFormat[2], pInfo->dataFormat[3],
586                         pInfo->formatVersion[0]);
587        *pErrorCode=U_UNSUPPORTED_ERROR;
588        return 0;
589    }
590
591    inBytes=(const uint8_t *)inData+headerSize;
592    outBytes=(uint8_t *)outData+headerSize;
593
594    int32_t size16 = 2; // 16bit plus padding
595    int32_t sizeStr = 5; // 4 char inv-str plus null
596    int32_t size = size16 + sizeStr;
597
598    if(length>=0) {
599        if(length<size) {
600            udata_printError(ds, "test_swap(): too few bytes (%d after header, wanted %d) for all of testdata\n",
601                             length, size);
602            *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
603            return 0;
604        }
605
606	offset =0;
607	/* swap a 1 entry array */
608        ds->swapArray16(ds, inBytes+offset, size16, outBytes+offset, pErrorCode);
609	offset+=size16;
610	ds->swapInvChars(ds, inBytes+offset, sizeStr, outBytes+offset, pErrorCode);
611    }
612
613    return headerSize+size;
614}
615
616/* swap any data (except a .dat package) ------------------------------------ */
617
618static const struct {
619    uint8_t dataFormat[4];
620    UDataSwapFn *swapFn;
621} swapFns[]={
622    { { 0x52, 0x65, 0x73, 0x42 }, ures_swap },          /* dataFormat="ResB" */
623#if !UCONFIG_NO_LEGACY_CONVERSION
624    { { 0x63, 0x6e, 0x76, 0x74 }, ucnv_swap },          /* dataFormat="cnvt" */
625#endif
626#if !UCONFIG_NO_CONVERSION
627    { { 0x43, 0x76, 0x41, 0x6c }, ucnv_swapAliases },   /* dataFormat="CvAl" */
628#endif
629#if !UCONFIG_NO_IDNA
630    { { 0x53, 0x50, 0x52, 0x50 }, usprep_swap },        /* dataFormat="SPRP" */
631#endif
632    /* insert data formats here, descending by expected frequency of occurrence */
633    { { 0x55, 0x50, 0x72, 0x6f }, uprops_swap },        /* dataFormat="UPro" */
634
635    { { UCASE_FMT_0, UCASE_FMT_1, UCASE_FMT_2, UCASE_FMT_3 },
636                                  ucase_swap },         /* dataFormat="cAsE" */
637
638    { { UBIDI_FMT_0, UBIDI_FMT_1, UBIDI_FMT_2, UBIDI_FMT_3 },
639                                  ubidi_swap },         /* dataFormat="BiDi" */
640
641#if !UCONFIG_NO_NORMALIZATION
642    { { 0x4e, 0x6f, 0x72, 0x6d }, unorm_swap },         /* dataFormat="Norm" */
643    { { 0x4e, 0x72, 0x6d, 0x32 }, unorm2_swap },        /* dataFormat="Nrm2" */
644#endif
645#if !UCONFIG_NO_COLLATION
646    { { 0x55, 0x43, 0x6f, 0x6c }, ucol_swap },          /* dataFormat="UCol" */
647    { { 0x49, 0x6e, 0x76, 0x43 }, ucol_swapInverseUCA },/* dataFormat="InvC" */
648#endif
649#if !UCONFIG_NO_BREAK_ITERATION
650    { { 0x42, 0x72, 0x6b, 0x20 }, ubrk_swap },          /* dataFormat="Brk " */
651    { { 0x54, 0x72, 0x44, 0x63 }, triedict_swap },      /* dataFormat="TrDc " */
652#endif
653    { { 0x70, 0x6e, 0x61, 0x6d }, upname_swap },        /* dataFormat="pnam" */
654    { { 0x75, 0x6e, 0x61, 0x6d }, uchar_swapNames },    /* dataFormat="unam" */
655#if !UCONFIG_NO_NORMALIZATION
656    { { 0x43, 0x66, 0x75, 0x20 }, uspoof_swap },         /* dataFormat="Cfu " */
657#endif
658    { { 0x54, 0x65, 0x73, 0x74 }, test_swap }            /* dataFormat="Test" */
659};
660
661U_CAPI int32_t U_EXPORT2
662udata_swap(const UDataSwapper *ds,
663           const void *inData, int32_t length, void *outData,
664           UErrorCode *pErrorCode) {
665    char dataFormatChars[4];
666    const UDataInfo *pInfo;
667    int32_t headerSize, i, swappedLength;
668
669    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
670        return 0;
671    }
672
673    /*
674     * Preflight the header first; checks for illegal arguments, too.
675     * Do not swap the header right away because the format-specific swapper
676     * will swap it, get the headerSize again, and also use the header
677     * information. Otherwise we would have to pass some of the information
678     * and not be able to use the UDataSwapFn signature.
679     */
680    headerSize=udata_swapDataHeader(ds, inData, -1, NULL, pErrorCode);
681
682    /*
683     * If we wanted udata_swap() to also handle non-loadable data like a UTrie,
684     * then we could check here for further known magic values and structures.
685     */
686    if(U_FAILURE(*pErrorCode)) {
687        return 0; /* the data format was not recognized */
688    }
689
690    pInfo=(const UDataInfo *)((const char *)inData+4);
691
692    {
693        /* convert the data format from ASCII to Unicode to the system charset */
694        UChar u[4]={
695             pInfo->dataFormat[0], pInfo->dataFormat[1],
696             pInfo->dataFormat[2], pInfo->dataFormat[3]
697        };
698
699        if(uprv_isInvariantUString(u, 4)) {
700            u_UCharsToChars(u, dataFormatChars, 4);
701        } else {
702            dataFormatChars[0]=dataFormatChars[1]=dataFormatChars[2]=dataFormatChars[3]='?';
703        }
704    }
705
706    /* dispatch to the swap function for the dataFormat */
707    for(i=0; i<LENGTHOF(swapFns); ++i) {
708        if(0==memcmp(swapFns[i].dataFormat, pInfo->dataFormat, 4)) {
709            swappedLength=swapFns[i].swapFn(ds, inData, length, outData, pErrorCode);
710
711            if(U_FAILURE(*pErrorCode)) {
712                udata_printError(ds, "udata_swap(): failure swapping data format %02x.%02x.%02x.%02x (\"%c%c%c%c\") - %s\n",
713                                 pInfo->dataFormat[0], pInfo->dataFormat[1],
714                                 pInfo->dataFormat[2], pInfo->dataFormat[3],
715                                 dataFormatChars[0], dataFormatChars[1],
716                                 dataFormatChars[2], dataFormatChars[3],
717                                 u_errorName(*pErrorCode));
718            } else if(swappedLength<(length-15)) {
719                /* swapped less than expected */
720                udata_printError(ds, "udata_swap() warning: swapped only %d out of %d bytes - data format %02x.%02x.%02x.%02x (\"%c%c%c%c\")\n",
721                                 swappedLength, length,
722                                 pInfo->dataFormat[0], pInfo->dataFormat[1],
723                                 pInfo->dataFormat[2], pInfo->dataFormat[3],
724                                 dataFormatChars[0], dataFormatChars[1],
725                                 dataFormatChars[2], dataFormatChars[3],
726                                 u_errorName(*pErrorCode));
727            }
728
729            return swappedLength;
730        }
731    }
732
733    /* the dataFormat was not recognized */
734    udata_printError(ds, "udata_swap(): unknown data format %02x.%02x.%02x.%02x (\"%c%c%c%c\")\n",
735                     pInfo->dataFormat[0], pInfo->dataFormat[1],
736                     pInfo->dataFormat[2], pInfo->dataFormat[3],
737                     dataFormatChars[0], dataFormatChars[1],
738                     dataFormatChars[2], dataFormatChars[3]);
739
740    *pErrorCode=U_UNSUPPORTED_ERROR;
741    return 0;
742}
743