#include <stdio.h>
#include <stdlib.h>
#include "unicode/utypes.h"
#include "unicode/uchar.h"
#include "cmemory.h"
#include "cstring.h"
#include "utrie.h"
#include "uarrsort.h"
#include "unicode/udata.h"
#include "unewdata.h"
#include "propsvec.h"
#include "writesrc.h"
#include "ubidi_props.h"
#include "genbidi.h"
#define LENGTHOF(array) (sizeof(array)/sizeof((array)[0]))
static UDataInfo dataInfo={
sizeof(UDataInfo),
0,
U_IS_BIG_ENDIAN,
U_CHARSET_FAMILY,
U_SIZEOF_UCHAR,
0,
{ UBIDI_FMT_0, UBIDI_FMT_1, UBIDI_FMT_2, UBIDI_FMT_3 },
{ 1, 0, UTRIE_SHIFT, UTRIE_INDEX_SHIFT },
{ 4, 0, 1, 0 }
};
static uint32_t mirrors[UBIDI_MAX_MIRROR_INDEX+1][2];
static uint16_t mirrorTop=0;
extern void
setUnicodeVersion(const char *v) {
UVersionInfo version;
u_versionFromString(version, v);
uprv_memcpy(dataInfo.dataVersion, version, 4);
}
extern void
addMirror(UChar32 src, UChar32 mirror) {
UErrorCode errorCode;
int32_t delta;
delta=mirror-src;
if(delta==0) {
return;
}
if(delta<UBIDI_MIN_MIRROR_DELTA || UBIDI_MAX_MIRROR_DELTA<delta) {
if(mirrorTop==LENGTHOF(mirrors)) {
fprintf(stderr, "genbidi error: too many long-distance mirroring mappings\n");
exit(U_BUFFER_OVERFLOW_ERROR);
}
mirrors[mirrorTop][0]=(uint32_t)src;
mirrors[mirrorTop][1]=(uint32_t)mirror;
++mirrorTop;
delta=UBIDI_ESC_MIRROR_DELTA;
}
errorCode=U_ZERO_ERROR;
if(
!upvec_setValue(
pv, src, src+1, 0,
(uint32_t)delta<<UBIDI_MIRROR_DELTA_SHIFT, (uint32_t)(-1)<<UBIDI_MIRROR_DELTA_SHIFT,
&errorCode)
) {
fprintf(stderr, "genbidi error: unable to set mirroring delta, code: %s\n",
u_errorName(errorCode));
exit(errorCode);
}
}
static int32_t U_CALLCONV
compareMirror(const void *context, const void *left, const void *right) {
UChar32 l, r;
l=UBIDI_GET_MIRROR_CODE_POINT(((const uint32_t *)left)[0]);
r=UBIDI_GET_MIRROR_CODE_POINT(((const uint32_t *)right)[0]);
return l-r;
}
static void
makeMirror() {
uint32_t *reducedMirror;
UErrorCode errorCode;
int32_t i, j, start, limit, step;
uint32_t c;
errorCode=U_ZERO_ERROR;
uprv_sortArray(mirrors, mirrorTop, 8,
compareMirror, NULL, FALSE, &errorCode);
for(i=0; i<mirrorTop; ++i) {
c=mirrors[i][1];
if(c>0x1fffff) {
continue;
}
if(c<mirrors[i][0]) {
start=i-1;
limit=-1;
step=-1;
} else {
start=i+1;
limit=mirrorTop;
step=1;
}
for(j=start;; j+=step) {
if(j==limit) {
fprintf(stderr,
"genbidi error: bidi mirror does not roundtrip - %04lx->%04lx->?\n",
(long)mirrors[i][0], (long)mirrors[i][1]);
errorCode=U_ILLEGAL_ARGUMENT_ERROR;
}
if(c==mirrors[j][0]) {
if(UBIDI_GET_MIRROR_CODE_POINT(mirrors[i][0])!=UBIDI_GET_MIRROR_CODE_POINT(mirrors[j][1])) {
fprintf(stderr,
"genbidi error: bidi mirrors do not roundtrip - %04lx->%04lx->%04lx\n",
(long)mirrors[i][0], (long)mirrors[i][1], (long)mirrors[j][1]);
errorCode=U_ILLEGAL_ARGUMENT_ERROR;
} else {
mirrors[i][1]|=(uint32_t)j<<UBIDI_MIRROR_INDEX_SHIFT;
mirrors[j][1]|=(uint32_t)i<<UBIDI_MIRROR_INDEX_SHIFT;
}
break;
}
}
}
reducedMirror=mirrors[0];
for(i=0; i<mirrorTop; ++i) {
reducedMirror[i]=mirrors[i][0]|(mirrors[i][1]&~0x1fffff);
}
if(U_FAILURE(errorCode)) {
exit(errorCode);
}
}
extern void
generateData(const char *dataDir, UBool csource) {
static int32_t indexes[UBIDI_IX_TOP]={
UBIDI_IX_TOP
};
static uint8_t trieBlock[40000];
static uint8_t jgArray[0x300];
const uint32_t *row;
UChar32 start, limit, prev, jgStart;
int32_t i;
UNewDataMemory *pData;
UNewTrie *pTrie;
UErrorCode errorCode=U_ZERO_ERROR;
int32_t trieSize;
long dataLength;
makeMirror();
pTrie=utrie_open(NULL, NULL, 20000, 0, 0, TRUE);
if(pTrie==NULL) {
fprintf(stderr, "genbidi error: unable to create a UNewTrie\n");
exit(U_MEMORY_ALLOCATION_ERROR);
}
prev=jgStart=0;
for(i=0; (row=upvec_getRow(pv, i, &start, &limit))!=NULL; ++i) {
if(!utrie_setRange32(pTrie, start, limit, *row, TRUE)) {
fprintf(stderr, "genbidi error: unable to set trie value (overflow)\n");
exit(U_BUFFER_OVERFLOW_ERROR);
}
if(row[1]!=0) {
if(start<0x600 || 0x900<=limit) {
fprintf(stderr, "genbidi error: Joining_Group for out-of-range code points U+%04lx..U+%04lx\n",
(long)start, (long)limit);
exit(U_ILLEGAL_ARGUMENT_ERROR);
}
if(prev==0) {
prev=jgStart=start;
} else {
while(prev<start) {
jgArray[prev++ -jgStart]=0;
}
}
while(prev<limit) {
jgArray[prev++ -jgStart]=(uint8_t)row[1];
}
}
}
while((prev-jgStart)&3) {
jgArray[prev++ -jgStart]=0;
}
indexes[UBIDI_IX_JG_START]=jgStart;
indexes[UBIDI_IX_JG_LIMIT]=prev;
trieSize=utrie_serialize(pTrie, trieBlock, sizeof(trieBlock), NULL, TRUE, &errorCode);
if(U_FAILURE(errorCode)) {
fprintf(stderr, "genbidi error: utrie_serialize failed: %s (length %ld)\n", u_errorName(errorCode), (long)trieSize);
exit(errorCode);
}
indexes[UBIDI_IX_TRIE_SIZE]=trieSize;
indexes[UBIDI_IX_MIRROR_LENGTH]=mirrorTop;
indexes[UBIDI_IX_LENGTH]=
(int32_t)sizeof(indexes)+
trieSize+
4*mirrorTop+
(prev-jgStart);
if(beVerbose) {
printf("trie size in bytes: %5d\n", (int)trieSize);
printf("size in bytes of mirroring table: %5d\n", (int)(4*mirrorTop));
printf("length of Joining_Group array: %5d (U+%04x..U+%04x)\n", (int)(prev-jgStart), (int)jgStart, (int)(prev-1));
printf("data size: %5d\n", (int)indexes[UBIDI_IX_LENGTH]);
}
indexes[UBIDI_MAX_VALUES_INDEX]=
((int32_t)U_CHAR_DIRECTION_COUNT-1)|
(((int32_t)U_JT_COUNT-1)<<UBIDI_JT_SHIFT)|
(((int32_t)U_JG_COUNT-1)<<UBIDI_MAX_JG_SHIFT);
if(csource) {
UTrie trie={ NULL };
FILE *f;
utrie_unserialize(&trie, trieBlock, trieSize, &errorCode);
if(U_FAILURE(errorCode)) {
fprintf(
stderr,
"genbidi error: failed to utrie_unserialize(ubidi.icu trie) - %s\n",
u_errorName(errorCode));
return;
}
f=usrc_create(dataDir, "ubidi_props_data.c");
if(f!=NULL) {
usrc_writeArray(f,
"static const UVersionInfo ubidi_props_dataVersion={",
dataInfo.dataVersion, 8, 4,
"};\n\n");
usrc_writeArray(f,
"static const int32_t ubidi_props_indexes[UBIDI_IX_TOP]={",
indexes, 32, UBIDI_IX_TOP,
"};\n\n");
usrc_writeUTrieArrays(f,
"static const uint16_t ubidi_props_trieIndex[%ld]={\n", NULL,
&trie,
"\n};\n\n");
usrc_writeArray(f,
"static const uint32_t ubidi_props_mirrors[%ld]={\n",
mirrors, 32, mirrorTop,
"\n};\n\n");
usrc_writeArray(f,
"static const uint8_t ubidi_props_jgArray[%ld]={\n",
jgArray, 8, prev-jgStart,
"\n};\n\n");
fputs(
"static const UBiDiProps ubidi_props_singleton={\n"
" NULL,\n"
" ubidi_props_indexes,\n"
" ubidi_props_mirrors,\n"
" ubidi_props_jgArray,\n",
f);
usrc_writeUTrieStruct(f,
" {\n",
&trie, "ubidi_props_trieIndex", NULL, NULL,
" },\n");
usrc_writeArray(f, " { ", dataInfo.formatVersion, 8, 4, " }\n");
fputs("};\n", f);
fclose(f);
}
} else {
pData=udata_create(dataDir, UBIDI_DATA_TYPE, UBIDI_DATA_NAME, &dataInfo,
haveCopyright ? U_COPYRIGHT_STRING : NULL, &errorCode);
if(U_FAILURE(errorCode)) {
fprintf(stderr, "genbidi: unable to create data memory, %s\n", u_errorName(errorCode));
exit(errorCode);
}
udata_writeBlock(pData, indexes, sizeof(indexes));
udata_writeBlock(pData, trieBlock, trieSize);
udata_writeBlock(pData, mirrors, 4*mirrorTop);
udata_writeBlock(pData, jgArray, prev-jgStart);
dataLength=udata_finish(pData, &errorCode);
if(U_FAILURE(errorCode)) {
fprintf(stderr, "genbidi: error %d writing the output file\n", errorCode);
exit(errorCode);
}
if(dataLength!=indexes[UBIDI_IX_LENGTH]) {
fprintf(stderr, "genbidi: data length %ld != calculated size %d\n",
dataLength, (int)indexes[UBIDI_IX_LENGTH]);
exit(U_INTERNAL_PROGRAM_ERROR);
}
}
utrie_close(pTrie);
upvec_close(pv);
}