• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *
6 *   Copyright (C) 2004-2016, International Business Machines
7 *   Corporation and others.  All Rights Reserved.
8 *
9 *******************************************************************************
10 *   file name:  bidipropsbuilder.cpp (was genbidi/store.c)
11 *   encoding:   US-ASCII
12 *   tab size:   8 (not used)
13 *   indentation:4
14 *
15 *   created on: 2004dec30
16 *   created by: Markus W. Scherer
17 *
18 *   Store Unicode bidi/shaping properties efficiently for
19 *   random access.
20 */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "unicode/utypes.h"
25 #include "unicode/uchar.h"
26 #include "unicode/uniset.h"
27 #include "cmemory.h"
28 #include "cstring.h"
29 #include "ppucd.h"
30 #include "uarrsort.h"
31 #include "unicode/udata.h"
32 #include "unewdata.h"
33 #include "utrie2.h"
34 #include "writesrc.h"
35 #include "ubidi_props.h"
36 #include "genprops.h"
37 
38 /* Unicode bidi/shaping properties file format ---------------------------------
39 
40 The file format prepared and written here contains several data
41 structures that store indexes or data.
42 
43 Before the data contents described below, there are the headers required by
44 the udata API for loading ICU data. Especially, a UDataInfo structure
45 precedes the actual data. It contains platform properties values and the
46 file format version.
47 
48 The following is a description of format version 2.2 .
49 
50 The file contains the following structures:
51 
52     const int32_t indexes[i0] with values i0, i1, ...:
53     (see UBIDI_IX_... constants for names of indexes)
54 
55     i0 indexLength; -- length of indexes[] (UBIDI_IX_TOP)
56     i1 dataLength; -- length in bytes of the post-header data (incl. indexes[])
57     i2 trieSize; -- size in bytes of the bidi/shaping properties trie
58     i3 mirrorLength; -- length in uint32_t of the bidi mirroring array
59 
60     i4 jgStart; -- first code point with Joining_Group data
61     i5 jgLimit; -- limit code point for Joining_Group data
62 
63     -- i6, i7 new in format version 2.2:
64     i6 jgStart2; -- first code point with Joining_Group data, second range
65     i7 jgLimit2; -- limit code point for Joining_Group data, second range
66 
67     i8..i14 reservedIndexes; -- reserved values; 0 for now
68 
69     i15 maxValues; -- maximum code values for enumerated properties
70                       bits 23..16 contain the max value for Joining_Group,
71                       otherwise the bits are used like enum fields in the trie word
72 
73     Serialized trie, see utrie2.h;
74 
75     const uint32_t mirrors[mirrorLength];
76 
77     const uint8_t jgArray[i5-i4]; -- (i5-i4)+(i7-i6) is always a multiple of 4
78     const uint8_t jgArray2[i7-i6]; -- new in format version 2.2
79 
80 Trie data word:
81 Bits
82 15..13  signed delta to bidi mirroring code point
83         (add delta to input code point)
84         0 no such code point (source maps to itself)
85         -3..-1, 1..3 delta
86         -4 look in mirrors table
87     12  is mirrored
88     11  Bidi_Control
89     10  Join_Control
90  9.. 8  Bidi_Paired_Bracket_Type(bpt) -- new in format version 2.1
91  7.. 5  Joining_Type
92  4.. 0  BiDi category
93 
94 
95 Mirrors:
96 Stores some of the bidi mirroring data, where each code point maps to
97 at most one other.
98 Most code points do not have a mirroring code point; most that do have a signed
99 delta stored in the trie data value. Only those where the delta does not fit
100 into the trie data are stored in this table.
101 
102 Logically, this is a two-column table with source and mirror code points.
103 
104 Physically, the table is compressed by taking advantage of the fact that each
105 mirror code point is also a source code point
106 (each of them is a mirror of the other).
107 Therefore, both logical columns contain the same set of code points, which needs
108 to be stored only once.
109 
110 The table stores source code points, and also for each the index of its mirror
111 code point in the same table, in a simple array of uint32_t.
112 Bits
113 31..21  index to mirror code point (unsigned)
114 20.. 0  source code point
115 
116 The table is sorted by source code points.
117 
118 
119 Joining_Group array:
120 The Joining_Group values do not fit into the 16-bit trie, but the data is also
121 limited to a small range of code points (Arabic and Syriac) and not
122 well compressible.
123 
124 The start and limit code points for the range are stored in the indexes[]
125 array, and the jgArray[] stores a byte for each of these code points,
126 containing the Joining_Group value.
127 
128 All code points outside of this range have No_Joining_Group (0).
129 
130 ICU 54 adds jgArray2[] for a second range.
131 
132 --- Changes in format version 2.2 ---
133 
134 Addition of second range for Joining_Group values (i6, i7),
135 for 10800..10FFF, including Unicode 7.0 10AC0..10AFF Manichaean.
136 
137 --- Changes in format version 2.1 ---
138 
139 Addition of Bidi_Paired_Bracket_Type(bpt) values.
140 (Trie data bits 9..8 were reserved.)
141 
142 --- Changes in format version 2 ---
143 
144 Change from UTrie to UTrie2.
145 
146 ----------------------------------------------------------------------------- */
147 
148 U_NAMESPACE_USE
149 
150 /* UDataInfo cf. udata.h */
151 static UDataInfo dataInfo={
152     sizeof(UDataInfo),
153     0,
154 
155     U_IS_BIG_ENDIAN,
156     U_CHARSET_FAMILY,
157     U_SIZEOF_UCHAR,
158     0,
159 
160     /* dataFormat="BiDi" */
161     { UBIDI_FMT_0, UBIDI_FMT_1, UBIDI_FMT_2, UBIDI_FMT_3 },
162     { 2, 2, 0, 0 },                             /* formatVersion */
163     { 6, 0, 0, 0 }                              /* dataVersion */
164 };
165 
166 /* -------------------------------------------------------------------------- */
167 
168 class BiDiPropsBuilder : public PropsBuilder {
169 public:
170     BiDiPropsBuilder(UErrorCode &errorCode);
171     virtual ~BiDiPropsBuilder();
172 
173     virtual void setUnicodeVersion(const UVersionInfo version);
174     virtual void setProps(const UniProps &, const UnicodeSet &newValues, UErrorCode &errorCode);
175     virtual void build(UErrorCode &errorCode);
176     virtual void writeCSourceFile(const char *path, UErrorCode &errorCode);
177     virtual void writeBinaryData(const char *path, UBool withCopyright, UErrorCode &errorCode);
178 
179 private:
180     int32_t encodeBidiMirroringGlyph(UChar32 src, UChar32 end, UChar32 mirror, UErrorCode &errorCode);
181     void makeMirror(UErrorCode &errorCode);
182 
183     static const UChar32 MIN_JG_START=0x600;
184     static const UChar32 MAX_JG_LIMIT=0x8ff+1;
185     static const UChar32 MIN_JG_START2=0x10800;
186     static const UChar32 MAX_JG_LIMIT2=0x10fff+1;
187 
188     UnicodeSet relevantProps;
189     UTrie2 *pTrie;
190     uint8_t jgArray[MAX_JG_LIMIT-MIN_JG_START];
191     uint8_t jgArray2[MAX_JG_LIMIT2-MIN_JG_START2];
192     uint32_t mirrors[UBIDI_MAX_MIRROR_INDEX+1][2];
193     int32_t mirrorTop;
194 };
195 
BiDiPropsBuilder(UErrorCode & errorCode)196 BiDiPropsBuilder::BiDiPropsBuilder(UErrorCode &errorCode)
197         : pTrie(NULL),
198           mirrorTop(0) {
199     // This builder encodes the following properties.
200     relevantProps.
201         add(UCHAR_BIDI_CONTROL).
202         add(UCHAR_BIDI_MIRRORED).
203         add(UCHAR_BIDI_CLASS).
204         add(UCHAR_BIDI_MIRRORING_GLYPH).
205         add(UCHAR_JOIN_CONTROL).
206         add(UCHAR_JOINING_GROUP).
207         add(UCHAR_JOINING_TYPE);
208     pTrie=utrie2_open(0, 0, &errorCode);
209     if(U_FAILURE(errorCode)) {
210         fprintf(stderr, "genprops error: bidipropsbuilder utrie2_open() failed - %s\n",
211                 u_errorName(errorCode));
212     }
213     uprv_memset(jgArray, U_JG_NO_JOINING_GROUP, sizeof(jgArray));
214     uprv_memset(jgArray2, U_JG_NO_JOINING_GROUP, sizeof(jgArray2));
215 }
216 
~BiDiPropsBuilder()217 BiDiPropsBuilder::~BiDiPropsBuilder() {
218     utrie2_close(pTrie);
219 }
220 
221 void
setUnicodeVersion(const UVersionInfo version)222 BiDiPropsBuilder::setUnicodeVersion(const UVersionInfo version) {
223     uprv_memcpy(dataInfo.dataVersion, version, 4);
224 }
225 
226 /* bidi mirroring table ----------------------------------------------------- */
227 
228 int32_t
encodeBidiMirroringGlyph(UChar32 src,UChar32 end,UChar32 mirror,UErrorCode & errorCode)229 BiDiPropsBuilder::encodeBidiMirroringGlyph(UChar32 src, UChar32 end, UChar32 mirror,
230                                            UErrorCode &errorCode) {
231     if(U_FAILURE(errorCode) || mirror<0) {
232         return 0;
233     }
234     if(src!=end) {
235         fprintf(stderr,
236                 "genprops error: range U+%04lX..U+%04lX all with the same "
237                 "Bidi_Mirroring_Glyph U+%04lX\n",
238                 (long)src, (long)end, (long)mirror);
239         errorCode=U_ILLEGAL_ARGUMENT_ERROR;
240         return 0;
241     }
242     int32_t delta=mirror-src;
243     if(delta==0) {
244         return 0; /* mapping to self=no mapping */
245     }
246 
247     if(delta<UBIDI_MIN_MIRROR_DELTA || UBIDI_MAX_MIRROR_DELTA<delta) {
248         /* delta does not fit into the trie properties value, store in the mirrors[] table */
249         if(mirrorTop==LENGTHOF(mirrors)) {
250             fprintf(stderr,
251                     "genprops error: too many long-distance Bidi_Mirroring_Glyph mappings; "
252                     "UBIDI_MAX_MIRROR_INDEX can only be increased by "
253                     "redesigning the ubidi.icu data bit fields\n");
254             errorCode=U_BUFFER_OVERFLOW_ERROR;
255             return 0;
256         }
257 
258         /* possible: search the table so far and see if src is already listed */
259 
260         mirrors[mirrorTop][0]=(uint32_t)src;
261         mirrors[mirrorTop][1]=(uint32_t)mirror;
262         ++mirrorTop;
263 
264         /* set an escape marker in src's properties */
265         delta=UBIDI_ESC_MIRROR_DELTA;
266     }
267     return delta;
268 }
269 
270 void
setProps(const UniProps & props,const UnicodeSet & newValues,UErrorCode & errorCode)271 BiDiPropsBuilder::setProps(const UniProps &props, const UnicodeSet &newValues,
272                            UErrorCode &errorCode) {
273     if(U_FAILURE(errorCode) || newValues.containsNone(relevantProps)) { return; }
274 
275     UChar32 start=props.start;
276     UChar32 end=props.end;
277 
278     // The runtime code relies on this invariant for returning both bmg and bpb
279     // from the same data.
280     int32_t bpt=props.getIntProp(UCHAR_BIDI_PAIRED_BRACKET_TYPE);
281     if(!(bpt==0 ? props.bpb==U_SENTINEL : props.bpb==props.bmg)) {
282         fprintf(stderr,
283                 "genprops error: invariant not true: "
284                 "if(bpt==None) then bpb=<none> else bpb=bmg\n");
285         return;
286     }
287     int32_t delta=encodeBidiMirroringGlyph(start, end, props.bmg, errorCode);
288     uint32_t value=(uint32_t)delta<<UBIDI_MIRROR_DELTA_SHIFT;
289     if(props.binProps[UCHAR_BIDI_MIRRORED]) {
290         value|=U_MASK(UBIDI_IS_MIRRORED_SHIFT);
291     }
292     if(props.binProps[UCHAR_BIDI_CONTROL]) {
293         value|=U_MASK(UBIDI_BIDI_CONTROL_SHIFT);
294     }
295     if(props.binProps[UCHAR_JOIN_CONTROL]) {
296         value|=U_MASK(UBIDI_JOIN_CONTROL_SHIFT);
297     }
298     value|=(uint32_t)bpt<<UBIDI_BPT_SHIFT;
299     value|=(uint32_t)props.getIntProp(UCHAR_JOINING_TYPE)<<UBIDI_JT_SHIFT;
300     value|=(uint32_t)props.getIntProp(UCHAR_BIDI_CLASS);
301     utrie2_setRange32(pTrie, start, end, value, TRUE, &errorCode);
302     if(U_FAILURE(errorCode)) {
303         fprintf(stderr, "genprops error: BiDiPropsBuilder utrie2_setRange32() failed - %s\n",
304                 u_errorName(errorCode));
305         return;
306     }
307 
308     // Store Joining_Group values from vector column 1 in simple byte arrays.
309     int32_t jg=props.getIntProp(UCHAR_JOINING_GROUP);
310     for(UChar32 c=start; c<=end; ++c) {
311         int32_t jgStart;
312         if(MIN_JG_START<=c && c<MAX_JG_LIMIT) {
313             jgArray[c-MIN_JG_START]=(uint8_t)jg;
314         } else if(MIN_JG_START2<=c && c<MAX_JG_LIMIT2) {
315             jgArray2[c-MIN_JG_START2]=(uint8_t)jg;
316         } else if(jg!=U_JG_NO_JOINING_GROUP) {
317             fprintf(stderr, "genprops error: Joining_Group for out-of-range code points U+%04lx..U+%04lx\n",
318                     (long)start, (long)end);
319             errorCode=U_ILLEGAL_ARGUMENT_ERROR;
320             return;
321         }
322     }
323 }
324 
325 /* generate output data ----------------------------------------------------- */
326 
327 static int32_t U_CALLCONV
compareMirror(const void * context,const void * left,const void * right)328 compareMirror(const void *context, const void *left, const void *right) {
329     UChar32 l, r;
330 
331     l=UBIDI_GET_MIRROR_CODE_POINT(((const uint32_t *)left)[0]);
332     r=UBIDI_GET_MIRROR_CODE_POINT(((const uint32_t *)right)[0]);
333     return l-r;
334 }
335 
336 void
makeMirror(UErrorCode & errorCode)337 BiDiPropsBuilder::makeMirror(UErrorCode &errorCode) {
338     /* sort the mirroring table by source code points */
339     uprv_sortArray(mirrors, mirrorTop, 8,
340                    compareMirror, NULL, FALSE, &errorCode);
341     if(U_FAILURE(errorCode)) { return; }
342 
343     /*
344      * reduce the 2-column table to a single column
345      * by putting the index to the mirror entry into the source entry
346      *
347      * first:
348      * find each mirror code point in the source column and set each other's indexes
349      *
350      * second:
351      * reduce the table, combine the source code points with their indexes
352      * and store as a simple array of uint32_t
353      */
354     for(int32_t i=0; i<mirrorTop; ++i) {
355         uint32_t c=mirrors[i][1]; /* mirror code point */
356         if(c>0x1fffff) {
357             continue; /* this entry already has an index */
358         }
359 
360         /* search for the mirror code point in the source column */
361         int32_t start, limit, step;
362         if(c<mirrors[i][0]) {
363             /* search before i */
364             start=i-1;
365             limit=-1;
366             step=-1;
367         } else {
368             start=i+1;
369             limit=mirrorTop;
370             step=1;
371         }
372 
373         for(int32_t j=start;; j+=step) {
374             if(j==limit) {
375                 fprintf(stderr,
376                         "genprops error: bidi mirror does not roundtrip - %04lx->%04lx->?\n",
377                         (long)mirrors[i][0], (long)mirrors[i][1]);
378                 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
379             }
380             if(c==mirrors[j][0]) {
381                 /*
382                  * found the mirror code point c in the source column,
383                  * set both entries' indexes to each other
384                  */
385                 if(UBIDI_GET_MIRROR_CODE_POINT(mirrors[i][0])!=UBIDI_GET_MIRROR_CODE_POINT(mirrors[j][1])) {
386                     /* roundtrip check fails */
387                     fprintf(stderr,
388                             "genprops error: bidi mirrors do not roundtrip - %04lx->%04lx->%04lx\n",
389                             (long)mirrors[i][0], (long)mirrors[i][1], (long)mirrors[j][1]);
390                     errorCode=U_ILLEGAL_ARGUMENT_ERROR;
391                 } else {
392                     mirrors[i][1]|=(uint32_t)j<<UBIDI_MIRROR_INDEX_SHIFT;
393                     mirrors[j][1]|=(uint32_t)i<<UBIDI_MIRROR_INDEX_SHIFT;
394                 }
395                 break;
396             }
397         }
398     }
399 
400     /* now the second step, the actual reduction of the table */
401     uint32_t *reducedMirror=mirrors[0];
402     for(int32_t i=0; i<mirrorTop; ++i) {
403         reducedMirror[i]=mirrors[i][0]|(mirrors[i][1]&~0x1fffff);
404     }
405 }
406 
407 static int32_t indexes[UBIDI_IX_TOP]={
408     UBIDI_IX_TOP, 0, 0, 0,
409     0, 0, 0, 0,
410     0, 0, 0, 0,
411     0, 0, 0, 0
412 };
413 
414 static uint8_t trieBlock[40000];
415 static int32_t trieSize;
416 
417 void
build(UErrorCode & errorCode)418 BiDiPropsBuilder::build(UErrorCode &errorCode) {
419     makeMirror(errorCode);
420     if(U_FAILURE(errorCode)) { return; }
421 
422     utrie2_freeze(pTrie, UTRIE2_16_VALUE_BITS, &errorCode);
423     trieSize=utrie2_serialize(pTrie, trieBlock, sizeof(trieBlock), &errorCode);
424     if(U_FAILURE(errorCode)) {
425         fprintf(stderr, "genprops error: utrie2_freeze()+utrie2_serialize() failed: %s (length %ld)\n",
426                 u_errorName(errorCode), (long)trieSize);
427         return;
428     }
429 
430     // Finish jgArray & jgArray2.
431     UChar32 jgStart;  // First code point with a Joining_Group, first range.
432     UChar32 jgLimit;  // One past the last one.
433     // Find the end of the range first, so that if it's empty we
434     // get jgStart=jgLimit=MIN_JG_START.
435     for(jgLimit=MAX_JG_LIMIT;
436         MIN_JG_START<jgLimit && jgArray[jgLimit-MIN_JG_START-1]==U_JG_NO_JOINING_GROUP;
437         --jgLimit) {}
438     for(jgStart=MIN_JG_START;
439         jgStart<jgLimit && jgArray[jgStart-MIN_JG_START]==U_JG_NO_JOINING_GROUP;
440         ++jgStart) {}
441 
442     UChar32 jgStart2;  // First code point with a Joining_Group, second range.
443     UChar32 jgLimit2;  // One past the last one.
444     for(jgLimit2=MAX_JG_LIMIT2;
445         MIN_JG_START2<jgLimit2 && jgArray2[jgLimit2-MIN_JG_START2-1]==U_JG_NO_JOINING_GROUP;
446         --jgLimit2) {}
447     for(jgStart2=MIN_JG_START2;
448         jgStart2<jgLimit2 && jgArray2[jgStart2-MIN_JG_START2]==U_JG_NO_JOINING_GROUP;
449         ++jgStart2) {}
450 
451     // Pad the total Joining_Group arrays length to a multiple of 4.
452     // Prefer rounding down starts before rounding up limits
453     // so that we are guaranteed not to increase the limits beyond
454     // the end of the arrays' code point ranges.
455     int32_t jgLength=jgLimit-jgStart+jgLimit2-jgStart2;
456     while(jgLength&3) {
457         if((jgStart<jgLimit) && (jgStart&3)) {
458             --jgStart;
459         } else if((jgStart2<jgLimit2) && (jgStart2&3)) {
460             --jgStart2;
461         } else if(jgStart<jgLimit) {
462             ++jgLimit;
463         } else {
464             ++jgLimit2;
465         }
466         ++jgLength;
467     }
468     indexes[UBIDI_IX_JG_START]=jgStart;
469     indexes[UBIDI_IX_JG_LIMIT]=jgLimit;
470     indexes[UBIDI_IX_JG_START2]=jgStart2;
471     indexes[UBIDI_IX_JG_LIMIT2]=jgLimit2;
472 
473     indexes[UBIDI_IX_TRIE_SIZE]=trieSize;
474     indexes[UBIDI_IX_MIRROR_LENGTH]=mirrorTop;
475     indexes[UBIDI_IX_LENGTH]=
476         (int32_t)sizeof(indexes)+
477         trieSize+
478         4*mirrorTop+
479         jgLength;
480 
481     if(!beQuiet) {
482         puts("* ubidi.icu stats *");
483         printf("trie size in bytes:                    %5d\n", (int)trieSize);
484         printf("size in bytes of mirroring table:      %5d\n", (int)(4*mirrorTop));
485         printf("length of Joining_Group array:         %5d (U+%04x..U+%04x)\n",
486                (int)(jgLimit-jgStart), (int)jgStart, (int)(jgLimit-1));
487         printf("length of Joining_Group array 2:       %5d (U+%04x..U+%04x)\n",
488                (int)(jgLimit2-jgStart2), (int)jgStart2, (int)(jgLimit2-1));
489         printf("data size:                             %5d\n", (int)indexes[UBIDI_IX_LENGTH]);
490     }
491 
492     indexes[UBIDI_MAX_VALUES_INDEX]=
493         ((int32_t)U_CHAR_DIRECTION_COUNT-1)|
494         (((int32_t)U_JT_COUNT-1)<<UBIDI_JT_SHIFT)|
495         (((int32_t)U_BPT_COUNT-1)<<UBIDI_BPT_SHIFT)|
496         (((int32_t)U_JG_COUNT-1)<<UBIDI_MAX_JG_SHIFT);
497 }
498 
499 void
writeCSourceFile(const char * path,UErrorCode & errorCode)500 BiDiPropsBuilder::writeCSourceFile(const char *path, UErrorCode &errorCode) {
501     if(U_FAILURE(errorCode)) { return; }
502 
503     FILE *f=usrc_create(path, "ubidi_props_data.h", 2016,
504                         "icu/tools/unicode/c/genprops/bidipropsbuilder.cpp");
505     if(f==NULL) {
506         errorCode=U_FILE_ACCESS_ERROR;
507         return;
508     }
509     fputs("#ifdef INCLUDED_FROM_UBIDI_PROPS_C\n\n", f);
510     usrc_writeArray(f,
511         "static const UVersionInfo ubidi_props_dataVersion={",
512         dataInfo.dataVersion, 8, 4,
513         "};\n\n");
514     usrc_writeArray(f,
515         "static const int32_t ubidi_props_indexes[UBIDI_IX_TOP]={",
516         indexes, 32, UBIDI_IX_TOP,
517         "};\n\n");
518     usrc_writeUTrie2Arrays(f,
519         "static const uint16_t ubidi_props_trieIndex[%ld]={\n", NULL,
520         pTrie,
521         "\n};\n\n");
522     usrc_writeArray(f,
523         "static const uint32_t ubidi_props_mirrors[%ld]={\n",
524         mirrors, 32, mirrorTop,
525         "\n};\n\n");
526     UChar32 jgStart=indexes[UBIDI_IX_JG_START];
527     UChar32 jgLimit=indexes[UBIDI_IX_JG_LIMIT];
528     usrc_writeArray(f,
529         "static const uint8_t ubidi_props_jgArray[%ld]={\n",
530         jgArray+(jgStart-MIN_JG_START), 8, jgLimit-jgStart,
531         "\n};\n\n");
532     UChar32 jgStart2=indexes[UBIDI_IX_JG_START2];
533     UChar32 jgLimit2=indexes[UBIDI_IX_JG_LIMIT2];
534     usrc_writeArray(f,
535         "static const uint8_t ubidi_props_jgArray2[%ld]={\n",
536         jgArray2+(jgStart2-MIN_JG_START2), 8, jgLimit2-jgStart2,
537         "\n};\n\n");
538     fputs(
539         "static const UBiDiProps ubidi_props_singleton={\n"
540         "  NULL,\n"
541         "  ubidi_props_indexes,\n"
542         "  ubidi_props_mirrors,\n"
543         "  ubidi_props_jgArray,\n"
544         "  ubidi_props_jgArray2,\n",
545         f);
546     usrc_writeUTrie2Struct(f,
547         "  {\n",
548         pTrie, "ubidi_props_trieIndex", NULL,
549         "  },\n");
550     usrc_writeArray(f, "  { ", dataInfo.formatVersion, 8, 4, " }\n");
551     fputs("};\n\n"
552           "#endif  // INCLUDED_FROM_UBIDI_PROPS_C\n", f);
553     fclose(f);
554 }
555 
556 void
writeBinaryData(const char * path,UBool withCopyright,UErrorCode & errorCode)557 BiDiPropsBuilder::writeBinaryData(const char *path, UBool withCopyright, UErrorCode &errorCode) {
558     if(U_FAILURE(errorCode)) { return; }
559 
560     UNewDataMemory *pData=udata_create(path, UBIDI_DATA_TYPE, UBIDI_DATA_NAME, &dataInfo,
561                                        withCopyright ? U_COPYRIGHT_STRING : NULL, &errorCode);
562     if(U_FAILURE(errorCode)) {
563         fprintf(stderr, "genprops: udata_create(%s, ubidi.icu) failed - %s\n",
564                 path, u_errorName(errorCode));
565         return;
566     }
567 
568     udata_writeBlock(pData, indexes, sizeof(indexes));
569     udata_writeBlock(pData, trieBlock, trieSize);
570     udata_writeBlock(pData, mirrors, 4*mirrorTop);
571     UChar32 jgStart=indexes[UBIDI_IX_JG_START];
572     UChar32 jgLimit=indexes[UBIDI_IX_JG_LIMIT];
573     udata_writeBlock(pData, jgArray+(jgStart-MIN_JG_START), jgLimit-jgStart);
574     UChar32 jgStart2=indexes[UBIDI_IX_JG_START2];
575     UChar32 jgLimit2=indexes[UBIDI_IX_JG_LIMIT2];
576     udata_writeBlock(pData, jgArray2+(jgStart2-MIN_JG_START2), jgLimit2-jgStart2);
577 
578     long dataLength=udata_finish(pData, &errorCode);
579     if(U_FAILURE(errorCode)) {
580         fprintf(stderr, "genprops error: bidipropsbuilder %d writing the output file\n", errorCode);
581         return;
582     }
583 
584     if(dataLength!=indexes[UBIDI_IX_LENGTH]) {
585         fprintf(stderr,
586                 "udata_finish(ubidi.icu) reports %ld bytes written but should be %ld\n",
587                 dataLength, (long)indexes[UBIDI_IX_LENGTH]);
588         errorCode=U_INTERNAL_PROGRAM_ERROR;
589     }
590 }
591 
592 PropsBuilder *
createBiDiPropsBuilder(UErrorCode & errorCode)593 createBiDiPropsBuilder(UErrorCode &errorCode) {
594     if(U_FAILURE(errorCode)) { return NULL; }
595     PropsBuilder *pb=new BiDiPropsBuilder(errorCode);
596     if(pb==NULL) {
597         errorCode=U_MEMORY_ALLOCATION_ERROR;
598     }
599     return pb;
600 }
601 
602 /*
603  * Hey, Emacs, please set the following:
604  *
605  * Local Variables:
606  * indent-tabs-mode: nil
607  * End:
608  *
609  */
610