• 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         if(MIN_JG_START<=c && c<MAX_JG_LIMIT) {
312             jgArray[c-MIN_JG_START]=(uint8_t)jg;
313         } else if(MIN_JG_START2<=c && c<MAX_JG_LIMIT2) {
314             jgArray2[c-MIN_JG_START2]=(uint8_t)jg;
315         } else if(jg!=U_JG_NO_JOINING_GROUP) {
316             fprintf(stderr, "genprops error: Joining_Group for out-of-range code points U+%04lx..U+%04lx\n",
317                     (long)start, (long)end);
318             errorCode=U_ILLEGAL_ARGUMENT_ERROR;
319             return;
320         }
321     }
322 }
323 
324 /* generate output data ----------------------------------------------------- */
325 
326 static int32_t U_CALLCONV
compareMirror(const void * context,const void * left,const void * right)327 compareMirror(const void *context, const void *left, const void *right) {
328     UChar32 l, r;
329 
330     l=UBIDI_GET_MIRROR_CODE_POINT(((const uint32_t *)left)[0]);
331     r=UBIDI_GET_MIRROR_CODE_POINT(((const uint32_t *)right)[0]);
332     return l-r;
333 }
334 
335 void
makeMirror(UErrorCode & errorCode)336 BiDiPropsBuilder::makeMirror(UErrorCode &errorCode) {
337     /* sort the mirroring table by source code points */
338     uprv_sortArray(mirrors, mirrorTop, 8,
339                    compareMirror, NULL, false, &errorCode);
340     if(U_FAILURE(errorCode)) { return; }
341 
342     /*
343      * reduce the 2-column table to a single column
344      * by putting the index to the mirror entry into the source entry
345      *
346      * first:
347      * find each mirror code point in the source column and set each other's indexes
348      *
349      * second:
350      * reduce the table, combine the source code points with their indexes
351      * and store as a simple array of uint32_t
352      */
353     for(int32_t i=0; i<mirrorTop; ++i) {
354         uint32_t c=mirrors[i][1]; /* mirror code point */
355         if(c>0x1fffff) {
356             continue; /* this entry already has an index */
357         }
358 
359         /* search for the mirror code point in the source column */
360         int32_t start, limit, step;
361         if(c<mirrors[i][0]) {
362             /* search before i */
363             start=i-1;
364             limit=-1;
365             step=-1;
366         } else {
367             start=i+1;
368             limit=mirrorTop;
369             step=1;
370         }
371 
372         for(int32_t j=start;; j+=step) {
373             if(j==limit) {
374                 fprintf(stderr,
375                         "genprops error: bidi mirror does not roundtrip - %04lx->%04lx->?\n",
376                         (long)mirrors[i][0], (long)mirrors[i][1]);
377                 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
378             }
379             if(c==mirrors[j][0]) {
380                 /*
381                  * found the mirror code point c in the source column,
382                  * set both entries' indexes to each other
383                  */
384                 if(UBIDI_GET_MIRROR_CODE_POINT(mirrors[i][0])!=UBIDI_GET_MIRROR_CODE_POINT(mirrors[j][1])) {
385                     /* roundtrip check fails */
386                     fprintf(stderr,
387                             "genprops error: bidi mirrors do not roundtrip - %04lx->%04lx->%04lx\n",
388                             (long)mirrors[i][0], (long)mirrors[i][1], (long)mirrors[j][1]);
389                     errorCode=U_ILLEGAL_ARGUMENT_ERROR;
390                 } else {
391                     mirrors[i][1]|=(uint32_t)j<<UBIDI_MIRROR_INDEX_SHIFT;
392                     mirrors[j][1]|=(uint32_t)i<<UBIDI_MIRROR_INDEX_SHIFT;
393                 }
394                 break;
395             }
396         }
397     }
398 
399     /* now the second step, the actual reduction of the table */
400     uint32_t *reducedMirror=mirrors[0];
401     for(int32_t i=0; i<mirrorTop; ++i) {
402         reducedMirror[i]=mirrors[i][0]|(mirrors[i][1]&~0x1fffff);
403     }
404 }
405 
406 static int32_t indexes[UBIDI_IX_TOP]={
407     UBIDI_IX_TOP, 0, 0, 0,
408     0, 0, 0, 0,
409     0, 0, 0, 0,
410     0, 0, 0, 0
411 };
412 
413 static uint8_t trieBlock[40000];
414 static int32_t trieSize;
415 
416 void
build(UErrorCode & errorCode)417 BiDiPropsBuilder::build(UErrorCode &errorCode) {
418     makeMirror(errorCode);
419     if(U_FAILURE(errorCode)) { return; }
420 
421     utrie2_freeze(pTrie, UTRIE2_16_VALUE_BITS, &errorCode);
422     trieSize=utrie2_serialize(pTrie, trieBlock, sizeof(trieBlock), &errorCode);
423     if(U_FAILURE(errorCode)) {
424         fprintf(stderr, "genprops error: utrie2_freeze()+utrie2_serialize() failed: %s (length %ld)\n",
425                 u_errorName(errorCode), (long)trieSize);
426         return;
427     }
428 
429     // Finish jgArray & jgArray2.
430     UChar32 jgStart;  // First code point with a Joining_Group, first range.
431     UChar32 jgLimit;  // One past the last one.
432     // Find the end of the range first, so that if it's empty we
433     // get jgStart=jgLimit=MIN_JG_START.
434     for(jgLimit=MAX_JG_LIMIT;
435         MIN_JG_START<jgLimit && jgArray[jgLimit-MIN_JG_START-1]==U_JG_NO_JOINING_GROUP;
436         --jgLimit) {}
437     for(jgStart=MIN_JG_START;
438         jgStart<jgLimit && jgArray[jgStart-MIN_JG_START]==U_JG_NO_JOINING_GROUP;
439         ++jgStart) {}
440 
441     UChar32 jgStart2;  // First code point with a Joining_Group, second range.
442     UChar32 jgLimit2;  // One past the last one.
443     for(jgLimit2=MAX_JG_LIMIT2;
444         MIN_JG_START2<jgLimit2 && jgArray2[jgLimit2-MIN_JG_START2-1]==U_JG_NO_JOINING_GROUP;
445         --jgLimit2) {}
446     for(jgStart2=MIN_JG_START2;
447         jgStart2<jgLimit2 && jgArray2[jgStart2-MIN_JG_START2]==U_JG_NO_JOINING_GROUP;
448         ++jgStart2) {}
449 
450     // Pad the total Joining_Group arrays length to a multiple of 4.
451     // Prefer rounding down starts before rounding up limits
452     // so that we are guaranteed not to increase the limits beyond
453     // the end of the arrays' code point ranges.
454     int32_t jgLength=jgLimit-jgStart+jgLimit2-jgStart2;
455     while(jgLength&3) {
456         if((jgStart<jgLimit) && (jgStart&3)) {
457             --jgStart;
458         } else if((jgStart2<jgLimit2) && (jgStart2&3)) {
459             --jgStart2;
460         } else if(jgStart<jgLimit) {
461             ++jgLimit;
462         } else {
463             ++jgLimit2;
464         }
465         ++jgLength;
466     }
467     indexes[UBIDI_IX_JG_START]=jgStart;
468     indexes[UBIDI_IX_JG_LIMIT]=jgLimit;
469     indexes[UBIDI_IX_JG_START2]=jgStart2;
470     indexes[UBIDI_IX_JG_LIMIT2]=jgLimit2;
471 
472     indexes[UBIDI_IX_TRIE_SIZE]=trieSize;
473     indexes[UBIDI_IX_MIRROR_LENGTH]=mirrorTop;
474     indexes[UBIDI_IX_LENGTH]=
475         (int32_t)sizeof(indexes)+
476         trieSize+
477         4*mirrorTop+
478         jgLength;
479 
480     if(!beQuiet) {
481         puts("* ubidi.icu stats *");
482         printf("trie size in bytes:                    %5d\n", (int)trieSize);
483         printf("size in bytes of mirroring table:      %5d\n", (int)(4*mirrorTop));
484         printf("length of Joining_Group array:         %5d (U+%04x..U+%04x)\n",
485                (int)(jgLimit-jgStart), (int)jgStart, (int)(jgLimit-1));
486         printf("length of Joining_Group array 2:       %5d (U+%04x..U+%04x)\n",
487                (int)(jgLimit2-jgStart2), (int)jgStart2, (int)(jgLimit2-1));
488         printf("data size:                             %5d\n", (int)indexes[UBIDI_IX_LENGTH]);
489     }
490 
491     indexes[UBIDI_MAX_VALUES_INDEX]=
492         ((int32_t)U_CHAR_DIRECTION_COUNT-1)|
493         (((int32_t)U_JT_COUNT-1)<<UBIDI_JT_SHIFT)|
494         (((int32_t)U_BPT_COUNT-1)<<UBIDI_BPT_SHIFT)|
495         (((int32_t)U_JG_COUNT-1)<<UBIDI_MAX_JG_SHIFT);
496 }
497 
498 void
writeCSourceFile(const char * path,UErrorCode & errorCode)499 BiDiPropsBuilder::writeCSourceFile(const char *path, UErrorCode &errorCode) {
500     if(U_FAILURE(errorCode)) { return; }
501 
502     FILE *f=usrc_create(path, "ubidi_props_data.h", 2016,
503                         "icu/tools/unicode/c/genprops/bidipropsbuilder.cpp");
504     if(f==NULL) {
505         errorCode=U_FILE_ACCESS_ERROR;
506         return;
507     }
508     fputs("#ifdef INCLUDED_FROM_UBIDI_PROPS_C\n\n", f);
509     usrc_writeArray(f,
510         "static const UVersionInfo ubidi_props_dataVersion={",
511         dataInfo.dataVersion, 8, 4,
512         "",
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         "",
518         "};\n\n");
519     usrc_writeUTrie2Arrays(f,
520         "static const uint16_t ubidi_props_trieIndex[%ld]={\n", NULL,
521         pTrie,
522         "\n};\n\n");
523     usrc_writeArray(f,
524         "static const uint32_t ubidi_props_mirrors[%ld]={\n",
525         mirrors, 32, mirrorTop,
526         "",
527         "\n};\n\n");
528     UChar32 jgStart=indexes[UBIDI_IX_JG_START];
529     UChar32 jgLimit=indexes[UBIDI_IX_JG_LIMIT];
530     usrc_writeArray(f,
531         "static const uint8_t ubidi_props_jgArray[%ld]={\n",
532         jgArray+(jgStart-MIN_JG_START), 8, jgLimit-jgStart,
533         "",
534         "\n};\n\n");
535     UChar32 jgStart2=indexes[UBIDI_IX_JG_START2];
536     UChar32 jgLimit2=indexes[UBIDI_IX_JG_LIMIT2];
537     usrc_writeArray(f,
538         "static const uint8_t ubidi_props_jgArray2[%ld]={\n",
539         jgArray2+(jgStart2-MIN_JG_START2), 8, jgLimit2-jgStart2,
540         "",
541         "\n};\n\n");
542     fputs(
543         "static const UBiDiProps ubidi_props_singleton={\n"
544         "  NULL,\n"
545         "  ubidi_props_indexes,\n"
546         "  ubidi_props_mirrors,\n"
547         "  ubidi_props_jgArray,\n"
548         "  ubidi_props_jgArray2,\n",
549         f);
550     usrc_writeUTrie2Struct(f,
551         "  {\n",
552         pTrie, "ubidi_props_trieIndex", NULL,
553         "  },\n");
554     usrc_writeArray(f, "  { ", dataInfo.formatVersion, 8, 4, "", " }\n");
555     fputs("};\n\n"
556           "#endif  // INCLUDED_FROM_UBIDI_PROPS_C\n", f);
557     fclose(f);
558 }
559 
560 void
writeBinaryData(const char * path,UBool withCopyright,UErrorCode & errorCode)561 BiDiPropsBuilder::writeBinaryData(const char *path, UBool withCopyright, UErrorCode &errorCode) {
562     if(U_FAILURE(errorCode)) { return; }
563 
564     UNewDataMemory *pData=udata_create(path, UBIDI_DATA_TYPE, UBIDI_DATA_NAME, &dataInfo,
565                                        withCopyright ? U_COPYRIGHT_STRING : NULL, &errorCode);
566     if(U_FAILURE(errorCode)) {
567         fprintf(stderr, "genprops: udata_create(%s, ubidi.icu) failed - %s\n",
568                 path, u_errorName(errorCode));
569         return;
570     }
571 
572     udata_writeBlock(pData, indexes, sizeof(indexes));
573     udata_writeBlock(pData, trieBlock, trieSize);
574     udata_writeBlock(pData, mirrors, 4*mirrorTop);
575     UChar32 jgStart=indexes[UBIDI_IX_JG_START];
576     UChar32 jgLimit=indexes[UBIDI_IX_JG_LIMIT];
577     udata_writeBlock(pData, jgArray+(jgStart-MIN_JG_START), jgLimit-jgStart);
578     UChar32 jgStart2=indexes[UBIDI_IX_JG_START2];
579     UChar32 jgLimit2=indexes[UBIDI_IX_JG_LIMIT2];
580     udata_writeBlock(pData, jgArray2+(jgStart2-MIN_JG_START2), jgLimit2-jgStart2);
581 
582     long dataLength=udata_finish(pData, &errorCode);
583     if(U_FAILURE(errorCode)) {
584         fprintf(stderr, "genprops error: bidipropsbuilder %d writing the output file\n", errorCode);
585         return;
586     }
587 
588     if(dataLength!=indexes[UBIDI_IX_LENGTH]) {
589         fprintf(stderr,
590                 "udata_finish(ubidi.icu) reports %ld bytes written but should be %ld\n",
591                 dataLength, (long)indexes[UBIDI_IX_LENGTH]);
592         errorCode=U_INTERNAL_PROGRAM_ERROR;
593     }
594 }
595 
596 PropsBuilder *
createBiDiPropsBuilder(UErrorCode & errorCode)597 createBiDiPropsBuilder(UErrorCode &errorCode) {
598     if(U_FAILURE(errorCode)) { return NULL; }
599     PropsBuilder *pb=new BiDiPropsBuilder(errorCode);
600     if(pb==NULL) {
601         errorCode=U_MEMORY_ALLOCATION_ERROR;
602     }
603     return pb;
604 }
605 
606 /*
607  * Hey, Emacs, please set the following:
608  *
609  * Local Variables:
610  * indent-tabs-mode: nil
611  * End:
612  *
613  */
614