/src/icu/source/common/ucol_swp.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  |  | *  | 
6  |  | *   Copyright (C) 2003-2015, International Business Machines  | 
7  |  | *   Corporation and others.  All Rights Reserved.  | 
8  |  | *  | 
9  |  | *******************************************************************************  | 
10  |  | *   file name:  ucol_swp.cpp  | 
11  |  | *   encoding:   UTF-8  | 
12  |  | *   tab size:   8 (not used)  | 
13  |  | *   indentation:4  | 
14  |  | *  | 
15  |  | *   created on: 2003sep10  | 
16  |  | *   created by: Markus W. Scherer  | 
17  |  | *  | 
18  |  | *   Swap collation binaries.  | 
19  |  | */  | 
20  |  |  | 
21  |  | #include "unicode/udata.h" /* UDataInfo */  | 
22  |  | #include "utrie.h"  | 
23  |  | #include "utrie2.h"  | 
24  |  | #include "udataswp.h"  | 
25  |  | #include "cmemory.h"  | 
26  |  | #include "ucol_data.h"  | 
27  |  | #include "ucol_swp.h"  | 
28  |  |  | 
29  |  | /* swapping ----------------------------------------------------------------- */  | 
30  |  |  | 
31  |  | #if !UCONFIG_NO_COLLATION  | 
32  |  |  | 
33  |  | U_CAPI UBool U_EXPORT2  | 
34  |  | ucol_looksLikeCollationBinary(const UDataSwapper *ds,  | 
35  | 0  |                               const void *inData, int32_t length) { | 
36  | 0  |     if(ds==NULL || inData==NULL || length<-1) { | 
37  | 0  |         return FALSE;  | 
38  | 0  |     }  | 
39  |  |  | 
40  |  |     // First check for format version 4+ which has a standard data header.  | 
41  | 0  |     UErrorCode errorCode=U_ZERO_ERROR;  | 
42  | 0  |     (void)udata_swapDataHeader(ds, inData, -1, NULL, &errorCode);  | 
43  | 0  |     if(U_SUCCESS(errorCode)) { | 
44  | 0  |         const UDataInfo &info=*(const UDataInfo *)((const char *)inData+4);  | 
45  | 0  |         if(info.dataFormat[0]==0x55 &&   // dataFormat="UCol"  | 
46  | 0  |                 info.dataFormat[1]==0x43 &&  | 
47  | 0  |                 info.dataFormat[2]==0x6f &&  | 
48  | 0  |                 info.dataFormat[3]==0x6c) { | 
49  | 0  |             return TRUE;  | 
50  | 0  |         }  | 
51  | 0  |     }  | 
52  |  |  | 
53  |  |     // Else check for format version 3.  | 
54  | 0  |     const UCATableHeader *inHeader=(const UCATableHeader *)inData;  | 
55  |  |  | 
56  |  |     /*  | 
57  |  |      * The collation binary must contain at least the UCATableHeader,  | 
58  |  |      * starting with its size field.  | 
59  |  |      * sizeof(UCATableHeader)==42*4 in ICU 2.8  | 
60  |  |      * check the length against the header size before reading the size field  | 
61  |  |      */  | 
62  | 0  |     UCATableHeader header;  | 
63  | 0  |     uprv_memset(&header, 0, sizeof(header));  | 
64  | 0  |     if(length<0) { | 
65  | 0  |         header.size=udata_readInt32(ds, inHeader->size);  | 
66  | 0  |     } else if((length<(42*4) || length<(header.size=udata_readInt32(ds, inHeader->size)))) { | 
67  | 0  |         return FALSE;  | 
68  | 0  |     }  | 
69  |  |  | 
70  | 0  |     header.magic=ds->readUInt32(inHeader->magic);  | 
71  | 0  |     if(!(  | 
72  | 0  |         header.magic==UCOL_HEADER_MAGIC &&  | 
73  | 0  |         inHeader->formatVersion[0]==3 /*&&  | 
74  |  |         inHeader->formatVersion[1]>=0*/  | 
75  | 0  |     )) { | 
76  | 0  |         return FALSE;  | 
77  | 0  |     }  | 
78  |  |  | 
79  | 0  |     if(inHeader->isBigEndian!=ds->inIsBigEndian || inHeader->charSetFamily!=ds->inCharset) { | 
80  | 0  |         return FALSE;  | 
81  | 0  |     }  | 
82  |  |  | 
83  | 0  |     return TRUE;  | 
84  | 0  | }  | 
85  |  |  | 
86  |  | namespace { | 
87  |  |  | 
88  |  | /* swap a header-less collation formatVersion=3 binary, inside a resource bundle or ucadata.icu */  | 
89  |  | int32_t  | 
90  |  | swapFormatVersion3(const UDataSwapper *ds,  | 
91  |  |                    const void *inData, int32_t length, void *outData,  | 
92  | 0  |                    UErrorCode *pErrorCode) { | 
93  | 0  |     const uint8_t *inBytes;  | 
94  | 0  |     uint8_t *outBytes;  | 
95  |  | 
  | 
96  | 0  |     const UCATableHeader *inHeader;  | 
97  | 0  |     UCATableHeader *outHeader;  | 
98  | 0  |     UCATableHeader header;  | 
99  |  | 
  | 
100  | 0  |     uint32_t count;  | 
101  |  |  | 
102  |  |     /* argument checking in case we were not called from ucol_swap() */  | 
103  | 0  |     if(U_FAILURE(*pErrorCode)) { | 
104  | 0  |         return 0;  | 
105  | 0  |     }  | 
106  | 0  |     if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) { | 
107  | 0  |         *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;  | 
108  | 0  |         return 0;  | 
109  | 0  |     }  | 
110  |  |  | 
111  | 0  |     inBytes=(const uint8_t *)inData;  | 
112  | 0  |     outBytes=(uint8_t *)outData;  | 
113  |  | 
  | 
114  | 0  |     inHeader=(const UCATableHeader *)inData;  | 
115  | 0  |     outHeader=(UCATableHeader *)outData;  | 
116  |  |  | 
117  |  |     /*  | 
118  |  |      * The collation binary must contain at least the UCATableHeader,  | 
119  |  |      * starting with its size field.  | 
120  |  |      * sizeof(UCATableHeader)==42*4 in ICU 2.8  | 
121  |  |      * check the length against the header size before reading the size field  | 
122  |  |      */  | 
123  | 0  |     uprv_memset(&header, 0, sizeof(header));  | 
124  | 0  |     if(length<0) { | 
125  | 0  |         header.size=udata_readInt32(ds, inHeader->size);  | 
126  | 0  |     } else if((length<(42*4) || length<(header.size=udata_readInt32(ds, inHeader->size)))) { | 
127  | 0  |         udata_printError(ds, "ucol_swap(formatVersion=3): too few bytes (%d after header) for collation data\n",  | 
128  | 0  |                          length);  | 
129  | 0  |         *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
130  | 0  |         return 0;  | 
131  | 0  |     }  | 
132  |  |  | 
133  | 0  |     header.magic=ds->readUInt32(inHeader->magic);  | 
134  | 0  |     if(!(  | 
135  | 0  |         header.magic==UCOL_HEADER_MAGIC &&  | 
136  | 0  |         inHeader->formatVersion[0]==3 /*&&  | 
137  |  |         inHeader->formatVersion[1]>=0*/  | 
138  | 0  |     )) { | 
139  | 0  |         udata_printError(ds, "ucol_swap(formatVersion=3): magic 0x%08x or format version %02x.%02x is not a collation binary\n",  | 
140  | 0  |                          header.magic,  | 
141  | 0  |                          inHeader->formatVersion[0], inHeader->formatVersion[1]);  | 
142  | 0  |         *pErrorCode=U_UNSUPPORTED_ERROR;  | 
143  | 0  |         return 0;  | 
144  | 0  |     }  | 
145  |  |  | 
146  | 0  |     if(inHeader->isBigEndian!=ds->inIsBigEndian || inHeader->charSetFamily!=ds->inCharset) { | 
147  | 0  |         udata_printError(ds, "ucol_swap(formatVersion=3): endianness %d or charset %d does not match the swapper\n",  | 
148  | 0  |                          inHeader->isBigEndian, inHeader->charSetFamily);  | 
149  | 0  |         *pErrorCode=U_INVALID_FORMAT_ERROR;  | 
150  | 0  |         return 0;  | 
151  | 0  |     }  | 
152  |  |  | 
153  | 0  |     if(length>=0) { | 
154  |  |         /* copy everything, takes care of data that needs no swapping */  | 
155  | 0  |         if(inBytes!=outBytes) { | 
156  | 0  |             uprv_memcpy(outBytes, inBytes, header.size);  | 
157  | 0  |         }  | 
158  |  |  | 
159  |  |         /* swap the necessary pieces in the order of their occurrence in the data */  | 
160  |  |  | 
161  |  |         /* read more of the UCATableHeader (the size field was read above) */  | 
162  | 0  |         header.options=                 ds->readUInt32(inHeader->options);  | 
163  | 0  |         header.UCAConsts=               ds->readUInt32(inHeader->UCAConsts);  | 
164  | 0  |         header.contractionUCACombos=    ds->readUInt32(inHeader->contractionUCACombos);  | 
165  | 0  |         header.mappingPosition=         ds->readUInt32(inHeader->mappingPosition);  | 
166  | 0  |         header.expansion=               ds->readUInt32(inHeader->expansion);  | 
167  | 0  |         header.contractionIndex=        ds->readUInt32(inHeader->contractionIndex);  | 
168  | 0  |         header.contractionCEs=          ds->readUInt32(inHeader->contractionCEs);  | 
169  | 0  |         header.contractionSize=         ds->readUInt32(inHeader->contractionSize);  | 
170  | 0  |         header.endExpansionCE=          ds->readUInt32(inHeader->endExpansionCE);  | 
171  | 0  |         header.expansionCESize=         ds->readUInt32(inHeader->expansionCESize);  | 
172  | 0  |         header.endExpansionCECount=     udata_readInt32(ds, inHeader->endExpansionCECount);  | 
173  | 0  |         header.contractionUCACombosSize=udata_readInt32(ds, inHeader->contractionUCACombosSize);  | 
174  | 0  |         header.scriptToLeadByte=        ds->readUInt32(inHeader->scriptToLeadByte);  | 
175  | 0  |         header.leadByteToScript=        ds->readUInt32(inHeader->leadByteToScript);  | 
176  |  |           | 
177  |  |         /* swap the 32-bit integers in the header */  | 
178  | 0  |         ds->swapArray32(ds, inHeader, (int32_t)((const char *)&inHeader->jamoSpecial-(const char *)inHeader),  | 
179  | 0  |                            outHeader, pErrorCode);  | 
180  | 0  |         ds->swapArray32(ds, &(inHeader->scriptToLeadByte), sizeof(header.scriptToLeadByte) + sizeof(header.leadByteToScript),  | 
181  | 0  |                            &(outHeader->scriptToLeadByte), pErrorCode);  | 
182  |  |         /* set the output platform properties */  | 
183  | 0  |         outHeader->isBigEndian=ds->outIsBigEndian;  | 
184  | 0  |         outHeader->charSetFamily=ds->outCharset;  | 
185  |  |  | 
186  |  |         /* swap the options */  | 
187  | 0  |         if(header.options!=0) { | 
188  | 0  |             ds->swapArray32(ds, inBytes+header.options, header.expansion-header.options,  | 
189  | 0  |                                outBytes+header.options, pErrorCode);  | 
190  | 0  |         }  | 
191  |  |  | 
192  |  |         /* swap the expansions */  | 
193  | 0  |         if(header.mappingPosition!=0 && header.expansion!=0) { | 
194  | 0  |             if(header.contractionIndex!=0) { | 
195  |  |                 /* expansions bounded by contractions */  | 
196  | 0  |                 count=header.contractionIndex-header.expansion;  | 
197  | 0  |             } else { | 
198  |  |                 /* no contractions: expansions bounded by the main trie */  | 
199  | 0  |                 count=header.mappingPosition-header.expansion;  | 
200  | 0  |             }  | 
201  | 0  |             ds->swapArray32(ds, inBytes+header.expansion, (int32_t)count,  | 
202  | 0  |                                outBytes+header.expansion, pErrorCode);  | 
203  | 0  |         }  | 
204  |  |  | 
205  |  |         /* swap the contractions */  | 
206  | 0  |         if(header.contractionSize!=0) { | 
207  |  |             /* contractionIndex: UChar[] */  | 
208  | 0  |             ds->swapArray16(ds, inBytes+header.contractionIndex, header.contractionSize*2,  | 
209  | 0  |                                outBytes+header.contractionIndex, pErrorCode);  | 
210  |  |  | 
211  |  |             /* contractionCEs: CEs[] */  | 
212  | 0  |             ds->swapArray32(ds, inBytes+header.contractionCEs, header.contractionSize*4,  | 
213  | 0  |                                outBytes+header.contractionCEs, pErrorCode);  | 
214  | 0  |         }  | 
215  |  |  | 
216  |  |         /* swap the main trie */  | 
217  | 0  |         if(header.mappingPosition!=0) { | 
218  | 0  |             count=header.endExpansionCE-header.mappingPosition;  | 
219  | 0  |             utrie_swap(ds, inBytes+header.mappingPosition, (int32_t)count,  | 
220  | 0  |                           outBytes+header.mappingPosition, pErrorCode);  | 
221  | 0  |         }  | 
222  |  |  | 
223  |  |         /* swap the max expansion table */  | 
224  | 0  |         if(header.endExpansionCECount!=0) { | 
225  | 0  |             ds->swapArray32(ds, inBytes+header.endExpansionCE, header.endExpansionCECount*4,  | 
226  | 0  |                                outBytes+header.endExpansionCE, pErrorCode);  | 
227  | 0  |         }  | 
228  |  |  | 
229  |  |         /* expansionCESize, unsafeCP, contrEndCP: uint8_t[], no need to swap */  | 
230  |  |  | 
231  |  |         /* swap UCA constants */  | 
232  | 0  |         if(header.UCAConsts!=0) { | 
233  |  |             /*  | 
234  |  |              * if UCAConsts!=0 then contractionUCACombos because we are swapping  | 
235  |  |              * the UCA data file, and we know that the UCA contains contractions  | 
236  |  |              */  | 
237  | 0  |             ds->swapArray32(ds, inBytes+header.UCAConsts, header.contractionUCACombos-header.UCAConsts,  | 
238  | 0  |                                outBytes+header.UCAConsts, pErrorCode);  | 
239  | 0  |         }  | 
240  |  |  | 
241  |  |         /* swap UCA contractions */  | 
242  | 0  |         if(header.contractionUCACombosSize!=0) { | 
243  | 0  |             count=header.contractionUCACombosSize*inHeader->contractionUCACombosWidth*U_SIZEOF_UCHAR;  | 
244  | 0  |             ds->swapArray16(ds, inBytes+header.contractionUCACombos, (int32_t)count,  | 
245  | 0  |                                outBytes+header.contractionUCACombos, pErrorCode);  | 
246  | 0  |         }  | 
247  |  |           | 
248  |  |         /* swap the script to lead bytes */  | 
249  | 0  |         if(header.scriptToLeadByte!=0) { | 
250  | 0  |             int indexCount = ds->readUInt16(*((uint16_t*)(inBytes+header.scriptToLeadByte))); // each entry = 2 * uint16  | 
251  | 0  |             int dataCount = ds->readUInt16(*((uint16_t*)(inBytes+header.scriptToLeadByte + 2))); // each entry = uint16  | 
252  | 0  |             ds->swapArray16(ds, inBytes+header.scriptToLeadByte,   | 
253  | 0  |                                 4 + (4 * indexCount) + (2 * dataCount),  | 
254  | 0  |                                 outBytes+header.scriptToLeadByte, pErrorCode);  | 
255  | 0  |         }  | 
256  |  |           | 
257  |  |         /* swap the lead byte to scripts */  | 
258  | 0  |         if(header.leadByteToScript!=0) { | 
259  | 0  |             int indexCount = ds->readUInt16(*((uint16_t*)(inBytes+header.leadByteToScript))); // each entry = uint16  | 
260  | 0  |             int dataCount = ds->readUInt16(*((uint16_t*)(inBytes+header.leadByteToScript + 2))); // each entry = uint16  | 
261  | 0  |             ds->swapArray16(ds, inBytes+header.leadByteToScript,   | 
262  | 0  |                                 4 + (2 * indexCount) + (2 * dataCount),  | 
263  | 0  |                                 outBytes+header.leadByteToScript, pErrorCode);  | 
264  | 0  |         }  | 
265  | 0  |     }  | 
266  |  | 
  | 
267  | 0  |     return header.size;  | 
268  | 0  | }  | 
269  |  |  | 
270  |  | // swap formatVersion 4 or 5 ----------------------------------------------- ***  | 
271  |  |  | 
272  |  | // The following are copied from CollationDataReader, trading an awkward copy of constants  | 
273  |  | // for an awkward relocation of the i18n collationdatareader.h file into the common library.  | 
274  |  | // Keep them in sync!  | 
275  |  |  | 
276  |  | enum { | 
277  |  |     IX_INDEXES_LENGTH,  // 0  | 
278  |  |     IX_OPTIONS,  | 
279  |  |     IX_RESERVED2,  | 
280  |  |     IX_RESERVED3,  | 
281  |  |  | 
282  |  |     IX_JAMO_CE32S_START,  // 4  | 
283  |  |     IX_REORDER_CODES_OFFSET,  | 
284  |  |     IX_REORDER_TABLE_OFFSET,  | 
285  |  |     IX_TRIE_OFFSET,  | 
286  |  |  | 
287  |  |     IX_RESERVED8_OFFSET,  // 8  | 
288  |  |     IX_CES_OFFSET,  | 
289  |  |     IX_RESERVED10_OFFSET,  | 
290  |  |     IX_CE32S_OFFSET,  | 
291  |  |  | 
292  |  |     IX_ROOT_ELEMENTS_OFFSET,  // 12  | 
293  |  |     IX_CONTEXTS_OFFSET,  | 
294  |  |     IX_UNSAFE_BWD_OFFSET,  | 
295  |  |     IX_FAST_LATIN_TABLE_OFFSET,  | 
296  |  |  | 
297  |  |     IX_SCRIPTS_OFFSET,  // 16  | 
298  |  |     IX_COMPRESSIBLE_BYTES_OFFSET,  | 
299  |  |     IX_RESERVED18_OFFSET,  | 
300  |  |     IX_TOTAL_SIZE  | 
301  |  | };  | 
302  |  |  | 
303  |  | int32_t  | 
304  |  | swapFormatVersion4(const UDataSwapper *ds,  | 
305  |  |                    const void *inData, int32_t length, void *outData,  | 
306  | 0  |                    UErrorCode &errorCode) { | 
307  | 0  |     if(U_FAILURE(errorCode)) { return 0; } | 
308  |  |  | 
309  | 0  |     const uint8_t *inBytes=(const uint8_t *)inData;  | 
310  | 0  |     uint8_t *outBytes=(uint8_t *)outData;  | 
311  |  | 
  | 
312  | 0  |     const int32_t *inIndexes=(const int32_t *)inBytes;  | 
313  | 0  |     int32_t indexes[IX_TOTAL_SIZE+1];  | 
314  |  |  | 
315  |  |     // Need at least IX_INDEXES_LENGTH and IX_OPTIONS.  | 
316  | 0  |     if(0<=length && length<8) { | 
317  | 0  |         udata_printError(ds, "ucol_swap(formatVersion=4): too few bytes "  | 
318  | 0  |                          "(%d after header) for collation data\n",  | 
319  | 0  |                          length);  | 
320  | 0  |         errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
321  | 0  |         return 0;  | 
322  | 0  |     }  | 
323  |  |  | 
324  | 0  |     int32_t indexesLength=indexes[0]=udata_readInt32(ds, inIndexes[0]);  | 
325  | 0  |     if(0<=length && length<(indexesLength*4)) { | 
326  | 0  |         udata_printError(ds, "ucol_swap(formatVersion=4): too few bytes "  | 
327  | 0  |                          "(%d after header) for collation data\n",  | 
328  | 0  |                          length);  | 
329  | 0  |         errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
330  | 0  |         return 0;  | 
331  | 0  |     }  | 
332  |  |  | 
333  | 0  |     for(int32_t i=1; i<=IX_TOTAL_SIZE && i<indexesLength; ++i) { | 
334  | 0  |         indexes[i]=udata_readInt32(ds, inIndexes[i]);  | 
335  | 0  |     }  | 
336  | 0  |     for(int32_t i=indexesLength; i<=IX_TOTAL_SIZE; ++i) { | 
337  | 0  |         indexes[i]=-1;  | 
338  | 0  |     }  | 
339  | 0  |     inIndexes=NULL;  // Make sure we do not accidentally use these instead of indexes[].  | 
340  |  |  | 
341  |  |     // Get the total length of the data.  | 
342  | 0  |     int32_t size;  | 
343  | 0  |     if(indexesLength>IX_TOTAL_SIZE) { | 
344  | 0  |         size=indexes[IX_TOTAL_SIZE];  | 
345  | 0  |     } else if(indexesLength>IX_REORDER_CODES_OFFSET) { | 
346  | 0  |         size=indexes[indexesLength-1];  | 
347  | 0  |     } else { | 
348  | 0  |         size=indexesLength*4;  | 
349  | 0  |     }  | 
350  | 0  |     if(length<0) { return size; } | 
351  |  |  | 
352  | 0  |     if(length<size) { | 
353  | 0  |         udata_printError(ds, "ucol_swap(formatVersion=4): too few bytes "  | 
354  | 0  |                          "(%d after header) for collation data\n",  | 
355  | 0  |                          length);  | 
356  | 0  |         errorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
357  | 0  |         return 0;  | 
358  | 0  |     }  | 
359  |  |  | 
360  |  |     // Copy the data for inaccessible bytes and arrays of bytes.  | 
361  | 0  |     if(inBytes!=outBytes) { | 
362  | 0  |         uprv_memcpy(outBytes, inBytes, size);  | 
363  | 0  |     }  | 
364  |  |  | 
365  |  |     // Swap the int32_t indexes[].  | 
366  | 0  |     ds->swapArray32(ds, inBytes, indexesLength * 4, outBytes, &errorCode);  | 
367  |  |  | 
368  |  |     // The following is a modified version of CollationDataReader::read().  | 
369  |  |     // Here we use indexes[] not inIndexes[] because  | 
370  |  |     // the inIndexes[] may not be in this machine's endianness.  | 
371  | 0  |     int32_t index;  // one of the indexes[] slots  | 
372  | 0  |     int32_t offset;  // byte offset for the index part  | 
373  |  |     // int32_t length;  // number of bytes in the index part  | 
374  |  | 
  | 
375  | 0  |     index = IX_REORDER_CODES_OFFSET;  | 
376  | 0  |     offset = indexes[index];  | 
377  | 0  |     length = indexes[index + 1] - offset;  | 
378  | 0  |     if(length > 0) { | 
379  | 0  |         ds->swapArray32(ds, inBytes + offset, length, outBytes + offset, &errorCode);  | 
380  | 0  |     }  | 
381  |  |  | 
382  |  |     // Skip the IX_REORDER_TABLE_OFFSET byte array.  | 
383  |  | 
  | 
384  | 0  |     index = IX_TRIE_OFFSET;  | 
385  | 0  |     offset = indexes[index];  | 
386  | 0  |     length = indexes[index + 1] - offset;  | 
387  | 0  |     if(length > 0) { | 
388  | 0  |         utrie2_swap(ds, inBytes + offset, length, outBytes + offset, &errorCode);  | 
389  | 0  |     }  | 
390  |  | 
  | 
391  | 0  |     index = IX_RESERVED8_OFFSET;  | 
392  | 0  |     offset = indexes[index];  | 
393  | 0  |     length = indexes[index + 1] - offset;  | 
394  | 0  |     if(length > 0) { | 
395  | 0  |         udata_printError(ds, "ucol_swap(formatVersion=4): unknown data at IX_RESERVED8_OFFSET\n", length);  | 
396  | 0  |         errorCode = U_UNSUPPORTED_ERROR;  | 
397  | 0  |         return 0;  | 
398  | 0  |     }  | 
399  |  |  | 
400  | 0  |     index = IX_CES_OFFSET;  | 
401  | 0  |     offset = indexes[index];  | 
402  | 0  |     length = indexes[index + 1] - offset;  | 
403  | 0  |     if(length > 0) { | 
404  | 0  |         ds->swapArray64(ds, inBytes + offset, length, outBytes + offset, &errorCode);  | 
405  | 0  |     }  | 
406  |  | 
  | 
407  | 0  |     index = IX_RESERVED10_OFFSET;  | 
408  | 0  |     offset = indexes[index];  | 
409  | 0  |     length = indexes[index + 1] - offset;  | 
410  | 0  |     if(length > 0) { | 
411  | 0  |         udata_printError(ds, "ucol_swap(formatVersion=4): unknown data at IX_RESERVED10_OFFSET\n", length);  | 
412  | 0  |         errorCode = U_UNSUPPORTED_ERROR;  | 
413  | 0  |         return 0;  | 
414  | 0  |     }  | 
415  |  |  | 
416  | 0  |     index = IX_CE32S_OFFSET;  | 
417  | 0  |     offset = indexes[index];  | 
418  | 0  |     length = indexes[index + 1] - offset;  | 
419  | 0  |     if(length > 0) { | 
420  | 0  |         ds->swapArray32(ds, inBytes + offset, length, outBytes + offset, &errorCode);  | 
421  | 0  |     }  | 
422  |  | 
  | 
423  | 0  |     index = IX_ROOT_ELEMENTS_OFFSET;  | 
424  | 0  |     offset = indexes[index];  | 
425  | 0  |     length = indexes[index + 1] - offset;  | 
426  | 0  |     if(length > 0) { | 
427  | 0  |         ds->swapArray32(ds, inBytes + offset, length, outBytes + offset, &errorCode);  | 
428  | 0  |     }  | 
429  |  | 
  | 
430  | 0  |     index = IX_CONTEXTS_OFFSET;  | 
431  | 0  |     offset = indexes[index];  | 
432  | 0  |     length = indexes[index + 1] - offset;  | 
433  | 0  |     if(length > 0) { | 
434  | 0  |         ds->swapArray16(ds, inBytes + offset, length, outBytes + offset, &errorCode);  | 
435  | 0  |     }  | 
436  |  | 
  | 
437  | 0  |     index = IX_UNSAFE_BWD_OFFSET;  | 
438  | 0  |     offset = indexes[index];  | 
439  | 0  |     length = indexes[index + 1] - offset;  | 
440  | 0  |     if(length > 0) { | 
441  | 0  |         ds->swapArray16(ds, inBytes + offset, length, outBytes + offset, &errorCode);  | 
442  | 0  |     }  | 
443  |  | 
  | 
444  | 0  |     index = IX_FAST_LATIN_TABLE_OFFSET;  | 
445  | 0  |     offset = indexes[index];  | 
446  | 0  |     length = indexes[index + 1] - offset;  | 
447  | 0  |     if(length > 0) { | 
448  | 0  |         ds->swapArray16(ds, inBytes + offset, length, outBytes + offset, &errorCode);  | 
449  | 0  |     }  | 
450  |  | 
  | 
451  | 0  |     index = IX_SCRIPTS_OFFSET;  | 
452  | 0  |     offset = indexes[index];  | 
453  | 0  |     length = indexes[index + 1] - offset;  | 
454  | 0  |     if(length > 0) { | 
455  | 0  |         ds->swapArray16(ds, inBytes + offset, length, outBytes + offset, &errorCode);  | 
456  | 0  |     }  | 
457  |  |  | 
458  |  |     // Skip the  IX_COMPRESSIBLE_BYTES_OFFSET byte array.  | 
459  |  | 
  | 
460  | 0  |     index = IX_RESERVED18_OFFSET;  | 
461  | 0  |     offset = indexes[index];  | 
462  | 0  |     length = indexes[index + 1] - offset;  | 
463  | 0  |     if(length > 0) { | 
464  | 0  |         udata_printError(ds, "ucol_swap(formatVersion=4): unknown data at IX_RESERVED18_OFFSET\n", length);  | 
465  | 0  |         errorCode = U_UNSUPPORTED_ERROR;  | 
466  | 0  |         return 0;  | 
467  | 0  |     }  | 
468  |  |  | 
469  | 0  |     return size;  | 
470  | 0  | }  | 
471  |  |  | 
472  |  | }  // namespace  | 
473  |  |  | 
474  |  | /* swap ICU collation data like ucadata.icu */  | 
475  |  | U_CAPI int32_t U_EXPORT2  | 
476  |  | ucol_swap(const UDataSwapper *ds,  | 
477  |  |           const void *inData, int32_t length, void *outData,  | 
478  | 0  |           UErrorCode *pErrorCode) { | 
479  | 0  |     if(U_FAILURE(*pErrorCode)) { return 0; } | 
480  |  |  | 
481  |  |     /* udata_swapDataHeader checks the arguments */  | 
482  | 0  |     int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);  | 
483  | 0  |     if(U_FAILURE(*pErrorCode)) { | 
484  |  |         // Try to swap the old format version which did not have a standard data header.  | 
485  | 0  |         *pErrorCode=U_ZERO_ERROR;  | 
486  | 0  |         return swapFormatVersion3(ds, inData, length, outData, pErrorCode);  | 
487  | 0  |     }  | 
488  |  |  | 
489  |  |     /* check data format and format version */  | 
490  | 0  |     const UDataInfo &info=*(const UDataInfo *)((const char *)inData+4);  | 
491  | 0  |     if(!(  | 
492  | 0  |         info.dataFormat[0]==0x55 &&   // dataFormat="UCol"  | 
493  | 0  |         info.dataFormat[1]==0x43 &&  | 
494  | 0  |         info.dataFormat[2]==0x6f &&  | 
495  | 0  |         info.dataFormat[3]==0x6c &&  | 
496  | 0  |         (3<=info.formatVersion[0] && info.formatVersion[0]<=5)  | 
497  | 0  |     )) { | 
498  | 0  |         udata_printError(ds, "ucol_swap(): data format %02x.%02x.%02x.%02x "  | 
499  | 0  |                          "(format version %02x.%02x) is not recognized as collation data\n",  | 
500  | 0  |                          info.dataFormat[0], info.dataFormat[1],  | 
501  | 0  |                          info.dataFormat[2], info.dataFormat[3],  | 
502  | 0  |                          info.formatVersion[0], info.formatVersion[1]);  | 
503  | 0  |         *pErrorCode=U_UNSUPPORTED_ERROR;  | 
504  | 0  |         return 0;  | 
505  | 0  |     }  | 
506  |  |  | 
507  | 0  |     inData=(const char *)inData+headerSize;  | 
508  | 0  |     if(length>=0) { length-=headerSize; } | 
509  | 0  |     outData=(char *)outData+headerSize;  | 
510  | 0  |     int32_t collationSize;  | 
511  | 0  |     if(info.formatVersion[0]>=4) { | 
512  | 0  |         collationSize=swapFormatVersion4(ds, inData, length, outData, *pErrorCode);  | 
513  | 0  |     } else { | 
514  | 0  |         collationSize=swapFormatVersion3(ds, inData, length, outData, pErrorCode);  | 
515  | 0  |     }  | 
516  | 0  |     if(U_SUCCESS(*pErrorCode)) { | 
517  | 0  |         return headerSize+collationSize;  | 
518  | 0  |     } else { | 
519  | 0  |         return 0;  | 
520  | 0  |     }  | 
521  | 0  | }  | 
522  |  |  | 
523  |  | /* swap inverse UCA collation data (invuca.icu) */  | 
524  |  | U_CAPI int32_t U_EXPORT2  | 
525  |  | ucol_swapInverseUCA(const UDataSwapper *ds,  | 
526  |  |                     const void *inData, int32_t length, void *outData,  | 
527  | 0  |                     UErrorCode *pErrorCode) { | 
528  | 0  |     const UDataInfo *pInfo;  | 
529  | 0  |     int32_t headerSize;  | 
530  |  | 
  | 
531  | 0  |     const uint8_t *inBytes;  | 
532  | 0  |     uint8_t *outBytes;  | 
533  |  | 
  | 
534  | 0  |     const InverseUCATableHeader *inHeader;  | 
535  | 0  |     InverseUCATableHeader *outHeader;  | 
536  | 0  |     InverseUCATableHeader header={ 0,0,0,0,0,{0,0,0,0},{0,0,0,0,0,0,0,0} }; | 
537  |  |  | 
538  |  |     /* udata_swapDataHeader checks the arguments */  | 
539  | 0  |     headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);  | 
540  | 0  |     if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { | 
541  | 0  |         return 0;  | 
542  | 0  |     }  | 
543  |  |  | 
544  |  |     /* check data format and format version */  | 
545  | 0  |     pInfo=(const UDataInfo *)((const char *)inData+4);  | 
546  | 0  |     if(!(  | 
547  | 0  |         pInfo->dataFormat[0]==0x49 &&   /* dataFormat="InvC" */  | 
548  | 0  |         pInfo->dataFormat[1]==0x6e &&  | 
549  | 0  |         pInfo->dataFormat[2]==0x76 &&  | 
550  | 0  |         pInfo->dataFormat[3]==0x43 &&  | 
551  | 0  |         pInfo->formatVersion[0]==2 &&  | 
552  | 0  |         pInfo->formatVersion[1]>=1  | 
553  | 0  |     )) { | 
554  | 0  |         udata_printError(ds, "ucol_swapInverseUCA(): data format %02x.%02x.%02x.%02x (format version %02x.%02x) is not an inverse UCA collation file\n",  | 
555  | 0  |                          pInfo->dataFormat[0], pInfo->dataFormat[1],  | 
556  | 0  |                          pInfo->dataFormat[2], pInfo->dataFormat[3],  | 
557  | 0  |                          pInfo->formatVersion[0], pInfo->formatVersion[1]);  | 
558  | 0  |         *pErrorCode=U_UNSUPPORTED_ERROR;  | 
559  | 0  |         return 0;  | 
560  | 0  |     }  | 
561  |  |  | 
562  | 0  |     inBytes=(const uint8_t *)inData+headerSize;  | 
563  | 0  |     outBytes=(uint8_t *)outData+headerSize;  | 
564  |  | 
  | 
