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