565  | 0  |     inHeader=(const InverseUCATableHeader *)inBytes;  | 
566  | 0  |     outHeader=(InverseUCATableHeader *)outBytes;  | 
567  |  |  | 
568  |  |     /*  | 
569  |  |      * The inverse UCA collation binary must contain at least the InverseUCATableHeader,  | 
570  |  |      * starting with its size field.  | 
571  |  |      * sizeof(UCATableHeader)==8*4 in ICU 2.8  | 
572  |  |      * check the length against the header size before reading the size field  | 
573  |  |      */  | 
574  | 0  |     if(length<0) { | 
575  | 0  |         header.byteSize=udata_readInt32(ds, inHeader->byteSize);  | 
576  | 0  |     } else if(  | 
577  | 0  |         ((length-headerSize)<(8*4) ||  | 
578  | 0  |          (uint32_t)(length-headerSize)<(header.byteSize=udata_readInt32(ds, inHeader->byteSize)))  | 
579  | 0  |     ) { | 
580  | 0  |         udata_printError(ds, "ucol_swapInverseUCA(): too few bytes (%d after header) for inverse UCA collation data\n",  | 
581  | 0  |                          length);  | 
582  | 0  |         *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;  | 
583  | 0  |         return 0;  | 
584  | 0  |     }  | 
585  |  |  | 
586  | 0  |     if(length>=0) { | 
587  |  |         /* copy everything, takes care of data that needs no swapping */  | 
588  | 0  |         if(inBytes!=outBytes) { | 
589  | 0  |             uprv_memcpy(outBytes, inBytes, header.byteSize);  | 
590  | 0  |         }  | 
591  |  |  | 
592  |  |         /* swap the necessary pieces in the order of their occurrence in the data */  | 
593  |  |  | 
594  |  |         /* read more of the InverseUCATableHeader (the byteSize field was read above) */  | 
595  | 0  |         header.tableSize=   ds->readUInt32(inHeader->tableSize);  | 
596  | 0  |         header.contsSize=   ds->readUInt32(inHeader->contsSize);  | 
597  | 0  |         header.table=       ds->readUInt32(inHeader->table);  | 
598  | 0  |         header.conts=       ds->readUInt32(inHeader->conts);  | 
599  |  |  | 
600  |  |         /* swap the 32-bit integers in the header */  | 
601  | 0  |         ds->swapArray32(ds, inHeader, 5*4, outHeader, pErrorCode);  | 
602  |  |  | 
603  |  |         /* swap the inverse table; tableSize counts uint32_t[3] rows */  | 
604  | 0  |         ds->swapArray32(ds, inBytes+header.table, header.tableSize*3*4,  | 
605  | 0  |                            outBytes+header.table, pErrorCode);  | 
606  |  |  | 
607  |  |         /* swap the continuation table; contsSize counts UChars */  | 
608  | 0  |         ds->swapArray16(ds, inBytes+header.conts, header.contsSize*U_SIZEOF_UCHAR,  | 
609  | 0  |                            outBytes+header.conts, pErrorCode);  | 
610  | 0  |     }  | 
611  |  | 
  | 
612  | 0  |     return headerSize+header.byteSize;  | 
613  | 0  | }  | 
614  |  |  | 
615  |  | #endif /* #if !UCONFIG_NO_COLLATION */  |