summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu/icu-xetex/i18n
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/icu/icu-xetex/i18n')
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/Makefile.in181
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/anytrans.cpp380
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/anytrans.h129
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/astro.cpp1563
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/astro.h793
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/basictz.cpp528
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/bocsu.c191
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/bocsu.h162
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/buddhcal.cpp216
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/buddhcal.h243
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/calendar.cpp3080
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/casetrn.cpp194
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/casetrn.h104
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/chnsecal.cpp13
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/chnsecal.h11
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/choicfmt.cpp746
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/coleitr.cpp493
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/coll.cpp809
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/cpdtrans.cpp578
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/cpdtrans.h248
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csdetect.cpp391
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csdetect.h56
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csmatch.cpp61
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csmatch.h44
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csr2022.cpp172
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csr2022.h86
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrecog.cpp28
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrecog.h42
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrmbcs.cpp517
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrmbcs.h205
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrsbcs.cpp1099
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrsbcs.h364
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrucode.cpp146
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrucode.h106
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrutf8.cpp111
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/csrutf8.h42
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/curramt.cpp50
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/currfmt.cpp66
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/currfmt.h98
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/currunit.cpp60
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/datefmt.cpp428
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/dcfmtsym.cpp298
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/decimfmt.cpp3748
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/digitlst.cpp674
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/digitlst.h267
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/dtfmtsym.cpp1520
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/dtptngen.cpp1849
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/dtptngen_impl.h256
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/dtrule.cpp137
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/esctrn.cpp179
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/esctrn.h142
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/fmtable.cpp679
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/fmtable_cnv.cpp44
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/format.cpp193
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/funcrepl.cpp124
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/funcrepl.h123
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/gregocal.cpp1345
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/gregoimp.cpp328
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/gregoimp.h363
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/hebrwcal.cpp747
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/hebrwcal.h486
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/i18n.rc108
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/i18n.vcproj2137
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/indiancal.cpp445
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/indiancal.h371
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/inputext.cpp162
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/inputext.h59
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/islamcal.cpp524
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/islamcal.h463
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/japancal.cpp545
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/japancal.h207
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/measfmt.cpp44
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/measure.cpp65
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/msgfmt.cpp1466
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/name2uni.cpp253
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/name2uni.h91
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nfrlist.h89
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nfrs.cpp944
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nfrs.h97
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nfrule.cpp1446
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nfrule.h114
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nfsubs.cpp1319
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nfsubs.h266
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nortrans.cpp231
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nortrans.h110
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nultrans.cpp36
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/nultrans.h71
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/numfmt.cpp925
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/olsontz.cpp959
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/olsontz.h382
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/persncal.cpp392
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/persncal.h325
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/quant.cpp146
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/quant.h128
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbnf.cpp1542
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt.cpp293
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt.h473
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt_data.cpp99
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt_data.h152
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt_pars.cpp1667
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt_pars.h355
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt_rule.cpp556
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt_rule.h308
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt_set.cpp455
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbt_set.h165
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rbtz.cpp931
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/regexcmp.cpp3529
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/regexcmp.h201
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/regexcst.h314
-rwxr-xr-xBuild/source/libs/icu/icu-xetex/i18n/regexcst.pl332
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/regexcst.txt266
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/regeximp.h344
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/regexst.cpp287
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/regexst.h57
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/reldtfmt.cpp317
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/reldtfmt.h262
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/rematch.cpp2299
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/remtrans.cpp68
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/remtrans.h78
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/repattrn.cpp617
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/search.cpp402
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/simpletz.cpp1180
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/smpdtfmt.cpp2401
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/sortkey.cpp403
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/strmatch.cpp289
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/strmatch.h254
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/strrepl.cpp328
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/strrepl.h165
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/stsearch.cpp461
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/taiwncal.cpp222
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/taiwncal.h225
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/tblcoll.cpp702
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/timezone.cpp1411
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/titletrn.cpp167
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/titletrn.h90
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/tolowtrn.cpp65
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/tolowtrn.h74
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/toupptrn.cpp65
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/toupptrn.h74
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/translit.cpp1584
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/transreg.cpp1313
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/transreg.h458
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/tridpars.cpp905
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/tridpars.h361
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/tzrule.cpp629
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/tztrans.cpp144
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucal.cpp472
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucln_in.c50
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucln_in.h54
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol.cpp8378
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_bld.cpp1312
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_bld.h62
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_cnt.cpp577
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_cnt.h105
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_elm.cpp1985
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_elm.h148
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_imp.h1016
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_res.cpp737
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_sit.cpp1184
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_tok.cpp1910
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_tok.h184
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_wgt.c564
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucol_wgt.h72
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucoleitr.cpp258
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucsdet.cpp180
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucurr.cpp1124
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ucurrimp.h57
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/udat.cpp811
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/udatpg.cpp248
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/ulocdata.c227
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/umsg.cpp706
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/umsg_imp.h45
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unesctrn.cpp287
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unesctrn.h110
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/uni2name.cpp120
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/uni2name.h87
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/basictz.h210
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/calendar.h2161
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/choicfmt.h780
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/coleitr.h399
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/coll.h1035
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/curramt.h130
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/currunit.h117
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/datefmt.h672
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/dcfmtsym.h370
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/decimfmt.h1902
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/dtfmtsym.h698
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/dtptngen.h416
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/dtrule.h250
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/fieldpos.h291
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/fmtable.h591
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/format.h296
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/gregocal.h823
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/measfmt.h77
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/measunit.h71
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/measure.h137
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/msgfmt.h829
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/numfmt.h861
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/rbnf.h1049
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/rbtz.h355
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/regex.h950
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/search.h569
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/simpletz.h927
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/smpdtfmt.h904
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/sortkey.h324
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/stsearch.h518
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/tblcoll.h924
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/timezone.h726
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/translit.h1323
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/tzrule.h828
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/tztrans.h195
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/ucal.h1089
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/ucol.h1223
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/ucoleitr.h268
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/ucsdet.h349
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/ucurr.h225
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/udat.h826
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/udatpg.h475
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/ulocdata.h194
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/umsg.h647
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/unirepl.h97
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/unum.h869
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/uregex.h631
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/usearch.h646
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/utmscale.h481
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/utrans.h583
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unicode/vtzone.h443
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/unum.cpp841
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/uregex.cpp1105
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/uregexc.cpp40
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/usearch.cpp3639
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/usrchimp.h134
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/utmscale.c114
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/utrans.cpp498
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/vtzone.cpp2469
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/windtfmt.cpp315
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/windtfmt.h148
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/winnmfmt.cpp354
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/winnmfmt.h168
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/zonemeta.cpp873
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/zonemeta.h84
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/zstrfmt.cpp1604
-rw-r--r--Build/source/libs/icu/icu-xetex/i18n/zstrfmt.h442
243 files changed, 141247 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-xetex/i18n/Makefile.in b/Build/source/libs/icu/icu-xetex/i18n/Makefile.in
new file mode 100644
index 00000000000..14bec19c0e8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/Makefile.in
@@ -0,0 +1,181 @@
+#******************************************************************************
+#
+# Copyright (C) 1998-2007, International Business Machines
+# Corporation and others. All Rights Reserved.
+#
+#******************************************************************************
+## Makefile.in for ICU - icui18n.so
+## Stephen F. Booth
+
+## Source directory information
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+
+top_builddir = ..
+
+## All the flags and other definitions are included here.
+include $(top_builddir)/icudefs.mk
+
+## Build directory information
+subdir = i18n
+
+## Extra files to remove for 'make clean'
+CLEANFILES = *~ $(DEPS) $(IMPORT_LIB) $(MIDDLE_IMPORT_LIB) $(FINAL_IMPORT_LIB)
+
+## Target information
+
+TARGET_STUBNAME=$(I18N_STUBNAME)
+
+ifneq ($(ENABLE_STATIC),)
+TARGET = $(LIBDIR)/$(LIBSICU)$(TARGET_STUBNAME)$(ICULIBSUFFIX).$(A)
+endif
+
+ifneq ($(ENABLE_SHARED),)
+SO_TARGET = $(LIBDIR)/$(LIBICU)$(TARGET_STUBNAME)$(ICULIBSUFFIX).$(SO)
+ALL_SO_TARGETS = $(SO_TARGET) $(MIDDLE_SO_TARGET) $(FINAL_SO_TARGET) $(SHARED_OBJECT)
+
+ifeq ($(ENABLE_SO_VERSION_DATA),1)
+SO_VERSION_DATA = i18n.res
+endif
+
+ifeq ($(OS390BATCH),1)
+BATCH_TARGET = $(BATCH_I18N_TARGET)
+BATCH_LIBS = $(BATCH_LIBICUUC) -lm
+endif # OS390BATCH
+
+endif # ENABLE_SHARED
+
+ALL_TARGETS = $(TARGET) $(ALL_SO_TARGETS) $(BATCH_TARGET)
+
+DYNAMICCPPFLAGS = $(SHAREDLIBCPPFLAGS)
+DYNAMICCFLAGS = $(SHAREDLIBCFLAGS)
+DYNAMICCXXFLAGS = $(SHAREDLIBCXXFLAGS)
+CFLAGS += $(LIBCFLAGS)
+CXXFLAGS += $(LIBCXXFLAGS)
+
+ifneq ($(top_builddir),$(top_srcdir))
+CPPFLAGS += -I$(top_builddir)/common
+endif
+CPPFLAGS += -I$(srcdir) -I$(top_srcdir)/common $(LIBCPPFLAGS)
+DEFS += -DU_I18N_IMPLEMENTATION
+LDFLAGS += $(LDFLAGSICUI18N)
+LIBS = $(LIBICUUC) $(DEFAULT_LIBS)
+
+OBJECTS = ucln_in.o \
+fmtable.o format.o msgfmt.o umsg.o numfmt.o unum.o decimfmt.o dcfmtsym.o \
+ucurr.o digitlst.o fmtable_cnv.o \
+choicfmt.o datefmt.o smpdtfmt.o reldtfmt.o dtfmtsym.o udat.o dtptngen.o \
+nfrs.o nfrule.o nfsubs.o rbnf.o ucsdet.o \
+ucal.o calendar.o gregocal.o timezone.o simpletz.o olsontz.o \
+astro.o taiwncal.o buddhcal.o persncal.o islamcal.o japancal.o gregoimp.o hebrwcal.o indiancal.o \
+coleitr.o coll.o tblcoll.o sortkey.o bocsu.o ucoleitr.o \
+ucol.o ucol_res.o ucol_bld.o ucol_sit.o ucol_tok.o ucol_wgt.o ucol_cnt.o ucol_elm.o \
+strmatch.o usearch.o search.o stsearch.o \
+translit.o utrans.o esctrn.o unesctrn.o funcrepl.o strrepl.o tridpars.o \
+cpdtrans.o rbt.o rbt_data.o rbt_pars.o rbt_rule.o rbt_set.o \
+nultrans.o remtrans.o casetrn.o titletrn.o tolowtrn.o toupptrn.o anytrans.o \
+name2uni.o uni2name.o nortrans.o quant.o transreg.o \
+regexcmp.o rematch.o repattrn.o regexst.o udatpg.o uregex.o uregexc.o \
+ulocdata.o measfmt.o currfmt.o curramt.o currunit.o measure.o utmscale.o \
+csdetect.o csmatch.o csr2022.o csrecog.o csrmbcs.o csrsbcs.o csrucode.o csrutf8.o inputext.o \
+windtfmt.o winnmfmt.o basictz.o dtrule.o rbtz.o tzrule.o tztrans.o vtzone.o zonemeta.o zstrfmt.o
+
+## Header files to install
+HEADERS = $(srcdir)/unicode/*.h
+
+STATIC_OBJECTS = $(OBJECTS:.o=.$(STATIC_O))
+
+DEPS = $(OBJECTS:.o=.d)
+
+-include Makefile.local
+
+## List of phony targets
+.PHONY : all all-local install install-local clean clean-local \
+distclean distclean-local install-library install-headers dist \
+dist-local check check-local
+
+## Clear suffix list
+.SUFFIXES :
+
+## List of standard targets
+all: all-local
+install: install-local
+clean: clean-local
+distclean : distclean-local
+dist: dist-local
+check: all check-local
+
+all-local: $(ALL_TARGETS)
+
+install-local: install-headers install-library
+
+install-library: all-local
+ $(MKINSTALLDIRS) $(DESTDIR)$(libdir)
+ifneq ($(ENABLE_STATIC),)
+ $(INSTALL-L) $(TARGET) $(DESTDIR)$(libdir)
+endif
+ifneq ($(ENABLE_SHARED),)
+ $(INSTALL-L) $(FINAL_SO_TARGET) $(DESTDIR)$(libdir)
+ifneq ($(FINAL_SO_TARGET),$(SO_TARGET))
+ cd $(DESTDIR)$(libdir) && $(RM) $(notdir $(SO_TARGET)) && ln -s $(notdir $(FINAL_SO_TARGET)) $(notdir $(SO_TARGET))
+ifneq ($(FINAL_SO_TARGET),$(MIDDLE_SO_TARGET))
+ cd $(DESTDIR)$(libdir) && $(RM) $(notdir $(MIDDLE_SO_TARGET)) && ln -s $(notdir $(FINAL_SO_TARGET)) $(notdir $(MIDDLE_SO_TARGET))
+endif
+endif
+ifneq ($(IMPORT_LIB_EXT),)
+ $(INSTALL-L) $(FINAL_IMPORT_LIB) $(DESTDIR)$(libdir)
+ifneq ($(IMPORT_LIB),$(FINAL_IMPORT_LIB))
+ cd $(DESTDIR)$(libdir) && $(RM) $(notdir $(IMPORT_LIB)) && ln -s $(notdir $(FINAL_IMPORT_LIB)) $(notdir $(IMPORT_LIB))
+endif
+ifneq ($(MIDDLE_IMPORT_LIB),$(FINAL_IMPORT_LIB))
+ cd $(DESTDIR)$(libdir) && $(RM) $(notdir $(MIDDLE_IMPORT_LIB)) && ln -s $(notdir $(FINAL_IMPORT_LIB)) $(notdir $(MIDDLE_IMPORT_LIB))
+endif
+endif
+endif
+
+install-headers:
+ $(MKINSTALLDIRS) $(DESTDIR)$(includedir)/unicode
+ @for file in $(HEADERS); do \
+ echo "$(INSTALL_DATA) $$file $(DESTDIR)$(includedir)/unicode"; \
+ $(INSTALL_DATA) $$file $(DESTDIR)$(includedir)/unicode || exit; \
+ done
+
+dist-local:
+
+clean-local:
+ test -z "$(CLEANFILES)" || $(RMV) $(CLEANFILES)
+ $(RMV) $(OBJECTS) $(STATIC_OBJECTS) $(ALL_TARGETS) $(SO_VERSION_DATA)
+
+distclean-local: clean-local
+ $(RMV) Makefile
+
+check-local:
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+ifneq ($(ENABLE_STATIC),)
+$(TARGET): $(STATIC_OBJECTS)
+ $(AR) $(ARFLAGS) $(AR_OUTOPT)$@ $^
+ $(RANLIB) $@
+endif
+
+ifneq ($(ENABLE_SHARED),)
+$(SHARED_OBJECT): $(OBJECTS) $(SO_VERSION_DATA)
+ $(SHLIB.cc) $(LD_SONAME) $(OUTOPT)$@ $^ $(LIBS)
+
+ifeq ($(OS390BATCH),1)
+$(BATCH_TARGET):$(OBJECTS)
+ $(SHLIB.cc) $(LD_SONAME) $(OUTOPT)$@ $^ $(BATCH_LIBS)
+endif # OS390BATCH
+endif # ENABLE_SHARED
+
+ifeq (,$(MAKECMDGOALS))
+-include $(DEPS)
+else
+ifneq ($(patsubst %clean,,$(MAKECMDGOALS)),)
+-include $(DEPS)
+endif
+endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/anytrans.cpp b/Build/source/libs/icu/icu-xetex/i18n/anytrans.cpp
new file mode 100644
index 00000000000..5b10caf1f93
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/anytrans.cpp
@@ -0,0 +1,380 @@
+/*
+*****************************************************************
+* Copyright (c) 2002-2006, International Business Machines Corporation
+* and others. All Rights Reserved.
+*****************************************************************
+* Date Name Description
+* 06/06/2002 aliu Creation.
+*****************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uobject.h"
+#include "unicode/uscript.h"
+#include "nultrans.h"
+#include "anytrans.h"
+#include "uvector.h"
+#include "tridpars.h"
+#include "hash.h"
+#include "putilimp.h"
+#include "uinvchar.h"
+
+//------------------------------------------------------------
+// Constants
+
+static const UChar TARGET_SEP = 45; // '-'
+static const UChar VARIANT_SEP = 47; // '/'
+static const UChar ANY[] = {65,110,121,0}; // "Any"
+static const UChar NULL_ID[] = {78,117,108,108,0}; // "Null"
+static const UChar LATIN_PIVOT[] = {45,76,97,116,105,110,59,76,97,116,105,110,45,0}; // "-Latin;Latin-"
+
+//------------------------------------------------------------
+
+U_CDECL_BEGIN
+/**
+ * Deleter function for Transliterator*.
+ */
+static void U_CALLCONV
+_deleteTransliterator(void *obj) {
+ delete (U_NAMESPACE_QUALIFIER Transliterator*) obj;
+}
+U_CDECL_END
+
+//------------------------------------------------------------
+
+U_NAMESPACE_BEGIN
+
+//------------------------------------------------------------
+// ScriptRunIterator
+
+/**
+ * Returns a series of ranges corresponding to scripts. They will be
+ * of the form:
+ *
+ * ccccSScSSccccTTcTcccc - c = common, S = first script, T = second
+ * | | - first run (start, limit)
+ * | | - second run (start, limit)
+ *
+ * That is, the runs will overlap. The reason for this is so that a
+ * transliterator can consider common characters both before and after
+ * the scripts.
+ */
+class ScriptRunIterator : public UMemory {
+private:
+ const Replaceable& text;
+ int32_t textStart;
+ int32_t textLimit;
+
+public:
+ /**
+ * The code of the current run, valid after next() returns. May
+ * be USCRIPT_INVALID_CODE if and only if the entire text is
+ * COMMON/INHERITED.
+ */
+ UScriptCode scriptCode;
+
+ /**
+ * The start of the run, inclusive, valid after next() returns.
+ */
+ int32_t start;
+
+ /**
+ * The end of the run, exclusive, valid after next() returns.
+ */
+ int32_t limit;
+
+ /**
+ * Constructs a run iterator over the given text from start
+ * (inclusive) to limit (exclusive).
+ */
+ ScriptRunIterator(const Replaceable& text, int32_t start, int32_t limit);
+
+ /**
+ * Returns TRUE if there are any more runs. TRUE is always
+ * returned at least once. Upon return, the caller should
+ * examine scriptCode, start, and limit.
+ */
+ UBool next();
+
+ /**
+ * Adjusts internal indices for a change in the limit index of the
+ * given delta. A positive delta means the limit has increased.
+ */
+ void adjustLimit(int32_t delta);
+
+private:
+ ScriptRunIterator(const ScriptRunIterator &other); // forbid copying of this class
+ ScriptRunIterator &operator=(const ScriptRunIterator &other); // forbid copying of this class
+};
+
+ScriptRunIterator::ScriptRunIterator(const Replaceable& theText,
+ int32_t myStart, int32_t myLimit) :
+ text(theText)
+{
+ textStart = myStart;
+ textLimit = myLimit;
+ limit = myStart;
+}
+
+UBool ScriptRunIterator::next() {
+ UChar32 ch;
+ UScriptCode s;
+ UErrorCode ec = U_ZERO_ERROR;
+
+ scriptCode = USCRIPT_INVALID_CODE; // don't know script yet
+ start = limit;
+
+ // Are we done?
+ if (start == textLimit) {
+ return FALSE;
+ }
+
+ // Move start back to include adjacent COMMON or INHERITED
+ // characters
+ while (start > textStart) {
+ ch = text.char32At(start - 1); // look back
+ s = uscript_getScript(ch, &ec);
+ if (s == USCRIPT_COMMON || s == USCRIPT_INHERITED) {
+ --start;
+ } else {
+ break;
+ }
+ }
+
+ // Move limit ahead to include COMMON, INHERITED, and characters
+ // of the current script.
+ while (limit < textLimit) {
+ ch = text.char32At(limit); // look ahead
+ s = uscript_getScript(ch, &ec);
+ if (s != USCRIPT_COMMON && s != USCRIPT_INHERITED) {
+ if (scriptCode == USCRIPT_INVALID_CODE) {
+ scriptCode = s;
+ } else if (s != scriptCode) {
+ break;
+ }
+ }
+ ++limit;
+ }
+
+ // Return TRUE even if the entire text is COMMON / INHERITED, in
+ // which case scriptCode will be USCRIPT_INVALID_CODE.
+ return TRUE;
+}
+
+void ScriptRunIterator::adjustLimit(int32_t delta) {
+ limit += delta;
+ textLimit += delta;
+}
+
+//------------------------------------------------------------
+// AnyTransliterator
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnyTransliterator)
+
+AnyTransliterator::AnyTransliterator(const UnicodeString& id,
+ const UnicodeString& theTarget,
+ const UnicodeString& theVariant,
+ UScriptCode theTargetScript,
+ UErrorCode& ec) :
+ Transliterator(id, NULL),
+ targetScript(theTargetScript)
+{
+ cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &ec);
+ uhash_setValueDeleter(cache, _deleteTransliterator);
+
+ target = theTarget;
+ if (theVariant.length() > 0) {
+ target.append(VARIANT_SEP).append(theVariant);
+ }
+}
+
+AnyTransliterator::~AnyTransliterator() {
+ uhash_close(cache);
+}
+
+/**
+ * Copy constructor.
+ */
+AnyTransliterator::AnyTransliterator(const AnyTransliterator& o) :
+ Transliterator(o),
+ target(o.target),
+ targetScript(o.targetScript)
+{
+ // Don't copy the cache contents
+ UErrorCode ec = U_ZERO_ERROR;
+ cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &ec);
+ uhash_setValueDeleter(cache, _deleteTransliterator);
+}
+
+/**
+ * Transliterator API.
+ */
+Transliterator* AnyTransliterator::clone() const {
+ return new AnyTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void AnyTransliterator::handleTransliterate(Replaceable& text, UTransPosition& pos,
+ UBool isIncremental) const {
+ int32_t allStart = pos.start;
+ int32_t allLimit = pos.limit;
+
+ ScriptRunIterator it(text, pos.contextStart, pos.contextLimit);
+
+ while (it.next()) {
+ // Ignore runs in the ante context
+ if (it.limit <= allStart) continue;
+
+ // Try to instantiate transliterator from it.scriptCode to
+ // our target or target/variant
+ Transliterator* t = getTransliterator(it.scriptCode);
+
+ if (t == NULL) {
+ // We have no transliterator. Do nothing, but keep
+ // pos.start up to date.
+ pos.start = it.limit;
+ continue;
+ }
+
+ // If the run end is before the transliteration limit, do
+ // a non-incremental transliteration. Otherwise do an
+ // incremental one.
+ UBool incremental = isIncremental && (it.limit >= allLimit);
+
+ pos.start = uprv_max(allStart, it.start);
+ pos.limit = uprv_min(allLimit, it.limit);
+ int32_t limit = pos.limit;
+ t->filteredTransliterate(text, pos, incremental);
+ int32_t delta = pos.limit - limit;
+ allLimit += delta;
+ it.adjustLimit(delta);
+
+ // We're done if we enter the post context
+ if (it.limit >= allLimit) break;
+ }
+
+ // Restore limit. pos.start is fine where the last transliterator
+ // left it, or at the end of the last run.
+ pos.limit = allLimit;
+}
+
+Transliterator* AnyTransliterator::getTransliterator(UScriptCode source) const {
+
+ if (source == targetScript || source == USCRIPT_INVALID_CODE) {
+ return NULL;
+ }
+
+ Transliterator* t = (Transliterator*) uhash_iget(cache, (int32_t) source);
+ if (t == NULL) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString sourceName(uscript_getName(source), -1, US_INV);
+ UnicodeString id(sourceName);
+ id.append(TARGET_SEP).append(target);
+
+ t = Transliterator::createInstance(id, UTRANS_FORWARD, ec);
+ if (U_FAILURE(ec) || t == NULL) {
+ delete t;
+
+ // Try to pivot around Latin, our most common script
+ id = sourceName;
+ id.append(LATIN_PIVOT).append(target);
+ t = Transliterator::createInstance(id, UTRANS_FORWARD, ec);
+ if (U_FAILURE(ec) || t == NULL) {
+ delete t;
+ t = NULL;
+ }
+ }
+
+ if (t != NULL) {
+ uhash_iput(cache, (int32_t) source, t, &ec);
+ }
+ }
+
+ return t;
+}
+
+/**
+ * Return the script code for a given name, or -1 if not found.
+ */
+static UScriptCode scriptNameToCode(const UnicodeString& name) {
+ char buf[128];
+ UScriptCode code;
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t nameLen = name.length();
+ UBool isInvariant = uprv_isInvariantUString(name.getBuffer(), nameLen);
+
+ if (isInvariant) {
+ name.extract(0, nameLen, buf, (int32_t)sizeof(buf), US_INV);
+ buf[127] = 0; // Make sure that we NULL terminate the string.
+ }
+ if (!isInvariant || uscript_getCode(buf, &code, 1, &ec) != 1 || U_FAILURE(ec))
+ {
+ code = USCRIPT_INVALID_CODE;
+ }
+ return code;
+}
+
+/**
+ * Registers standard transliterators with the system. Called by
+ * Transliterator during initialization. Scan all current targets and
+ * register those that are scripts T as Any-T/V.
+ */
+void AnyTransliterator::registerIDs() {
+
+ UErrorCode ec = U_ZERO_ERROR;
+ Hashtable seen(TRUE, ec);
+
+ int32_t sourceCount = Transliterator::_countAvailableSources();
+ for (int32_t s=0; s<sourceCount; ++s) {
+ UnicodeString source;
+ Transliterator::_getAvailableSource(s, source);
+
+ // Ignore the "Any" source
+ if (source.caseCompare(ANY, 0 /*U_FOLD_CASE_DEFAULT*/) == 0) continue;
+
+ int32_t targetCount = Transliterator::_countAvailableTargets(source);
+ for (int32_t t=0; t<targetCount; ++t) {
+ UnicodeString target;
+ Transliterator::_getAvailableTarget(t, source, target);
+
+ // Only process each target once
+ if (seen.geti(target) != 0) continue;
+ ec = U_ZERO_ERROR;
+ seen.puti(target, 1, ec);
+
+ // Get the script code for the target. If not a script, ignore.
+ UScriptCode targetScript = scriptNameToCode(target);
+ if (targetScript == USCRIPT_INVALID_CODE) continue;
+
+ int32_t variantCount = Transliterator::_countAvailableVariants(source, target);
+ // assert(variantCount >= 1);
+ for (int32_t v=0; v<variantCount; ++v) {
+ UnicodeString variant;
+ Transliterator::_getAvailableVariant(v, source, target, variant);
+
+ UnicodeString id;
+ TransliteratorIDParser::STVtoID(ANY, target, variant, id);
+ ec = U_ZERO_ERROR;
+ AnyTransliterator* t = new AnyTransliterator(id, target, variant,
+ targetScript, ec);
+ if (U_FAILURE(ec)) {
+ delete t;
+ } else {
+ Transliterator::_registerInstance(t);
+ Transliterator::_registerSpecialInverse(target, NULL_ID, FALSE);
+ }
+ }
+ }
+ }
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/anytrans.h b/Build/source/libs/icu/icu-xetex/i18n/anytrans.h
new file mode 100644
index 00000000000..228ccbe03af
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/anytrans.h
@@ -0,0 +1,129 @@
+/*
+***********************************************************************
+* Copyright (c) 2002-2007, International Business Machines Corporation
+* and others. All Rights Reserved.
+***********************************************************************
+* Date Name Description
+* 06/06/2002 aliu Creation.
+***********************************************************************
+*/
+#ifndef _ANYTRANS_H_
+#define _ANYTRANS_H_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "unicode/uscript.h"
+#include "uhash.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator named Any-T or Any-T/V, where T is the target
+ * script and V is the optional variant, that uses multiple
+ * transliterators, all going to T or T/V, all with script sources.
+ * The target must be a script. It partitions text into runs of the
+ * same script, and then based on the script of each run,
+ * transliterates from that script to the given target or
+ * target/variant. Adjacent COMMON or INHERITED script characters are
+ * included in each run.
+ *
+ * @author Alan Liu
+ */
+class AnyTransliterator : public Transliterator {
+
+ /**
+ * Cache mapping UScriptCode values to Transliterator*.
+ */
+ UHashtable* cache;
+
+ /**
+ * The target or target/variant string.
+ */
+ UnicodeString target;
+
+ /**
+ * The target script code. Never USCRIPT_INVALID_CODE.
+ */
+ UScriptCode targetScript;
+
+public:
+
+ /**
+ * Destructor.
+ */
+ virtual ~AnyTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ AnyTransliterator(const AnyTransliterator&);
+
+ /**
+ * Transliterator API.
+ */
+ virtual Transliterator* clone() const;
+
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& index,
+ UBool incremental) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+
+ /**
+ * Private constructor
+ * @param id the ID of the form S-T or S-T/V, where T is theTarget
+ * and V is theVariant. Must not be empty.
+ * @param theTarget the target name. Must not be empty, and must
+ * name a script corresponding to theTargetScript.
+ * @param theVariant the variant name, or the empty string if
+ * there is no variant
+ * @param theTargetScript the script code corresponding to
+ * theTarget.
+ * @param ec error code, fails if the internal hashtable cannot be
+ * allocated
+ */
+ AnyTransliterator(const UnicodeString& id,
+ const UnicodeString& theTarget,
+ const UnicodeString& theVariant,
+ UScriptCode theTargetScript,
+ UErrorCode& ec);
+
+ /**
+ * Returns a transliterator from the given source to our target or
+ * target/variant. Returns NULL if the source is the same as our
+ * target script, or if the source is USCRIPT_INVALID_CODE.
+ * Caches the result and returns the same transliterator the next
+ * time. The caller does NOT own the result and must not delete
+ * it.
+ */
+ Transliterator* getTransliterator(UScriptCode source) const;
+
+ /**
+ * Registers standard transliterators with the system. Called by
+ * Transliterator during initialization.
+ */
+ static void registerIDs();
+
+ friend class Transliterator; // for registerIDs()
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/astro.cpp b/Build/source/libs/icu/icu-xetex/i18n/astro.cpp
new file mode 100644
index 00000000000..566d498d904
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/astro.cpp
@@ -0,0 +1,1563 @@
+/************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation *
+ * and others. All Rights Reserved. *
+ ************************************************************************
+ * 2003-nov-07 srl Port from Java
+ */
+
+#include "astro.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include <math.h>
+#include <float.h>
+#include "unicode/putil.h"
+#include "uhash.h"
+#include "umutex.h"
+#include "ucln_in.h"
+#include "putilimp.h"
+#include <stdio.h> // for toString()
+
+#ifdef U_DEBUG_ASTRO
+# include "uresimp.h" // for debugging
+
+static void debug_astro_loc(const char *f, int32_t l)
+{
+ fprintf(stderr, "%s:%d: ", f, l);
+}
+
+static void debug_astro_msg(const char *pat, ...)
+{
+ va_list ap;
+ va_start(ap, pat);
+ vfprintf(stderr, pat, ap);
+ fflush(stderr);
+}
+#include "unicode/datefmt.h"
+#include "unicode/ustring.h"
+static const char * debug_astro_date(UDate d) {
+ static char gStrBuf[1024];
+ static DateFormat *df = NULL;
+ if(df == NULL) {
+ df = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::MEDIUM, Locale::getUS());
+ df->adoptTimeZone(TimeZone::getGMT()->clone());
+ }
+ UnicodeString str;
+ df->format(d,str);
+ u_austrncpy(gStrBuf,str.getTerminatedBuffer(),sizeof(gStrBuf)-1);
+ return gStrBuf;
+}
+
+// must use double parens, i.e.: U_DEBUG_ASTRO_MSG(("four is: %d",4));
+#define U_DEBUG_ASTRO_MSG(x) {debug_astro_loc(__FILE__,__LINE__);debug_astro_msg x;}
+#else
+#define U_DEBUG_ASTRO_MSG(x)
+#endif
+
+static inline UBool isINVALID(double d) {
+ return(uprv_isNaN(d));
+}
+
+static UMTX ccLock = NULL;
+
+U_CDECL_BEGIN
+static UBool calendar_astro_cleanup(void) {
+ umtx_destroy(&ccLock);
+ return TRUE;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+/**
+ * The number of standard hours in one sidereal day.
+ * Approximately 24.93.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define SIDEREAL_DAY (23.93446960027)
+
+/**
+ * The number of sidereal hours in one mean solar day.
+ * Approximately 24.07.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define SOLAR_DAY (24.065709816)
+
+/**
+ * The average number of solar days from one new moon to the next. This is the time
+ * it takes for the moon to return the same ecliptic longitude as the sun.
+ * It is longer than the sidereal month because the sun's longitude increases
+ * during the year due to the revolution of the earth around the sun.
+ * Approximately 29.53.
+ *
+ * @see #SIDEREAL_MONTH
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+const double CalendarAstronomer::SYNODIC_MONTH = 29.530588853;
+
+/**
+ * The average number of days it takes
+ * for the moon to return to the same ecliptic longitude relative to the
+ * stellar background. This is referred to as the sidereal month.
+ * It is shorter than the synodic month due to
+ * the revolution of the earth around the sun.
+ * Approximately 27.32.
+ *
+ * @see #SYNODIC_MONTH
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define SIDEREAL_MONTH 27.32166
+
+/**
+ * The average number number of days between successive vernal equinoxes.
+ * Due to the precession of the earth's
+ * axis, this is not precisely the same as the sidereal year.
+ * Approximately 365.24
+ *
+ * @see #SIDEREAL_YEAR
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define TROPICAL_YEAR 365.242191
+
+/**
+ * The average number of days it takes
+ * for the sun to return to the same position against the fixed stellar
+ * background. This is the duration of one orbit of the earth about the sun
+ * as it would appear to an outside observer.
+ * Due to the precession of the earth's
+ * axis, this is not precisely the same as the tropical year.
+ * Approximately 365.25.
+ *
+ * @see #TROPICAL_YEAR
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define SIDEREAL_YEAR 365.25636
+
+//-------------------------------------------------------------------------
+// Time-related constants
+//-------------------------------------------------------------------------
+
+/**
+ * The number of milliseconds in one second.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define SECOND_MS U_MILLIS_PER_SECOND
+
+/**
+ * The number of milliseconds in one minute.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define MINUTE_MS U_MILLIS_PER_MINUTE
+
+/**
+ * The number of milliseconds in one hour.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define HOUR_MS U_MILLIS_PER_HOUR
+
+/**
+ * The number of milliseconds in one day.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define DAY_MS U_MILLIS_PER_DAY
+
+/**
+ * The start of the julian day numbering scheme used by astronomers, which
+ * is 1/1/4713 BC (Julian), 12:00 GMT. This is given as the number of milliseconds
+ * since 1/1/1970 AD (Gregorian), a negative number.
+ * Note that julian day numbers and
+ * the Julian calendar are <em>not</em> the same thing. Also note that
+ * julian days start at <em>noon</em>, not midnight.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+#define JULIAN_EPOCH_MS -210866760000000.0
+
+
+/**
+ * Milliseconds value for 0.0 January 2000 AD.
+ */
+#define EPOCH_2000_MS 946598400000.0
+
+//-------------------------------------------------------------------------
+// Assorted private data used for conversions
+//-------------------------------------------------------------------------
+
+// My own copies of these so compilers are more likely to optimize them away
+const double CalendarAstronomer::PI = 3.14159265358979323846;
+
+#define CalendarAstronomer_PI2 (CalendarAstronomer::PI*2.0)
+#define RAD_HOUR ( 12 / CalendarAstronomer::PI ) // radians -> hours
+#define DEG_RAD ( CalendarAstronomer::PI / 180 ) // degrees -> radians
+#define RAD_DEG ( 180 / CalendarAstronomer::PI ) // radians -> degrees
+
+//-------------------------------------------------------------------------
+// Constructors
+//-------------------------------------------------------------------------
+
+/**
+ * Construct a new <code>CalendarAstronomer</code> object that is initialized to
+ * the current date and time.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+CalendarAstronomer::CalendarAstronomer():
+ fTime(Calendar::getNow()), fLongitude(0.0), fLatitude(0.0), fGmtOffset(0.0), moonPosition(0,0), moonPositionSet(FALSE) {
+ clearCache();
+}
+
+/**
+ * Construct a new <code>CalendarAstronomer</code> object that is initialized to
+ * the specified date and time.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+CalendarAstronomer::CalendarAstronomer(UDate d): fTime(d), fLongitude(0.0), fLatitude(0.0), fGmtOffset(0.0), moonPosition(0,0), moonPositionSet(FALSE) {
+ clearCache();
+}
+
+/**
+ * Construct a new <code>CalendarAstronomer</code> object with the given
+ * latitude and longitude. The object's time is set to the current
+ * date and time.
+ * <p>
+ * @param longitude The desired longitude, in <em>degrees</em> east of
+ * the Greenwich meridian.
+ *
+ * @param latitude The desired latitude, in <em>degrees</em>. Positive
+ * values signify North, negative South.
+ *
+ * @see java.util.Date#getTime()
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+CalendarAstronomer::CalendarAstronomer(double longitude, double latitude) :
+ fTime(Calendar::getNow()), moonPosition(0,0), moonPositionSet(FALSE) {
+ fLongitude = normPI(longitude * (double)DEG_RAD);
+ fLatitude = normPI(latitude * (double)DEG_RAD);
+ fGmtOffset = (double)(fLongitude * 24. * (double)HOUR_MS / (double)CalendarAstronomer_PI2);
+ clearCache();
+}
+
+CalendarAstronomer::~CalendarAstronomer()
+{
+}
+
+//-------------------------------------------------------------------------
+// Time and date getters and setters
+//-------------------------------------------------------------------------
+
+/**
+ * Set the current date and time of this <code>CalendarAstronomer</code> object. All
+ * astronomical calculations are performed based on this time setting.
+ *
+ * @param aTime the date and time, expressed as the number of milliseconds since
+ * 1/1/1970 0:00 GMT (Gregorian).
+ *
+ * @see #setDate
+ * @see #getTime
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+void CalendarAstronomer::setTime(UDate aTime) {
+ fTime = aTime;
+ U_DEBUG_ASTRO_MSG(("setTime(%.1lf, %sL)\n", aTime, debug_astro_date(aTime+fGmtOffset)));
+ clearCache();
+}
+
+/**
+ * Set the current date and time of this <code>CalendarAstronomer</code> object. All
+ * astronomical calculations are performed based on this time setting.
+ *
+ * @param jdn the desired time, expressed as a "julian day number",
+ * which is the number of elapsed days since
+ * 1/1/4713 BC (Julian), 12:00 GMT. Note that julian day
+ * numbers start at <em>noon</em>. To get the jdn for
+ * the corresponding midnight, subtract 0.5.
+ *
+ * @see #getJulianDay
+ * @see #JULIAN_EPOCH_MS
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+void CalendarAstronomer::setJulianDay(double jdn) {
+ fTime = (double)(jdn * DAY_MS) + JULIAN_EPOCH_MS;
+ clearCache();
+ julianDay = jdn;
+}
+
+/**
+ * Get the current time of this <code>CalendarAstronomer</code> object,
+ * represented as the number of milliseconds since
+ * 1/1/1970 AD 0:00 GMT (Gregorian).
+ *
+ * @see #setTime
+ * @see #getDate
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+UDate CalendarAstronomer::getTime() {
+ return fTime;
+}
+
+/**
+ * Get the current time of this <code>CalendarAstronomer</code> object,
+ * expressed as a "julian day number", which is the number of elapsed
+ * days since 1/1/4713 BC (Julian), 12:00 GMT.
+ *
+ * @see #setJulianDay
+ * @see #JULIAN_EPOCH_MS
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+double CalendarAstronomer::getJulianDay() {
+ if (isINVALID(julianDay)) {
+ julianDay = (fTime - (double)JULIAN_EPOCH_MS) / (double)DAY_MS;
+ }
+ return julianDay;
+}
+
+/**
+ * Return this object's time expressed in julian centuries:
+ * the number of centuries after 1/1/1900 AD, 12:00 GMT
+ *
+ * @see #getJulianDay
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+double CalendarAstronomer::getJulianCentury() {
+ if (isINVALID(julianCentury)) {
+ julianCentury = (getJulianDay() - 2415020.0) / 36525.0;
+ }
+ return julianCentury;
+}
+
+/**
+ * Returns the current Greenwich sidereal time, measured in hours
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+double CalendarAstronomer::getGreenwichSidereal() {
+ if (isINVALID(siderealTime)) {
+ // See page 86 of "Practial Astronomy with your Calculator",
+ // by Peter Duffet-Smith, for details on the algorithm.
+
+ double UT = normalize(fTime/(double)HOUR_MS, 24.);
+
+ siderealTime = normalize(getSiderealOffset() + UT*1.002737909, 24.);
+ }
+ return siderealTime;
+}
+
+double CalendarAstronomer::getSiderealOffset() {
+ if (isINVALID(siderealT0)) {
+ double JD = uprv_floor(getJulianDay() - 0.5) + 0.5;
+ double S = JD - 2451545.0;
+ double T = S / 36525.0;
+ siderealT0 = normalize(6.697374558 + 2400.051336*T + 0.000025862*T*T, 24);
+ }
+ return siderealT0;
+}
+
+/**
+ * Returns the current local sidereal time, measured in hours
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+double CalendarAstronomer::getLocalSidereal() {
+ return normalize(getGreenwichSidereal() + (fGmtOffset/(double)HOUR_MS), 24.);
+}
+
+/**
+ * Converts local sidereal time to Universal Time.
+ *
+ * @param lst The Local Sidereal Time, in hours since sidereal midnight
+ * on this object's current date.
+ *
+ * @return The corresponding Universal Time, in milliseconds since
+ * 1 Jan 1970, GMT.
+ */
+double CalendarAstronomer::lstToUT(double lst) {
+ // Convert to local mean time
+ double lt = normalize((lst - getSiderealOffset()) * 0.9972695663, 24);
+
+ // Then find local midnight on this day
+ double base = (DAY_MS * Math::floorDivide(fTime + fGmtOffset,(double)DAY_MS)) - fGmtOffset;
+
+ //out(" lt =" + lt + " hours");
+ //out(" base=" + new Date(base));
+
+ return base + (long)(lt * HOUR_MS);
+}
+
+
+//-------------------------------------------------------------------------
+// Coordinate transformations, all based on the current time of this object
+//-------------------------------------------------------------------------
+
+/**
+ * Convert from ecliptic to equatorial coordinates.
+ *
+ * @param ecliptic A point in the sky in ecliptic coordinates.
+ * @return The corresponding point in equatorial coordinates.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+CalendarAstronomer::Equatorial& CalendarAstronomer::eclipticToEquatorial(CalendarAstronomer::Equatorial& result, const CalendarAstronomer::Ecliptic& ecliptic)
+{
+ return eclipticToEquatorial(result, ecliptic.longitude, ecliptic.latitude);
+}
+
+/**
+ * Convert from ecliptic to equatorial coordinates.
+ *
+ * @param eclipLong The ecliptic longitude
+ * @param eclipLat The ecliptic latitude
+ *
+ * @return The corresponding point in equatorial coordinates.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+CalendarAstronomer::Equatorial& CalendarAstronomer::eclipticToEquatorial(CalendarAstronomer::Equatorial& result, double eclipLong, double eclipLat)
+{
+ // See page 42 of "Practial Astronomy with your Calculator",
+ // by Peter Duffet-Smith, for details on the algorithm.
+
+ double obliq = eclipticObliquity();
+ double sinE = ::sin(obliq);
+ double cosE = cos(obliq);
+
+ double sinL = ::sin(eclipLong);
+ double cosL = cos(eclipLong);
+
+ double sinB = ::sin(eclipLat);
+ double cosB = cos(eclipLat);
+ double tanB = tan(eclipLat);
+
+ result.set(atan2(sinL*cosE - tanB*sinE, cosL),
+ asin(sinB*cosE + cosB*sinE*sinL) );
+ return result;
+}
+
+/**
+ * Convert from ecliptic longitude to equatorial coordinates.
+ *
+ * @param eclipLong The ecliptic longitude
+ *
+ * @return The corresponding point in equatorial coordinates.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+CalendarAstronomer::Equatorial& CalendarAstronomer::eclipticToEquatorial(CalendarAstronomer::Equatorial& result, double eclipLong)
+{
+ return eclipticToEquatorial(result, eclipLong, 0); // TODO: optimize
+}
+
+/**
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+CalendarAstronomer::Horizon& CalendarAstronomer::eclipticToHorizon(CalendarAstronomer::Horizon& result, double eclipLong)
+{
+ Equatorial equatorial;
+ eclipticToEquatorial(equatorial, eclipLong);
+
+ double H = getLocalSidereal()*CalendarAstronomer::PI/12 - equatorial.ascension; // Hour-angle
+
+ double sinH = ::sin(H);
+ double cosH = cos(H);
+ double sinD = ::sin(equatorial.declination);
+ double cosD = cos(equatorial.declination);
+ double sinL = ::sin(fLatitude);
+ double cosL = cos(fLatitude);
+
+ double altitude = asin(sinD*sinL + cosD*cosL*cosH);
+ double azimuth = atan2(-cosD*cosL*sinH, sinD - sinL * ::sin(altitude));
+
+ result.set(azimuth, altitude);
+ return result;
+}
+
+
+//-------------------------------------------------------------------------
+// The Sun
+//-------------------------------------------------------------------------
+
+//
+// Parameters of the Sun's orbit as of the epoch Jan 0.0 1990
+// Angles are in radians (after multiplying by CalendarAstronomer::PI/180)
+//
+#define JD_EPOCH 2447891.5 // Julian day of epoch
+
+#define SUN_ETA_G (279.403303 * CalendarAstronomer::PI/180) // Ecliptic longitude at epoch
+#define SUN_OMEGA_G (282.768422 * CalendarAstronomer::PI/180) // Ecliptic longitude of perigee
+#define SUN_E 0.016713 // Eccentricity of orbit
+//double sunR0 1.495585e8 // Semi-major axis in KM
+//double sunTheta0 (0.533128 * CalendarAstronomer::PI/180) // Angular diameter at R0
+
+// The following three methods, which compute the sun parameters
+// given above for an arbitrary epoch (whatever time the object is
+// set to), make only a small difference as compared to using the
+// above constants. E.g., Sunset times might differ by ~12
+// seconds. Furthermore, the eta-g computation is befuddled by
+// Duffet-Smith's incorrect coefficients (p.86). I've corrected
+// the first-order coefficient but the others may be off too - no
+// way of knowing without consulting another source.
+
+// /**
+// * Return the sun's ecliptic longitude at perigee for the current time.
+// * See Duffett-Smith, p. 86.
+// * @return radians
+// */
+// private double getSunOmegaG() {
+// double T = getJulianCentury();
+// return (281.2208444 + (1.719175 + 0.000452778*T)*T) * DEG_RAD;
+// }
+
+// /**
+// * Return the sun's ecliptic longitude for the current time.
+// * See Duffett-Smith, p. 86.
+// * @return radians
+// */
+// private double getSunEtaG() {
+// double T = getJulianCentury();
+// //return (279.6966778 + (36000.76892 + 0.0003025*T)*T) * DEG_RAD;
+// //
+// // The above line is from Duffett-Smith, and yields manifestly wrong
+// // results. The below constant is derived empirically to match the
+// // constant he gives for the 1990 EPOCH.
+// //
+// return (279.6966778 + (-0.3262541582718024 + 0.0003025*T)*T) * DEG_RAD;
+// }
+
+// /**
+// * Return the sun's eccentricity of orbit for the current time.
+// * See Duffett-Smith, p. 86.
+// * @return double
+// */
+// private double getSunE() {
+// double T = getJulianCentury();
+// return 0.01675104 - (0.0000418 + 0.000000126*T)*T;
+// }
+
+/**
+ * The longitude of the sun at the time specified by this object.
+ * The longitude is measured in radians along the ecliptic
+ * from the "first point of Aries," the point at which the ecliptic
+ * crosses the earth's equatorial plane at the vernal equinox.
+ * <p>
+ * Currently, this method uses an approximation of the two-body Kepler's
+ * equation for the earth and the sun. It does not take into account the
+ * perturbations caused by the other planets, the moon, etc.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+double CalendarAstronomer::getSunLongitude()
+{
+ // See page 86 of "Practial Astronomy with your Calculator",
+ // by Peter Duffet-Smith, for details on the algorithm.
+
+ if (isINVALID(sunLongitude)) {
+ getSunLongitude(getJulianDay(), sunLongitude, meanAnomalySun);
+ }
+ return sunLongitude;
+}
+
+/**
+ * TODO Make this public when the entire class is package-private.
+ */
+/*public*/ void CalendarAstronomer::getSunLongitude(double jDay, double &longitude, double &meanAnomaly)
+{
+ // See page 86 of "Practial Astronomy with your Calculator",
+ // by Peter Duffet-Smith, for details on the algorithm.
+
+ double day = jDay - JD_EPOCH; // Days since epoch
+
+ // Find the angular distance the sun in a fictitious
+ // circular orbit has travelled since the epoch.
+ double epochAngle = norm2PI(CalendarAstronomer_PI2/TROPICAL_YEAR*day);
+
+ // The epoch wasn't at the sun's perigee; find the angular distance
+ // since perigee, which is called the "mean anomaly"
+ meanAnomaly = norm2PI(epochAngle + SUN_ETA_G - SUN_OMEGA_G);
+
+ // Now find the "true anomaly", e.g. the real solar longitude
+ // by solving Kepler's equation for an elliptical orbit
+ // NOTE: The 3rd ed. of the book lists omega_g and eta_g in different
+ // equations; omega_g is to be correct.
+ longitude = norm2PI(trueAnomaly(meanAnomaly, SUN_E) + SUN_OMEGA_G);
+}
+
+/**
+ * The position of the sun at this object's current date and time,
+ * in equatorial coordinates.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+CalendarAstronomer::Equatorial& CalendarAstronomer::getSunPosition(CalendarAstronomer::Equatorial& result) {
+ return eclipticToEquatorial(result, getSunLongitude(), 0);
+}
+
+
+/**
+ * Constant representing the vernal equinox.
+ * For use with {@link #getSunTime getSunTime}.
+ * Note: In this case, "vernal" refers to the northern hemisphere's seasons.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+/*double CalendarAstronomer::VERNAL_EQUINOX() {
+ return 0;
+}*/
+
+/**
+ * Constant representing the summer solstice.
+ * For use with {@link #getSunTime getSunTime}.
+ * Note: In this case, "summer" refers to the northern hemisphere's seasons.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+double CalendarAstronomer::SUMMER_SOLSTICE() {
+ return (CalendarAstronomer::PI/2);
+}
+
+/**
+ * Constant representing the autumnal equinox.
+ * For use with {@link #getSunTime getSunTime}.
+ * Note: In this case, "autumn" refers to the northern hemisphere's seasons.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+/*double CalendarAstronomer::AUTUMN_EQUINOX() {
+ return (CalendarAstronomer::PI);
+}*/
+
+/**
+ * Constant representing the winter solstice.
+ * For use with {@link #getSunTime getSunTime}.
+ * Note: In this case, "winter" refers to the northern hemisphere's seasons.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+/*double CalendarAstronomer::WINTER_SOLSTICE() {
+ return ((CalendarAstronomer::PI*3)/2);
+}*/
+
+CalendarAstronomer::AngleFunc::~AngleFunc() {}
+
+/**
+ * Find the next time at which the sun's ecliptic longitude will have
+ * the desired value.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+class SunTimeAngleFunc : public CalendarAstronomer::AngleFunc {
+public:
+ virtual double eval(CalendarAstronomer& a) { return a.getSunLongitude(); }
+};
+
+UDate CalendarAstronomer::getSunTime(double desired, UBool next)
+{
+ SunTimeAngleFunc func;
+ return timeOfAngle( func,
+ desired,
+ TROPICAL_YEAR,
+ MINUTE_MS,
+ next);
+}
+
+CalendarAstronomer::CoordFunc::~CoordFunc() {}
+
+class RiseSetCoordFunc : public CalendarAstronomer::CoordFunc {
+public:
+ virtual void eval(CalendarAstronomer::Equatorial& result, CalendarAstronomer&a) { a.getSunPosition(result); }
+};
+
+UDate CalendarAstronomer::getSunRiseSet(UBool rise)
+{
+ UDate t0 = fTime;
+
+ // Make a rough guess: 6am or 6pm local time on the current day
+ double noon = Math::floorDivide(fTime + fGmtOffset, (double)DAY_MS)*DAY_MS - fGmtOffset + (12*HOUR_MS);
+
+ U_DEBUG_ASTRO_MSG(("Noon=%.2lf, %sL, gmtoff %.2lf\n", noon, debug_astro_date(noon+fGmtOffset), fGmtOffset));
+ setTime(noon + ((rise ? -6 : 6) * HOUR_MS));
+ U_DEBUG_ASTRO_MSG(("added %.2lf ms as a guess,\n", ((rise ? -6. : 6.) * HOUR_MS)));
+
+ RiseSetCoordFunc func;
+ double t = riseOrSet(func,
+ rise,
+ .533 * DEG_RAD, // Angular Diameter
+ 34. /60.0 * DEG_RAD, // Refraction correction
+ MINUTE_MS / 12.); // Desired accuracy
+
+ setTime(t0);
+ return t;
+}
+
+// Commented out - currently unused. ICU 2.6, Alan
+// //-------------------------------------------------------------------------
+// // Alternate Sun Rise/Set
+// // See Duffett-Smith p.93
+// //-------------------------------------------------------------------------
+//
+// // This yields worse results (as compared to USNO data) than getSunRiseSet().
+// /**
+// * TODO Make this when the entire class is package-private.
+// */
+// /*public*/ long getSunRiseSet2(boolean rise) {
+// // 1. Calculate coordinates of the sun's center for midnight
+// double jd = uprv_floor(getJulianDay() - 0.5) + 0.5;
+// double[] sl = getSunLongitude(jd);// double lambda1 = sl[0];
+// Equatorial pos1 = eclipticToEquatorial(lambda1, 0);
+//
+// // 2. Add ... to lambda to get position 24 hours later
+// double lambda2 = lambda1 + 0.985647*DEG_RAD;
+// Equatorial pos2 = eclipticToEquatorial(lambda2, 0);
+//
+// // 3. Calculate LSTs of rising and setting for these two positions
+// double tanL = ::tan(fLatitude);
+// double H = ::acos(-tanL * ::tan(pos1.declination));
+// double lst1r = (CalendarAstronomer_PI2 + pos1.ascension - H) * 24 / CalendarAstronomer_PI2;
+// double lst1s = (pos1.ascension + H) * 24 / CalendarAstronomer_PI2;
+// H = ::acos(-tanL * ::tan(pos2.declination));
+// double lst2r = (CalendarAstronomer_PI2-H + pos2.ascension ) * 24 / CalendarAstronomer_PI2;
+// double lst2s = (H + pos2.ascension ) * 24 / CalendarAstronomer_PI2;
+// if (lst1r > 24) lst1r -= 24;
+// if (lst1s > 24) lst1s -= 24;
+// if (lst2r > 24) lst2r -= 24;
+// if (lst2s > 24) lst2s -= 24;
+//
+// // 4. Convert LSTs to GSTs. If GST1 > GST2, add 24 to GST2.
+// double gst1r = lstToGst(lst1r);
+// double gst1s = lstToGst(lst1s);
+// double gst2r = lstToGst(lst2r);
+// double gst2s = lstToGst(lst2s);
+// if (gst1r > gst2r) gst2r += 24;
+// if (gst1s > gst2s) gst2s += 24;
+//
+// // 5. Calculate GST at 0h UT of this date
+// double t00 = utToGst(0);
+//
+// // 6. Calculate GST at 0h on the observer's longitude
+// double offset = ::round(fLongitude*12/PI); // p.95 step 6; he _rounds_ to nearest 15 deg.
+// double t00p = t00 - offset*1.002737909;
+// if (t00p < 0) t00p += 24; // do NOT normalize
+//
+// // 7. Adjust
+// if (gst1r < t00p) {
+// gst1r += 24;
+// gst2r += 24;
+// }
+// if (gst1s < t00p) {
+// gst1s += 24;
+// gst2s += 24;
+// }
+//
+// // 8.
+// double gstr = (24.07*gst1r-t00*(gst2r-gst1r))/(24.07+gst1r-gst2r);
+// double gsts = (24.07*gst1s-t00*(gst2s-gst1s))/(24.07+gst1s-gst2s);
+//
+// // 9. Correct for parallax, refraction, and sun's diameter
+// double dec = (pos1.declination + pos2.declination) / 2;
+// double psi = ::acos(sin(fLatitude) / cos(dec));
+// double x = 0.830725 * DEG_RAD; // parallax+refraction+diameter
+// double y = ::asin(sin(x) / ::sin(psi)) * RAD_DEG;
+// double delta_t = 240 * y / cos(dec) / 3600; // hours
+//
+// // 10. Add correction to GSTs, subtract from GSTr
+// gstr -= delta_t;
+// gsts += delta_t;
+//
+// // 11. Convert GST to UT and then to local civil time
+// double ut = gstToUt(rise ? gstr : gsts);
+// //System.out.println((rise?"rise=":"set=") + ut + ", delta_t=" + delta_t);
+// long midnight = DAY_MS * (time / DAY_MS); // Find UT midnight on this day
+// return midnight + (long) (ut * 3600000);
+// }
+
+// Commented out - currently unused. ICU 2.6, Alan
+// /**
+// * Convert local sidereal time to Greenwich sidereal time.
+// * Section 15. Duffett-Smith p.21
+// * @param lst in hours (0..24)
+// * @return GST in hours (0..24)
+// */
+// double lstToGst(double lst) {
+// double delta = fLongitude * 24 / CalendarAstronomer_PI2;
+// return normalize(lst - delta, 24);
+// }
+
+// Commented out - currently unused. ICU 2.6, Alan
+// /**
+// * Convert UT to GST on this date.
+// * Section 12. Duffett-Smith p.17
+// * @param ut in hours
+// * @return GST in hours
+// */
+// double utToGst(double ut) {
+// return normalize(getT0() + ut*1.002737909, 24);
+// }
+
+// Commented out - currently unused. ICU 2.6, Alan
+// /**
+// * Convert GST to UT on this date.
+// * Section 13. Duffett-Smith p.18
+// * @param gst in hours
+// * @return UT in hours
+// */
+// double gstToUt(double gst) {
+// return normalize(gst - getT0(), 24) * 0.9972695663;
+// }
+
+// Commented out - currently unused. ICU 2.6, Alan
+// double getT0() {
+// // Common computation for UT <=> GST
+//
+// // Find JD for 0h UT
+// double jd = uprv_floor(getJulianDay() - 0.5) + 0.5;
+//
+// double s = jd - 2451545.0;
+// double t = s / 36525.0;
+// double t0 = 6.697374558 + (2400.051336 + 0.000025862*t)*t;
+// return t0;
+// }
+
+// Commented out - currently unused. ICU 2.6, Alan
+// //-------------------------------------------------------------------------
+// // Alternate Sun Rise/Set
+// // See sci.astro FAQ
+// // http://www.faqs.org/faqs/astronomy/faq/part3/section-5.html
+// //-------------------------------------------------------------------------
+//
+// // Note: This method appears to produce inferior accuracy as
+// // compared to getSunRiseSet().
+//
+// /**
+// * TODO Make this when the entire class is package-private.
+// */
+// /*public*/ long getSunRiseSet3(boolean rise) {
+//
+// // Compute day number for 0.0 Jan 2000 epoch
+// double d = (double)(time - EPOCH_2000_MS) / DAY_MS;
+//
+// // Now compute the Local Sidereal Time, LST:
+// //
+// double LST = 98.9818 + 0.985647352 * d + /*UT*15 + long*/
+// fLongitude*RAD_DEG;
+// //
+// // (east long. positive). Note that LST is here expressed in degrees,
+// // where 15 degrees corresponds to one hour. Since LST really is an angle,
+// // it's convenient to use one unit---degrees---throughout.
+//
+// // COMPUTING THE SUN'S POSITION
+// // ----------------------------
+// //
+// // To be able to compute the Sun's rise/set times, you need to be able to
+// // compute the Sun's position at any time. First compute the "day
+// // number" d as outlined above, for the desired moment. Next compute:
+// //
+// double oblecl = 23.4393 - 3.563E-7 * d;
+// //
+// double w = 282.9404 + 4.70935E-5 * d;
+// double M = 356.0470 + 0.9856002585 * d;
+// double e = 0.016709 - 1.151E-9 * d;
+// //
+// // This is the obliquity of the ecliptic, plus some of the elements of
+// // the Sun's apparent orbit (i.e., really the Earth's orbit): w =
+// // argument of perihelion, M = mean anomaly, e = eccentricity.
+// // Semi-major axis is here assumed to be exactly 1.0 (while not strictly
+// // true, this is still an accurate approximation). Next compute E, the
+// // eccentric anomaly:
+// //
+// double E = M + e*(180/PI) * ::sin(M*DEG_RAD) * ( 1.0 + e*cos(M*DEG_RAD) );
+// //
+// // where E and M are in degrees. This is it---no further iterations are
+// // needed because we know e has a sufficiently small value. Next compute
+// // the true anomaly, v, and the distance, r:
+// //
+// /* r * cos(v) = */ double A = cos(E*DEG_RAD) - e;
+// /* r * ::sin(v) = */ double B = ::sqrt(1 - e*e) * ::sin(E*DEG_RAD);
+// //
+// // and
+// //
+// // r = sqrt( A*A + B*B )
+// double v = ::atan2( B, A )*RAD_DEG;
+// //
+// // The Sun's true longitude, slon, can now be computed:
+// //
+// double slon = v + w;
+// //
+// // Since the Sun is always at the ecliptic (or at least very very close to
+// // it), we can use simplified formulae to convert slon (the Sun's ecliptic
+// // longitude) to sRA and sDec (the Sun's RA and Dec):
+// //
+// // ::sin(slon) * cos(oblecl)
+// // tan(sRA) = -------------------------
+// // cos(slon)
+// //
+// // ::sin(sDec) = ::sin(oblecl) * ::sin(slon)
+// //
+// // As was the case when computing az, the Azimuth, if possible use an
+// // atan2() function to compute sRA.
+//
+// double sRA = ::atan2(sin(slon*DEG_RAD) * cos(oblecl*DEG_RAD), cos(slon*DEG_RAD))*RAD_DEG;
+//
+// double sin_sDec = ::sin(oblecl*DEG_RAD) * ::sin(slon*DEG_RAD);
+// double sDec = ::asin(sin_sDec)*RAD_DEG;
+//
+// // COMPUTING RISE AND SET TIMES
+// // ----------------------------
+// //
+// // To compute when an object rises or sets, you must compute when it
+// // passes the meridian and the HA of rise/set. Then the rise time is
+// // the meridian time minus HA for rise/set, and the set time is the
+// // meridian time plus the HA for rise/set.
+// //
+// // To find the meridian time, compute the Local Sidereal Time at 0h local
+// // time (or 0h UT if you prefer to work in UT) as outlined above---name
+// // that quantity LST0. The Meridian Time, MT, will now be:
+// //
+// // MT = RA - LST0
+// double MT = normalize(sRA - LST, 360);
+// //
+// // where "RA" is the object's Right Ascension (in degrees!). If negative,
+// // add 360 deg to MT. If the object is the Sun, leave the time as it is,
+// // but if it's stellar, multiply MT by 365.2422/366.2422, to convert from
+// // sidereal to solar time. Now, compute HA for rise/set, name that
+// // quantity HA0:
+// //
+// // ::sin(h0) - ::sin(lat) * ::sin(Dec)
+// // cos(HA0) = ---------------------------------
+// // cos(lat) * cos(Dec)
+// //
+// // where h0 is the altitude selected to represent rise/set. For a purely
+// // mathematical horizon, set h0 = 0 and simplify to:
+// //
+// // cos(HA0) = - tan(lat) * tan(Dec)
+// //
+// // If you want to account for refraction on the atmosphere, set h0 = -35/60
+// // degrees (-35 arc minutes), and if you want to compute the rise/set times
+// // for the Sun's upper limb, set h0 = -50/60 (-50 arc minutes).
+// //
+// double h0 = -50/60 * DEG_RAD;
+//
+// double HA0 = ::acos(
+// (sin(h0) - ::sin(fLatitude) * sin_sDec) /
+// (cos(fLatitude) * cos(sDec*DEG_RAD)))*RAD_DEG;
+//
+// // When HA0 has been computed, leave it as it is for the Sun but multiply
+// // by 365.2422/366.2422 for stellar objects, to convert from sidereal to
+// // solar time. Finally compute:
+// //
+// // Rise time = MT - HA0
+// // Set time = MT + HA0
+// //
+// // convert the times from degrees to hours by dividing by 15.
+// //
+// // If you'd like to check that your calculations are accurate or just
+// // need a quick result, check the USNO's Sun or Moon Rise/Set Table,
+// // <URL:http://aa.usno.navy.mil/AA/data/docs/RS_OneYear.html>.
+//
+// double result = MT + (rise ? -HA0 : HA0); // in degrees
+//
+// // Find UT midnight on this day
+// long midnight = DAY_MS * (time / DAY_MS);
+//
+// return midnight + (long) (result * 3600000 / 15);
+// }
+
+//-------------------------------------------------------------------------
+// The Moon
+//-------------------------------------------------------------------------
+
+#define moonL0 (318.351648 * CalendarAstronomer::PI/180 ) // Mean long. at epoch
+#define moonP0 ( 36.340410 * CalendarAstronomer::PI/180 ) // Mean long. of perigee
+#define moonN0 ( 318.510107 * CalendarAstronomer::PI/180 ) // Mean long. of node
+#define moonI ( 5.145366 * CalendarAstronomer::PI/180 ) // Inclination of orbit
+#define moonE ( 0.054900 ) // Eccentricity of orbit
+
+// These aren't used right now
+#define moonA ( 3.84401e5 ) // semi-major axis (km)
+#define moonT0 ( 0.5181 * CalendarAstronomer::PI/180 ) // Angular size at distance A
+#define moonPi ( 0.9507 * CalendarAstronomer::PI/180 ) // Parallax at distance A
+
+/**
+ * The position of the moon at the time set on this
+ * object, in equatorial coordinates.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+const CalendarAstronomer::Equatorial& CalendarAstronomer::getMoonPosition()
+{
+ //
+ // See page 142 of "Practial Astronomy with your Calculator",
+ // by Peter Duffet-Smith, for details on the algorithm.
+ //
+ if (moonPositionSet == FALSE) {
+ // Calculate the solar longitude. Has the side effect of
+ // filling in "meanAnomalySun" as well.
+ getSunLongitude();
+
+ //
+ // Find the # of days since the epoch of our orbital parameters.
+ // TODO: Convert the time of day portion into ephemeris time
+ //
+ double day = getJulianDay() - JD_EPOCH; // Days since epoch
+
+ // Calculate the mean longitude and anomaly of the moon, based on
+ // a circular orbit. Similar to the corresponding solar calculation.
+ double meanLongitude = norm2PI(13.1763966*PI/180*day + moonL0);
+ meanAnomalyMoon = norm2PI(meanLongitude - 0.1114041*PI/180 * day - moonP0);
+
+ //
+ // Calculate the following corrections:
+ // Evection: the sun's gravity affects the moon's eccentricity
+ // Annual Eqn: variation in the effect due to earth-sun distance
+ // A3: correction factor (for ???)
+ //
+ double evection = 1.2739*PI/180 * ::sin(2 * (meanLongitude - sunLongitude)
+ - meanAnomalyMoon);
+ double annual = 0.1858*PI/180 * ::sin(meanAnomalySun);
+ double a3 = 0.3700*PI/180 * ::sin(meanAnomalySun);
+
+ meanAnomalyMoon += evection - annual - a3;
+
+ //
+ // More correction factors:
+ // center equation of the center correction
+ // a4 yet another error correction (???)
+ //
+ // TODO: Skip the equation of the center correction and solve Kepler's eqn?
+ //
+ double center = 6.2886*PI/180 * ::sin(meanAnomalyMoon);
+ double a4 = 0.2140*PI/180 * ::sin(2 * meanAnomalyMoon);
+
+ // Now find the moon's corrected longitude
+ moonLongitude = meanLongitude + evection + center - annual + a4;
+
+ //
+ // And finally, find the variation, caused by the fact that the sun's
+ // gravitational pull on the moon varies depending on which side of
+ // the earth the moon is on
+ //
+ double variation = 0.6583*CalendarAstronomer::PI/180 * ::sin(2*(moonLongitude - sunLongitude));
+
+ moonLongitude += variation;
+
+ //
+ // What we've calculated so far is the moon's longitude in the plane
+ // of its own orbit. Now map to the ecliptic to get the latitude
+ // and longitude. First we need to find the longitude of the ascending
+ // node, the position on the ecliptic where it is crossed by the moon's
+ // orbit as it crosses from the southern to the northern hemisphere.
+ //
+ double nodeLongitude = norm2PI(moonN0 - 0.0529539*PI/180 * day);
+
+ nodeLongitude -= 0.16*PI/180 * ::sin(meanAnomalySun);
+
+ double y = ::sin(moonLongitude - nodeLongitude);
+ double x = cos(moonLongitude - nodeLongitude);
+
+ moonEclipLong = ::atan2(y*cos(moonI), x) + nodeLongitude;
+ double moonEclipLat = ::asin(y * ::sin(moonI));
+
+ eclipticToEquatorial(moonPosition, moonEclipLong, moonEclipLat);
+ moonPositionSet = TRUE;
+ }
+ return moonPosition;
+}
+
+/**
+ * The "age" of the moon at the time specified in this object.
+ * This is really the angle between the
+ * current ecliptic longitudes of the sun and the moon,
+ * measured in radians.
+ *
+ * @see #getMoonPhase
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+double CalendarAstronomer::getMoonAge() {
+ // See page 147 of "Practial Astronomy with your Calculator",
+ // by Peter Duffet-Smith, for details on the algorithm.
+ //
+ // Force the moon's position to be calculated. We're going to use
+ // some the intermediate results cached during that calculation.
+ //
+ getMoonPosition();
+
+ return norm2PI(moonEclipLong - sunLongitude);
+}
+
+/**
+ * Calculate the phase of the moon at the time set in this object.
+ * The returned phase is a <code>double</code> in the range
+ * <code>0 <= phase < 1</code>, interpreted as follows:
+ * <ul>
+ * <li>0.00: New moon
+ * <li>0.25: First quarter
+ * <li>0.50: Full moon
+ * <li>0.75: Last quarter
+ * </ul>
+ *
+ * @see #getMoonAge
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+double CalendarAstronomer::getMoonPhase() {
+ // See page 147 of "Practial Astronomy with your Calculator",
+ // by Peter Duffet-Smith, for details on the algorithm.
+ return 0.5 * (1 - cos(getMoonAge()));
+}
+
+/**
+ * Constant representing a new moon.
+ * For use with {@link #getMoonTime getMoonTime}
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+/*const CalendarAstronomer::MoonAge CalendarAstronomer::NEW_MOON() {
+ return CalendarAstronomer::MoonAge(0);
+}*/
+
+/**
+ * Constant representing the moon's first quarter.
+ * For use with {@link #getMoonTime getMoonTime}
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+/*const CalendarAstronomer::MoonAge CalendarAstronomer::FIRST_QUARTER() {
+ return CalendarAstronomer::MoonAge(CalendarAstronomer::PI/2);
+}*/
+
+/**
+ * Constant representing a full moon.
+ * For use with {@link #getMoonTime getMoonTime}
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+const CalendarAstronomer::MoonAge CalendarAstronomer::FULL_MOON() {
+ return CalendarAstronomer::MoonAge(CalendarAstronomer::PI);
+}
+/**
+ * Constant representing the moon's last quarter.
+ * For use with {@link #getMoonTime getMoonTime}
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+
+class MoonTimeAngleFunc : public CalendarAstronomer::AngleFunc {
+public:
+ virtual double eval(CalendarAstronomer&a) { return a.getMoonAge(); }
+};
+
+/*const CalendarAstronomer::MoonAge CalendarAstronomer::LAST_QUARTER() {
+ return CalendarAstronomer::MoonAge((CalendarAstronomer::PI*3)/2);
+}*/
+
+/**
+ * Find the next or previous time at which the Moon's ecliptic
+ * longitude will have the desired value.
+ * <p>
+ * @param desired The desired longitude.
+ * @param next <tt>true</tt> if the next occurrance of the phase
+ * is desired, <tt>false</tt> for the previous occurrance.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+UDate CalendarAstronomer::getMoonTime(double desired, UBool next)
+{
+ MoonTimeAngleFunc func;
+ return timeOfAngle( func,
+ desired,
+ SYNODIC_MONTH,
+ MINUTE_MS,
+ next);
+}
+
+/**
+ * Find the next or previous time at which the moon will be in the
+ * desired phase.
+ * <p>
+ * @param desired The desired phase of the moon.
+ * @param next <tt>true</tt> if the next occurrance of the phase
+ * is desired, <tt>false</tt> for the previous occurrance.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+UDate CalendarAstronomer::getMoonTime(const CalendarAstronomer::MoonAge& desired, UBool next) {
+ return getMoonTime(desired.value, next);
+}
+
+class MoonRiseSetCoordFunc : public CalendarAstronomer::CoordFunc {
+public:
+ virtual void eval(CalendarAstronomer::Equatorial& result, CalendarAstronomer&a) { result = a.getMoonPosition(); }
+};
+
+/**
+ * Returns the time (GMT) of sunrise or sunset on the local date to which
+ * this calendar is currently set.
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+UDate CalendarAstronomer::getMoonRiseSet(UBool rise)
+{
+ MoonRiseSetCoordFunc func;
+ return riseOrSet(func,
+ rise,
+ .533 * DEG_RAD, // Angular Diameter
+ 34 /60.0 * DEG_RAD, // Refraction correction
+ MINUTE_MS); // Desired accuracy
+}
+
+//-------------------------------------------------------------------------
+// Interpolation methods for finding the time at which a given event occurs
+//-------------------------------------------------------------------------
+
+UDate CalendarAstronomer::timeOfAngle(AngleFunc& func, double desired,
+ double periodDays, double epsilon, UBool next)
+{
+ // Find the value of the function at the current time
+ double lastAngle = func.eval(*this);
+
+ // Find out how far we are from the desired angle
+ double deltaAngle = norm2PI(desired - lastAngle) ;
+
+ // Using the average period, estimate the next (or previous) time at
+ // which the desired angle occurs.
+ double deltaT = (deltaAngle + (next ? 0.0 : - CalendarAstronomer_PI2 )) * (periodDays*DAY_MS) / CalendarAstronomer_PI2;
+
+ double lastDeltaT = deltaT; // Liu
+ UDate startTime = fTime; // Liu
+
+ setTime(fTime + uprv_ceil(deltaT));
+
+ // Now iterate until we get the error below epsilon. Throughout
+ // this loop we use normPI to get values in the range -Pi to Pi,
+ // since we're using them as correction factors rather than absolute angles.
+ do {
+ // Evaluate the function at the time we've estimated
+ double angle = func.eval(*this);
+
+ // Find the # of milliseconds per radian at this point on the curve
+ double factor = uprv_fabs(deltaT / normPI(angle-lastAngle));
+
+ // Correct the time estimate based on how far off the angle is
+ deltaT = normPI(desired - angle) * factor;
+
+ // HACK:
+ //
+ // If abs(deltaT) begins to diverge we need to quit this loop.
+ // This only appears to happen when attempting to locate, for
+ // example, a new moon on the day of the new moon. E.g.:
+ //
+ // This result is correct:
+ // newMoon(7508(Mon Jul 23 00:00:00 CST 1990,false))=
+ // Sun Jul 22 10:57:41 CST 1990
+ //
+ // But attempting to make the same call a day earlier causes deltaT
+ // to diverge:
+ // CalendarAstronomer.timeOfAngle() diverging: 1.348508727575625E9 ->
+ // 1.3649828540224032E9
+ // newMoon(7507(Sun Jul 22 00:00:00 CST 1990,false))=
+ // Sun Jul 08 13:56:15 CST 1990
+ //
+ // As a temporary solution, we catch this specific condition and
+ // adjust our start time by one eighth period days (either forward
+ // or backward) and try again.
+ // Liu 11/9/00
+ if (uprv_fabs(deltaT) > uprv_fabs(lastDeltaT)) {
+ double delta = uprv_ceil (periodDays * DAY_MS / 8.0);
+ setTime(startTime + (next ? delta : -delta));
+ return timeOfAngle(func, desired, periodDays, epsilon, next);
+ }
+
+ lastDeltaT = deltaT;
+ lastAngle = angle;
+
+ setTime(fTime + uprv_ceil(deltaT));
+ }
+ while (uprv_fabs(deltaT) > epsilon);
+
+ return fTime;
+}
+
+UDate CalendarAstronomer::riseOrSet(CoordFunc& func, UBool rise,
+ double diameter, double refraction,
+ double epsilon)
+{
+ Equatorial pos;
+ double tanL = ::tan(fLatitude);
+ double deltaT = 0;
+ int32_t count = 0;
+
+ //
+ // Calculate the object's position at the current time, then use that
+ // position to calculate the time of rising or setting. The position
+ // will be different at that time, so iterate until the error is allowable.
+ //
+ U_DEBUG_ASTRO_MSG(("setup rise=%s, dia=%.3lf, ref=%.3lf, eps=%.3lf\n",
+ rise?"T":"F", diameter, refraction, epsilon));
+ do {
+ // See "Practical Astronomy With Your Calculator, section 33.
+ func.eval(pos, *this);
+ double angle = ::acos(-tanL * ::tan(pos.declination));
+ double lst = ((rise ? CalendarAstronomer_PI2-angle : angle) + pos.ascension ) * 24 / CalendarAstronomer_PI2;
+
+ // Convert from LST to Universal Time.
+ UDate newTime = lstToUT( lst );
+
+ deltaT = newTime - fTime;
+ setTime(newTime);
+ U_DEBUG_ASTRO_MSG(("%d] dT=%.3lf, angle=%.3lf, lst=%.3lf, A=%.3lf/D=%.3lf\n",
+ count, deltaT, angle, lst, pos.ascension, pos.declination));
+ }
+ while (++ count < 5 && uprv_fabs(deltaT) > epsilon);
+
+ // Calculate the correction due to refraction and the object's angular diameter
+ double cosD = ::cos(pos.declination);
+ double psi = ::acos(sin(fLatitude) / cosD);
+ double x = diameter / 2 + refraction;
+ double y = ::asin(sin(x) / ::sin(psi));
+ long delta = (long)((240 * y * RAD_DEG / cosD)*SECOND_MS);
+
+ return fTime + (rise ? -delta : delta);
+}
+
+/**
+ * Find the "true anomaly" (longitude) of an object from
+ * its mean anomaly and the eccentricity of its orbit. This uses
+ * an iterative solution to Kepler's equation.
+ *
+ * @param meanAnomaly The object's longitude calculated as if it were in
+ * a regular, circular orbit, measured in radians
+ * from the point of perigee.
+ *
+ * @param eccentricity The eccentricity of the orbit
+ *
+ * @return The true anomaly (longitude) measured in radians
+ */
+double CalendarAstronomer::trueAnomaly(double meanAnomaly, double eccentricity)
+{
+ // First, solve Kepler's equation iteratively
+ // Duffett-Smith, p.90
+ double delta;
+ double E = meanAnomaly;
+ do {
+ delta = E - eccentricity * ::sin(E) - meanAnomaly;
+ E = E - delta / (1 - eccentricity * ::cos(E));
+ }
+ while (uprv_fabs(delta) > 1e-5); // epsilon = 1e-5 rad
+
+ return 2.0 * ::atan( ::tan(E/2) * ::sqrt( (1+eccentricity)
+ /(1-eccentricity) ) );
+}
+
+/**
+ * Return the obliquity of the ecliptic (the angle between the ecliptic
+ * and the earth's equator) at the current time. This varies due to
+ * the precession of the earth's axis.
+ *
+ * @return the obliquity of the ecliptic relative to the equator,
+ * measured in radians.
+ */
+double CalendarAstronomer::eclipticObliquity() {
+ if (isINVALID(eclipObliquity)) {
+ const double epoch = 2451545.0; // 2000 AD, January 1.5
+
+ double T = (getJulianDay() - epoch) / 36525;
+
+ eclipObliquity = 23.439292
+ - 46.815/3600 * T
+ - 0.0006/3600 * T*T
+ + 0.00181/3600 * T*T*T;
+
+ eclipObliquity *= DEG_RAD;
+ }
+ return eclipObliquity;
+}
+
+
+//-------------------------------------------------------------------------
+// Private data
+//-------------------------------------------------------------------------
+void CalendarAstronomer::clearCache() {
+ const double INVALID = uprv_getNaN();
+
+ julianDay = INVALID;
+ julianCentury = INVALID;
+ sunLongitude = INVALID;
+ meanAnomalySun = INVALID;
+ moonLongitude = INVALID;
+ moonEclipLong = INVALID;
+ meanAnomalyMoon = INVALID;
+ eclipObliquity = INVALID;
+ siderealTime = INVALID;
+ siderealT0 = INVALID;
+ moonPositionSet = FALSE;
+}
+
+//private static void out(String s) {
+// System.out.println(s);
+//}
+
+//private static String deg(double rad) {
+// return Double.toString(rad * RAD_DEG);
+//}
+
+//private static String hours(long ms) {
+// return Double.toString((double)ms / HOUR_MS) + " hours";
+//}
+
+/**
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+/*UDate CalendarAstronomer::local(UDate localMillis) {
+ // TODO - srl ?
+ TimeZone *tz = TimeZone::createDefault();
+ int32_t rawOffset;
+ int32_t dstOffset;
+ UErrorCode status = U_ZERO_ERROR;
+ tz->getOffset(localMillis, TRUE, rawOffset, dstOffset, status);
+ delete tz;
+ return localMillis - rawOffset;
+}*/
+
+// Debugging functions
+UnicodeString CalendarAstronomer::Ecliptic::toString() const
+{
+#ifdef U_DEBUG_ASTRO
+ char tmp[800];
+ sprintf(tmp, "[%.5f,%.5f]", longitude*RAD_DEG, latitude*RAD_DEG);
+ return UnicodeString(tmp, "");
+#else
+ return UnicodeString();
+#endif
+}
+
+UnicodeString CalendarAstronomer::Equatorial::toString() const
+{
+#ifdef U_DEBUG_ASTRO
+ char tmp[400];
+ sprintf(tmp, "%f,%f",
+ (ascension*RAD_DEG), (declination*RAD_DEG));
+ return UnicodeString(tmp, "");
+#else
+ return UnicodeString();
+#endif
+}
+
+UnicodeString CalendarAstronomer::Horizon::toString() const
+{
+#ifdef U_DEBUG_ASTRO
+ char tmp[800];
+ sprintf(tmp, "[%.5f,%.5f]", altitude*RAD_DEG, azimuth*RAD_DEG);
+ return UnicodeString(tmp, "");
+#else
+ return UnicodeString();
+#endif
+}
+
+
+// static private String radToHms(double angle) {
+// int hrs = (int) (angle*RAD_HOUR);
+// int min = (int)((angle*RAD_HOUR - hrs) * 60);
+// int sec = (int)((angle*RAD_HOUR - hrs - min/60.0) * 3600);
+
+// return Integer.toString(hrs) + "h" + min + "m" + sec + "s";
+// }
+
+// static private String radToDms(double angle) {
+// int deg = (int) (angle*RAD_DEG);
+// int min = (int)((angle*RAD_DEG - deg) * 60);
+// int sec = (int)((angle*RAD_DEG - deg - min/60.0) * 3600);
+
+// return Integer.toString(deg) + "\u00b0" + min + "'" + sec + "\"";
+// }
+
+// =============== Calendar Cache ================
+
+void CalendarCache::createCache(CalendarCache** cache, UErrorCode& status) {
+ ucln_i18n_registerCleanup(UCLN_I18N_ASTRO_CALENDAR, calendar_astro_cleanup);
+ if(cache == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ *cache = new CalendarCache(32, status);
+ if(U_FAILURE(status)) {
+ delete *cache;
+ *cache = NULL;
+ }
+ }
+}
+
+int32_t CalendarCache::get(CalendarCache** cache, int32_t key, UErrorCode &status) {
+ int32_t res;
+
+ if(U_FAILURE(status)) {
+ return 0;
+ }
+ umtx_lock(&ccLock);
+
+ if(*cache == NULL) {
+ createCache(cache, status);
+ if(U_FAILURE(status)) {
+ umtx_unlock(&ccLock);
+ return 0;
+ }
+ }
+
+ res = uhash_igeti((*cache)->fTable, key);
+ U_DEBUG_ASTRO_MSG(("%p: GET: [%d] == %d\n", (*cache)->fTable, key, res));
+
+ umtx_unlock(&ccLock);
+ return res;
+}
+
+void CalendarCache::put(CalendarCache** cache, int32_t key, int32_t value, UErrorCode &status) {
+ if(U_FAILURE(status)) {
+ return;
+ }
+ umtx_lock(&ccLock);
+
+ if(*cache == NULL) {
+ createCache(cache, status);
+ if(U_FAILURE(status)) {
+ umtx_unlock(&ccLock);
+ return;
+ }
+ }
+
+ uhash_iputi((*cache)->fTable, key, value, &status);
+ U_DEBUG_ASTRO_MSG(("%p: PUT: [%d] := %d\n", (*cache)->fTable, key, value));
+
+ umtx_unlock(&ccLock);
+}
+
+CalendarCache::CalendarCache(int32_t size, UErrorCode &status) {
+ fTable = uhash_openSize(uhash_hashLong, uhash_compareLong, NULL, size, &status);
+ U_DEBUG_ASTRO_MSG(("%p: Opening.\n", fTable));
+}
+
+CalendarCache::~CalendarCache() {
+ if(fTable != NULL) {
+ U_DEBUG_ASTRO_MSG(("%p: Closing.\n", fTable));
+ uhash_close(fTable);
+ }
+}
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
diff --git a/Build/source/libs/icu/icu-xetex/i18n/astro.h b/Build/source/libs/icu/icu-xetex/i18n/astro.h
new file mode 100644
index 00000000000..6c28f2e3e0e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/astro.h
@@ -0,0 +1,793 @@
+/************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation *
+ * and others. All Rights Reserved. *
+ ************************************************************************
+ * 2003-nov-07 srl Port from Java
+ */
+
+#ifndef ASTRO_H
+#define ASTRO_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "gregoimp.h" // for Math
+#include "unicode/unistr.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * <code>CalendarAstronomer</code> is a class that can perform the calculations to
+ * determine the positions of the sun and moon, the time of sunrise and
+ * sunset, and other astronomy-related data. The calculations it performs
+ * are in some cases quite complicated, and this utility class saves you
+ * the trouble of worrying about them.
+ * <p>
+ * The measurement of time is a very important part of astronomy. Because
+ * astronomical bodies are constantly in motion, observations are only valid
+ * at a given moment in time. Accordingly, each <code>CalendarAstronomer</code>
+ * object has a <code>time</code> property that determines the date
+ * and time for which its calculations are performed. You can set and
+ * retrieve this property with {@link #setDate setDate}, {@link #getDate getDate}
+ * and related methods.
+ * <p>
+ * Almost all of the calculations performed by this class, or by any
+ * astronomer, are approximations to various degrees of accuracy. The
+ * calculations in this class are mostly modelled after those described
+ * in the book
+ * <a href="http://www.amazon.com/exec/obidos/ISBN=0521356997" target="_top">
+ * Practical Astronomy With Your Calculator</a>, by Peter J.
+ * Duffett-Smith, Cambridge University Press, 1990. This is an excellent
+ * book, and if you want a greater understanding of how these calculations
+ * are performed it a very good, readable starting point.
+ * <p>
+ * <strong>WARNING:</strong> This class is very early in its development, and
+ * it is highly likely that its API will change to some degree in the future.
+ * At the moment, it basically does just enough to support {@link IslamicCalendar}
+ * and {@link ChineseCalendar}.
+ *
+ * @author Laura Werner
+ * @author Alan Liu
+ * @internal
+ */
+class U_I18N_API CalendarAstronomer : public UMemory {
+public:
+ // some classes
+
+public:
+ /**
+ * Represents the position of an object in the sky relative to the ecliptic,
+ * the plane of the earth's orbit around the Sun.
+ * This is a spherical coordinate system in which the latitude
+ * specifies the position north or south of the plane of the ecliptic.
+ * The longitude specifies the position along the ecliptic plane
+ * relative to the "First Point of Aries", which is the Sun's position in the sky
+ * at the Vernal Equinox.
+ * <p>
+ * Note that Ecliptic objects are immutable and cannot be modified
+ * once they are constructed. This allows them to be passed and returned by
+ * value without worrying about whether other code will modify them.
+ *
+ * @see CalendarAstronomer.Equatorial
+ * @see CalendarAstronomer.Horizon
+ * @internal
+ */
+ class U_I18N_API Ecliptic : public UMemory {
+ public:
+ /**
+ * Constructs an Ecliptic coordinate object.
+ * <p>
+ * @param lat The ecliptic latitude, measured in radians.
+ * @param lon The ecliptic longitude, measured in radians.
+ * @internal
+ */
+ Ecliptic(double lat = 0, double lon = 0) {
+ latitude = lat;
+ longitude = lon;
+ }
+
+ /**
+ * Setter for Ecliptic Coordinate object
+ * @param lat The ecliptic latitude, measured in radians.
+ * @param lon The ecliptic longitude, measured in radians.
+ * @internal
+ */
+ void set(double lat, double lon) {
+ latitude = lat;
+ longitude = lon;
+ }
+
+ /**
+ * Return a string representation of this object
+ * @internal
+ */
+ UnicodeString toString() const;
+
+ /**
+ * The ecliptic latitude, in radians. This specifies an object's
+ * position north or south of the plane of the ecliptic,
+ * with positive angles representing north.
+ * @internal
+ */
+ double latitude;
+
+ /**
+ * The ecliptic longitude, in radians.
+ * This specifies an object's position along the ecliptic plane
+ * relative to the "First Point of Aries", which is the Sun's position
+ * in the sky at the Vernal Equinox,
+ * with positive angles representing east.
+ * <p>
+ * A bit of trivia: the first point of Aries is currently in the
+ * constellation Pisces, due to the precession of the earth's axis.
+ * @internal
+ */
+ double longitude;
+ };
+
+ /**
+ * Represents the position of an
+ * object in the sky relative to the plane of the earth's equator.
+ * The <i>Right Ascension</i> specifies the position east or west
+ * along the equator, relative to the sun's position at the vernal
+ * equinox. The <i>Declination</i> is the position north or south
+ * of the equatorial plane.
+ * <p>
+ * Note that Equatorial objects are immutable and cannot be modified
+ * once they are constructed. This allows them to be passed and returned by
+ * value without worrying about whether other code will modify them.
+ *
+ * @see CalendarAstronomer.Ecliptic
+ * @see CalendarAstronomer.Horizon
+ * @internal
+ */
+ class U_I18N_API Equatorial : public UMemory {
+ public:
+ /**
+ * Constructs an Equatorial coordinate object.
+ * <p>
+ * @param asc The right ascension, measured in radians.
+ * @param dec The declination, measured in radians.
+ * @internal
+ */
+ Equatorial(double asc = 0, double dec = 0)
+ : ascension(asc), declination(dec) { }
+
+ /**
+ * Setter
+ * @param asc The right ascension, measured in radians.
+ * @param dec The declination, measured in radians.
+ * @internal
+ */
+ void set(double asc, double dec) {
+ ascension = asc;
+ declination = dec;
+ }
+
+ /**
+ * Return a string representation of this object, with the
+ * angles measured in degrees.
+ * @internal
+ */
+ UnicodeString toString() const;
+
+ /**
+ * Return a string representation of this object with the right ascension
+ * measured in hours, minutes, and seconds.
+ * @internal
+ */
+ //String toHmsString() {
+ //return radToHms(ascension) + "," + radToDms(declination);
+ //}
+
+ /**
+ * The right ascension, in radians.
+ * This is the position east or west along the equator
+ * relative to the sun's position at the vernal equinox,
+ * with positive angles representing East.
+ * @internal
+ */
+ double ascension;
+
+ /**
+ * The declination, in radians.
+ * This is the position north or south of the equatorial plane,
+ * with positive angles representing north.
+ * @internal
+ */
+ double declination;
+ };
+
+ /**
+ * Represents the position of an object in the sky relative to
+ * the local horizon.
+ * The <i>Altitude</i> represents the object's elevation above the horizon,
+ * with objects below the horizon having a negative altitude.
+ * The <i>Azimuth</i> is the geographic direction of the object from the
+ * observer's position, with 0 representing north. The azimuth increases
+ * clockwise from north.
+ * <p>
+ * Note that Horizon objects are immutable and cannot be modified
+ * once they are constructed. This allows them to be passed and returned by
+ * value without worrying about whether other code will modify them.
+ *
+ * @see CalendarAstronomer.Ecliptic
+ * @see CalendarAstronomer.Equatorial
+ * @internal
+ */
+ class U_I18N_API Horizon : public UMemory {
+ public:
+ /**
+ * Constructs a Horizon coordinate object.
+ * <p>
+ * @param alt The altitude, measured in radians above the horizon.
+ * @param azim The azimuth, measured in radians clockwise from north.
+ * @internal
+ */
+ Horizon(double alt=0, double azim=0)
+ : altitude(alt), azimuth(azim) { }
+
+ /**
+ * Setter for Ecliptic Coordinate object
+ * @param alt The altitude, measured in radians above the horizon.
+ * @param azim The azimuth, measured in radians clockwise from north.
+ * @internal
+ */
+ void set(double alt, double azim) {
+ altitude = alt;
+ azimuth = azim;
+ }
+
+ /**
+ * Return a string representation of this object, with the
+ * angles measured in degrees.
+ * @internal
+ */
+ UnicodeString toString() const;
+
+ /**
+ * The object's altitude above the horizon, in radians.
+ * @internal
+ */
+ double altitude;
+
+ /**
+ * The object's direction, in radians clockwise from north.
+ * @internal
+ */
+ double azimuth;
+ };
+
+public:
+ //-------------------------------------------------------------------------
+ // Assorted private data used for conversions
+ //-------------------------------------------------------------------------
+
+ // My own copies of these so compilers are more likely to optimize them away
+ static const double PI;
+
+ /**
+ * The average number of solar days from one new moon to the next. This is the time
+ * it takes for the moon to return the same ecliptic longitude as the sun.
+ * It is longer than the sidereal month because the sun's longitude increases
+ * during the year due to the revolution of the earth around the sun.
+ * Approximately 29.53.
+ *
+ * @see #SIDEREAL_MONTH
+ * @internal
+ * @deprecated ICU 2.4. This class may be removed or modified.
+ */
+ static const double SYNODIC_MONTH;
+
+ //-------------------------------------------------------------------------
+ // Constructors
+ //-------------------------------------------------------------------------
+
+ /**
+ * Construct a new <code>CalendarAstronomer</code> object that is initialized to
+ * the current date and time.
+ * @internal
+ */
+ CalendarAstronomer();
+
+ /**
+ * Construct a new <code>CalendarAstronomer</code> object that is initialized to
+ * the specified date and time.
+ * @internal
+ */
+ CalendarAstronomer(UDate d);
+
+ /**
+ * Construct a new <code>CalendarAstronomer</code> object with the given
+ * latitude and longitude. The object's time is set to the current
+ * date and time.
+ * <p>
+ * @param longitude The desired longitude, in <em>degrees</em> east of
+ * the Greenwich meridian.
+ *
+ * @param latitude The desired latitude, in <em>degrees</em>. Positive
+ * values signify North, negative South.
+ *
+ * @see java.util.Date#getTime()
+ * @internal
+ */
+ CalendarAstronomer(double longitude, double latitude);
+
+ /**
+ * Destructor
+ * @internal
+ */
+ ~CalendarAstronomer();
+
+ //-------------------------------------------------------------------------
+ // Time and date getters and setters
+ //-------------------------------------------------------------------------
+
+ /**
+ * Set the current date and time of this <code>CalendarAstronomer</code> object. All
+ * astronomical calculations are performed based on this time setting.
+ *
+ * @param aTime the date and time, expressed as the number of milliseconds since
+ * 1/1/1970 0:00 GMT (Gregorian).
+ *
+ * @see #setDate
+ * @see #getTime
+ * @internal
+ */
+ void setTime(UDate aTime);
+
+
+ /**
+ * Set the current date and time of this <code>CalendarAstronomer</code> object. All
+ * astronomical calculations are performed based on this time setting.
+ *
+ * @param aTime the date and time, expressed as the number of milliseconds since
+ * 1/1/1970 0:00 GMT (Gregorian).
+ *
+ * @see #getTime
+ * @internal
+ */
+ void setDate(UDate aDate) { setTime(aDate); }
+
+ /**
+ * Set the current date and time of this <code>CalendarAstronomer</code> object. All
+ * astronomical calculations are performed based on this time setting.
+ *
+ * @param jdn the desired time, expressed as a "julian day number",
+ * which is the number of elapsed days since
+ * 1/1/4713 BC (Julian), 12:00 GMT. Note that julian day
+ * numbers start at <em>noon</em>. To get the jdn for
+ * the corresponding midnight, subtract 0.5.
+ *
+ * @see #getJulianDay
+ * @see #JULIAN_EPOCH_MS
+ * @internal
+ */
+ void setJulianDay(double jdn);
+
+ /**
+ * Get the current time of this <code>CalendarAstronomer</code> object,
+ * represented as the number of milliseconds since
+ * 1/1/1970 AD 0:00 GMT (Gregorian).
+ *
+ * @see #setTime
+ * @see #getDate
+ * @internal
+ */
+ UDate getTime();
+
+ /**
+ * Get the current time of this <code>CalendarAstronomer</code> object,
+ * expressed as a "julian day number", which is the number of elapsed
+ * days since 1/1/4713 BC (Julian), 12:00 GMT.
+ *
+ * @see #setJulianDay
+ * @see #JULIAN_EPOCH_MS
+ * @internal
+ */
+ double getJulianDay();
+
+ /**
+ * Return this object's time expressed in julian centuries:
+ * the number of centuries after 1/1/1900 AD, 12:00 GMT
+ *
+ * @see #getJulianDay
+ * @internal
+ */
+ double getJulianCentury();
+
+ /**
+ * Returns the current Greenwich sidereal time, measured in hours
+ * @internal
+ */
+ double getGreenwichSidereal();
+
+private:
+ double getSiderealOffset();
+public:
+ /**
+ * Returns the current local sidereal time, measured in hours
+ * @internal
+ */
+ double getLocalSidereal();
+
+ /**
+ * Converts local sidereal time to Universal Time.
+ *
+ * @param lst The Local Sidereal Time, in hours since sidereal midnight
+ * on this object's current date.
+ *
+ * @return The corresponding Universal Time, in milliseconds since
+ * 1 Jan 1970, GMT.
+ */
+ //private:
+ double lstToUT(double lst);
+
+ /**
+ *
+ * Convert from ecliptic to equatorial coordinates.
+ *
+ * @param ecliptic The ecliptic
+ * @param result Fillin result
+ * @return reference to result
+ */
+ Equatorial& eclipticToEquatorial(Equatorial& result, const Ecliptic& ecliptic);
+
+ /**
+ * Convert from ecliptic to equatorial coordinates.
+ *
+ * @param eclipLong The ecliptic longitude
+ * @param eclipLat The ecliptic latitude
+ *
+ * @return The corresponding point in equatorial coordinates.
+ * @internal
+ */
+ Equatorial& eclipticToEquatorial(Equatorial& result, double eclipLong, double eclipLat);
+
+ /**
+ * Convert from ecliptic longitude to equatorial coordinates.
+ *
+ * @param eclipLong The ecliptic longitude
+ *
+ * @return The corresponding point in equatorial coordinates.
+ * @internal
+ */
+ Equatorial& eclipticToEquatorial(Equatorial& result, double eclipLong) ;
+
+ /**
+ * @internal
+ */
+ Horizon& eclipticToHorizon(Horizon& result, double eclipLong) ;
+
+ //-------------------------------------------------------------------------
+ // The Sun
+ //-------------------------------------------------------------------------
+
+ /**
+ * The longitude of the sun at the time specified by this object.
+ * The longitude is measured in radians along the ecliptic
+ * from the "first point of Aries," the point at which the ecliptic
+ * crosses the earth's equatorial plane at the vernal equinox.
+ * <p>
+ * Currently, this method uses an approximation of the two-body Kepler's
+ * equation for the earth and the sun. It does not take into account the
+ * perturbations caused by the other planets, the moon, etc.
+ * @internal
+ */
+ double getSunLongitude();
+
+ /**
+ * TODO Make this public when the entire class is package-private.
+ */
+ /*public*/ void getSunLongitude(double julianDay, double &longitude, double &meanAnomaly);
+
+ /**
+ * The position of the sun at this object's current date and time,
+ * in equatorial coordinates.
+ * @param result fillin for the result
+ * @internal
+ */
+ Equatorial& getSunPosition(Equatorial& result);
+
+public:
+ /**
+ * Constant representing the vernal equinox.
+ * For use with {@link #getSunTime getSunTime}.
+ * Note: In this case, "vernal" refers to the northern hemisphere's seasons.
+ * @internal
+ */
+// static double VERNAL_EQUINOX();
+
+ /**
+ * Constant representing the summer solstice.
+ * For use with {@link #getSunTime getSunTime}.
+ * Note: In this case, "summer" refers to the northern hemisphere's seasons.
+ * @internal
+ */
+ static double SUMMER_SOLSTICE();
+
+ /**
+ * Constant representing the autumnal equinox.
+ * For use with {@link #getSunTime getSunTime}.
+ * Note: In this case, "autumn" refers to the northern hemisphere's seasons.
+ * @internal
+ */
+// static double AUTUMN_EQUINOX();
+
+ /**
+ * Constant representing the winter solstice.
+ * For use with {@link #getSunTime getSunTime}.
+ * Note: In this case, "winter" refers to the northern hemisphere's seasons.
+ * @internal
+ */
+// static double WINTER_SOLSTICE();
+
+ /**
+ * Find the next time at which the sun's ecliptic longitude will have
+ * the desired value.
+ * @internal
+ */
+ UDate getSunTime(double desired, UBool next);
+
+ /**
+ * Returns the time (GMT) of sunrise or sunset on the local date to which
+ * this calendar is currently set.
+ *
+ * NOTE: This method only works well if this object is set to a
+ * time near local noon. Because of variations between the local
+ * official time zone and the geographic longitude, the
+ * computation can flop over into an adjacent day if this object
+ * is set to a time near local midnight.
+ *
+ * @internal
+ */
+ UDate getSunRiseSet(UBool rise);
+
+ //-------------------------------------------------------------------------
+ // The Moon
+ //-------------------------------------------------------------------------
+
+ /**
+ * The position of the moon at the time set on this
+ * object, in equatorial coordinates.
+ * @internal
+ * @return const reference to internal field of calendar astronomer. Do not use outside of the lifetime of this astronomer.
+ */
+ const Equatorial& getMoonPosition();
+
+ /**
+ * The "age" of the moon at the time specified in this object.
+ * This is really the angle between the
+ * current ecliptic longitudes of the sun and the moon,
+ * measured in radians.
+ *
+ * @see #getMoonPhase
+ * @internal
+ */
+ double getMoonAge();
+
+ /**
+ * Calculate the phase of the moon at the time set in this object.
+ * The returned phase is a <code>double</code> in the range
+ * <code>0 <= phase < 1</code>, interpreted as follows:
+ * <ul>
+ * <li>0.00: New moon
+ * <li>0.25: First quarter
+ * <li>0.50: Full moon
+ * <li>0.75: Last quarter
+ * </ul>
+ *
+ * @see #getMoonAge
+ * @internal
+ */
+ double getMoonPhase();
+
+ class U_I18N_API MoonAge : public UMemory {
+ public:
+ MoonAge(double l)
+ : value(l) { }
+ void set(double l) { value = l; }
+ double value;
+ };
+
+ /**
+ * Constant representing a new moon.
+ * For use with {@link #getMoonTime getMoonTime}
+ * @internal
+ */
+// static const MoonAge NEW_MOON();
+
+ /**
+ * Constant representing the moon's first quarter.
+ * For use with {@link #getMoonTime getMoonTime}
+ * @internal
+ */
+// static const MoonAge FIRST_QUARTER();
+
+ /**
+ * Constant representing a full moon.
+ * For use with {@link #getMoonTime getMoonTime}
+ * @internal
+ */
+ static const MoonAge FULL_MOON();
+
+ /**
+ * Constant representing the moon's last quarter.
+ * For use with {@link #getMoonTime getMoonTime}
+ * @internal
+ */
+// static const MoonAge LAST_QUARTER();
+
+ /**
+ * Find the next or previous time at which the Moon's ecliptic
+ * longitude will have the desired value.
+ * <p>
+ * @param desired The desired longitude.
+ * @param next <tt>true</tt> if the next occurrance of the phase
+ * is desired, <tt>false</tt> for the previous occurrance.
+ * @internal
+ */
+ UDate getMoonTime(double desired, UBool next);
+ UDate getMoonTime(const MoonAge& desired, UBool next);
+
+ /**
+ * Returns the time (GMT) of sunrise or sunset on the local date to which
+ * this calendar is currently set.
+ * @internal
+ */
+ UDate getMoonRiseSet(UBool rise);
+
+ //-------------------------------------------------------------------------
+ // Interpolation methods for finding the time at which a given event occurs
+ //-------------------------------------------------------------------------
+
+ // private
+ class AngleFunc : public UMemory {
+ public:
+ virtual double eval(CalendarAstronomer&) = 0;
+ virtual ~AngleFunc();
+ };
+ friend class AngleFunc;
+
+ UDate timeOfAngle(AngleFunc& func, double desired,
+ double periodDays, double epsilon, UBool next);
+
+ class CoordFunc : public UMemory {
+ public:
+ virtual void eval(Equatorial& result, CalendarAstronomer&) = 0;
+ virtual ~CoordFunc();
+ };
+ friend class CoordFunc;
+
+ double riseOrSet(CoordFunc& func, UBool rise,
+ double diameter, double refraction,
+ double epsilon);
+
+ //-------------------------------------------------------------------------
+ // Other utility methods
+ //-------------------------------------------------------------------------
+private:
+ /***
+ * Given 'value', add or subtract 'range' until 0 <= 'value' < range.
+ * The modulus operator.
+ */
+ inline static double normalize(double value, double range) {
+ return value - range * Math::floorDivide(value, range);
+ }
+
+ /**
+ * Normalize an angle so that it's in the range 0 - 2pi.
+ * For positive angles this is just (angle % 2pi), but the Java
+ * mod operator doesn't work that way for negative numbers....
+ */
+ inline static double norm2PI(double angle) {
+ return normalize(angle, CalendarAstronomer::PI * 2.0);
+ }
+
+ /**
+ * Normalize an angle into the range -PI - PI
+ */
+ inline static double normPI(double angle) {
+ return normalize(angle + PI, CalendarAstronomer::PI * 2.0) - PI;
+ }
+
+ /**
+ * Find the "true anomaly" (longitude) of an object from
+ * its mean anomaly and the eccentricity of its orbit. This uses
+ * an iterative solution to Kepler's equation.
+ *
+ * @param meanAnomaly The object's longitude calculated as if it were in
+ * a regular, circular orbit, measured in radians
+ * from the point of perigee.
+ *
+ * @param eccentricity The eccentricity of the orbit
+ *
+ * @return The true anomaly (longitude) measured in radians
+ */
+ double trueAnomaly(double meanAnomaly, double eccentricity);
+
+ /**
+ * Return the obliquity of the ecliptic (the angle between the ecliptic
+ * and the earth's equator) at the current time. This varies due to
+ * the precession of the earth's axis.
+ *
+ * @return the obliquity of the ecliptic relative to the equator,
+ * measured in radians.
+ */
+ double eclipticObliquity();
+
+ //-------------------------------------------------------------------------
+ // Private data
+ //-------------------------------------------------------------------------
+private:
+ /**
+ * Current time in milliseconds since 1/1/1970 AD
+ * @see java.util.Date#getTime
+ */
+ UDate fTime;
+
+ /* These aren't used yet, but they'll be needed for sunset calculations
+ * and equatorial to horizon coordinate conversions
+ */
+ double fLongitude;
+ double fLatitude;
+ double fGmtOffset;
+
+ //
+ // The following fields are used to cache calculated results for improved
+ // performance. These values all depend on the current time setting
+ // of this object, so the clearCache method is provided.
+ //
+
+ double julianDay;
+ double julianCentury;
+ double sunLongitude;
+ double meanAnomalySun;
+ double moonLongitude;
+ double moonEclipLong;
+ double meanAnomalyMoon;
+ double eclipObliquity;
+ double siderealT0;
+ double siderealTime;
+
+ void clearCache();
+
+ Equatorial moonPosition;
+ UBool moonPositionSet;
+
+ /**
+ * @internal
+ */
+// UDate local(UDate localMillis);
+};
+
+U_NAMESPACE_END
+
+struct UHashtable;
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Cache of month -> julian day
+ * @internal
+ */
+class CalendarCache : public UMemory {
+public:
+ static int32_t get(CalendarCache** cache, int32_t key, UErrorCode &status);
+ static void put(CalendarCache** cache, int32_t key, int32_t value, UErrorCode &status);
+ virtual ~CalendarCache();
+private:
+ CalendarCache(int32_t size, UErrorCode& status);
+ static void createCache(CalendarCache** cache, UErrorCode& status);
+ /**
+ * not implemented
+ */
+ CalendarCache();
+ UHashtable *fTable;
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/basictz.cpp b/Build/source/libs/icu/icu-xetex/i18n/basictz.cpp
new file mode 100644
index 00000000000..546adb691b5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/basictz.cpp
@@ -0,0 +1,528 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/basictz.h"
+#include "gregoimp.h"
+#include "uvector.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+#define MILLIS_PER_YEAR (365*24*60*60*1000.0)
+
+BasicTimeZone::BasicTimeZone()
+: TimeZone() {
+}
+
+BasicTimeZone::BasicTimeZone(const UnicodeString &id)
+: TimeZone(id) {
+}
+
+BasicTimeZone::BasicTimeZone(const BasicTimeZone& source)
+: TimeZone(source) {
+}
+
+BasicTimeZone::~BasicTimeZone() {
+}
+
+UBool
+BasicTimeZone::hasEquivalentTransitions(/*const*/ BasicTimeZone& tz, UDate start, UDate end,
+ UBool ignoreDstAmount, UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (hasSameRules(tz)) {
+ return TRUE;
+ }
+ // Check the offsets at the start time
+ int32_t raw1, raw2, dst1, dst2;
+ getOffset(start, FALSE, raw1, dst1, status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ tz.getOffset(start, FALSE, raw2, dst2, status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (ignoreDstAmount) {
+ if ((raw1 + dst1 != raw2 + dst2)
+ || (dst1 != 0 && dst2 == 0)
+ || (dst1 == 0 && dst2 != 0)) {
+ return FALSE;
+ }
+ } else {
+ if (raw1 != raw2 || dst1 != dst2) {
+ return FALSE;
+ }
+ }
+ // Check transitions in the range
+ UDate time = start;
+ TimeZoneTransition tr1, tr2;
+ while (TRUE) {
+ UBool avail1 = getNextTransition(time, FALSE, tr1);
+ UBool avail2 = tz.getNextTransition(time, FALSE, tr2);
+
+ if (ignoreDstAmount) {
+ // Skip a transition which only differ the amount of DST savings
+ if (avail1
+ && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings()
+ == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings())
+ && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) {
+ getNextTransition(tr1.getTime(), FALSE, tr1);
+ }
+ if (avail2
+ && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings()
+ == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings())
+ && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) {
+ getNextTransition(tr2.getTime(), FALSE, tr2);
+ }
+ }
+
+ UBool inRange1 = (avail1 && tr1.getTime() <= end);
+ UBool inRange2 = (avail2 && tr2.getTime() <= end);
+ if (!inRange1 && !inRange2) {
+ // No more transition in the range
+ break;
+ }
+ if (!inRange1 || !inRange2) {
+ return FALSE;
+ }
+ if (tr1.getTime() != tr2.getTime()) {
+ return FALSE;
+ }
+ if (ignoreDstAmount) {
+ if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()
+ != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()
+ || tr1.getTo()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() == 0
+ || tr1.getTo()->getDSTSavings() == 0 && tr2.getTo()->getDSTSavings() != 0) {
+ return FALSE;
+ }
+ } else {
+ if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() ||
+ tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) {
+ return FALSE;
+ }
+ }
+ time = tr1.getTime();
+ }
+ return TRUE;
+}
+
+void
+BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
+ AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) /*const*/ {
+ initial = NULL;
+ std = NULL;
+ dst = NULL;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ int32_t initialRaw, initialDst;
+ UnicodeString initialName;
+
+ AnnualTimeZoneRule *ar1 = NULL;
+ AnnualTimeZoneRule *ar2 = NULL;
+ UnicodeString name;
+
+ UBool avail;
+ TimeZoneTransition tr;
+ // Get the next transition
+ avail = getNextTransition(date, FALSE, tr);
+ if (avail) {
+ tr.getFrom()->getName(initialName);
+ initialRaw = tr.getFrom()->getRawOffset();
+ initialDst = tr.getFrom()->getDSTSavings();
+
+ // Check if the next transition is either DST->STD or STD->DST and
+ // within roughly 1 year from the specified date
+ UDate nextTransitionTime = tr.getTime();
+ if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
+ || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
+ && (date + MILLIS_PER_YEAR > nextTransitionTime)) {
+
+ int32_t year, month, dom, dow, doy, mid;
+ UDate d;
+
+ // Get local wall time for the next transition time
+ Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
+ year, month, dom, dow, doy, mid);
+ int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
+ // Create DOW rule
+ DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
+ tr.getTo()->getName(name);
+ ar1 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(),
+ dtr, year, AnnualTimeZoneRule::MAX_YEAR);
+
+ // Get the next next transition
+ avail = getNextTransition(nextTransitionTime, FALSE, tr);
+ if (avail) {
+ // Check if the next next transition is either DST->STD or STD->DST
+ // and within roughly 1 year from the next transition
+ if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
+ || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
+ && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) {
+
+ // Get local wall time for the next transition time
+ Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
+ year, month, dom, dow, doy, mid);
+ weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
+ // Generate another DOW rule
+ dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
+ tr.getTo()->getName(name);
+ ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(),
+ dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR);
+
+ // Make sure this rule can be applied to the specified date
+ avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), TRUE, d);
+ if (!avail || d > date
+ || initialRaw != tr.getTo()->getRawOffset()
+ || initialDst != tr.getTo()->getDSTSavings()) {
+ // We cannot use this rule as the second transition rule
+ delete ar2;
+ ar2 = NULL;
+ }
+ }
+ }
+ if (ar2 == NULL) {
+ // Try previous transition
+ avail = getPreviousTransition(date, TRUE, tr);
+ if (avail) {
+ // Check if the previous transition is either DST->STD or STD->DST.
+ // The actual transition time does not matter here.
+ if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
+ || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) {
+
+ // Generate another DOW rule
+ Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
+ year, month, dom, dow, doy, mid);
+ weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
+ dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
+ tr.getTo()->getName(name);
+ ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(),
+ dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR);
+
+ // Check if this rule start after the first rule after the specified date
+ avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), FALSE, d);
+ if (!avail || d <= nextTransitionTime) {
+ // We cannot use this rule as the second transition rule
+ delete ar2;
+ ar2 = NULL;
+ }
+ }
+ }
+ }
+ if (ar2 == NULL) {
+ // Cannot find a good pair of AnnualTimeZoneRule
+ delete ar1;
+ ar1 = NULL;
+ } else {
+ // The initial rule should represent the rule before the previous transition
+ ar1->getName(initialName);
+ initialRaw = ar1->getRawOffset();
+ initialDst = ar1->getDSTSavings();
+ }
+ }
+ } else {
+ // Try the previous one
+ avail = getPreviousTransition(date, TRUE, tr);
+ if (avail) {
+ tr.getTo()->getName(initialName);
+ initialRaw = tr.getTo()->getRawOffset();
+ initialDst = tr.getTo()->getDSTSavings();
+ } else {
+ // No transitions in the past. Just use the current offsets
+ getOffset(date, FALSE, initialRaw, initialDst, status);
+ if (U_FAILURE(status)) {
+ if (ar1 != NULL) {
+ delete ar1;
+ }
+ if (ar2 != NULL) {
+ delete ar2;
+ }
+ return;
+ }
+ }
+ }
+ // Set the initial rule
+ initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst);
+
+ // Set the standard and daylight saving rules
+ if (ar1 != NULL && ar2 != NULL) {
+ if (ar1->getDSTSavings() != 0) {
+ dst = ar1;
+ std = ar2;
+ } else {
+ std = ar1;
+ dst = ar2;
+ }
+ }
+}
+
+void
+BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
+ UVector*& transitionRules, UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ const InitialTimeZoneRule *orgini;
+ const TimeZoneRule **orgtrs = NULL;
+ TimeZoneTransition tzt;
+ UBool avail;
+ UVector *orgRules = NULL;
+ int32_t ruleCount;
+ TimeZoneRule *r = NULL;
+ UBool *done = NULL;
+ InitialTimeZoneRule *res_initial = NULL;
+ UVector *filteredRules = NULL;
+ UnicodeString name;
+ int32_t i;
+ UDate time, t;
+ UDate *newTimes = NULL;
+ UDate firstStart;
+ UBool bFinalStd = FALSE, bFinalDst = FALSE;
+
+ // Original transition rules
+ ruleCount = countTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ orgRules = new UVector(ruleCount, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ orgtrs = (const TimeZoneRule**)uprv_malloc(sizeof(TimeZoneRule*)*ruleCount);
+ if (orgtrs == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto error;
+ }
+ getTimeZoneRules(orgini, orgtrs, ruleCount, status);
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+ for (i = 0; i < ruleCount; i++) {
+ orgRules->addElement(orgtrs[i]->clone(), status);
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+ }
+ uprv_free(orgtrs);
+ orgtrs = NULL;
+
+ avail = getPreviousTransition(start, TRUE, tzt);
+ if (!avail) {
+ // No need to filter out rules only applicable to time before the start
+ initial = orgini->clone();
+ transitionRules = orgRules;
+ return;
+ }
+
+ done = (UBool*)uprv_malloc(sizeof(UBool)*ruleCount);
+ if (done == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto error;
+ }
+ filteredRules = new UVector(status);
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+
+ // Create initial rule
+ tzt.getTo()->getName(name);
+ res_initial = new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(),
+ tzt.getTo()->getDSTSavings());
+
+ // Mark rules which does not need to be processed
+ for (i = 0; i < ruleCount; i++) {
+ r = (TimeZoneRule*)orgRules->elementAt(i);
+ avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), FALSE, time);
+ done[i] = !avail;
+ }
+
+ time = start;
+ while (!bFinalStd || !bFinalDst) {
+ avail = getNextTransition(time, FALSE, tzt);
+ if (!avail) {
+ break;
+ }
+ time = tzt.getTime();
+
+ const TimeZoneRule *toRule = tzt.getTo();
+ for (i = 0; i < ruleCount; i++) {
+ r = (TimeZoneRule*)orgRules->elementAt(i);
+ if (*r == *toRule) {
+ break;
+ }
+ }
+ if (i >= ruleCount) {
+ // This case should never happen
+ status = U_INVALID_STATE_ERROR;
+ goto error;
+ }
+ if (done[i]) {
+ continue;
+ }
+ if (toRule->getDynamicClassID() == TimeArrayTimeZoneRule::getStaticClassID()) {
+ TimeArrayTimeZoneRule *tar = (TimeArrayTimeZoneRule*)toRule;
+
+ // Get the previous raw offset and DST savings before the very first start time
+ TimeZoneTransition tzt0;
+ t = start;
+ while (TRUE) {
+ avail = getNextTransition(t, FALSE, tzt0);
+ if (!avail) {
+ break;
+ }
+ if (*(tzt0.getTo()) == *tar) {
+ break;
+ }
+ t = tzt0.getTime();
+ }
+ if (avail) {
+ // Check if the entire start times to be added
+ tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
+ if (firstStart > start) {
+ // Just add the rule as is
+ filteredRules->addElement(tar->clone(), status);
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+ } else {
+ // Colllect transitions after the start time
+ int32_t startTimes;
+ DateTimeRule::TimeRuleType timeType;
+ int32_t idx;
+
+ startTimes = tar->countStartTimes();
+ timeType = tar->getTimeType();
+ for (idx = 0; idx < startTimes; idx++) {
+ tar->getStartTimeAt(idx, t);
+ if (timeType == DateTimeRule::STANDARD_TIME) {
+ t -= tzt.getFrom()->getRawOffset();
+ }
+ if (timeType == DateTimeRule::WALL_TIME) {
+ t -= tzt.getFrom()->getDSTSavings();
+ }
+ if (t > start) {
+ break;
+ }
+ }
+ int32_t asize = startTimes - idx;
+ if (asize > 0) {
+ newTimes = (UDate*)uprv_malloc(sizeof(UDate) * asize);
+ if (newTimes == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto error;
+ }
+ for (int32_t newidx = 0; newidx < asize; newidx++) {
+ tar->getStartTimeAt(idx + newidx, newTimes[newidx]);
+ if (U_FAILURE(status)) {
+ uprv_free(newTimes);
+ newTimes = NULL;
+ goto error;
+ }
+ }
+ tar->getName(name);
+ TimeArrayTimeZoneRule *newTar = new TimeArrayTimeZoneRule(name,
+ tar->getRawOffset(), tar->getDSTSavings(), newTimes, asize, timeType);
+ uprv_free(newTimes);
+ filteredRules->addElement(newTar, status);
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+ }
+ }
+ }
+ } else if (toRule->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()) {
+ AnnualTimeZoneRule *ar = (AnnualTimeZoneRule*)toRule;
+ ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
+ if (firstStart == tzt.getTime()) {
+ // Just add the rule as is
+ filteredRules->addElement(ar->clone(), status);
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+ } else {
+ // Calculate the transition year
+ int32_t year, month, dom, dow, doy, mid;
+ Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid);
+ // Re-create the rule
+ ar->getName(name);
+ AnnualTimeZoneRule *newAr = new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(),
+ *(ar->getRule()), year, ar->getEndYear());
+ filteredRules->addElement(newAr, status);
+ if (U_FAILURE(status)) {
+ goto error;
+ }
+ }
+ // check if this is a final rule
+ if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
+ // After bot final standard and dst rules are processed,
+ // exit this while loop.
+ if (ar->getDSTSavings() == 0) {
+ bFinalStd = TRUE;
+ } else {
+ bFinalDst = TRUE;
+ }
+ }
+ }
+ done[i] = TRUE;
+ }
+
+ // Set the results
+ if (orgRules != NULL) {
+ while (!orgRules->isEmpty()) {
+ r = (TimeZoneRule*)orgRules->orphanElementAt(0);
+ delete r;
+ }
+ delete orgRules;
+ }
+ if (done != NULL) {
+ uprv_free(done);
+ }
+
+ initial = res_initial;
+ transitionRules = filteredRules;
+ return;
+
+error:
+ if (orgtrs != NULL) {
+ uprv_free(orgtrs);
+ }
+ if (orgRules != NULL) {
+ while (!orgRules->isEmpty()) {
+ r = (TimeZoneRule*)orgRules->orphanElementAt(0);
+ delete r;
+ }
+ delete orgRules;
+ }
+ if (done != NULL) {
+ uprv_free(done);
+ }
+
+ initial = NULL;
+ transitionRules = NULL;
+}
+
+void
+BasicTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ status = U_UNSUPPORTED_ERROR;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/bocsu.c b/Build/source/libs/icu/icu-xetex/i18n/bocsu.c
new file mode 100644
index 00000000000..d4c6ab86ec8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/bocsu.c
@@ -0,0 +1,191 @@
+/*
+*******************************************************************************
+* Copyright (C) 2001-2003, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: bocsu.c
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Author: Markus W. Scherer
+*
+* Modification history:
+* 05/18/2001 weiv Made into separate module
+*/
+
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "bocsu.h"
+
+/*
+ * encode one difference value -0x10ffff..+0x10ffff in 1..3 bytes,
+ * preserving lexical order
+ */
+U_CFUNC uint8_t *
+u_writeDiff(int32_t diff, uint8_t *p) {
+ if(diff>=SLOPE_REACH_NEG_1) {
+ if(diff<=SLOPE_REACH_POS_1) {
+ *p++=(uint8_t)(SLOPE_MIDDLE+diff);
+ } else if(diff<=SLOPE_REACH_POS_2) {
+ *p++=(uint8_t)(SLOPE_START_POS_2+(diff/SLOPE_TAIL_COUNT));
+ *p++=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ } else if(diff<=SLOPE_REACH_POS_3) {
+ p[2]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ diff/=SLOPE_TAIL_COUNT;
+ p[1]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ *p=(uint8_t)(SLOPE_START_POS_3+(diff/SLOPE_TAIL_COUNT));
+ p+=3;
+ } else {
+ p[3]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ diff/=SLOPE_TAIL_COUNT;
+ p[2]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ diff/=SLOPE_TAIL_COUNT;
+ p[1]=(uint8_t)(SLOPE_MIN+diff%SLOPE_TAIL_COUNT);
+ *p=SLOPE_MAX;
+ p+=4;
+ }
+ } else {
+ int32_t m;
+
+ if(diff>=SLOPE_REACH_NEG_2) {
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ *p++=(uint8_t)(SLOPE_START_NEG_2+diff);
+ *p++=(uint8_t)(SLOPE_MIN+m);
+ } else if(diff>=SLOPE_REACH_NEG_3) {
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[2]=(uint8_t)(SLOPE_MIN+m);
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[1]=(uint8_t)(SLOPE_MIN+m);
+ *p=(uint8_t)(SLOPE_START_NEG_3+diff);
+ p+=3;
+ } else {
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[3]=(uint8_t)(SLOPE_MIN+m);
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[2]=(uint8_t)(SLOPE_MIN+m);
+ NEGDIVMOD(diff, SLOPE_TAIL_COUNT, m);
+ p[1]=(uint8_t)(SLOPE_MIN+m);
+ *p=SLOPE_MIN;
+ p+=4;
+ }
+ }
+ return p;
+}
+
+/* How many bytes would writeDiff() write? */
+static int32_t
+lengthOfDiff(int32_t diff) {
+ if(diff>=SLOPE_REACH_NEG_1) {
+ if(diff<=SLOPE_REACH_POS_1) {
+ return 1;
+ } else if(diff<=SLOPE_REACH_POS_2) {
+ return 2;
+ } else if(diff<=SLOPE_REACH_POS_3) {
+ return 3;
+ } else {
+ return 4;
+ }
+ } else {
+ if(diff>=SLOPE_REACH_NEG_2) {
+ return 2;
+ } else if(diff>=SLOPE_REACH_NEG_3) {
+ return 3;
+ } else {
+ return 4;
+ }
+ }
+}
+
+/*
+ * Encode the code points of a string as
+ * a sequence of byte-encoded differences (slope detection),
+ * preserving lexical order.
+ *
+ * Optimize the difference-taking for runs of Unicode text within
+ * small scripts:
+ *
+ * Most small scripts are allocated within aligned 128-blocks of Unicode
+ * code points. Lexical order is preserved if "prev" is always moved
+ * into the middle of such a block.
+ *
+ * Additionally, "prev" is moved from anywhere in the Unihan
+ * area into the middle of that area.
+ * Note that the identical-level run in a sort key is generated from
+ * NFD text - there are never Hangul characters included.
+ */
+U_CFUNC int32_t
+u_writeIdenticalLevelRun(const UChar *s, int32_t length, uint8_t *p) {
+ uint8_t *p0;
+ int32_t c, prev;
+ int32_t i;
+
+ prev=0;
+ p0=p;
+ i=0;
+ while(i<length) {
+ if(prev<0x4e00 || prev>=0xa000) {
+ prev=(prev&~0x7f)-SLOPE_REACH_NEG_1;
+ } else {
+ /*
+ * Unihan U+4e00..U+9fa5:
+ * double-bytes down from the upper end
+ */
+ prev=0x9fff-SLOPE_REACH_POS_2;
+ }
+
+ UTF_NEXT_CHAR(s, i, length, c);
+ p=u_writeDiff(c-prev, p);
+ prev=c;
+ }
+ return (int32_t)(p-p0);
+}
+
+U_CFUNC int32_t
+u_writeIdenticalLevelRunTwoChars(UChar32 first, UChar32 second, uint8_t *p) {
+ uint8_t *p0 = p;
+ if(first<0x4e00 || first>=0xa000) {
+ first=(first&~0x7f)-SLOPE_REACH_NEG_1;
+ } else {
+ /*
+ * Unihan U+4e00..U+9fa5:
+ * double-bytes down from the upper end
+ */
+ first=0x9fff-SLOPE_REACH_POS_2;
+ }
+
+ p=u_writeDiff(second-first, p);
+ return (int32_t)(p-p0);
+}
+
+/* How many bytes would writeIdenticalLevelRun() write? */
+U_CFUNC int32_t
+u_lengthOfIdenticalLevelRun(const UChar *s, int32_t length) {
+ int32_t c, prev;
+ int32_t i, runLength;
+
+ prev=0;
+ runLength=0;
+ i=0;
+ while(i<length) {
+ if(prev<0x4e00 || prev>=0xa000) {
+ prev=(prev&~0x7f)-SLOPE_REACH_NEG_1;
+ } else {
+ /*
+ * Unihan U+4e00..U+9fa5:
+ * double-bytes down from the upper end
+ */
+ prev=0x9fff-SLOPE_REACH_POS_2;
+ }
+
+ UTF_NEXT_CHAR(s, i, length, c);
+ runLength+=lengthOfDiff(c-prev);
+ prev=c;
+ }
+ return runLength;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/bocsu.h b/Build/source/libs/icu/icu-xetex/i18n/bocsu.h
new file mode 100644
index 00000000000..26562b19948
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/bocsu.h
@@ -0,0 +1,162 @@
+/*
+*******************************************************************************
+* Copyright (C) 2001-2003, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: bocsu.c
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Author: Markus W. Scherer
+*
+* Modification history:
+* 05/18/2001 weiv Made into separate module
+*/
+
+#ifndef BOCSU_H
+#define BOCSU_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+/*
+ * "BOCSU"
+ * Binary Ordered Compression Scheme for Unicode
+ *
+ * Specific application:
+ *
+ * Encode a Unicode string for the identical level of a sort key.
+ * Restrictions:
+ * - byte stream (unsigned 8-bit bytes)
+ * - lexical order of the identical-level run must be
+ * the same as code point order for the string
+ * - avoid byte values 0, 1, 2
+ *
+ * Method: Slope Detection
+ * Remember the previous code point (initial 0).
+ * For each cp in the string, encode the difference to the previous one.
+ *
+ * With a compact encoding of differences, this yields good results for
+ * small scripts and UTF-like results otherwise.
+ *
+ * Encoding of differences:
+ * - Similar to a UTF, encoding the length of the byte sequence in the lead bytes.
+ * - Does not need to be friendly for decoding or random access
+ * (trail byte values may overlap with lead/single byte values).
+ * - The signedness must be encoded as the most significant part.
+ *
+ * We encode differences with few bytes if their absolute values are small.
+ * For correct ordering, we must treat the entire value range -10ffff..+10ffff
+ * in ascending order, which forbids encoding the sign and the absolute value separately.
+ * Instead, we split the lead byte range in the middle and encode non-negative values
+ * going up and negative values going down.
+ *
+ * For very small absolute values, the difference is added to a middle byte value
+ * for single-byte encoded differences.
+ * For somewhat larger absolute values, the difference is divided by the number
+ * of byte values available, the modulo is used for one trail byte, and the remainder
+ * is added to a lead byte avoiding the single-byte range.
+ * For large absolute values, the difference is similarly encoded in three bytes.
+ *
+ * This encoding does not use byte values 0, 1, 2, but uses all other byte values
+ * for lead/single bytes so that the middle range of single bytes is as large
+ * as possible.
+ * Note that the lead byte ranges overlap some, but that the sequences as a whole
+ * are well ordered. I.e., even if the lead byte is the same for sequences of different
+ * lengths, the trail bytes establish correct order.
+ * It would be possible to encode slightly larger ranges for each length (>1) by
+ * subtracting the lower bound of the range. However, that would also slow down the
+ * calculation.
+ *
+ * For the actual string encoding, an optimization moves the previous code point value
+ * to the middle of its Unicode script block to minimize the differences in
+ * same-script text runs.
+ */
+
+/* Do not use byte values 0, 1, 2 because they are separators in sort keys. */
+#define SLOPE_MIN 3
+#define SLOPE_MAX 0xff
+#define SLOPE_MIDDLE 0x81
+
+#define SLOPE_TAIL_COUNT (SLOPE_MAX-SLOPE_MIN+1)
+
+#define SLOPE_MAX_BYTES 4
+
+/*
+ * Number of lead bytes:
+ * 1 middle byte for 0
+ * 2*80=160 single bytes for !=0
+ * 2*42=84 for double-byte values
+ * 2*3=6 for 3-byte values
+ * 2*1=2 for 4-byte values
+ *
+ * The sum must be <=SLOPE_TAIL_COUNT.
+ *
+ * Why these numbers?
+ * - There should be >=128 single-byte values to cover 128-blocks
+ * with small scripts.
+ * - There should be >=20902 single/double-byte values to cover Unihan.
+ * - It helps CJK Extension B some if there are 3-byte values that cover
+ * the distance between them and Unihan.
+ * This also helps to jump among distant places in the BMP.
+ * - Four-byte values are necessary to cover the rest of Unicode.
+ *
+ * Symmetrical lead byte counts are for convenience.
+ * With an equal distribution of even and odd differences there is also
+ * no advantage to asymmetrical lead byte counts.
+ */
+#define SLOPE_SINGLE 80
+#define SLOPE_LEAD_2 42
+#define SLOPE_LEAD_3 3
+#define SLOPE_LEAD_4 1
+
+/* The difference value range for single-byters. */
+#define SLOPE_REACH_POS_1 SLOPE_SINGLE
+#define SLOPE_REACH_NEG_1 (-SLOPE_SINGLE)
+
+/* The difference value range for double-byters. */
+#define SLOPE_REACH_POS_2 (SLOPE_LEAD_2*SLOPE_TAIL_COUNT+(SLOPE_LEAD_2-1))
+#define SLOPE_REACH_NEG_2 (-SLOPE_REACH_POS_2-1)
+
+/* The difference value range for 3-byters. */
+#define SLOPE_REACH_POS_3 (SLOPE_LEAD_3*SLOPE_TAIL_COUNT*SLOPE_TAIL_COUNT+(SLOPE_LEAD_3-1)*SLOPE_TAIL_COUNT+(SLOPE_TAIL_COUNT-1))
+#define SLOPE_REACH_NEG_3 (-SLOPE_REACH_POS_3-1)
+
+/* The lead byte start values. */
+#define SLOPE_START_POS_2 (SLOPE_MIDDLE+SLOPE_SINGLE+1)
+#define SLOPE_START_POS_3 (SLOPE_START_POS_2+SLOPE_LEAD_2)
+
+#define SLOPE_START_NEG_2 (SLOPE_MIDDLE+SLOPE_REACH_NEG_1)
+#define SLOPE_START_NEG_3 (SLOPE_START_NEG_2-SLOPE_LEAD_2)
+
+/*
+ * Integer division and modulo with negative numerators
+ * yields negative modulo results and quotients that are one more than
+ * what we need here.
+ */
+#define NEGDIVMOD(n, d, m) { \
+ (m)=(n)%(d); \
+ (n)/=(d); \
+ if((m)<0) { \
+ --(n); \
+ (m)+=(d); \
+ } \
+}
+
+U_CFUNC int32_t
+u_writeIdenticalLevelRun(const UChar *s, int32_t length, uint8_t *p);
+
+U_CFUNC int32_t
+u_writeIdenticalLevelRunTwoChars(UChar32 first, UChar32 second, uint8_t *p);
+
+U_CFUNC int32_t
+u_lengthOfIdenticalLevelRun(const UChar *s, int32_t length);
+
+U_CFUNC uint8_t *
+u_writeDiff(int32_t diff, uint8_t *p);
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/buddhcal.cpp b/Build/source/libs/icu/icu-xetex/i18n/buddhcal.cpp
new file mode 100644
index 00000000000..a887cbff02e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/buddhcal.cpp
@@ -0,0 +1,216 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File BUDDHCAL.CPP
+*
+* Modification History:
+* 05/13/2003 srl copied from gregocal.cpp
+*
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "buddhcal.h"
+#include "unicode/gregocal.h"
+#include "umutex.h"
+#include <float.h>
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(BuddhistCalendar)
+
+static const int32_t kMaxEra = 0; // only 1 era
+
+static const int32_t kBuddhistEraStart = -543; // 544 BC (Gregorian)
+
+static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR
+
+BuddhistCalendar::BuddhistCalendar(const Locale& aLocale, UErrorCode& success)
+: GregorianCalendar(aLocale, success)
+{
+ setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
+}
+
+BuddhistCalendar::~BuddhistCalendar()
+{
+}
+
+BuddhistCalendar::BuddhistCalendar(const BuddhistCalendar& source)
+: GregorianCalendar(source)
+{
+}
+
+BuddhistCalendar& BuddhistCalendar::operator= ( const BuddhistCalendar& right)
+{
+ GregorianCalendar::operator=(right);
+ return *this;
+}
+
+Calendar* BuddhistCalendar::clone(void) const
+{
+ return new BuddhistCalendar(*this);
+}
+
+const char *BuddhistCalendar::getType() const
+{
+ return "buddhist";
+}
+
+int32_t BuddhistCalendar::handleGetExtendedYear()
+{
+ // EXTENDED_YEAR in BuddhistCalendar is a Gregorian year.
+ // The default value of EXTENDED_YEAR is 1970 (Buddhist 2513)
+ int32_t year;
+ if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
+ year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
+ } else {
+ // extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
+ year = internalGet(UCAL_YEAR, kGregorianEpoch - kBuddhistEraStart)
+ + kBuddhistEraStart;
+ }
+ return year;
+}
+
+int32_t BuddhistCalendar::handleComputeMonthStart(int32_t eyear, int32_t month,
+
+ UBool useMonth) const
+{
+ return GregorianCalendar::handleComputeMonthStart(eyear, month, useMonth);
+}
+
+void BuddhistCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
+{
+ GregorianCalendar::handleComputeFields(julianDay, status);
+ int32_t y = internalGet(UCAL_EXTENDED_YEAR) - kBuddhistEraStart;
+ internalSet(UCAL_ERA, 0);
+ internalSet(UCAL_YEAR, y);
+}
+
+int32_t BuddhistCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
+{
+ if(field == UCAL_ERA) {
+ return BE;
+ } else {
+ return GregorianCalendar::handleGetLimit(field,limitType);
+ }
+}
+
+#if 0
+void BuddhistCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& status)
+{
+ //Calendar::timeToFields(theTime, quick, status);
+
+ int32_t era = internalGet(UCAL_ERA);
+ int32_t year = internalGet(UCAL_YEAR);
+
+ if(era == GregorianCalendar::BC) {
+ year = 1-year;
+ era = BuddhistCalendar::BE;
+ } else if(era == GregorianCalendar::AD) {
+ era = BuddhistCalendar::BE;
+ } else {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ }
+
+ year = year - kBuddhistEraStart;
+
+ internalSet(UCAL_ERA, era);
+ internalSet(UCAL_YEAR, year);
+}
+#endif
+
+// default century
+const UDate BuddhistCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t BuddhistCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate BuddhistCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t BuddhistCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+
+UBool BuddhistCalendar::haveDefaultCentury() const
+{
+ return TRUE;
+}
+
+UDate BuddhistCalendar::defaultCenturyStart() const
+{
+ return internalGetDefaultCenturyStart();
+}
+
+int32_t BuddhistCalendar::defaultCenturyStartYear() const
+{
+ return internalGetDefaultCenturyStartYear();
+}
+
+UDate
+BuddhistCalendar::internalGetDefaultCenturyStart() const
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStart
+
+ return fgSystemDefaultCenturyStart;
+}
+
+int32_t
+BuddhistCalendar::internalGetDefaultCenturyStartYear() const
+{
+ // lazy-evaluate systemDefaultCenturyStartYear
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStartYear
+
+ return fgSystemDefaultCenturyStartYear;
+}
+
+void
+BuddhistCalendar::initializeSystemDefaultCentury()
+{
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ // No point in locking as it should be idempotent.
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ BuddhistCalendar calendar(Locale("@calendar=buddhist"),status);
+ if (U_SUCCESS(status))
+ {
+ calendar.setTime(Calendar::getNow(), status);
+ calendar.add(UCAL_YEAR, -80, status);
+ UDate newStart = calendar.getTime(status);
+ int32_t newYear = calendar.get(UCAL_YEAR, status);
+ {
+ umtx_lock(NULL);
+ fgSystemDefaultCenturyStart = newStart;
+ fgSystemDefaultCenturyStartYear = newYear;
+ umtx_unlock(NULL);
+ }
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/buddhcal.h b/Build/source/libs/icu/icu-xetex/i18n/buddhcal.h
new file mode 100644
index 00000000000..735f61890a7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/buddhcal.h
@@ -0,0 +1,243 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ********************************************************************************
+ *
+ * File BUDDHCAL.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 05/13/2003 srl copied from gregocal.h
+ ********************************************************************************
+ */
+
+#ifndef BUDDHCAL_H
+#define BUDDHCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Concrete class which provides the Buddhist calendar.
+ * <P>
+ * <code>BuddhistCalendar</code> is a subclass of <code>GregorianCalendar</code>
+ * that numbers years since the birth of the Buddha. This is the civil calendar
+ * in some predominantly Buddhist countries such as Thailand, and it is used for
+ * religious purposes elsewhere.
+ * <p>
+ * The Buddhist calendar is identical to the Gregorian calendar in all respects
+ * except for the year and era. Years are numbered since the birth of the
+ * Buddha in 543 BC (Gregorian), so that 1 AD (Gregorian) is equivalent to 544
+ * BE (Buddhist Era) and 1998 AD is 2541 BE.
+ * <p>
+ * The Buddhist Calendar has only one allowable era: <code>BE</code>. If the
+ * calendar is not in lenient mode (see <code>setLenient</code>), dates before
+ * 1/1/1 BE are rejected as an illegal argument.
+ * <p>
+ * @internal
+ */
+class BuddhistCalendar : public GregorianCalendar {
+public:
+
+ /**
+ * Useful constants for BuddhistCalendar. Only one Era.
+ * @internal
+ */
+ enum EEras {
+ BE
+ };
+
+ /**
+ * Constructs a BuddhistCalendar based on the current time in the default time zone
+ * with the given locale.
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the status of BuddhistCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @internal
+ */
+ BuddhistCalendar(const Locale& aLocale, UErrorCode& success);
+
+
+ /**
+ * Destructor
+ * @internal
+ */
+ virtual ~BuddhistCalendar();
+
+ /**
+ * Copy constructor
+ * @param source the object to be copied.
+ * @internal
+ */
+ BuddhistCalendar(const BuddhistCalendar& source);
+
+ /**
+ * Default assignment operator
+ * @param right the object to be copied.
+ * @internal
+ */
+ BuddhistCalendar& operator=(const BuddhistCalendar& right);
+
+ /**
+ * Create and return a polymorphic copy of this calendar.
+ * @return return a polymorphic copy of this calendar.
+ * @internal
+ */
+ virtual Calendar* clone(void) const;
+
+public:
+ /**
+ * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
+ * override. This method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
+ * this method.
+ *
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @internal
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to a return
+ * value from getDynamicClassID(). For example:
+ *
+ * Base* polymorphic_pointer = createPolymorphicObject();
+ * if (polymorphic_pointer->getDynamicClassID() ==
+ * Derived::getStaticClassID()) ...
+ *
+ * @return The class ID for all objects of this class.
+ * @internal
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * return the calendar type, "buddhist".
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+private:
+ BuddhistCalendar(); // default constructor not implemented
+
+ protected:
+ /**
+ * Return the extended year defined by the current fields. This will
+ * use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
+ * as UCAL_ERA) specific to the calendar system, depending on which set of
+ * fields is newer.
+ * @return the extended year
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+ /**
+ * Subclasses may override this method to compute several fields
+ * specific to each calendar system.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode& status);
+ /**
+ * Subclass API for defining limits of different types.
+ * @param field one of the field numbers
+ * @param limitType one of <code>MINIMUM</code>, <code>GREATEST_MINIMUM</code>,
+ * <code>LEAST_MAXIMUM</code>, or <code>MAXIMUM</code>
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+ /**
+ * Return the Julian day number of day before the first day of the
+ * given month in the given extended year. Subclasses should override
+ * this method to implement their calendar system.
+ * @param eyear the extended year
+ * @param month the zero-based month, or 0 if useMonth is false
+ * @param useMonth if false, compute the day before the first day of
+ * the given year, otherwise, compute the day before the first day of
+ * the given month
+ * @param return the Julian day number of the day before the first
+ * day of the given month and year
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month,
+ UBool useMonth) const;
+
+ /**
+ * Returns TRUE because the Buddhist Calendar does have a default century
+ * @internal
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * Returns the date of the start of the default century
+ * @return start of century - in milliseconds since epoch, 1970
+ * @internal
+ */
+ virtual UDate defaultCenturyStart() const;
+
+ /**
+ * Returns the year in which the default century begins
+ * @internal
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+ private: // default century stuff.
+ /**
+ * The system maintains a static default century start date. This is initialized
+ * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
+ * indicate an uninitialized state. Once the system default century date and year
+ * are set, they do not change.
+ */
+ static UDate fgSystemDefaultCenturyStart;
+
+ /**
+ * See documentation for systemDefaultCenturyStart.
+ */
+ static int32_t fgSystemDefaultCenturyStartYear;
+
+ /**
+ * Default value that indicates the defaultCenturyStartYear is unitialized
+ */
+ static const int32_t fgSystemDefaultCenturyYear;
+
+ /**
+ * start of default century, as a date
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * Returns the beginning date of the 100-year window that dates
+ * with 2-digit years are considered to fall within.
+ */
+ UDate internalGetDefaultCenturyStart(void) const;
+
+ /**
+ * Returns the first year of the 100-year window that dates with
+ * 2-digit years are considered to fall within.
+ */
+ int32_t internalGetDefaultCenturyStartYear(void) const;
+
+ /**
+ * Initializes the 100-year window that dates with 2-digit years
+ * are considered to fall within so that its start date is 80 years
+ * before the current time.
+ */
+ static void initializeSystemDefaultCentury(void);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _GREGOCAL
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/calendar.cpp b/Build/source/libs/icu/icu-xetex/i18n/calendar.cpp
new file mode 100644
index 00000000000..03bedde03ee
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/calendar.cpp
@@ -0,0 +1,3080 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File CALENDAR.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/03/97 clhuang Creation.
+* 04/22/97 aliu Cleaned up, fixed memory leak, made
+* setWeekCountData() more robust.
+* Moved platform code to TPlatformUtilities.
+* 05/01/97 aliu Made equals(), before(), after() arguments const.
+* 05/20/97 aliu Changed logic of when to compute fields and time
+* to fix bugs.
+* 08/12/97 aliu Added equivalentTo. Misc other fixes.
+* 07/28/98 stephen Sync up with JDK 1.2
+* 09/02/98 stephen Sync with JDK 1.2 8/31 build (getActualMin/Max)
+* 03/17/99 stephen Changed adoptTimeZone() - now fAreFieldsSet is
+* set to FALSE to force update of time.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/gregocal.h"
+#include "gregoimp.h"
+#include "buddhcal.h"
+#include "taiwncal.h"
+#include "japancal.h"
+#include "islamcal.h"
+#include "hebrwcal.h"
+#include "persncal.h"
+#include "indiancal.h"
+//#include "chnsecal.h"
+#include "unicode/calendar.h"
+#include "cpputils.h"
+#include "servloc.h"
+#include "ucln_in.h"
+#include "cstring.h"
+#include "locbased.h"
+#include "uresimp.h"
+
+#if !UCONFIG_NO_SERVICE
+static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
+#endif
+
+// INTERNAL - for cleanup
+
+U_CDECL_BEGIN
+static UBool calendar_cleanup(void) {
+#if !UCONFIG_NO_SERVICE
+ if (gService) {
+ delete gService;
+ gService = NULL;
+ }
+#endif
+ return TRUE;
+}
+U_CDECL_END
+
+// ------------------------------------------
+//
+// Registration
+//
+//-------------------------------------------
+//#define U_DEBUG_CALSVC 1
+//
+
+#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
+#include <stdio.h>
+
+
+/**
+* convert a UCalendarDateFields into a string - for debugging
+* @param f field enum
+* @return static string to the field name
+* @internal
+*/
+#error fldName() has been removed. Please use udbg_ucal_fieldName() from libctestfw instead. The following code might work.
+
+static const char* fldName(UCalendarDateFields f) {
+ const char *udbg_ucal_fieldName(int32_t fld);
+ return udbg_ucal_fieldName((int32_t)f);
+}
+
+
+
+#if UCAL_DEBUG_DUMP
+// from CalendarTest::calToStr - but doesn't modify contents.
+void ucal_dump(const Calendar &cal) {
+ cal.dump();
+}
+
+void Calendar::dump() const {
+ int i;
+ fprintf(stderr, "@calendar=%s, timeset=%c, fieldset=%c, allfields=%c, virtualset=%c, t=%.2f",
+ getType(), fIsTimeSet?'y':'n', fAreFieldsSet?'y':'n', fAreAllFieldsSet?'y':'n',
+ fAreFieldsVirtuallySet?'y':'n',
+ fTime);
+
+ // can add more things here: DST, zone, etc.
+ fprintf(stderr, "\n");
+ for(i = 0;i<UCAL_FIELD_COUNT;i++) {
+ int n;
+ const char *f = fldName((UCalendarDateFields)i);
+ fprintf(stderr, " %25s: %-11ld", f, fFields[i]);
+ if(fStamp[i] == kUnset) {
+ fprintf(stderr, " (unset) ");
+ } else if(fStamp[i] == kInternallySet) {
+ fprintf(stderr, " (internally set) ");
+ //} else if(fStamp[i] == kInternalDefault) {
+ // fprintf(stderr, " (internal default) ");
+ } else {
+ fprintf(stderr, " %%%d ", fStamp[i]);
+ }
+ fprintf(stderr, "\n");
+
+ }
+}
+
+U_CFUNC void ucal_dump(UCalendar* cal) {
+ ucal_dump( *((Calendar*)cal) );
+}
+#endif
+
+#endif
+
+static const char * const gCalendarKeywords[] = {
+ "gregorian",
+ "japanese",
+ "buddhist",
+ "taiwan",
+ "persian",
+ "islamic-civil",
+ "islamic",
+ "hebrew",
+ "chinese",
+ "indian",
+ NULL
+};
+
+U_NAMESPACE_BEGIN
+
+static UBool isStandardSupportedKeyword(const char *keyword, UErrorCode& status) {
+ if(U_FAILURE(status)) {
+ return FALSE;
+ }
+ for(int32_t i=0; gCalendarKeywords[i] != NULL; i++) {
+ if(uprv_strcmp(gCalendarKeywords[i], keyword) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void getCalendarKeyword(const UnicodeString &id, char *targetBuffer, int32_t targetBufferSize) {
+ UnicodeString calendarKeyword = UNICODE_STRING_SIMPLE("calendar=");
+ int32_t calKeyLen = calendarKeyword.length();
+ int32_t keyLen = 0;
+
+ int32_t keywordIdx = id.indexOf((UChar)0x003D); /* '=' */
+ if (id[0] == 0x40/*'@'*/
+ && id.compareBetween(1, keywordIdx+1, calendarKeyword, 0, calKeyLen) == 0)
+ {
+ keyLen = id.extract(keywordIdx+1, id.length(), targetBuffer, targetBufferSize, US_INV);
+ }
+ targetBuffer[keyLen] = 0;
+}
+
+static Calendar *createStandardCalendar(char *calType, const Locale &canLoc, UErrorCode& status) {
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, "BasicCalendarFactory %p: creating type for %s\n",
+ this, (const char*)curLoc.getName());
+ fflush(stderr);
+#endif
+
+ if(!calType || !*calType || !uprv_strcmp(calType,"gregorian")) { // Gregorian (default)
+ return new GregorianCalendar(canLoc, status);
+ } else if(!uprv_strcmp(calType, "japanese")) {
+ return new JapaneseCalendar(canLoc, status);
+ } else if(!uprv_strcmp(calType, "buddhist")) {
+ return new BuddhistCalendar(canLoc, status);
+ } else if(!uprv_strcmp(calType, "taiwan")) {
+ return new TaiwanCalendar(canLoc, status);
+ } else if(!uprv_strcmp(calType, "islamic-civil")) {
+ return new IslamicCalendar(canLoc, status, IslamicCalendar::CIVIL);
+ } else if(!uprv_strcmp(calType, "islamic")) {
+ return new IslamicCalendar(canLoc, status, IslamicCalendar::ASTRONOMICAL);
+ } else if(!uprv_strcmp(calType, "hebrew")) {
+ return new HebrewCalendar(canLoc, status);
+ } else if(!uprv_strcmp(calType, "persian")) {
+ return new PersianCalendar(canLoc, status);
+ //} else if(!uprv_strcmp(calType, "chinese")) {
+ //return new ChineseCalendar(canLoc, status);
+ } else if(!uprv_strcmp(calType, "indian")) {
+ return new IndianCalendar(canLoc, status);
+ } else {
+ status = U_UNSUPPORTED_ERROR;
+ return NULL;
+ }
+}
+
+#if !UCONFIG_NO_SERVICE
+
+// -------------------------------------
+
+/**
+* a Calendar Factory which creates the "basic" calendar types, that is, those
+* shipped with ICU.
+*/
+class BasicCalendarFactory : public LocaleKeyFactory {
+public:
+ /**
+ * @param calendarType static const string (caller owns storage - will be aliased) to calendar type
+ */
+ BasicCalendarFactory()
+ : LocaleKeyFactory(LocaleKeyFactory::INVISIBLE) { }
+
+ virtual ~BasicCalendarFactory() {}
+
+protected:
+ //virtual UBool isSupportedID( const UnicodeString& id, UErrorCode& status) const {
+ // if(U_FAILURE(status)) {
+ // return FALSE;
+ // }
+ // char keyword[ULOC_FULLNAME_CAPACITY];
+ // getCalendarKeyword(id, keyword, (int32_t)sizeof(keyword));
+ // return isStandardSupportedKeyword(keyword, status);
+ //}
+
+ virtual void updateVisibleIDs(Hashtable& result, UErrorCode& status) const
+ {
+ if (U_SUCCESS(status)) {
+ for(int32_t i=0;gCalendarKeywords[i] != NULL;i++) {
+ UnicodeString id((UChar)0x40); /* '@' a variant character */
+ id.append(UNICODE_STRING_SIMPLE("calendar="));
+ id.append(UnicodeString(gCalendarKeywords[i], -1, US_INV));
+ result.put(id, (void*)this, status);
+ }
+ }
+ }
+
+ virtual UObject* create(const ICUServiceKey& key, const ICUService* /*service*/, UErrorCode& status) const {
+#ifdef U_DEBUG_CALSVC
+ if(key.getDynamicClassID() != LocaleKey::getStaticClassID()) {
+ fprintf(stderr, "::create - not a LocaleKey!\n");
+ }
+#endif
+ const LocaleKey& lkey = (LocaleKey&)key;
+ Locale curLoc; // current locale
+ Locale canLoc; // Canonical locale
+
+ lkey.currentLocale(curLoc);
+ lkey.canonicalLocale(canLoc);
+
+ char keyword[ULOC_FULLNAME_CAPACITY];
+ UnicodeString str;
+
+ key.currentID(str);
+ getCalendarKeyword(str, keyword, (int32_t) sizeof(keyword));
+
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, "BasicCalendarFactory::create() - cur %s, can %s\n", (const char*)curLoc.getName(), (const char*)canLoc.getName());
+#endif
+
+ if(!isStandardSupportedKeyword(keyword,status)) { // Do we handle this type?
+#ifdef U_DEBUG_CALSVC
+
+ fprintf(stderr, "BasicCalendarFactory - not handling %s.[%s]\n", (const char*) curLoc.getName(), tmp );
+#endif
+ return NULL;
+ }
+
+ return createStandardCalendar(keyword, canLoc, status);
+ }
+};
+
+
+/**
+* A factory which looks up the DefaultCalendar resource to determine which class of calendar to use
+*/
+
+class DefaultCalendarFactory : public ICUResourceBundleFactory {
+public:
+ DefaultCalendarFactory(): ICUResourceBundleFactory() { }
+protected:
+ virtual UObject* create(const ICUServiceKey& key, const ICUService* /*service*/, UErrorCode& status) const {
+
+ LocaleKey &lkey = (LocaleKey&)key;
+ Locale loc;
+ lkey.currentLocale(loc);
+
+ UnicodeString myString;
+
+ // attempt keyword lookup
+ char keyword[128];
+
+ if(!loc.getKeywordValue("calendar", keyword, sizeof(keyword)-1, status)) {
+ // fetch default calendar id
+ char funcEquiv[ULOC_FULLNAME_CAPACITY];
+ ures_getFunctionalEquivalent(funcEquiv, sizeof(funcEquiv)-1,
+ NULL, "calendar", "calendar",
+ loc.getName(),
+ NULL, FALSE, &status);
+ uloc_getKeywordValue(funcEquiv, "calendar", keyword,
+ sizeof(keyword)-1, &status);
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, " getFunctionalEquivalent calendar=%s [%s]\n", keyword, u_errorName(status));
+#endif
+ }
+#ifdef U_DEBUG_CALSVC
+ else { fprintf(stderr, " explicit calendar=%s\n", keyword); }
+#endif
+
+
+ if(U_FAILURE(status)) {
+ return NULL;
+ } else {
+ UnicodeString *ret = new UnicodeString();
+ ret->append((UChar)0x40); // '@' is a variant character
+ ret->append(UNICODE_STRING("calendar=", 9));
+ (*ret) += UnicodeString(keyword,-1,US_INV);
+ return ret;
+ }
+ }
+};
+
+// -------------------------------------
+class CalendarService : public ICULocaleService {
+public:
+ CalendarService()
+ : ICULocaleService(UNICODE_STRING_SIMPLE("Calendar"))
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ registerFactory(new DefaultCalendarFactory(), status);
+ }
+
+ virtual UObject* cloneInstance(UObject* instance) const {
+ if(instance->getDynamicClassID() == UnicodeString::getStaticClassID()) {
+ return ((UnicodeString*)instance)->clone();
+ } else {
+#ifdef U_DEBUG_CALSVC_F
+ UErrorCode status2 = U_ZERO_ERROR;
+ fprintf(stderr, "Cloning a %s calendar with tz=%ld\n", ((Calendar*)instance)->getType(), ((Calendar*)instance)->get(UCAL_ZONE_OFFSET, status2));
+#endif
+ return ((Calendar*)instance)->clone();
+ }
+ }
+
+ virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /*actualID*/, UErrorCode& status) const {
+ LocaleKey& lkey = (LocaleKey&)key;
+ //int32_t kind = lkey.kind();
+
+ Locale loc;
+ lkey.canonicalLocale(loc);
+
+#ifdef U_DEBUG_CALSVC
+ Locale loc2;
+ lkey.currentLocale(loc2);
+ fprintf(stderr, "CalSvc:handleDefault for currentLoc %s, canloc %s\n", (const char*)loc.getName(), (const char*)loc2.getName());
+#endif
+ Calendar *nc = new GregorianCalendar(loc, status);
+
+#ifdef U_DEBUG_CALSVC
+ UErrorCode status2 = U_ZERO_ERROR;
+ fprintf(stderr, "New default calendar has tz=%d\n", ((Calendar*)nc)->get(UCAL_ZONE_OFFSET, status2));
+#endif
+ return nc;
+ }
+
+ virtual UBool isDefault() const {
+ return countFactories() == 1;
+ }
+};
+
+// -------------------------------------
+
+static inline UBool
+isCalendarServiceUsed() {
+ UBool retVal;
+ UMTX_CHECK(NULL, gService != NULL, retVal);
+ return retVal;
+}
+
+// -------------------------------------
+
+static ICULocaleService*
+getCalendarService(UErrorCode &status)
+{
+ UBool needInit;
+ UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
+ if (needInit) {
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, "Spinning up Calendar Service\n");
+#endif
+ ICULocaleService * newservice = new CalendarService();
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, "Registering classes..\n");
+#endif
+
+ // Register all basic instances.
+ newservice->registerFactory(new BasicCalendarFactory(),status);
+
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, "Done..\n");
+#endif
+
+ if(U_FAILURE(status)) {
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status));
+#endif
+ delete newservice;
+ newservice = NULL;
+ }
+
+ if (newservice) {
+ umtx_lock(NULL);
+ if (gService == NULL) {
+ gService = newservice;
+ newservice = NULL;
+ }
+ umtx_unlock(NULL);
+ }
+ if (newservice) {
+ delete newservice;
+ } else {
+ // we won the contention - we can register the cleanup.
+ ucln_i18n_registerCleanup(UCLN_I18N_CALENDAR, calendar_cleanup);
+ }
+ }
+ return gService;
+}
+
+URegistryKey Calendar::registerFactory(ICUServiceFactory* toAdopt, UErrorCode& status)
+{
+ return getCalendarService(status)->registerFactory(toAdopt, status);
+}
+
+UBool Calendar::unregister(URegistryKey key, UErrorCode& status) {
+ return getCalendarService(status)->unregister(key, status);
+}
+#endif /* UCONFIG_NO_SERVICE */
+
+// -------------------------------------
+
+static const int32_t kCalendarLimits[UCAL_FIELD_COUNT][4] = {
+ // Minimum Greatest min Least max Greatest max
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // ERA
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // YEAR
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // MONTH
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // WEEK_OF_YEAR
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // WEEK_OF_MONTH
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // DAY_OF_MONTH
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // DAY_OF_YEAR
+ { 1, 1, 7, 7 }, // DAY_OF_WEEK
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // DAY_OF_WEEK_IN_MONTH
+ { 0, 0, 1, 1 }, // AM_PM
+ { 0, 0, 11, 11 }, // HOUR
+ { 0, 0, 23, 23 }, // HOUR_OF_DAY
+ { 0, 0, 59, 59 }, // MINUTE
+ { 0, 0, 59, 59 }, // SECOND
+ { 0, 0, 999, 999 }, // MILLISECOND
+ {-12*kOneHour, -12*kOneHour, 12*kOneHour, 15*kOneHour }, // ZONE_OFFSET
+ { 0, 0, 1*kOneHour, 1*kOneHour }, // DST_OFFSET
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // YEAR_WOY
+ { 1, 1, 7, 7 }, // DOW_LOCAL
+ {/*N/A*/-1, /*N/A*/-1, /*N/A*/-1, /*N/A*/-1}, // EXTENDED_YEAR
+ { -0x7F000000, -0x7F000000, 0x7F000000, 0x7F000000 }, // JULIAN_DAY
+ { 0, 0, 24*kOneHour-1, 24*kOneHour-1 } // MILLISECONDS_IN_DAY
+};
+
+// Resource bundle tags read by this class
+static const char gDateTimeElements[] = "DateTimeElements";
+
+// Data flow in Calendar
+// ---------------------
+
+// The current time is represented in two ways by Calendar: as UTC
+// milliseconds from the epoch start (1 January 1970 0:00 UTC), and as local
+// fields such as MONTH, HOUR, AM_PM, etc. It is possible to compute the
+// millis from the fields, and vice versa. The data needed to do this
+// conversion is encapsulated by a TimeZone object owned by the Calendar.
+// The data provided by the TimeZone object may also be overridden if the
+// user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
+// keeps track of what information was most recently set by the caller, and
+// uses that to compute any other information as needed.
+
+// If the user sets the fields using set(), the data flow is as follows.
+// This is implemented by the Calendar subclass's computeTime() method.
+// During this process, certain fields may be ignored. The disambiguation
+// algorithm for resolving which fields to pay attention to is described
+// above.
+
+// local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
+// |
+// | Using Calendar-specific algorithm
+// V
+// local standard millis
+// |
+// | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
+// V
+// UTC millis (in time data member)
+
+// If the user sets the UTC millis using setTime(), the data flow is as
+// follows. This is implemented by the Calendar subclass's computeFields()
+// method.
+
+// UTC millis (in time data member)
+// |
+// | Using TimeZone getOffset()
+// V
+// local standard millis
+// |
+// | Using Calendar-specific algorithm
+// V
+// local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
+
+// In general, a round trip from fields, through local and UTC millis, and
+// back out to fields is made when necessary. This is implemented by the
+// complete() method. Resolving a partial set of fields into a UTC millis
+// value allows all remaining fields to be generated from that value. If
+// the Calendar is lenient, the fields are also renormalized to standard
+// ranges when they are regenerated.
+
+// -------------------------------------
+
+Calendar::Calendar(UErrorCode& success)
+: UObject(),
+fIsTimeSet(FALSE),
+fAreFieldsSet(FALSE),
+fAreAllFieldsSet(FALSE),
+fAreFieldsVirtuallySet(FALSE),
+fNextStamp((int32_t)kMinimumUserStamp),
+fTime(0),
+fLenient(TRUE),
+fZone(0)
+{
+ clear();
+ fZone = TimeZone::createDefault();
+ setWeekCountData(Locale::getDefault(), NULL, success);
+}
+
+// -------------------------------------
+
+Calendar::Calendar(TimeZone* zone, const Locale& aLocale, UErrorCode& success)
+: UObject(),
+fIsTimeSet(FALSE),
+fAreFieldsSet(FALSE),
+fAreAllFieldsSet(FALSE),
+fAreFieldsVirtuallySet(FALSE),
+fNextStamp((int32_t)kMinimumUserStamp),
+fTime(0),
+fLenient(TRUE),
+fZone(0)
+{
+ if(zone == 0) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because timezone cannot be 0\n",
+ __FILE__, __LINE__);
+#endif
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ clear();
+ fZone = zone;
+
+ setWeekCountData(aLocale, NULL, success);
+}
+
+// -------------------------------------
+
+Calendar::Calendar(const TimeZone& zone, const Locale& aLocale, UErrorCode& success)
+: UObject(),
+fIsTimeSet(FALSE),
+fAreFieldsSet(FALSE),
+fAreAllFieldsSet(FALSE),
+fAreFieldsVirtuallySet(FALSE),
+fNextStamp((int32_t)kMinimumUserStamp),
+fTime(0),
+fLenient(TRUE),
+fZone(0)
+{
+ clear();
+ fZone = zone.clone();
+ setWeekCountData(aLocale, NULL, success);
+}
+
+// -------------------------------------
+
+Calendar::~Calendar()
+{
+ delete fZone;
+}
+
+// -------------------------------------
+
+Calendar::Calendar(const Calendar &source)
+: UObject(source)
+{
+ fZone = 0;
+ *this = source;
+}
+
+// -------------------------------------
+
+Calendar &
+Calendar::operator=(const Calendar &right)
+{
+ if (this != &right) {
+ uprv_arrayCopy(right.fFields, fFields, UCAL_FIELD_COUNT);
+ uprv_arrayCopy(right.fIsSet, fIsSet, UCAL_FIELD_COUNT);
+ uprv_arrayCopy(right.fStamp, fStamp, UCAL_FIELD_COUNT);
+ fTime = right.fTime;
+ fIsTimeSet = right.fIsTimeSet;
+ fAreAllFieldsSet = right.fAreAllFieldsSet;
+ fAreFieldsSet = right.fAreFieldsSet;
+ fAreFieldsVirtuallySet = right.fAreFieldsVirtuallySet;
+ fLenient = right.fLenient;
+ delete fZone;
+ fZone = right.fZone->clone();
+ fFirstDayOfWeek = right.fFirstDayOfWeek;
+ fMinimalDaysInFirstWeek = right.fMinimalDaysInFirstWeek;
+ fNextStamp = right.fNextStamp;
+ }
+
+ return *this;
+}
+
+// -------------------------------------
+
+Calendar* U_EXPORT2
+Calendar::createInstance(UErrorCode& success)
+{
+ return createInstance(TimeZone::createDefault(), Locale::getDefault(), success);
+}
+
+// -------------------------------------
+
+Calendar* U_EXPORT2
+Calendar::createInstance(const TimeZone& zone, UErrorCode& success)
+{
+ return createInstance(zone, Locale::getDefault(), success);
+}
+
+// -------------------------------------
+
+Calendar* U_EXPORT2
+Calendar::createInstance(const Locale& aLocale, UErrorCode& success)
+{
+ return createInstance(TimeZone::createDefault(), aLocale, success);
+}
+
+// ------------------------------------- Adopting
+
+// Note: this is the bottleneck that actually calls the service routines.
+
+Calendar* U_EXPORT2
+Calendar::createInstance(TimeZone* zone, const Locale& aLocale, UErrorCode& success)
+{
+ Locale actualLoc;
+ UObject* u;
+#if !UCONFIG_NO_SERVICE
+ if (isCalendarServiceUsed()) {
+ u = getCalendarService(success)->get(aLocale, LocaleKey::KIND_ANY, &actualLoc, success);
+ }
+ else
+#endif
+ {
+ UErrorCode feErr;
+ char calLocaleType[ULOC_FULLNAME_CAPACITY];
+ calLocaleType[0] = 0; // NULL terminate
+ int32_t keywordCapacity = aLocale.getKeywordValue("calendar", calLocaleType, sizeof(calLocaleType)-1, success);
+ if (keywordCapacity == 0) {
+ char funcEquiv[ULOC_FULLNAME_CAPACITY];
+
+ feErr = success;
+
+ // fetch default calendar id
+ ures_getFunctionalEquivalent(funcEquiv, sizeof(funcEquiv)-1,
+ NULL, "calendar", "calendar",
+ aLocale.getName(),
+ NULL, FALSE, &feErr);
+ keywordCapacity = uloc_getKeywordValue(funcEquiv, "calendar", calLocaleType,
+ sizeof(calLocaleType)-1, &feErr); // This can fail if there is no data.
+ // Don't want to stop calendar construction just because we couldn't get this type.
+ if (keywordCapacity == 0 || U_FAILURE(feErr)) {
+ // no calendar type. Default to nothing.
+ calLocaleType[0] = 0;
+ }
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, " getFunctionalEquivalent calendar=%s [%s]\n", keyword, u_errorName(status));
+#endif
+ }
+#ifdef U_DEBUG_CALSVC
+ else { fprintf(stderr, " explicit calendar=%s\n", keyword); }
+#endif
+ u = createStandardCalendar(calLocaleType, aLocale, success);
+ }
+ Calendar* c = NULL;
+
+ if(U_FAILURE(success) || !u) {
+ delete zone;
+ if(U_SUCCESS(success)) { // Propagate some kind of err
+ success = U_INTERNAL_PROGRAM_ERROR;
+ }
+ return NULL;
+ }
+
+#if !UCONFIG_NO_SERVICE
+ if(u->getDynamicClassID() == UnicodeString::getStaticClassID()) {
+ // It's a unicode string telling us what type of calendar to load ("gregorian", etc)
+ const UnicodeString& str = *(UnicodeString*)u;
+
+ // Create a Locale over this string
+ Locale l("");
+ LocaleUtility::initLocaleFromName(str, l);
+
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, "Calendar::createInstance(%s), looking up [%s]\n", aLocale.getName(), l.getName());
+#endif
+
+ Locale actualLoc2;
+ delete u;
+ u = NULL;
+
+ // Don't overwrite actualLoc, since the actual loc from this call
+ // may be something like "@calendar=gregorian" -- TODO investigate
+ // further...
+ c = (Calendar*)getCalendarService(success)->get(l, LocaleKey::KIND_ANY, &actualLoc2, success);
+
+ if(U_FAILURE(success) || !c) {
+ delete zone;
+ if(U_SUCCESS(success)) {
+ success = U_INTERNAL_PROGRAM_ERROR; // Propagate some err
+ }
+ return NULL;
+ }
+
+ if(c->getDynamicClassID() == UnicodeString::getStaticClassID()) {
+ // recursed! Second lookup returned a UnicodeString.
+ // Perhaps DefaultCalendar{} was set to another locale.
+#ifdef U_DEBUG_CALSVC
+ char tmp[200];
+ const UnicodeString& str = *(UnicodeString*)c;
+ // Extract a char* out of it..
+ int32_t len = str.length();
+ int32_t actLen = sizeof(tmp)-1;
+ if(len > actLen) {
+ len = actLen;
+ }
+ str.extract(0,len,tmp);
+ tmp[len]=0;
+
+ fprintf(stderr, "err - recursed, 2nd lookup was unistring %s\n", tmp);
+#endif
+ success = U_MISSING_RESOURCE_ERROR; // requested a calendar type which could NOT be found.
+ delete c;
+ delete zone;
+ return NULL;
+ }
+#ifdef U_DEBUG_CALSVC
+ fprintf(stderr, "%p: setting week count data to locale %s, actual locale %s\n", c, (const char*)aLocale.getName(), (const char *)actualLoc.getName());
+#endif
+ c->setWeekCountData(aLocale, c->getType(), success); // set the correct locale (this was an indirected calendar)
+ }
+ else
+#endif /* UCONFIG_NO_SERVICE */
+ {
+ // a calendar was returned - we assume the factory did the right thing.
+ c = (Calendar*)u;
+ }
+
+ // Now, reset calendar to default state:
+ c->adoptTimeZone(zone); // Set the correct time zone
+ c->setTimeInMillis(getNow(), success); // let the new calendar have the current time.
+
+ return c;
+}
+
+// -------------------------------------
+
+Calendar* U_EXPORT2
+Calendar::createInstance(const TimeZone& zone, const Locale& aLocale, UErrorCode& success)
+{
+ Calendar* c = createInstance(aLocale, success);
+ if(U_SUCCESS(success) && c) {
+ c->setTimeZone(zone);
+ }
+ return c;
+}
+
+// -------------------------------------
+
+UBool
+Calendar::operator==(const Calendar& that) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ return isEquivalentTo(that) &&
+ getTimeInMillis(status) == that.getTimeInMillis(status) &&
+ U_SUCCESS(status);
+}
+
+UBool
+Calendar::isEquivalentTo(const Calendar& other) const
+{
+ return getDynamicClassID() == other.getDynamicClassID() &&
+ fLenient == other.fLenient &&
+ fFirstDayOfWeek == other.fFirstDayOfWeek &&
+ fMinimalDaysInFirstWeek == other.fMinimalDaysInFirstWeek &&
+ *fZone == *other.fZone;
+}
+
+// -------------------------------------
+
+UBool
+Calendar::equals(const Calendar& when, UErrorCode& status) const
+{
+ return (this == &when ||
+ getTime(status) == when.getTime(status));
+}
+
+// -------------------------------------
+
+UBool
+Calendar::before(const Calendar& when, UErrorCode& status) const
+{
+ return (this != &when &&
+ getTimeInMillis(status) < when.getTimeInMillis(status));
+}
+
+// -------------------------------------
+
+UBool
+Calendar::after(const Calendar& when, UErrorCode& status) const
+{
+ return (this != &when &&
+ getTimeInMillis(status) > when.getTimeInMillis(status));
+}
+
+// -------------------------------------
+
+
+const Locale* U_EXPORT2
+Calendar::getAvailableLocales(int32_t& count)
+{
+ return Locale::getAvailableLocales(count);
+}
+
+// -------------------------------------
+
+UDate U_EXPORT2
+Calendar::getNow()
+{
+ return uprv_getUTCtime(); // return as milliseconds
+}
+
+// -------------------------------------
+
+/**
+* Gets this Calendar's current time as a long.
+* @return the current time as UTC milliseconds from the epoch.
+*/
+double
+Calendar::getTimeInMillis(UErrorCode& status) const
+{
+ if(U_FAILURE(status))
+ return 0.0;
+
+ if ( ! fIsTimeSet)
+ ((Calendar*)this)->updateTime(status);
+
+ /* Test for buffer overflows */
+ if(U_FAILURE(status)) {
+ return 0.0;
+ }
+ return fTime;
+}
+
+// -------------------------------------
+
+/**
+* Sets this Calendar's current time from the given long value.
+* @param date the new time in UTC milliseconds from the epoch.
+*/
+void
+Calendar::setTimeInMillis( double millis, UErrorCode& status ) {
+ if(U_FAILURE(status))
+ return;
+
+ if (millis > MAX_MILLIS) {
+ millis = MAX_MILLIS;
+ } else if (millis < MIN_MILLIS) {
+ millis = MIN_MILLIS;
+ }
+
+ fTime = millis;
+ fAreFieldsSet = fAreAllFieldsSet = FALSE;
+ fIsTimeSet = fAreFieldsVirtuallySet = TRUE;
+}
+
+// -------------------------------------
+
+int32_t
+Calendar::get(UCalendarDateFields field, UErrorCode& status) const
+{
+ // field values are only computed when actually requested; for more on when computation
+ // of various things happens, see the "data flow in Calendar" description at the top
+ // of this file
+ if (U_SUCCESS(status)) ((Calendar*)this)->complete(status); // Cast away const
+ return U_SUCCESS(status) ? fFields[field] : 0;
+}
+
+// -------------------------------------
+
+void
+Calendar::set(UCalendarDateFields field, int32_t value)
+{
+ if (fAreFieldsVirtuallySet) {
+ UErrorCode ec = U_ZERO_ERROR;
+ computeFields(ec);
+ }
+ fFields[field] = value;
+ fStamp[field] = fNextStamp++;
+ fIsSet[field] = TRUE; // Remove later
+ fIsTimeSet = fAreFieldsSet = fAreFieldsVirtuallySet = FALSE;
+}
+
+// -------------------------------------
+
+void
+Calendar::set(int32_t year, int32_t month, int32_t date)
+{
+ set(UCAL_YEAR, year);
+ set(UCAL_MONTH, month);
+ set(UCAL_DATE, date);
+}
+
+// -------------------------------------
+
+void
+Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute)
+{
+ set(UCAL_YEAR, year);
+ set(UCAL_MONTH, month);
+ set(UCAL_DATE, date);
+ set(UCAL_HOUR_OF_DAY, hour);
+ set(UCAL_MINUTE, minute);
+}
+
+// -------------------------------------
+
+void
+Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute, int32_t second)
+{
+ set(UCAL_YEAR, year);
+ set(UCAL_MONTH, month);
+ set(UCAL_DATE, date);
+ set(UCAL_HOUR_OF_DAY, hour);
+ set(UCAL_MINUTE, minute);
+ set(UCAL_SECOND, second);
+}
+
+// -------------------------------------
+
+void
+Calendar::clear()
+{
+ for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
+ fFields[i] = 0; // Must do this; other code depends on it
+ fStamp[i] = kUnset;
+ fIsSet[i] = FALSE; // Remove later
+ }
+ fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = FALSE;
+ // fTime is not 'cleared' - may be used if no fields are set.
+}
+
+// -------------------------------------
+
+void
+Calendar::clear(UCalendarDateFields field)
+{
+ if (fAreFieldsVirtuallySet) {
+ UErrorCode ec = U_ZERO_ERROR;
+ computeFields(ec);
+ }
+ fFields[field] = 0;
+ fStamp[field] = kUnset;
+ fIsSet[field] = FALSE; // Remove later
+ fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = FALSE;
+}
+
+// -------------------------------------
+
+UBool
+Calendar::isSet(UCalendarDateFields field) const
+{
+ return fAreFieldsVirtuallySet || (fStamp[field] != kUnset);
+}
+
+
+int32_t Calendar::newestStamp(UCalendarDateFields first, UCalendarDateFields last, int32_t bestStampSoFar) const
+{
+ int32_t bestStamp = bestStampSoFar;
+ for (int32_t i=(int32_t)first; i<=(int32_t)last; ++i) {
+ if (fStamp[i] > bestStamp) {
+ bestStamp = fStamp[i];
+ }
+ }
+ return bestStamp;
+}
+
+
+// -------------------------------------
+
+void
+Calendar::complete(UErrorCode& status)
+{
+ if (!fIsTimeSet) {
+ updateTime(status);
+ /* Test for buffer overflows */
+ if(U_FAILURE(status)) {
+ return;
+ }
+ }
+ if (!fAreFieldsSet) {
+ computeFields(status); // fills in unset fields
+ /* Test for buffer overflows */
+ if(U_FAILURE(status)) {
+ return;
+ }
+ fAreFieldsSet = TRUE;
+ fAreAllFieldsSet = TRUE;
+ }
+}
+
+//-------------------------------------------------------------------------
+// Protected utility methods for use by subclasses. These are very handy
+// for implementing add, roll, and computeFields.
+//-------------------------------------------------------------------------
+
+/**
+* Adjust the specified field so that it is within
+* the allowable range for the date to which this calendar is set.
+* For example, in a Gregorian calendar pinning the {@link #DAY_OF_MONTH DAY_OF_MONTH}
+* field for a calendar set to April 31 would cause it to be set
+* to April 30.
+* <p>
+* <b>Subclassing:</b>
+* <br>
+* This utility method is intended for use by subclasses that need to implement
+* their own overrides of {@link #roll roll} and {@link #add add}.
+* <p>
+* <b>Note:</b>
+* <code>pinField</code> is implemented in terms of
+* {@link #getActualMinimum getActualMinimum}
+* and {@link #getActualMaximum getActualMaximum}. If either of those methods uses
+* a slow, iterative algorithm for a particular field, it would be
+* unwise to attempt to call <code>pinField</code> for that field. If you
+* really do need to do so, you should override this method to do
+* something more efficient for that field.
+* <p>
+* @param field The calendar field whose value should be pinned.
+*
+* @see #getActualMinimum
+* @see #getActualMaximum
+* @stable ICU 2.0
+*/
+void Calendar::pinField(UCalendarDateFields field, UErrorCode& status) {
+ int32_t max = getActualMaximum(field, status);
+ int32_t min = getActualMinimum(field, status);
+
+ if (fFields[field] > max) {
+ set(field, max);
+ } else if (fFields[field] < min) {
+ set(field, min);
+ }
+}
+
+
+void Calendar::computeFields(UErrorCode &ec)
+{
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ // Compute local wall millis
+ double localMillis = internalGetTime();
+ int32_t rawOffset, dstOffset;
+ getTimeZone().getOffset(localMillis, FALSE, rawOffset, dstOffset, ec);
+ localMillis += (rawOffset + dstOffset);
+
+ // Mark fields as set. Do this before calling handleComputeFields().
+ uint32_t mask = //fInternalSetMask;
+ (1 << UCAL_ERA) |
+ (1 << UCAL_YEAR) |
+ (1 << UCAL_MONTH) |
+ (1 << UCAL_DAY_OF_MONTH) | // = UCAL_DATE
+ (1 << UCAL_DAY_OF_YEAR) |
+ (1 << UCAL_EXTENDED_YEAR);
+
+ for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) {
+ if ((mask & 1) == 0) {
+ fStamp[i] = kInternallySet;
+ fIsSet[i] = TRUE; // Remove later
+ } else {
+ fStamp[i] = kUnset;
+ fIsSet[i] = FALSE; // Remove later
+ }
+ mask >>= 1;
+ }
+
+ // We used to check for and correct extreme millis values (near
+ // Long.MIN_VALUE or Long.MAX_VALUE) here. Such values would cause
+ // overflows from positive to negative (or vice versa) and had to
+ // be manually tweaked. We no longer need to do this because we
+ // have limited the range of supported dates to those that have a
+ // Julian day that fits into an int. This allows us to implement a
+ // JULIAN_DAY field and also removes some inelegant code. - Liu
+ // 11/6/00
+
+ int32_t days = (int32_t)Math::floorDivide(localMillis, (double)kOneDay);
+
+ internalSet(UCAL_JULIAN_DAY,days + kEpochStartAsJulianDay);
+
+#if defined (U_DEBUG_CAL)
+ //fprintf(stderr, "%s:%d- Hmm! Jules @ %d, as per %.0lf millis\n",
+ //__FILE__, __LINE__, fFields[UCAL_JULIAN_DAY], localMillis);
+#endif
+
+ computeGregorianAndDOWFields(fFields[UCAL_JULIAN_DAY], ec);
+
+ // Call framework method to have subclass compute its fields.
+ // These must include, at a minimum, MONTH, DAY_OF_MONTH,
+ // EXTENDED_YEAR, YEAR, DAY_OF_YEAR. This method will call internalSet(),
+ // which will update stamp[].
+ handleComputeFields(fFields[UCAL_JULIAN_DAY], ec);
+
+ // Compute week-related fields, based on the subclass-computed
+ // fields computed by handleComputeFields().
+ computeWeekFields(ec);
+
+ // Compute time-related fields. These are indepent of the date and
+ // of the subclass algorithm. They depend only on the local zone
+ // wall milliseconds in day.
+ int32_t millisInDay = (int32_t) (localMillis - (days * kOneDay));
+ fFields[UCAL_MILLISECONDS_IN_DAY] = millisInDay;
+ fFields[UCAL_MILLISECOND] = millisInDay % 1000;
+ millisInDay /= 1000;
+ fFields[UCAL_SECOND] = millisInDay % 60;
+ millisInDay /= 60;
+ fFields[UCAL_MINUTE] = millisInDay % 60;
+ millisInDay /= 60;
+ fFields[UCAL_HOUR_OF_DAY] = millisInDay;
+ fFields[UCAL_AM_PM] = millisInDay / 12; // Assume AM == 0
+ fFields[UCAL_HOUR] = millisInDay % 12;
+ fFields[UCAL_ZONE_OFFSET] = rawOffset;
+ fFields[UCAL_DST_OFFSET] = dstOffset;
+}
+
+uint8_t Calendar::julianDayToDayOfWeek(double julian)
+{
+ // If julian is negative, then julian%7 will be negative, so we adjust
+ // accordingly. We add 1 because Julian day 0 is Monday.
+ int8_t dayOfWeek = (int8_t) uprv_fmod(julian + 1, 7);
+
+ uint8_t result = (uint8_t)(dayOfWeek + ((dayOfWeek < 0) ? (7+UCAL_SUNDAY ) : UCAL_SUNDAY));
+ return result;
+}
+
+/**
+* Compute the Gregorian calendar year, month, and day of month from
+* the given Julian day. These values are not stored in fields, but in
+* member variables gregorianXxx. Also compute the DAY_OF_WEEK and
+* DOW_LOCAL fields.
+*/
+void Calendar::computeGregorianAndDOWFields(int32_t julianDay, UErrorCode &ec)
+{
+ computeGregorianFields(julianDay, ec);
+
+ // Compute day of week: JD 0 = Monday
+ int32_t dow = julianDayToDayOfWeek(julianDay);
+ internalSet(UCAL_DAY_OF_WEEK,dow);
+
+ // Calculate 1-based localized day of week
+ int32_t dowLocal = dow - getFirstDayOfWeek() + 1;
+ if (dowLocal < 1) {
+ dowLocal += 7;
+ }
+ internalSet(UCAL_DOW_LOCAL,dowLocal);
+ fFields[UCAL_DOW_LOCAL] = dowLocal;
+}
+
+/**
+* Compute the Gregorian calendar year, month, and day of month from the
+* Julian day. These values are not stored in fields, but in member
+* variables gregorianXxx. They are used for time zone computations and by
+* subclasses that are Gregorian derivatives. Subclasses may call this
+* method to perform a Gregorian calendar millis->fields computation.
+* To perform a Gregorian calendar fields->millis computation, call
+* computeGregorianMonthStart().
+* @see #computeGregorianMonthStart
+*/
+void Calendar::computeGregorianFields(int32_t julianDay, UErrorCode & /* ec */) {
+ int32_t gregorianDayOfWeekUnused;
+ Grego::dayToFields(julianDay - kEpochStartAsJulianDay, fGregorianYear, fGregorianMonth, fGregorianDayOfMonth, gregorianDayOfWeekUnused, fGregorianDayOfYear);
+}
+
+/**
+* Compute the fields WEEK_OF_YEAR, YEAR_WOY, WEEK_OF_MONTH,
+* DAY_OF_WEEK_IN_MONTH, and DOW_LOCAL from EXTENDED_YEAR, YEAR,
+* DAY_OF_WEEK, and DAY_OF_YEAR. The latter fields are computed by the
+* subclass based on the calendar system.
+*
+* <p>The YEAR_WOY field is computed simplistically. It is equal to YEAR
+* most of the time, but at the year boundary it may be adjusted to YEAR-1
+* or YEAR+1 to reflect the overlap of a week into an adjacent year. In
+* this case, a simple increment or decrement is performed on YEAR, even
+* though this may yield an invalid YEAR value. For instance, if the YEAR
+* is part of a calendar system with an N-year cycle field CYCLE, then
+* incrementing the YEAR may involve incrementing CYCLE and setting YEAR
+* back to 0 or 1. This is not handled by this code, and in fact cannot be
+* simply handled without having subclasses define an entire parallel set of
+* fields for fields larger than or equal to a year. This additional
+* complexity is not warranted, since the intention of the YEAR_WOY field is
+* to support ISO 8601 notation, so it will typically be used with a
+* proleptic Gregorian calendar, which has no field larger than a year.
+*/
+void Calendar::computeWeekFields(UErrorCode &ec) {
+ if(U_FAILURE(ec)) {
+ return;
+ }
+ int32_t eyear = fFields[UCAL_EXTENDED_YEAR];
+ int32_t year = fFields[UCAL_YEAR];
+ int32_t dayOfWeek = fFields[UCAL_DAY_OF_WEEK];
+ int32_t dayOfYear = fFields[UCAL_DAY_OF_YEAR];
+
+ // WEEK_OF_YEAR start
+ // Compute the week of the year. For the Gregorian calendar, valid week
+ // numbers run from 1 to 52 or 53, depending on the year, the first day
+ // of the week, and the minimal days in the first week. For other
+ // calendars, the valid range may be different -- it depends on the year
+ // length. Days at the start of the year may fall into the last week of
+ // the previous year; days at the end of the year may fall into the
+ // first week of the next year. ASSUME that the year length is less than
+ // 7000 days.
+ int32_t yearOfWeekOfYear = year;
+ int32_t relDow = (dayOfWeek + 7 - getFirstDayOfWeek()) % 7; // 0..6
+ int32_t relDowJan1 = (dayOfWeek - dayOfYear + 7001 - getFirstDayOfWeek()) % 7; // 0..6
+ int32_t woy = (dayOfYear - 1 + relDowJan1) / 7; // 0..53
+ if ((7 - relDowJan1) >= getMinimalDaysInFirstWeek()) {
+ ++woy;
+ }
+
+ // Adjust for weeks at the year end that overlap into the previous or
+ // next calendar year.
+ if (woy == 0) {
+ // We are the last week of the previous year.
+ // Check to see if we are in the last week; if so, we need
+ // to handle the case in which we are the first week of the
+ // next year.
+
+ int32_t prevDoy = dayOfYear + handleGetYearLength(eyear - 1);
+ woy = weekNumber(prevDoy, dayOfWeek);
+ yearOfWeekOfYear--;
+ } else {
+ int32_t lastDoy = handleGetYearLength(eyear);
+ // Fast check: For it to be week 1 of the next year, the DOY
+ // must be on or after L-5, where L is yearLength(), then it
+ // cannot possibly be week 1 of the next year:
+ // L-5 L
+ // doy: 359 360 361 362 363 364 365 001
+ // dow: 1 2 3 4 5 6 7
+ if (dayOfYear >= (lastDoy - 5)) {
+ int32_t lastRelDow = (relDow + lastDoy - dayOfYear) % 7;
+ if (lastRelDow < 0) {
+ lastRelDow += 7;
+ }
+ if (((6 - lastRelDow) >= getMinimalDaysInFirstWeek()) &&
+ ((dayOfYear + 7 - relDow) > lastDoy)) {
+ woy = 1;
+ yearOfWeekOfYear++;
+ }
+ }
+ }
+ fFields[UCAL_WEEK_OF_YEAR] = woy;
+ fFields[UCAL_YEAR_WOY] = yearOfWeekOfYear;
+ // WEEK_OF_YEAR end
+
+ int32_t dayOfMonth = fFields[UCAL_DAY_OF_MONTH];
+ fFields[UCAL_WEEK_OF_MONTH] = weekNumber(dayOfMonth, dayOfWeek);
+ fFields[UCAL_DAY_OF_WEEK_IN_MONTH] = (dayOfMonth-1) / 7 + 1;
+#if defined (U_DEBUG_CAL)
+ if(fFields[UCAL_DAY_OF_WEEK_IN_MONTH]==0) fprintf(stderr, "%s:%d: DOWIM %d on %g\n",
+ __FILE__, __LINE__,fFields[UCAL_DAY_OF_WEEK_IN_MONTH], fTime);
+#endif
+}
+
+
+int32_t Calendar::weekNumber(int32_t desiredDay, int32_t dayOfPeriod, int32_t dayOfWeek)
+{
+ // Determine the day of the week of the first day of the period
+ // in question (either a year or a month). Zero represents the
+ // first day of the week on this calendar.
+ int32_t periodStartDayOfWeek = (dayOfWeek - getFirstDayOfWeek() - dayOfPeriod + 1) % 7;
+ if (periodStartDayOfWeek < 0) periodStartDayOfWeek += 7;
+
+ // Compute the week number. Initially, ignore the first week, which
+ // may be fractional (or may not be). We add periodStartDayOfWeek in
+ // order to fill out the first week, if it is fractional.
+ int32_t weekNo = (desiredDay + periodStartDayOfWeek - 1)/7;
+
+ // If the first week is long enough, then count it. If
+ // the minimal days in the first week is one, or if the period start
+ // is zero, we always increment weekNo.
+ if ((7 - periodStartDayOfWeek) >= getMinimalDaysInFirstWeek()) ++weekNo;
+
+ return weekNo;
+}
+
+void Calendar::handleComputeFields(int32_t /* julianDay */, UErrorCode &/* status */)
+{
+ internalSet(UCAL_MONTH, getGregorianMonth());
+ internalSet(UCAL_DAY_OF_MONTH, getGregorianDayOfMonth());
+ internalSet(UCAL_DAY_OF_YEAR, getGregorianDayOfYear());
+ int32_t eyear = getGregorianYear();
+ internalSet(UCAL_EXTENDED_YEAR, eyear);
+ int32_t era = GregorianCalendar::AD;
+ if (eyear < 1) {
+ era = GregorianCalendar::BC;
+ eyear = 1 - eyear;
+ }
+ internalSet(UCAL_ERA, era);
+ internalSet(UCAL_YEAR, eyear);
+}
+// -------------------------------------
+
+
+void Calendar::roll(EDateFields field, int32_t amount, UErrorCode& status)
+{
+ roll((UCalendarDateFields)field, amount, status);
+}
+
+void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
+{
+ if (amount == 0) {
+ return; // Nothing to do
+ }
+
+ complete(status);
+
+ if(U_FAILURE(status)) {
+ return;
+ }
+ switch (field) {
+ case UCAL_DAY_OF_MONTH:
+ case UCAL_AM_PM:
+ case UCAL_MINUTE:
+ case UCAL_SECOND:
+ case UCAL_MILLISECOND:
+ case UCAL_MILLISECONDS_IN_DAY:
+ case UCAL_ERA:
+ // These are the standard roll instructions. These work for all
+ // simple cases, that is, cases in which the limits are fixed, such
+ // as the hour, the day of the month, and the era.
+ {
+ int32_t min = getActualMinimum(field,status);
+ int32_t max = getActualMaximum(field,status);
+ int32_t gap = max - min + 1;
+
+ int32_t value = internalGet(field) + amount;
+ value = (value - min) % gap;
+ if (value < 0) {
+ value += gap;
+ }
+ value += min;
+
+ set(field, value);
+ return;
+ }
+
+ case UCAL_HOUR:
+ case UCAL_HOUR_OF_DAY:
+ // Rolling the hour is difficult on the ONSET and CEASE days of
+ // daylight savings. For example, if the change occurs at
+ // 2 AM, we have the following progression:
+ // ONSET: 12 Std -> 1 Std -> 3 Dst -> 4 Dst
+ // CEASE: 12 Dst -> 1 Dst -> 1 Std -> 2 Std
+ // To get around this problem we don't use fields; we manipulate
+ // the time in millis directly.
+ {
+ // Assume min == 0 in calculations below
+ double start = getTimeInMillis(status);
+ int32_t oldHour = internalGet(field);
+ int32_t max = getMaximum(field);
+ int32_t newHour = (oldHour + amount) % (max + 1);
+ if (newHour < 0) {
+ newHour += max + 1;
+ }
+ setTimeInMillis(start + kOneHour * (newHour - oldHour),status);
+ return;
+ }
+
+ case UCAL_MONTH:
+ // Rolling the month involves both pinning the final value
+ // and adjusting the DAY_OF_MONTH if necessary. We only adjust the
+ // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
+ // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
+ {
+ int32_t max = getActualMaximum(UCAL_MONTH, status);
+ int32_t mon = (internalGet(UCAL_MONTH) + amount) % (max+1);
+
+ if (mon < 0) {
+ mon += (max + 1);
+ }
+ set(UCAL_MONTH, mon);
+
+ // Keep the day of month in range. We don't want to spill over
+ // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
+ // mar3.
+ pinField(UCAL_DAY_OF_MONTH,status);
+ return;
+ }
+
+ case UCAL_YEAR:
+ case UCAL_YEAR_WOY:
+ case UCAL_EXTENDED_YEAR:
+ // Rolling the year can involve pinning the DAY_OF_MONTH.
+ set(field, internalGet(field) + amount);
+ pinField(UCAL_MONTH,status);
+ pinField(UCAL_DAY_OF_MONTH,status);
+ return;
+
+ case UCAL_WEEK_OF_MONTH:
+ {
+ // This is tricky, because during the roll we may have to shift
+ // to a different day of the week. For example:
+
+ // s m t w r f s
+ // 1 2 3 4 5
+ // 6 7 8 9 10 11 12
+
+ // When rolling from the 6th or 7th back one week, we go to the
+ // 1st (assuming that the first partial week counts). The same
+ // thing happens at the end of the month.
+
+ // The other tricky thing is that we have to figure out whether
+ // the first partial week actually counts or not, based on the
+ // minimal first days in the week. And we have to use the
+ // correct first day of the week to delineate the week
+ // boundaries.
+
+ // Here's our algorithm. First, we find the real boundaries of
+ // the month. Then we discard the first partial week if it
+ // doesn't count in this locale. Then we fill in the ends with
+ // phantom days, so that the first partial week and the last
+ // partial week are full weeks. We then have a nice square
+ // block of weeks. We do the usual rolling within this block,
+ // as is done elsewhere in this method. If we wind up on one of
+ // the phantom days that we added, we recognize this and pin to
+ // the first or the last day of the month. Easy, eh?
+
+ // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
+ // in this locale. We have dow in 0..6.
+ int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
+ if (dow < 0) dow += 7;
+
+ // Find the day of the week (normalized for locale) for the first
+ // of the month.
+ int32_t fdm = (dow - internalGet(UCAL_DAY_OF_MONTH) + 1) % 7;
+ if (fdm < 0) fdm += 7;
+
+ // Get the first day of the first full week of the month,
+ // including phantom days, if any. Figure out if the first week
+ // counts or not; if it counts, then fill in phantom days. If
+ // not, advance to the first real full week (skip the partial week).
+ int32_t start;
+ if ((7 - fdm) < getMinimalDaysInFirstWeek())
+ start = 8 - fdm; // Skip the first partial week
+ else
+ start = 1 - fdm; // This may be zero or negative
+
+ // Get the day of the week (normalized for locale) for the last
+ // day of the month.
+ int32_t monthLen = getActualMaximum(UCAL_DAY_OF_MONTH, status);
+ int32_t ldm = (monthLen - internalGet(UCAL_DAY_OF_MONTH) + dow) % 7;
+ // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.
+
+ // Get the limit day for the blocked-off rectangular month; that
+ // is, the day which is one past the last day of the month,
+ // after the month has already been filled in with phantom days
+ // to fill out the last week. This day has a normalized DOW of 0.
+ int32_t limit = monthLen + 7 - ldm;
+
+ // Now roll between start and (limit - 1).
+ int32_t gap = limit - start;
+ int32_t day_of_month = (internalGet(UCAL_DAY_OF_MONTH) + amount*7 -
+ start) % gap;
+ if (day_of_month < 0) day_of_month += gap;
+ day_of_month += start;
+
+ // Finally, pin to the real start and end of the month.
+ if (day_of_month < 1) day_of_month = 1;
+ if (day_of_month > monthLen) day_of_month = monthLen;
+
+ // Set the DAY_OF_MONTH. We rely on the fact that this field
+ // takes precedence over everything else (since all other fields
+ // are also set at this point). If this fact changes (if the
+ // disambiguation algorithm changes) then we will have to unset
+ // the appropriate fields here so that DAY_OF_MONTH is attended
+ // to.
+ set(UCAL_DAY_OF_MONTH, day_of_month);
+ return;
+ }
+ case UCAL_WEEK_OF_YEAR:
+ {
+ // This follows the outline of WEEK_OF_MONTH, except it applies
+ // to the whole year. Please see the comment for WEEK_OF_MONTH
+ // for general notes.
+
+ // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
+ // in this locale. We have dow in 0..6.
+ int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
+ if (dow < 0) dow += 7;
+
+ // Find the day of the week (normalized for locale) for the first
+ // of the year.
+ int32_t fdy = (dow - internalGet(UCAL_DAY_OF_YEAR) + 1) % 7;
+ if (fdy < 0) fdy += 7;
+
+ // Get the first day of the first full week of the year,
+ // including phantom days, if any. Figure out if the first week
+ // counts or not; if it counts, then fill in phantom days. If
+ // not, advance to the first real full week (skip the partial week).
+ int32_t start;
+ if ((7 - fdy) < getMinimalDaysInFirstWeek())
+ start = 8 - fdy; // Skip the first partial week
+ else
+ start = 1 - fdy; // This may be zero or negative
+
+ // Get the day of the week (normalized for locale) for the last
+ // day of the year.
+ int32_t yearLen = getActualMaximum(UCAL_DAY_OF_YEAR,status);
+ int32_t ldy = (yearLen - internalGet(UCAL_DAY_OF_YEAR) + dow) % 7;
+ // We know yearLen >= DAY_OF_YEAR so we skip the += 7 step here.
+
+ // Get the limit day for the blocked-off rectangular year; that
+ // is, the day which is one past the last day of the year,
+ // after the year has already been filled in with phantom days
+ // to fill out the last week. This day has a normalized DOW of 0.
+ int32_t limit = yearLen + 7 - ldy;
+
+ // Now roll between start and (limit - 1).
+ int32_t gap = limit - start;
+ int32_t day_of_year = (internalGet(UCAL_DAY_OF_YEAR) + amount*7 -
+ start) % gap;
+ if (day_of_year < 0) day_of_year += gap;
+ day_of_year += start;
+
+ // Finally, pin to the real start and end of the month.
+ if (day_of_year < 1) day_of_year = 1;
+ if (day_of_year > yearLen) day_of_year = yearLen;
+
+ // Make sure that the year and day of year are attended to by
+ // clearing other fields which would normally take precedence.
+ // If the disambiguation algorithm is changed, this section will
+ // have to be updated as well.
+ set(UCAL_DAY_OF_YEAR, day_of_year);
+ clear(UCAL_MONTH);
+ return;
+ }
+ case UCAL_DAY_OF_YEAR:
+ {
+ // Roll the day of year using millis. Compute the millis for
+ // the start of the year, and get the length of the year.
+ double delta = amount * kOneDay; // Scale up from days to millis
+ double min2 = internalGet(UCAL_DAY_OF_YEAR)-1;
+ min2 *= kOneDay;
+ min2 = internalGetTime() - min2;
+
+ // double min2 = internalGetTime() - (internalGet(UCAL_DAY_OF_YEAR) - 1.0) * kOneDay;
+ double newtime;
+
+ double yearLength = getActualMaximum(UCAL_DAY_OF_YEAR,status);
+ double oneYear = yearLength;
+ oneYear *= kOneDay;
+ newtime = uprv_fmod((internalGetTime() + delta - min2), oneYear);
+ if (newtime < 0) newtime += oneYear;
+ setTimeInMillis(newtime + min2, status);
+ return;
+ }
+ case UCAL_DAY_OF_WEEK:
+ case UCAL_DOW_LOCAL:
+ {
+ // Roll the day of week using millis. Compute the millis for
+ // the start of the week, using the first day of week setting.
+ // Restrict the millis to [start, start+7days).
+ double delta = amount * kOneDay; // Scale up from days to millis
+ // Compute the number of days before the current day in this
+ // week. This will be a value 0..6.
+ int32_t leadDays = internalGet(field);
+ leadDays -= (field == UCAL_DAY_OF_WEEK) ? getFirstDayOfWeek() : 1;
+ if (leadDays < 0) leadDays += 7;
+ double min2 = internalGetTime() - leadDays * kOneDay;
+ double newtime = uprv_fmod((internalGetTime() + delta - min2), kOneWeek);
+ if (newtime < 0) newtime += kOneWeek;
+ setTimeInMillis(newtime + min2, status);
+ return;
+ }
+ case UCAL_DAY_OF_WEEK_IN_MONTH:
+ {
+ // Roll the day of week in the month using millis. Determine
+ // the first day of the week in the month, and then the last,
+ // and then roll within that range.
+ double delta = amount * kOneWeek; // Scale up from weeks to millis
+ // Find the number of same days of the week before this one
+ // in this month.
+ int32_t preWeeks = (internalGet(UCAL_DAY_OF_MONTH) - 1) / 7;
+ // Find the number of same days of the week after this one
+ // in this month.
+ int32_t postWeeks = (getActualMaximum(UCAL_DAY_OF_MONTH,status) -
+ internalGet(UCAL_DAY_OF_MONTH)) / 7;
+ // From these compute the min and gap millis for rolling.
+ double min2 = internalGetTime() - preWeeks * kOneWeek;
+ double gap2 = kOneWeek * (preWeeks + postWeeks + 1); // Must add 1!
+ // Roll within this range
+ double newtime = uprv_fmod((internalGetTime() + delta - min2), gap2);
+ if (newtime < 0) newtime += gap2;
+ setTimeInMillis(newtime + min2, status);
+ return;
+ }
+ case UCAL_JULIAN_DAY:
+ set(field, internalGet(field) + amount);
+ return;
+ default:
+ // Other fields cannot be rolled by this method
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because of roll on non-rollable field %s\n",
+ __FILE__, __LINE__,fldName(field));
+#endif
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+void Calendar::add(EDateFields field, int32_t amount, UErrorCode& status)
+{
+ Calendar::add((UCalendarDateFields)field, amount, status);
+}
+
+// -------------------------------------
+void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status)
+{
+ if (amount == 0) {
+ return; // Do nothing!
+ }
+
+ // We handle most fields in the same way. The algorithm is to add
+ // a computed amount of millis to the current millis. The only
+ // wrinkle is with DST -- for some fields, like the DAY_OF_MONTH,
+ // we don't want the HOUR to shift due to changes in DST. If the
+ // result of the add operation is to move from DST to Standard, or
+ // vice versa, we need to adjust by an hour forward or back,
+ // respectively. For such fields we set keepHourInvariant to TRUE.
+
+ // We only adjust the DST for fields larger than an hour. For
+ // fields smaller than an hour, we cannot adjust for DST without
+ // causing problems. for instance, if you add one hour to April 5,
+ // 1998, 1:00 AM, in PST, the time becomes "2:00 AM PDT" (an
+ // illegal value), but then the adjustment sees the change and
+ // compensates by subtracting an hour. As a result the time
+ // doesn't advance at all.
+
+ // For some fields larger than a day, such as a UCAL_MONTH, we pin the
+ // UCAL_DAY_OF_MONTH. This allows <March 31>.add(UCAL_MONTH, 1) to be
+ // <April 30>, rather than <April 31> => <May 1>.
+
+ double delta = amount; // delta in ms
+ UBool keepHourInvariant = TRUE;
+
+ switch (field) {
+ case UCAL_ERA:
+ set(field, get(field, status) + amount);
+ pinField(UCAL_ERA, status);
+ return;
+
+ case UCAL_YEAR:
+ case UCAL_EXTENDED_YEAR:
+ case UCAL_YEAR_WOY:
+ case UCAL_MONTH:
+ set(field, get(field, status) + amount);
+ pinField(UCAL_DAY_OF_MONTH, status);
+ return;
+
+ case UCAL_WEEK_OF_YEAR:
+ case UCAL_WEEK_OF_MONTH:
+ case UCAL_DAY_OF_WEEK_IN_MONTH:
+ delta *= kOneWeek;
+ break;
+
+ case UCAL_AM_PM:
+ delta *= 12 * kOneHour;
+ break;
+
+ case UCAL_DAY_OF_MONTH:
+ case UCAL_DAY_OF_YEAR:
+ case UCAL_DAY_OF_WEEK:
+ case UCAL_DOW_LOCAL:
+ case UCAL_JULIAN_DAY:
+ delta *= kOneDay;
+ break;
+
+ case UCAL_HOUR_OF_DAY:
+ case UCAL_HOUR:
+ delta *= kOneHour;
+ keepHourInvariant = FALSE;
+ break;
+
+ case UCAL_MINUTE:
+ delta *= kOneMinute;
+ keepHourInvariant = FALSE;
+ break;
+
+ case UCAL_SECOND:
+ delta *= kOneSecond;
+ keepHourInvariant = FALSE;
+ break;
+
+ case UCAL_MILLISECOND:
+ case UCAL_MILLISECONDS_IN_DAY:
+ keepHourInvariant = FALSE;
+ break;
+
+ default:
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s not addable",
+ __FILE__, __LINE__, fldName(field));
+#endif
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ // throw new IllegalArgumentException("Calendar.add(" + fieldName(field) +
+ // ") not supported");
+ }
+
+ // In order to keep the hour invariant (for fields where this is
+ // appropriate), record the DST_OFFSET before and after the add()
+ // operation. If it has changed, then adjust the millis to
+ // compensate.
+ int32_t dst = 0;
+ int32_t hour = 0;
+ if (keepHourInvariant) {
+ dst = get(UCAL_DST_OFFSET, status);
+ hour = internalGet(UCAL_HOUR_OF_DAY);
+ }
+
+ setTimeInMillis(getTimeInMillis(status) + delta, status);
+
+ if (keepHourInvariant) {
+ dst -= get(UCAL_DST_OFFSET, status);
+ if (dst != 0) {
+ // We have done an hour-invariant adjustment but the
+ // DST offset has altered. We adjust millis to keep
+ // the hour constant. In cases such as midnight after
+ // a DST change which occurs at midnight, there is the
+ // danger of adjusting into a different day. To avoid
+ // this we make the adjustment only if it actually
+ // maintains the hour.
+ double t = internalGetTime();
+ setTimeInMillis(t + dst, status);
+ if (get(UCAL_HOUR_OF_DAY, status) != hour) {
+ setTimeInMillis(t, status);
+ }
+ }
+ }
+}
+
+// -------------------------------------
+int32_t Calendar::fieldDifference(UDate when, EDateFields field, UErrorCode& status) {
+ return fieldDifference(when, (UCalendarDateFields) field, status);
+}
+
+int32_t Calendar::fieldDifference(UDate targetMs, UCalendarDateFields field, UErrorCode& ec) {
+ if (U_FAILURE(ec)) return 0;
+ int32_t min = 0;
+ double startMs = getTimeInMillis(ec);
+ // Always add from the start millis. This accomodates
+ // operations like adding years from February 29, 2000 up to
+ // February 29, 2004. If 1, 1, 1, 1 is added to the year
+ // field, the DOM gets pinned to 28 and stays there, giving an
+ // incorrect DOM difference of 1. We have to add 1, reset, 2,
+ // reset, 3, reset, 4.
+ if (startMs < targetMs) {
+ int32_t max = 1;
+ // Find a value that is too large
+ while (U_SUCCESS(ec)) {
+ setTimeInMillis(startMs, ec);
+ add(field, max, ec);
+ double ms = getTimeInMillis(ec);
+ if (ms == targetMs) {
+ return max;
+ } else if (ms > targetMs) {
+ break;
+ } else {
+ max <<= 1;
+ if (max < 0) {
+ // Field difference too large to fit into int32_t
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
+ __FILE__, __LINE__, fldName(field));
+#endif
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ }
+ }
+ // Do a binary search
+ while ((max - min) > 1 && U_SUCCESS(ec)) {
+ int32_t t = (min + max) / 2;
+ setTimeInMillis(startMs, ec);
+ add(field, t, ec);
+ double ms = getTimeInMillis(ec);
+ if (ms == targetMs) {
+ return t;
+ } else if (ms > targetMs) {
+ max = t;
+ } else {
+ min = t;
+ }
+ }
+ } else if (startMs > targetMs) {
+ int32_t max = -1;
+ // Find a value that is too small
+ while (U_SUCCESS(ec)) {
+ setTimeInMillis(startMs, ec);
+ add(field, max, ec);
+ double ms = getTimeInMillis(ec);
+ if (ms == targetMs) {
+ return max;
+ } else if (ms < targetMs) {
+ break;
+ } else {
+ max <<= 1;
+ if (max == 0) {
+ // Field difference too large to fit into int32_t
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
+ __FILE__, __LINE__, fldName(field));
+#endif
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ }
+ }
+ // Do a binary search
+ while ((min - max) > 1 && U_SUCCESS(ec)) {
+ int32_t t = (min + max) / 2;
+ setTimeInMillis(startMs, ec);
+ add(field, t, ec);
+ double ms = getTimeInMillis(ec);
+ if (ms == targetMs) {
+ return t;
+ } else if (ms < targetMs) {
+ max = t;
+ } else {
+ min = t;
+ }
+ }
+ }
+ // Set calendar to end point
+ setTimeInMillis(startMs, ec);
+ add(field, min, ec);
+
+ /* Test for buffer overflows */
+ if(U_FAILURE(ec)) {
+ return 0;
+ }
+ return min;
+}
+
+// -------------------------------------
+
+void
+Calendar::adoptTimeZone(TimeZone* zone)
+{
+ // Do nothing if passed-in zone is NULL
+ if (zone == NULL) return;
+
+ // fZone should always be non-null
+ if (fZone != NULL) delete fZone;
+ fZone = zone;
+
+ // if the zone changes, we need to recompute the time fields
+ fAreFieldsSet = FALSE;
+}
+
+// -------------------------------------
+void
+Calendar::setTimeZone(const TimeZone& zone)
+{
+ adoptTimeZone(zone.clone());
+}
+
+// -------------------------------------
+
+const TimeZone&
+Calendar::getTimeZone() const
+{
+ return *fZone;
+}
+
+// -------------------------------------
+
+TimeZone*
+Calendar::orphanTimeZone()
+{
+ TimeZone *z = fZone;
+ // we let go of the time zone; the new time zone is the system default time zone
+ fZone = TimeZone::createDefault();
+ return z;
+}
+
+// -------------------------------------
+
+void
+Calendar::setLenient(UBool lenient)
+{
+ fLenient = lenient;
+}
+
+// -------------------------------------
+
+UBool
+Calendar::isLenient() const
+{
+ return fLenient;
+}
+
+// -------------------------------------
+
+void
+Calendar::setFirstDayOfWeek(UCalendarDaysOfWeek value)
+{
+ if (fFirstDayOfWeek != value &&
+ value >= UCAL_SUNDAY && value <= UCAL_SATURDAY) {
+ fFirstDayOfWeek = value;
+ fAreFieldsSet = FALSE;
+ }
+}
+
+// -------------------------------------
+
+Calendar::EDaysOfWeek
+Calendar::getFirstDayOfWeek() const
+{
+ return (Calendar::EDaysOfWeek)fFirstDayOfWeek;
+}
+
+UCalendarDaysOfWeek
+Calendar::getFirstDayOfWeek(UErrorCode & /*status*/) const
+{
+ return fFirstDayOfWeek;
+}
+// -------------------------------------
+
+void
+Calendar::setMinimalDaysInFirstWeek(uint8_t value)
+{
+ // Values less than 1 have the same effect as 1; values greater
+ // than 7 have the same effect as 7. However, we normalize values
+ // so operator== and so forth work.
+ if (value < 1) {
+ value = 1;
+ } else if (value > 7) {
+ value = 7;
+ }
+ if (fMinimalDaysInFirstWeek != value) {
+ fMinimalDaysInFirstWeek = value;
+ fAreFieldsSet = FALSE;
+ }
+}
+
+// -------------------------------------
+
+uint8_t
+Calendar::getMinimalDaysInFirstWeek() const
+{
+ return fMinimalDaysInFirstWeek;
+}
+
+// ------------------------------------- limits
+
+int32_t
+Calendar::getMinimum(EDateFields field) const {
+ return getLimit((UCalendarDateFields) field,UCAL_LIMIT_MINIMUM);
+}
+
+int32_t
+Calendar::getMinimum(UCalendarDateFields field) const
+{
+ return getLimit(field,UCAL_LIMIT_MINIMUM);
+}
+
+// -------------------------------------
+int32_t
+Calendar::getMaximum(EDateFields field) const
+{
+ return getLimit((UCalendarDateFields) field,UCAL_LIMIT_MAXIMUM);
+}
+
+int32_t
+Calendar::getMaximum(UCalendarDateFields field) const
+{
+ return getLimit(field,UCAL_LIMIT_MAXIMUM);
+}
+
+// -------------------------------------
+int32_t
+Calendar::getGreatestMinimum(EDateFields field) const
+{
+ return getLimit((UCalendarDateFields)field,UCAL_LIMIT_GREATEST_MINIMUM);
+}
+
+int32_t
+Calendar::getGreatestMinimum(UCalendarDateFields field) const
+{
+ return getLimit(field,UCAL_LIMIT_GREATEST_MINIMUM);
+}
+
+// -------------------------------------
+int32_t
+Calendar::getLeastMaximum(EDateFields field) const
+{
+ return getLimit((UCalendarDateFields) field,UCAL_LIMIT_LEAST_MAXIMUM);
+}
+
+int32_t
+Calendar::getLeastMaximum(UCalendarDateFields field) const
+{
+ return getLimit( field,UCAL_LIMIT_LEAST_MAXIMUM);
+}
+
+// -------------------------------------
+int32_t
+Calendar::getActualMinimum(EDateFields field, UErrorCode& status) const
+{
+ return getActualMinimum((UCalendarDateFields) field, status);
+}
+
+int32_t Calendar::getLimit(UCalendarDateFields field, ELimitType limitType) const {
+ switch (field) {
+ case UCAL_DAY_OF_WEEK:
+ case UCAL_AM_PM:
+ case UCAL_HOUR:
+ case UCAL_HOUR_OF_DAY:
+ case UCAL_MINUTE:
+ case UCAL_SECOND:
+ case UCAL_MILLISECOND:
+ case UCAL_ZONE_OFFSET:
+ case UCAL_DST_OFFSET:
+ case UCAL_DOW_LOCAL:
+ case UCAL_JULIAN_DAY:
+ case UCAL_MILLISECONDS_IN_DAY:
+ return kCalendarLimits[field][limitType];
+ default:
+ return handleGetLimit(field, limitType);
+ }
+}
+
+
+int32_t
+Calendar::getActualMinimum(UCalendarDateFields field, UErrorCode& status) const
+{
+ int32_t fieldValue = getGreatestMinimum(field);
+ int32_t endValue = getMinimum(field);
+
+ // if we know that the minimum value is always the same, just return it
+ if (fieldValue == endValue) {
+ return fieldValue;
+ }
+
+ // clone the calendar so we don't mess with the real one, and set it to
+ // accept anything for the field values
+ Calendar *work = (Calendar*)this->clone();
+ work->setLenient(TRUE);
+
+ // now try each value from getLeastMaximum() to getMaximum() one by one until
+ // we get a value that normalizes to another value. The last value that
+ // normalizes to itself is the actual minimum for the current date
+ int32_t result = fieldValue;
+
+ do {
+ work->set(field, fieldValue);
+ if (work->get(field, status) != fieldValue) {
+ break;
+ }
+ else {
+ result = fieldValue;
+ fieldValue--;
+ }
+ } while (fieldValue >= endValue);
+
+ delete work;
+
+ /* Test for buffer overflows */
+ if(U_FAILURE(status)) {
+ return 0;
+ }
+ return result;
+}
+
+// -------------------------------------
+
+
+
+/**
+* Ensure that each field is within its valid range by calling {@link
+* #validateField(int)} on each field that has been set. This method
+* should only be called if this calendar is not lenient.
+* @see #isLenient
+* @see #validateField(int)
+*/
+void Calendar::validateFields(UErrorCode &status) {
+ for (int32_t field = 0; U_SUCCESS(status) && (field < UCAL_FIELD_COUNT); field++) {
+ if (isSet((UCalendarDateFields)field)) {
+ validateField((UCalendarDateFields)field, status);
+ }
+ }
+}
+
+/**
+* Validate a single field of this calendar. Subclasses should
+* override this method to validate any calendar-specific fields.
+* Generic fields can be handled by
+* <code>Calendar.validateField()</code>.
+* @see #validateField(int, int, int)
+*/
+void Calendar::validateField(UCalendarDateFields field, UErrorCode &status) {
+ int32_t y;
+ switch (field) {
+ case UCAL_DAY_OF_MONTH:
+ y = handleGetExtendedYear();
+ validateField(field, 1, handleGetMonthLength(y, internalGet(UCAL_MONTH)), status);
+ break;
+ case UCAL_DAY_OF_YEAR:
+ y = handleGetExtendedYear();
+ validateField(field, 1, handleGetYearLength(y), status);
+ break;
+ case UCAL_DAY_OF_WEEK_IN_MONTH:
+ if (internalGet(field) == 0) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because DOW in month cannot be 0\n",
+ __FILE__, __LINE__);
+#endif
+ status = U_ILLEGAL_ARGUMENT_ERROR; // "DAY_OF_WEEK_IN_MONTH cannot be zero"
+ return;
+ }
+ validateField(field, getMinimum(field), getMaximum(field), status);
+ break;
+ default:
+ validateField(field, getMinimum(field), getMaximum(field), status);
+ break;
+ }
+}
+
+/**
+* Validate a single field of this calendar given its minimum and
+* maximum allowed value. If the field is out of range, throw a
+* descriptive <code>IllegalArgumentException</code>. Subclasses may
+* use this method in their implementation of {@link
+* #validateField(int)}.
+*/
+void Calendar::validateField(UCalendarDateFields field, int32_t min, int32_t max, UErrorCode& status)
+{
+ int32_t value = fFields[field];
+ if (value < min || value > max) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: ILLEGAL ARG because of field %s out of range %d..%d at %d\n",
+ __FILE__, __LINE__,fldName(field),min,max,value);
+#endif
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+}
+
+// -------------------------
+
+const UFieldResolutionTable* Calendar::getFieldResolutionTable() const {
+ return kDatePrecedence;
+}
+
+
+UCalendarDateFields Calendar::newerField(UCalendarDateFields defaultField, UCalendarDateFields alternateField) const
+{
+ if (fStamp[alternateField] > fStamp[defaultField]) {
+ return alternateField;
+ }
+ return defaultField;
+}
+
+UCalendarDateFields Calendar::resolveFields(const UFieldResolutionTable* precedenceTable) {
+ int32_t bestField = UCAL_FIELD_COUNT;
+ for (int32_t g=0; precedenceTable[g][0][0] != -1 && (bestField == UCAL_FIELD_COUNT); ++g) {
+ int32_t bestStamp = kUnset;
+ for (int32_t l=0; precedenceTable[g][l][0] != -1; ++l) {
+ int32_t lineStamp = kUnset;
+ // Skip over first entry if it is negative
+ for (int32_t i=((precedenceTable[g][l][0]>=kResolveRemap)?1:0); precedenceTable[g][l][i]!=-1; ++i) {
+ int32_t s = fStamp[precedenceTable[g][l][i]];
+ // If any field is unset then don't use this line
+ if (s == kUnset) {
+ goto linesInGroup;
+ } else if(s > lineStamp) {
+ lineStamp = s;
+ }
+ }
+ // Record new maximum stamp & field no.
+ if (lineStamp > bestStamp) {
+ bestStamp = lineStamp;
+ bestField = precedenceTable[g][l][0]; // First field refers to entire line
+ }
+linesInGroup:
+ ;
+ }
+ }
+ return (UCalendarDateFields)( (bestField>=kResolveRemap)?(bestField&(kResolveRemap-1)):bestField );
+}
+
+const UFieldResolutionTable Calendar::kDatePrecedence[] =
+{
+ {
+ { UCAL_DAY_OF_MONTH, kResolveSTOP },
+ { UCAL_WEEK_OF_YEAR, UCAL_DAY_OF_WEEK, kResolveSTOP },
+ { UCAL_WEEK_OF_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
+ { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
+ { UCAL_WEEK_OF_YEAR, UCAL_DOW_LOCAL, kResolveSTOP },
+ { UCAL_WEEK_OF_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
+ { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
+ { UCAL_DAY_OF_YEAR, kResolveSTOP },
+ { kResolveRemap | UCAL_DAY_OF_MONTH, UCAL_YEAR, kResolveSTOP }, // if YEAR is set over YEAR_WOY use DAY_OF_MONTH
+ { kResolveRemap | UCAL_WEEK_OF_YEAR, UCAL_YEAR_WOY, kResolveSTOP }, // if YEAR_WOY is set, calc based on WEEK_OF_YEAR
+ { kResolveSTOP }
+ },
+ {
+ { UCAL_WEEK_OF_YEAR, kResolveSTOP },
+ { UCAL_WEEK_OF_MONTH, kResolveSTOP },
+ { UCAL_DAY_OF_WEEK_IN_MONTH, kResolveSTOP },
+ { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP },
+ { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP },
+ { kResolveSTOP }
+ },
+ {{kResolveSTOP}}
+};
+
+
+const UFieldResolutionTable Calendar::kDOWPrecedence[] =
+{
+ {
+ { UCAL_DAY_OF_WEEK,kResolveSTOP, kResolveSTOP },
+ { UCAL_DOW_LOCAL,kResolveSTOP, kResolveSTOP },
+ {kResolveSTOP}
+ },
+ {{kResolveSTOP}}
+};
+
+// precedence for calculating a year
+const UFieldResolutionTable Calendar::kYearPrecedence[] =
+{
+ {
+ { UCAL_YEAR, kResolveSTOP },
+ { UCAL_EXTENDED_YEAR, kResolveSTOP },
+ { UCAL_YEAR_WOY, UCAL_WEEK_OF_YEAR, kResolveSTOP }, // YEAR_WOY is useless without WEEK_OF_YEAR
+ { kResolveSTOP }
+ },
+ {{kResolveSTOP}}
+};
+
+
+// -------------------------
+
+
+void Calendar::computeTime(UErrorCode& status) {
+ if (!isLenient()) {
+ validateFields(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+
+ // Compute the Julian day
+ int32_t julianDay = computeJulianDay();
+
+ double millis = Grego::julianDayToMillis(julianDay);
+
+#if defined (U_DEBUG_CAL)
+ // int32_t julianInsanityCheck = (int32_t)Math::floorDivide(millis, kOneDay);
+ // julianInsanityCheck += kEpochStartAsJulianDay;
+ // if(1 || julianInsanityCheck != julianDay) {
+ // fprintf(stderr, "%s:%d- D'oh- computed jules %d, to mills (%s)%.lf, recomputed %d\n",
+ // __FILE__, __LINE__, julianDay, millis<0.0?"NEG":"", millis, julianInsanityCheck);
+ // }
+#endif
+
+ int32_t millisInDay;
+
+ // We only use MILLISECONDS_IN_DAY if it has been set by the user.
+ // This makes it possible for the caller to set the calendar to a
+ // time and call clear(MONTH) to reset the MONTH to January. This
+ // is legacy behavior. Without this, clear(MONTH) has no effect,
+ // since the internally set JULIAN_DAY is used.
+ if (fStamp[UCAL_MILLISECONDS_IN_DAY] >= ((int32_t)kMinimumUserStamp) &&
+ newestStamp(UCAL_AM_PM, UCAL_MILLISECOND, kUnset) <= fStamp[UCAL_MILLISECONDS_IN_DAY]) {
+ millisInDay = internalGet(UCAL_MILLISECONDS_IN_DAY);
+ } else {
+ millisInDay = computeMillisInDay();
+ }
+
+ // Compute the time zone offset and DST offset. There are two potential
+ // ambiguities here. We'll assume a 2:00 am (wall time) switchover time
+ // for discussion purposes here.
+ // 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am
+ // can be in standard or in DST depending. However, 2:00 am is an invalid
+ // representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
+ // We assume standard time, that is, 2:30 am is interpreted as 3:30 am DST.
+ // 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
+ // can be in standard or DST. Both are valid representations (the rep
+ // jumps from 1:59:59 DST to 1:00:00 Std).
+ // Again, we assume standard time, that is, 1:30 am is interpreted as 1:30 am Std.
+ // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
+ // or DST_OFFSET fields; then we use those fields.
+ if (fStamp[UCAL_ZONE_OFFSET] >= ((int32_t)kMinimumUserStamp) ||
+ fStamp[UCAL_DST_OFFSET] >= ((int32_t)kMinimumUserStamp)) {
+ millisInDay -= internalGet(UCAL_ZONE_OFFSET) + internalGet(UCAL_DST_OFFSET);
+ } else {
+ millisInDay -= computeZoneOffset(millis, millisInDay,status);
+ }
+
+ internalSetTime(millis + millisInDay);
+}
+
+/**
+* Compute the milliseconds in the day from the fields. This is a
+* value from 0 to 23:59:59.999 inclusive, unless fields are out of
+* range, in which case it can be an arbitrary value. This value
+* reflects local zone wall time.
+* @stable ICU 2.0
+*/
+int32_t Calendar::computeMillisInDay() {
+ // Do the time portion of the conversion.
+
+ int32_t millisInDay = 0;
+
+ // Find the best set of fields specifying the time of day. There
+ // are only two possibilities here; the HOUR_OF_DAY or the
+ // AM_PM and the HOUR.
+ int32_t hourOfDayStamp = fStamp[UCAL_HOUR_OF_DAY];
+ int32_t hourStamp = (fStamp[UCAL_HOUR] > fStamp[UCAL_AM_PM])?fStamp[UCAL_HOUR]:fStamp[UCAL_AM_PM];
+ int32_t bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
+
+ // Hours
+ if (bestStamp != kUnset) {
+ if (bestStamp == hourOfDayStamp) {
+ // Don't normalize here; let overflow bump into the next period.
+ // This is consistent with how we handle other fields.
+ millisInDay += internalGet(UCAL_HOUR_OF_DAY);
+ } else {
+ // Don't normalize here; let overflow bump into the next period.
+ // This is consistent with how we handle other fields.
+ millisInDay += internalGet(UCAL_HOUR);
+ millisInDay += 12 * internalGet(UCAL_AM_PM); // Default works for unset AM_PM
+ }
+ }
+
+ // We use the fact that unset == 0; we start with millisInDay
+ // == HOUR_OF_DAY.
+ millisInDay *= 60;
+ millisInDay += internalGet(UCAL_MINUTE); // now have minutes
+ millisInDay *= 60;
+ millisInDay += internalGet(UCAL_SECOND); // now have seconds
+ millisInDay *= 1000;
+ millisInDay += internalGet(UCAL_MILLISECOND); // now have millis
+
+ return millisInDay;
+}
+
+/**
+* This method can assume EXTENDED_YEAR has been set.
+* @param millis milliseconds of the date fields
+* @param millisInDay milliseconds of the time fields; may be out
+* or range.
+* @stable ICU 2.0
+*/
+int32_t Calendar::computeZoneOffset(double millis, int32_t millisInDay, UErrorCode &ec) {
+ int32_t rawOffset, dstOffset;
+ getTimeZone().getOffset(millis+millisInDay, TRUE, rawOffset, dstOffset, ec);
+ return rawOffset + dstOffset;
+ // Note: Because we pass in wall millisInDay, rather than
+ // standard millisInDay, we interpret "1:00 am" on the day
+ // of cessation of DST as "1:00 am Std" (assuming the time
+ // of cessation is 2:00 am).
+}
+
+int32_t Calendar::computeJulianDay()
+{
+ // We want to see if any of the date fields is newer than the
+ // JULIAN_DAY. If not, then we use JULIAN_DAY. If so, then we do
+ // the normal resolution. We only use JULIAN_DAY if it has been
+ // set by the user. This makes it possible for the caller to set
+ // the calendar to a time and call clear(MONTH) to reset the MONTH
+ // to January. This is legacy behavior. Without this,
+ // clear(MONTH) has no effect, since the internally set JULIAN_DAY
+ // is used.
+ if (fStamp[UCAL_JULIAN_DAY] >= (int32_t)kMinimumUserStamp) {
+ int32_t bestStamp = newestStamp(UCAL_ERA, UCAL_DAY_OF_WEEK_IN_MONTH, kUnset);
+ bestStamp = newestStamp(UCAL_YEAR_WOY, UCAL_EXTENDED_YEAR, bestStamp);
+ if (bestStamp <= fStamp[UCAL_JULIAN_DAY]) {
+ return internalGet(UCAL_JULIAN_DAY);
+ }
+ }
+
+ UCalendarDateFields bestField = resolveFields(getFieldResolutionTable());
+ if (bestField == UCAL_FIELD_COUNT) {
+ bestField = UCAL_DAY_OF_MONTH;
+ }
+
+ return handleComputeJulianDay(bestField);
+}
+
+// -------------------------------------------
+
+int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField) {
+ UBool useMonth = (bestField == UCAL_DAY_OF_MONTH ||
+ bestField == UCAL_WEEK_OF_MONTH ||
+ bestField == UCAL_DAY_OF_WEEK_IN_MONTH);
+ int32_t year;
+
+ if (bestField == UCAL_WEEK_OF_YEAR) {
+ year = internalGet(UCAL_YEAR_WOY, handleGetExtendedYear());
+ internalSet(UCAL_EXTENDED_YEAR, year);
+ } else {
+ year = handleGetExtendedYear();
+ internalSet(UCAL_EXTENDED_YEAR, year);
+ }
+
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: bestField= %s - y=%d\n", __FILE__, __LINE__, fldName(bestField), year);
+#endif
+
+ // Get the Julian day of the day BEFORE the start of this year.
+ // If useMonth is true, get the day before the start of the month.
+
+ // give calendar subclass a chance to have a default 'first' month
+ int32_t month;
+
+ if(isSet(UCAL_MONTH)) {
+ month = internalGet(UCAL_MONTH);
+ } else {
+ month = getDefaultMonthInYear();
+ }
+
+ int32_t julianDay = handleComputeMonthStart(year, useMonth ? month : 0, useMonth);
+
+ if (bestField == UCAL_DAY_OF_MONTH) {
+
+ // give calendar subclass a chance to have a default 'first' dom
+ int32_t dayOfMonth;
+ if(isSet(UCAL_DAY_OF_MONTH)) {
+ dayOfMonth = internalGet(UCAL_DAY_OF_MONTH,1);
+ } else {
+ dayOfMonth = getDefaultDayInMonth(month);
+ }
+ return julianDay + dayOfMonth;
+ }
+
+ if (bestField == UCAL_DAY_OF_YEAR) {
+ return julianDay + internalGet(UCAL_DAY_OF_YEAR);
+ }
+
+ int32_t firstDayOfWeek = getFirstDayOfWeek(); // Localized fdw
+
+ // At this point julianDay is the 0-based day BEFORE the first day of
+ // January 1, year 1 of the given calendar. If julianDay == 0, it
+ // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
+ // or Gregorian). (or it is before the month we are in, if useMonth is True)
+
+ // At this point we need to process the WEEK_OF_MONTH or
+ // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH.
+ // First, perform initial shared computations. These locate the
+ // first week of the period.
+
+ // Get the 0-based localized DOW of day one of the month or year.
+ // Valid range 0..6.
+ int32_t first = julianDayToDayOfWeek(julianDay + 1) - firstDayOfWeek;
+ if (first < 0) {
+ first += 7;
+ }
+
+ int32_t dowLocal = getLocalDOW();
+
+ // Find the first target DOW (dowLocal) in the month or year.
+ // Actually, it may be just before the first of the month or year.
+ // It will be an integer from -5..7.
+ int32_t date = 1 - first + dowLocal;
+
+ if (bestField == UCAL_DAY_OF_WEEK_IN_MONTH) {
+ // Adjust the target DOW to be in the month or year.
+ if (date < 1) {
+ date += 7;
+ }
+
+ // The only trickiness occurs if the day-of-week-in-month is
+ // negative.
+ int32_t dim = internalGet(UCAL_DAY_OF_WEEK_IN_MONTH, 1);
+ if (dim >= 0) {
+ date += 7*(dim - 1);
+
+ } else {
+ // Move date to the last of this day-of-week in this month,
+ // then back up as needed. If dim==-1, we don't back up at
+ // all. If dim==-2, we back up once, etc. Don't back up
+ // past the first of the given day-of-week in this month.
+ // Note that we handle -2, -3, etc. correctly, even though
+ // values < -1 are technically disallowed.
+ int32_t m = internalGet(UCAL_MONTH, UCAL_JANUARY);
+ int32_t monthLength = handleGetMonthLength(year, m);
+ date += ((monthLength - date) / 7 + dim + 1) * 7;
+ }
+ } else {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - bf= %s\n", __FILE__, __LINE__, fldName(bestField));
+#endif
+
+ if(bestField == UCAL_WEEK_OF_YEAR) { // ------------------------------------- WOY -------------
+ if(!isSet(UCAL_YEAR_WOY) || // YWOY not set at all or
+ ( (resolveFields(kYearPrecedence) != UCAL_YEAR_WOY) // YWOY doesn't have precedence
+ && (fStamp[UCAL_YEAR_WOY]!=kInternallySet) ) ) // (excluding where all fields are internally set - then YWOY is used)
+ {
+ // need to be sure to stay in 'real' year.
+ int32_t woy = internalGet(bestField);
+
+ int32_t nextJulianDay = handleComputeMonthStart(year+1, 0, FALSE); // jd of day before jan 1
+ int32_t nextFirst = julianDayToDayOfWeek(nextJulianDay + 1) - firstDayOfWeek;
+
+ if (nextFirst < 0) { // 0..6 ldow of Jan 1
+ nextFirst += 7;
+ }
+
+ if(woy==1) { // FIRST WEEK ---------------------------------
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - woy=%d, yp=%d, nj(%d)=%d, nf=%d", __FILE__, __LINE__,
+ internalGet(bestField), resolveFields(kYearPrecedence), year+1,
+ nextJulianDay, nextFirst);
+
+ fprintf(stderr, " next: %d DFW, min=%d \n", (7-nextFirst), getMinimalDaysInFirstWeek() );
+#endif
+
+ // nextFirst is now the localized DOW of Jan 1 of y-woy+1
+ if((nextFirst > 0) && // Jan 1 starts on FDOW
+ (7-nextFirst) >= getMinimalDaysInFirstWeek()) // or enough days in the week
+ {
+ // Jan 1 of (yearWoy+1) is in yearWoy+1 - recalculate JD to next year
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - was going to move JD from %d to %d [d%d]\n", __FILE__, __LINE__,
+ julianDay, nextJulianDay, (nextJulianDay-julianDay));
+#endif
+ julianDay = nextJulianDay;
+
+ // recalculate 'first' [0-based local dow of jan 1]
+ first = julianDayToDayOfWeek(julianDay + 1) - firstDayOfWeek;
+ if (first < 0) {
+ first += 7;
+ }
+ // recalculate date.
+ date = 1 - first + dowLocal;
+ }
+ } else if(woy>=getLeastMaximum(bestField)) {
+ // could be in the last week- find out if this JD would overstep
+ int32_t testDate = date;
+ if ((7 - first) < getMinimalDaysInFirstWeek()) {
+ testDate += 7;
+ }
+
+ // Now adjust for the week number.
+ testDate += 7 * (woy - 1);
+
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - y=%d, y-1=%d doy%d, njd%d (C.F. %d)\n",
+ __FILE__, __LINE__, year, year-1, testDate, julianDay+testDate, nextJulianDay);
+#endif
+ if(julianDay+testDate > nextJulianDay) { // is it past Dec 31? (nextJulianDay is day BEFORE year+1's Jan 1)
+ // Fire up the calculating engines.. retry YWOY = (year-1)
+ julianDay = handleComputeMonthStart(year-1, 0, FALSE); // jd before Jan 1 of previous year
+ first = julianDayToDayOfWeek(julianDay + 1) - firstDayOfWeek; // 0 based local dow of first week
+
+ if(first < 0) { // 0..6
+ first += 7;
+ }
+ date = 1 - first + dowLocal;
+
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - date now %d, jd%d, ywoy%d\n",
+ __FILE__, __LINE__, date, julianDay, year-1);
+#endif
+
+
+ } /* correction needed */
+ } /* leastmaximum */
+ } /* resolvefields(year) != year_woy */
+ } /* bestfield != week_of_year */
+
+ // assert(bestField == WEEK_OF_MONTH || bestField == WEEK_OF_YEAR)
+ // Adjust for minimal days in first week
+ if ((7 - first) < getMinimalDaysInFirstWeek()) {
+ date += 7;
+ }
+
+ // Now adjust for the week number.
+ date += 7 * (internalGet(bestField) - 1);
+ }
+
+ return julianDay + date;
+}
+
+int32_t
+Calendar::getDefaultMonthInYear()
+{
+ return 0;
+}
+
+int32_t
+Calendar::getDefaultDayInMonth(int32_t /*month*/)
+{
+ return 1;
+}
+
+
+int32_t Calendar::getLocalDOW()
+{
+ // Get zero-based localized DOW, valid range 0..6. This is the DOW
+ // we are looking for.
+ int32_t dowLocal = 0;
+ switch (resolveFields(kDOWPrecedence)) {
+ case UCAL_DAY_OF_WEEK:
+ dowLocal = internalGet(UCAL_DAY_OF_WEEK) - fFirstDayOfWeek;
+ break;
+ case UCAL_DOW_LOCAL:
+ dowLocal = internalGet(UCAL_DOW_LOCAL) - 1;
+ break;
+ default:
+ break;
+ }
+ dowLocal = dowLocal % 7;
+ if (dowLocal < 0) {
+ dowLocal += 7;
+ }
+ return dowLocal;
+}
+
+int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy)
+{
+ // We have UCAL_YEAR_WOY and UCAL_WEEK_OF_YEAR - from those, determine
+ // what year we fall in, so that other code can set it properly.
+ // (code borrowed from computeWeekFields and handleComputeJulianDay)
+ //return yearWoy;
+
+ // First, we need a reliable DOW.
+ UCalendarDateFields bestField = resolveFields(kDatePrecedence); // !! Note: if subclasses have a different table, they should override handleGetExtendedYearFromWeekFields
+
+ // Now, a local DOW
+ int32_t dowLocal = getLocalDOW(); // 0..6
+ int32_t firstDayOfWeek = getFirstDayOfWeek(); // Localized fdw
+ int32_t jan1Start = handleComputeMonthStart(yearWoy, 0, FALSE);
+ int32_t nextJan1Start = handleComputeMonthStart(yearWoy+1, 0, FALSE); // next year's Jan1 start
+
+ // At this point julianDay is the 0-based day BEFORE the first day of
+ // January 1, year 1 of the given calendar. If julianDay == 0, it
+ // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
+ // or Gregorian). (or it is before the month we are in, if useMonth is True)
+
+ // At this point we need to process the WEEK_OF_MONTH or
+ // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH.
+ // First, perform initial shared computations. These locate the
+ // first week of the period.
+
+ // Get the 0-based localized DOW of day one of the month or year.
+ // Valid range 0..6.
+ int32_t first = julianDayToDayOfWeek(jan1Start + 1) - firstDayOfWeek;
+ if (first < 0) {
+ first += 7;
+ }
+ int32_t nextFirst = julianDayToDayOfWeek(nextJan1Start + 1) - firstDayOfWeek;
+ if (nextFirst < 0) {
+ nextFirst += 7;
+ }
+
+ int32_t minDays = getMinimalDaysInFirstWeek();
+ UBool jan1InPrevYear = FALSE; // January 1st in the year of WOY is the 1st week? (i.e. first week is < minimal )
+ //UBool nextJan1InPrevYear = FALSE; // January 1st of Year of WOY + 1 is in the first week?
+
+ if((7 - first) < minDays) {
+ jan1InPrevYear = TRUE;
+ }
+
+ // if((7 - nextFirst) < minDays) {
+ // nextJan1InPrevYear = TRUE;
+ // }
+
+ switch(bestField) {
+ case UCAL_WEEK_OF_YEAR:
+ if(woy == 1) {
+ if(jan1InPrevYear == TRUE) {
+ // the first week of January is in the previous year
+ // therefore WOY1 is always solidly within yearWoy
+ return yearWoy;
+ } else {
+ // First WOY is split between two years
+ if( dowLocal < first) { // we are prior to Jan 1
+ return yearWoy-1; // previous year
+ } else {
+ return yearWoy; // in this year
+ }
+ }
+ } else if(woy >= getLeastMaximum(bestField)) {
+ // we _might_ be in the last week..
+ int32_t jd = // Calculate JD of our target day:
+ jan1Start + // JD of Jan 1
+ (7-first) + // days in the first week (Jan 1.. )
+ (woy-1)*7 + // add the weeks of the year
+ dowLocal; // the local dow (0..6) of last week
+ if(jan1InPrevYear==FALSE) {
+ jd -= 7; // woy already includes Jan 1's week.
+ }
+
+ if( (jd+1) >= nextJan1Start ) {
+ // we are in week 52 or 53 etc. - actual year is yearWoy+1
+ return yearWoy+1;
+ } else {
+ // still in yearWoy;
+ return yearWoy;
+ }
+ } else {
+ // we're not possibly in the last week -must be ywoy
+ return yearWoy;
+ }
+ break;
+
+ case UCAL_DATE:
+ if((internalGet(UCAL_MONTH)==0) &&
+ (woy >= getLeastMaximum(UCAL_WEEK_OF_YEAR))) {
+ return yearWoy+1; // month 0, late woy = in the next year
+ } else if(woy==1) {
+ //if(nextJan1InPrevYear) {
+ if(internalGet(UCAL_MONTH)==0) {
+ return yearWoy;
+ } else {
+ return yearWoy-1;
+ }
+ //}
+ }
+
+ //(internalGet(UCAL_DATE) <= (7-first)) /* && in minDow */ ) {
+ //within 1st week and in this month..
+ //return yearWoy+1;
+ return yearWoy;
+ break;
+
+ default: // assume the year is appropriate
+ return yearWoy;
+ break;
+ }
+
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - forgot a return on field %s\n", __FILE__, __LINE__, fldName(bestField));
+#endif
+
+ return yearWoy;
+}
+
+int32_t Calendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const
+{
+ return handleComputeMonthStart(extendedYear, month+1, TRUE) -
+ handleComputeMonthStart(extendedYear, month, TRUE);
+}
+
+int32_t Calendar::handleGetYearLength(int32_t eyear) const {
+ return handleComputeMonthStart(eyear+1, 0, FALSE) -
+ handleComputeMonthStart(eyear, 0, FALSE);
+}
+
+int32_t
+Calendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
+{
+ int32_t result;
+ switch (field) {
+ case UCAL_DATE:
+ {
+ if(U_FAILURE(status)) return 0;
+ Calendar *cal = clone();
+ if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; }
+ cal->prepareGetActual(field,FALSE,status);
+ result = handleGetMonthLength(cal->get(UCAL_EXTENDED_YEAR, status), cal->get(UCAL_MONTH, status));
+ delete cal;
+ }
+ break;
+
+ case UCAL_DAY_OF_YEAR:
+ {
+ if(U_FAILURE(status)) return 0;
+ Calendar *cal = clone();
+ if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; }
+ cal->prepareGetActual(field,FALSE,status);
+ result = handleGetYearLength(cal->get(UCAL_EXTENDED_YEAR, status));
+ delete cal;
+ }
+ break;
+
+ case UCAL_DAY_OF_WEEK:
+ case UCAL_AM_PM:
+ case UCAL_HOUR:
+ case UCAL_HOUR_OF_DAY:
+ case UCAL_MINUTE:
+ case UCAL_SECOND:
+ case UCAL_MILLISECOND:
+ case UCAL_ZONE_OFFSET:
+ case UCAL_DST_OFFSET:
+ case UCAL_DOW_LOCAL:
+ case UCAL_JULIAN_DAY:
+ case UCAL_MILLISECONDS_IN_DAY:
+ // These fields all have fixed minima/maxima
+ result = getMaximum(field);
+ break;
+
+ default:
+ // For all other fields, do it the hard way....
+ result = getActualHelper(field, getLeastMaximum(field), getMaximum(field),status);
+ break;
+ }
+ return result;
+}
+
+
+/**
+* Prepare this calendar for computing the actual minimum or maximum.
+* This method modifies this calendar's fields; it is called on a
+* temporary calendar.
+*
+* <p>Rationale: The semantics of getActualXxx() is to return the
+* maximum or minimum value that the given field can take, taking into
+* account other relevant fields. In general these other fields are
+* larger fields. For example, when computing the actual maximum
+* DATE, the current value of DATE itself is ignored,
+* as is the value of any field smaller.
+*
+* <p>The time fields all have fixed minima and maxima, so we don't
+* need to worry about them. This also lets us set the
+* MILLISECONDS_IN_DAY to zero to erase any effects the time fields
+* might have when computing date fields.
+*
+* <p>DAY_OF_WEEK is adjusted specially for the WEEK_OF_MONTH and
+* WEEK_OF_YEAR fields to ensure that they are computed correctly.
+* @internal
+*/
+void Calendar::prepareGetActual(UCalendarDateFields field, UBool isMinimum, UErrorCode &status)
+{
+ set(UCAL_MILLISECONDS_IN_DAY, 0);
+
+ switch (field) {
+ case UCAL_YEAR:
+ case UCAL_YEAR_WOY:
+ case UCAL_EXTENDED_YEAR:
+ set(UCAL_DAY_OF_YEAR, getGreatestMinimum(UCAL_DAY_OF_YEAR));
+ break;
+
+ case UCAL_MONTH:
+ set(UCAL_DATE, getGreatestMinimum(UCAL_DATE));
+ break;
+
+ case UCAL_DAY_OF_WEEK_IN_MONTH:
+ // For dowim, the maximum occurs for the DOW of the first of the
+ // month.
+ set(UCAL_DATE, 1);
+ set(UCAL_DAY_OF_WEEK, get(UCAL_DAY_OF_WEEK, status)); // Make this user set
+ break;
+
+ case UCAL_WEEK_OF_MONTH:
+ case UCAL_WEEK_OF_YEAR:
+ // If we're counting weeks, set the day of the week to either the
+ // first or last localized DOW. We know the last week of a month
+ // or year will contain the first day of the week, and that the
+ // first week will contain the last DOW.
+ {
+ int32_t dow = fFirstDayOfWeek;
+ if (isMinimum) {
+ dow = (dow + 6) % 7; // set to last DOW
+ if (dow < UCAL_SUNDAY) {
+ dow += 7;
+ }
+ }
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "prepareGetActualHelper(WOM/WOY) - dow=%d\n", dow);
+#endif
+ set(UCAL_DAY_OF_WEEK, dow);
+ }
+ break;
+ default:
+ ;
+ }
+
+ // Do this last to give it the newest time stamp
+ set(field, getGreatestMinimum(field));
+}
+
+int32_t Calendar::getActualHelper(UCalendarDateFields field, int32_t startValue, int32_t endValue, UErrorCode &status) const
+{
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "getActualHelper(%d,%d .. %d, %s)\n", field, startValue, endValue, u_errorName(status));
+#endif
+ if (startValue == endValue) {
+ // if we know that the maximum value is always the same, just return it
+ return startValue;
+ }
+
+ int32_t delta = (endValue > startValue) ? 1 : -1;
+
+ // clone the calendar so we don't mess with the real one, and set it to
+ // accept anything for the field values
+ if(U_FAILURE(status)) return startValue;
+ Calendar *work = clone();
+ if(!work) { status = U_MEMORY_ALLOCATION_ERROR; return startValue; }
+ work->setLenient(TRUE);
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - getActualHelper - %s\n", __FILE__, __LINE__, u_errorName(status));
+#endif
+ work->prepareGetActual(field, delta < 0, status);
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - getActualHelper - %s\n", __FILE__, __LINE__, u_errorName(status));
+#endif
+
+ // now try each value from the start to the end one by one until
+ // we get a value that normalizes to another value. The last value that
+ // normalizes to itself is the actual maximum for the current date
+ int32_t result = startValue;
+ do {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - getActualHelper - %s\n", __FILE__, __LINE__, u_errorName(status));
+#endif
+ work->set(field, startValue);
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - getActualHelper - %s (set to %d)\n", __FILE__, __LINE__, u_errorName(status), startValue);
+#endif
+ if (work->get(field, status) != startValue) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "getActualHelper(fld %d) - got %d (not %d), BREAK - %s\n", field, work->get(field,status), startValue, u_errorName(status));
+#endif
+ break;
+ } else {
+ result = startValue;
+ startValue += delta;
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "getActualHelper(%d) result=%d (start), start += %d to %d\n", field, result, delta, startValue);
+#endif
+ }
+ } while (result != endValue && U_SUCCESS(status));
+ delete work;
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "getActualHelper(%d) = %d\n", field, result);
+#endif
+ return result;
+}
+
+
+
+
+// -------------------------------------
+
+void
+Calendar::setWeekCountData(const Locale& desiredLocale, const char *type, UErrorCode& status)
+{
+ // Read the week count data from the resource bundle. This should
+ // have the form:
+ //
+ // DateTimeElements:intvector {
+ // 1, // first day of week
+ // 1 // min days in week
+ // }
+ // Both have a range of 1..7
+
+
+ if (U_FAILURE(status)) return;
+
+ fFirstDayOfWeek = UCAL_SUNDAY;
+ fMinimalDaysInFirstWeek = 1;
+
+ CalendarData calData(desiredLocale, type, status);
+ // If the resource data doesn't seem to be present at all, then use last-resort
+ // hard-coded data.
+ UResourceBundle *dateTimeElements = calData.getByKey(gDateTimeElements, status);
+
+ if (U_FAILURE(status))
+ {
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, " Failure loading dateTimeElements = %s\n", u_errorName(status));
+#endif
+ status = U_USING_FALLBACK_WARNING;
+ return;
+ }
+
+ U_LOCALE_BASED(locBased, *this);
+ locBased.setLocaleIDs(ures_getLocaleByType(dateTimeElements, ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(dateTimeElements, ULOC_ACTUAL_LOCALE, &status));
+ if (U_SUCCESS(status)) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, " Valid=%s, Actual=%s\n", validLocale, actualLocale);
+#endif
+ int32_t arrLen;
+ const int32_t *dateTimeElementsArr = ures_getIntVector(dateTimeElements, &arrLen, &status);
+
+ if(U_SUCCESS(status) && arrLen == 2
+ && 1 <= dateTimeElementsArr[0] && dateTimeElementsArr[0] <= 7
+ && 1 <= dateTimeElementsArr[1] && dateTimeElementsArr[1] <= 7)
+ {
+ fFirstDayOfWeek = (UCalendarDaysOfWeek)dateTimeElementsArr[0];
+ fMinimalDaysInFirstWeek = (uint8_t)dateTimeElementsArr[1];
+ }
+ else {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ }
+
+ // do NOT close dateTimeElements
+}
+
+/**
+* Recompute the time and update the status fields isTimeSet
+* and areFieldsSet. Callers should check isTimeSet and only
+* call this method if isTimeSet is false.
+*/
+void
+Calendar::updateTime(UErrorCode& status)
+{
+ computeTime(status);
+ if(U_FAILURE(status))
+ return;
+
+ // If we are lenient, we need to recompute the fields to normalize
+ // the values. Also, if we haven't set all the fields yet (i.e.,
+ // in a newly-created object), we need to fill in the fields. [LIU]
+ if (isLenient() || ! fAreAllFieldsSet)
+ fAreFieldsSet = FALSE;
+
+ fIsTimeSet = TRUE;
+ fAreFieldsVirtuallySet = FALSE;
+}
+
+Locale
+Calendar::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
+ U_LOCALE_BASED(locBased, *this);
+ return locBased.getLocale(type, status);
+}
+
+const char *
+Calendar::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
+ U_LOCALE_BASED(locBased, *this);
+ return locBased.getLocaleID(type, status);
+}
+
+// Deprecated function. This doesn't need to be inline.
+void
+Calendar::internalSet(EDateFields field, int32_t value)
+{
+ internalSet((UCalendarDateFields) field, value);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/casetrn.cpp b/Build/source/libs/icu/icu-xetex/i18n/casetrn.cpp
new file mode 100644
index 00000000000..96778af6522
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/casetrn.cpp
@@ -0,0 +1,194 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: casetrn.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2004sep03
+* created by: Markus W. Scherer
+*
+* Implementation class for lower-/upper-/title-casing transliterators.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "tolowtrn.h"
+#include "ucase.h"
+#include "cpputils.h"
+
+/* case context iterator using a Replaceable */
+U_CFUNC UChar32 U_CALLCONV
+utrans_rep_caseContextIterator(void *context, int8_t dir)
+{
+ U_NAMESPACE_USE
+
+ UCaseContext *csc=(UCaseContext *)context;
+ Replaceable *rep=(Replaceable *)csc->p;
+ UChar32 c;
+
+ if(dir<0) {
+ /* reset for backward iteration */
+ csc->index=csc->cpStart;
+ csc->dir=dir;
+ } else if(dir>0) {
+ /* reset for forward iteration */
+ csc->index=csc->cpLimit;
+ csc->dir=dir;
+ } else {
+ /* continue current iteration direction */
+ dir=csc->dir;
+ }
+
+ // automatically adjust start and limit if the Replaceable disagrees
+ // with the original values
+ if(dir<0) {
+ if(csc->start<csc->index) {
+ c=rep->char32At(csc->index-1);
+ if(c<0) {
+ csc->start=csc->index;
+ } else {
+ csc->index-=U16_LENGTH(c);
+ return c;
+ }
+ }
+ } else {
+ // detect, and store in csc->b1, if we hit the limit
+ if(csc->index<csc->limit) {
+ c=rep->char32At(csc->index);
+ if(c<0) {
+ csc->limit=csc->index;
+ csc->b1=TRUE;
+ } else {
+ csc->index+=U16_LENGTH(c);
+ return c;
+ }
+ } else {
+ csc->b1=TRUE;
+ }
+ }
+ return U_SENTINEL;
+}
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CaseMapTransliterator)
+
+/**
+ * Constructs a transliterator.
+ */
+CaseMapTransliterator::CaseMapTransliterator(const UnicodeString &id, UCaseMapFull *map) :
+ Transliterator(id, 0),
+ fCsp(NULL),
+ fMap(map)
+{
+ UErrorCode errorCode = U_ZERO_ERROR;
+ fCsp = ucase_getSingleton(&errorCode); // expect to get NULL if failure
+
+ // TODO test incremental mode with context-sensitive text (e.g. greek sigma)
+ // TODO need to call setMaximumContextLength()?!
+}
+
+/**
+ * Destructor.
+ */
+CaseMapTransliterator::~CaseMapTransliterator() {
+}
+
+/**
+ * Copy constructor.
+ */
+CaseMapTransliterator::CaseMapTransliterator(const CaseMapTransliterator& o) :
+ Transliterator(o),
+ fCsp(o.fCsp), fMap(o.fMap)
+{
+}
+
+/**
+ * Assignment operator.
+ */
+/*CaseMapTransliterator& CaseMapTransliterator::operator=(const CaseMapTransliterator& o) {
+ Transliterator::operator=(o);
+ fCsp = o.fCsp;
+ fMap = o.fMap;
+ return *this;
+}*/
+
+/**
+ * Transliterator API.
+ */
+Transliterator* CaseMapTransliterator::clone(void) const {
+ return new CaseMapTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void CaseMapTransliterator::handleTransliterate(Replaceable& text,
+ UTransPosition& offsets,
+ UBool isIncremental) const
+{
+ if (offsets.start >= offsets.limit) {
+ return;
+ }
+
+ UCaseContext csc;
+ uprv_memset(&csc, 0, sizeof(csc));
+ csc.p = &text;
+ csc.start = offsets.contextStart;
+ csc.limit = offsets.contextLimit;
+
+ UnicodeString tmp;
+ const UChar *s;
+ UChar32 c;
+ int32_t textPos, delta, result, locCache=0;
+
+ for(textPos=offsets.start; textPos<offsets.limit;) {
+ csc.cpStart=textPos;
+ c=text.char32At(textPos);
+ csc.cpLimit=textPos+=U16_LENGTH(c);
+
+ result=fMap(fCsp, c, utrans_rep_caseContextIterator, &csc, &s, "", &locCache);
+
+ if(csc.b1 && isIncremental) {
+ // fMap() tried to look beyond the context limit
+ // wait for more input
+ offsets.start=csc.cpStart;
+ return;
+ }
+
+ if(result>=0) {
+ // replace the current code point with its full case mapping result
+ // see UCASE_MAX_STRING_LENGTH
+ if(result<=UCASE_MAX_STRING_LENGTH) {
+ // string s[result]
+ tmp.setTo(FALSE, s, result);
+ delta=result-U16_LENGTH(c);
+ } else {
+ // single code point
+ tmp.setTo(result);
+ delta=tmp.length()-U16_LENGTH(c);
+ }
+ text.handleReplaceBetween(csc.cpStart, textPos, tmp);
+ if(delta!=0) {
+ textPos+=delta;
+ csc.limit=offsets.contextLimit+=delta;
+ offsets.limit+=delta;
+ }
+ }
+ }
+ offsets.start=textPos;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/casetrn.h b/Build/source/libs/icu/icu-xetex/i18n/casetrn.h
new file mode 100644
index 00000000000..2e6ab15161b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/casetrn.h
@@ -0,0 +1,104 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: casetrn.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2004sep03
+* created by: Markus W. Scherer
+*
+* Implementation class for lower-/upper-/title-casing transliterators.
+*/
+
+#ifndef __CASETRN_H__
+#define __CASETRN_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "ucase.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that performs locale-sensitive
+ * case mapping.
+ */
+class U_I18N_API CaseMapTransliterator : public Transliterator {
+public:
+ /**
+ * Constructs a transliterator.
+ * @param loc the given locale.
+ * @param id the transliterator ID.
+ * @param map the full case mapping function (see ucase.h)
+ */
+ CaseMapTransliterator(const UnicodeString &id, UCaseMapFull *map);
+
+ /**
+ * Destructor.
+ */
+ virtual ~CaseMapTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ CaseMapTransliterator(const CaseMapTransliterator&);
+
+ /**
+ * Transliterator API.
+ * @return a copy of the object.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+protected:
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param offset the start and limit of the text, the position
+ * of the cursor, and the start and limit of transliteration.
+ * @param incremental if true, assume more text may be coming after
+ * pos.contextLimit. Otherwise, assume the text is complete.
+ */
+ virtual void handleTransliterate(Replaceable& text,
+ UTransPosition& offsets,
+ UBool isIncremental) const;
+
+ const UCaseProps *fCsp;
+ UCaseMapFull *fMap;
+
+private:
+ /**
+ * Assignment operator.
+ */
+ CaseMapTransliterator& operator=(const CaseMapTransliterator&);
+
+};
+
+U_NAMESPACE_END
+
+/** case context iterator using a Replaceable. This must be a C function because it is a callback. */
+U_CFUNC UChar32 U_CALLCONV
+utrans_rep_caseContextIterator(void *context, int8_t dir);
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/chnsecal.cpp b/Build/source/libs/icu/icu-xetex/i18n/chnsecal.cpp
new file mode 100644
index 00000000000..fda2aaca16e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/chnsecal.cpp
@@ -0,0 +1,13 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 2003-2004, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ ******************************************************************************
+ *
+ *
+ ******************************************************************************
+ */
+#include "chnsecal.h"
+
+// Placeholder for now until the implementation can be finished.
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/chnsecal.h b/Build/source/libs/icu/icu-xetex/i18n/chnsecal.h
new file mode 100644
index 00000000000..9d5a9f7709e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/chnsecal.h
@@ -0,0 +1,11 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2003, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ ******************************************************************************
+ *
+ *
+ **************************************************************************
+ */
+
+// placeholder
diff --git a/Build/source/libs/icu/icu-xetex/i18n/choicfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/choicfmt.cpp
new file mode 100644
index 00000000000..b9caa9a3b9c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/choicfmt.cpp
@@ -0,0 +1,746 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File CHOICFMT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/20/97 helena Finished first cut of implementation and got rid
+* of nextDouble/previousDouble and replaced with
+* boolean array.
+* 4/10/97 aliu Clean up. Modified to work on AIX.
+* 06/04/97 helena Fixed applyPattern(), toPattern() and not to include
+* wchar.h.
+* 07/09/97 helena Made ParsePosition into a class.
+* 08/06/97 nos removed overloaded constructor, fixed 'format(array)'
+* 07/22/98 stephen JDK 1.2 Sync - removed UBool array (doubleFlags)
+* 02/22/99 stephen Removed character literals for EBCDIC safety
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/choicfmt.h"
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+#include "cpputils.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include <stdio.h>
+#include <float.h>
+
+// *****************************************************************************
+// class ChoiceFormat
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat)
+
+// Special characters used by ChoiceFormat. There are two characters
+// used interchangeably to indicate <=. Either is parsed, but only
+// LESS_EQUAL is generated by toPattern().
+#define SINGLE_QUOTE ((UChar)0x0027) /*'*/
+#define LESS_THAN ((UChar)0x003C) /*<*/
+#define LESS_EQUAL ((UChar)0x0023) /*#*/
+#define LESS_EQUAL2 ((UChar)0x2264)
+#define VERTICAL_BAR ((UChar)0x007C) /*|*/
+#define MINUS ((UChar)0x002D) /*-*/
+#define INFINITY ((UChar)0x221E)
+
+static const UChar gPositiveInfinity[] = {INFINITY, 0};
+static const UChar gNegativeInfinity[] = {MINUS, INFINITY, 0};
+#define POSITIVE_INF_STRLEN 1
+#define NEGATIVE_INF_STRLEN 2
+
+// -------------------------------------
+// Creates a ChoiceFormat instance based on the pattern.
+
+ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
+ UErrorCode& status)
+: fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0),
+ fCount(0)
+{
+ applyPattern(newPattern, status);
+}
+
+// -------------------------------------
+// Creates a ChoiceFormat instance with the limit array and
+// format strings for each limit.
+
+ChoiceFormat::ChoiceFormat(const double* limits,
+ const UnicodeString* formats,
+ int32_t cnt )
+: fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0),
+ fCount(0)
+{
+ setChoices(limits, formats, cnt );
+}
+
+// -------------------------------------
+
+ChoiceFormat::ChoiceFormat(const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t cnt )
+: fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0),
+ fCount(0)
+{
+ setChoices(limits, closures, formats, cnt );
+}
+
+// -------------------------------------
+// copy constructor
+
+ChoiceFormat::ChoiceFormat(const ChoiceFormat& that)
+: NumberFormat(that),
+ fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0)
+{
+ *this = that;
+}
+
+// -------------------------------------
+// Private constructor that creates a
+// ChoiceFormat instance based on the
+// pattern and populates UParseError
+
+ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
+ UParseError& parseError,
+ UErrorCode& status)
+: fChoiceLimits(0),
+ fClosures(0),
+ fChoiceFormats(0),
+ fCount(0)
+{
+ applyPattern(newPattern,parseError, status);
+}
+// -------------------------------------
+
+UBool
+ChoiceFormat::operator==(const Format& that) const
+{
+ if (this == &that) return TRUE;
+ if (!NumberFormat::operator==(that)) return FALSE;
+ ChoiceFormat& thatAlias = (ChoiceFormat&)that;
+ if (fCount != thatAlias.fCount) return FALSE;
+ // Checks the limits, the corresponding format string and LE or LT flags.
+ // LE means less than and equal to, LT means less than.
+ for (int32_t i = 0; i < fCount; i++) {
+ if ((fChoiceLimits[i] != thatAlias.fChoiceLimits[i]) ||
+ (fClosures[i] != thatAlias.fClosures[i]) ||
+ (fChoiceFormats[i] != thatAlias.fChoiceFormats[i]))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// -------------------------------------
+// copy constructor
+
+const ChoiceFormat&
+ChoiceFormat::operator=(const ChoiceFormat& that)
+{
+ if (this != &that) {
+ NumberFormat::operator=(that);
+ fCount = that.fCount;
+ uprv_free(fChoiceLimits);
+ fChoiceLimits = NULL;
+ uprv_free(fClosures);
+ fClosures = NULL;
+ delete [] fChoiceFormats;
+ fChoiceFormats = NULL;
+
+ fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
+ fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
+ fChoiceFormats = new UnicodeString[fCount];
+
+ uprv_arrayCopy(that.fChoiceLimits, fChoiceLimits, fCount);
+ uprv_arrayCopy(that.fClosures, fClosures, fCount);
+ uprv_arrayCopy(that.fChoiceFormats, fChoiceFormats, fCount);
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+ChoiceFormat::~ChoiceFormat()
+{
+ uprv_free(fChoiceLimits);
+ fChoiceLimits = NULL;
+ uprv_free(fClosures);
+ fClosures = NULL;
+ delete [] fChoiceFormats;
+ fChoiceFormats = NULL;
+ fCount = 0;
+}
+
+/**
+ * Convert a string to a double value
+ */
+double
+ChoiceFormat::stod(const UnicodeString& string)
+{
+ char source[256];
+ char* end;
+
+ string.extract(0, string.length(), source, (int32_t)sizeof(source), US_INV); /* invariant codepage */
+ return uprv_strtod(source,&end);
+}
+
+// -------------------------------------
+
+/**
+ * Convert a double value to a string
+ */
+UnicodeString&
+ChoiceFormat::dtos(double value,
+ UnicodeString& string)
+{
+ /* Buffer to contain the digits and any extra formatting stuff. */
+ char temp[DBL_DIG + 16];
+ char *itrPtr = temp;
+ char *startPtr;
+
+ sprintf(temp, "%.*f", DBL_DIG, value);
+
+ /* Find and convert the decimal point.
+ Using setlocale on some machines will cause sprintf to use a comma for certain locales.
+ */
+ while (*itrPtr && (*itrPtr == '-' || isdigit(*itrPtr))) {
+ itrPtr++;
+ }
+ if (*itrPtr) {
+ *itrPtr = '.';
+ }
+
+ /* remove trailing zeros, except the one after '.' */
+ startPtr = itrPtr + 1;
+ itrPtr = uprv_strchr(startPtr, 0);
+ while(--itrPtr > startPtr){
+ if(*itrPtr == '0'){
+ *itrPtr = 0;
+ }else{
+ break;
+ }
+ }
+ string = UnicodeString(temp, -1, US_INV); /* invariant codepage */
+ return string;
+}
+
+// -------------------------------------
+// calls the overloaded applyPattern method.
+
+void
+ChoiceFormat::applyPattern(const UnicodeString& pattern,
+ UErrorCode& status)
+{
+ UParseError parseError;
+ applyPattern(pattern, parseError, status);
+}
+
+// -------------------------------------
+// Applies the pattern to this ChoiceFormat instance.
+
+void
+ChoiceFormat::applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status))
+ {
+ return;
+ }
+
+ // Clear error struct
+ parseError.offset = -1;
+ parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
+
+ // Perform 2 passes. The first computes the number of limits in
+ // this pattern (fCount), which is 1 more than the number of
+ // literal VERTICAL_BAR characters.
+ int32_t count = 1;
+ int32_t i;
+ for (i=0; i<pattern.length(); ++i) {
+ UChar c = pattern[i];
+ if (c == SINGLE_QUOTE) {
+ // Skip over the entire quote, including embedded
+ // contiguous pairs of SINGLE_QUOTE.
+ for (;;) {
+ do {
+ ++i;
+ } while (i<pattern.length() &&
+ pattern[i] != SINGLE_QUOTE);
+ if ((i+1)<pattern.length() &&
+ pattern[i+1] == SINGLE_QUOTE) {
+ // SINGLE_QUOTE pair; skip over it
+ ++i;
+ } else {
+ break;
+ }
+ }
+ } else if (c == VERTICAL_BAR) {
+ ++count;
+ }
+ }
+
+ // Allocate the required storage.
+ double *newLimits = (double*) uprv_malloc( sizeof(double) * count);
+ /* test for NULL */
+ if (newLimits == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ UBool *newClosures = (UBool*) uprv_malloc( sizeof(UBool) * count);
+ /* test for NULL */
+ if (newClosures == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(newLimits);
+ return;
+ }
+ UnicodeString *newFormats = new UnicodeString[count];
+ /* test for NULL */
+ if (newFormats == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(newLimits);
+ uprv_free(newClosures);
+ return;
+ }
+
+ // Perform the second pass
+ int32_t k = 0; // index into newXxx[] arrays
+ UnicodeString buf; // scratch buffer
+ UBool inQuote = FALSE;
+ UBool inNumber = TRUE; // TRUE before < or #, FALSE after
+
+ for (i=0; i<pattern.length(); ++i) {
+ UChar c = pattern[i];
+ if (c == SINGLE_QUOTE) {
+ // Check for SINGLE_QUOTE pair indicating a literal quote
+ if ((i+1) < pattern.length() &&
+ pattern[i+1] == SINGLE_QUOTE) {
+ buf += SINGLE_QUOTE;
+ ++i;
+ } else {
+ inQuote = !inQuote;
+ }
+ } else if (inQuote) {
+ buf += c;
+ } else if (c == LESS_THAN || c == LESS_EQUAL || c == LESS_EQUAL2) {
+ if (!inNumber || buf.length() == 0) {
+ goto error;
+ }
+ inNumber = FALSE;
+
+ double limit;
+ buf.trim();
+ if (!buf.compare(gPositiveInfinity, POSITIVE_INF_STRLEN)) {
+ limit = uprv_getInfinity();
+ } else if (!buf.compare(gNegativeInfinity, NEGATIVE_INF_STRLEN)) {
+ limit = -uprv_getInfinity();
+ } else {
+ limit = stod(buf);
+ }
+
+ if (k == count) {
+ // This shouldn't happen. If it does, it means that
+ // the count determined in the first pass did not
+ // match the number of elements found in the second
+ // pass.
+ goto error;
+ }
+ newLimits[k] = limit;
+ newClosures[k] = (c == LESS_THAN);
+
+ if (k > 0 && limit <= newLimits[k-1]) {
+ // Each limit must be strictly > than the previous
+ // limit. One exception: Two subsequent limits may be
+ // == if the first closure is FALSE and the second
+ // closure is TRUE. This places the limit value in
+ // the second interval.
+ if (!(limit == newLimits[k-1] &&
+ !newClosures[k-1] &&
+ newClosures[k])) {
+ goto error;
+ }
+ }
+
+ buf.truncate(0);
+ } else if (c == VERTICAL_BAR) {
+ if (inNumber) {
+ goto error;
+ }
+ inNumber = TRUE;
+
+ newFormats[k] = buf;
+ ++k;
+ buf.truncate(0);
+ } else {
+ buf += c;
+ }
+ }
+
+ if (k != (count-1) || inNumber || inQuote) {
+ goto error;
+ }
+ newFormats[k] = buf;
+
+ // Don't modify this object until the parse succeeds
+ uprv_free(fChoiceLimits);
+ uprv_free(fClosures);
+ delete[] fChoiceFormats;
+ fCount = count;
+ fChoiceLimits = newLimits;
+ fClosures = newClosures;
+ fChoiceFormats = newFormats;
+ return;
+
+error:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ syntaxError(pattern,i,parseError);
+ uprv_free(newLimits);
+ uprv_free(newClosures);
+ delete[] newFormats;
+ return;
+
+}
+// -------------------------------------
+// Reconstruct the original input pattern.
+
+UnicodeString&
+ChoiceFormat::toPattern(UnicodeString& result) const
+{
+ result.remove();
+ for (int32_t i = 0; i < fCount; ++i) {
+ if (i != 0) {
+ result += VERTICAL_BAR;
+ }
+ UnicodeString buf;
+ if (uprv_isPositiveInfinity(fChoiceLimits[i])) {
+ result += INFINITY;
+ } else if (uprv_isNegativeInfinity(fChoiceLimits[i])) {
+ result += MINUS;
+ result += INFINITY;
+ } else {
+ result += dtos(fChoiceLimits[i], buf);
+ }
+ if (fClosures[i]) {
+ result += LESS_THAN;
+ } else {
+ result += LESS_EQUAL;
+ }
+ // Append fChoiceFormats[i], using quotes if there are special
+ // characters. Single quotes themselves must be escaped in
+ // either case.
+ const UnicodeString& text = fChoiceFormats[i];
+ UBool needQuote = text.indexOf(LESS_THAN) >= 0
+ || text.indexOf(LESS_EQUAL) >= 0
+ || text.indexOf(LESS_EQUAL2) >= 0
+ || text.indexOf(VERTICAL_BAR) >= 0;
+ if (needQuote) {
+ result += SINGLE_QUOTE;
+ }
+ if (text.indexOf(SINGLE_QUOTE) < 0) {
+ result += text;
+ }
+ else {
+ for (int32_t j = 0; j < text.length(); ++j) {
+ UChar c = text[j];
+ result += c;
+ if (c == SINGLE_QUOTE) {
+ result += c;
+ }
+ }
+ }
+ if (needQuote) {
+ result += SINGLE_QUOTE;
+ }
+ }
+
+ return result;
+}
+
+#ifdef U_USE_CHOICE_FORMAT_DEPRECATES
+// -------------------------------------
+// Adopts the limit and format arrays.
+
+void
+ChoiceFormat::adoptChoices(double *limits,
+ UnicodeString *formats,
+ int32_t cnt )
+{
+ adoptChoices(limits, (UBool *)0, formats, cnt);
+}
+
+// -------------------------------------
+// Adopts the limit and format arrays.
+
+void
+ChoiceFormat::adoptChoices(double *limits,
+ UBool *closures,
+ UnicodeString *formats,
+ int32_t cnt )
+{
+ if(limits == 0 || formats == 0)
+ return;
+
+ uprv_free(fChoiceLimits);
+ uprv_free(fClosures);
+ delete [] fChoiceFormats;
+ fChoiceLimits = limits;
+ fClosures = closures;
+ fChoiceFormats = formats;
+ fCount = cnt;
+
+ if (fClosures == 0) {
+ fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
+ int32_t i;
+ for (i=0; i<fCount; ++i) {
+ fClosures[i] = FALSE;
+ }
+ }
+}
+#endif
+
+// -------------------------------------
+// Sets the limit and format arrays.
+void
+ChoiceFormat::setChoices( const double* limits,
+ const UnicodeString* formats,
+ int32_t cnt )
+{
+ setChoices(limits, 0, formats, cnt);
+}
+
+// -------------------------------------
+// Sets the limit and format arrays.
+void
+ChoiceFormat::setChoices( const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t cnt )
+{
+ if(limits == 0 || formats == 0)
+ return;
+
+ uprv_free(fChoiceLimits);
+ uprv_free(fClosures);
+ delete [] fChoiceFormats;
+
+ // Note that the old arrays are deleted and this owns
+ // the created array.
+ fCount = cnt;
+ fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
+ fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
+ fChoiceFormats = new UnicodeString[fCount];
+
+ uprv_arrayCopy(limits, fChoiceLimits, fCount);
+ uprv_arrayCopy(formats, fChoiceFormats, fCount);
+
+ if (closures != 0) {
+ uprv_arrayCopy(closures, fClosures, fCount);
+ } else {
+ int32_t i;
+ for (i=0; i<fCount; ++i) {
+ fClosures[i] = FALSE;
+ }
+ }
+}
+
+// -------------------------------------
+// Gets the limit array.
+
+const double*
+ChoiceFormat::getLimits(int32_t& cnt) const
+{
+ cnt = fCount;
+ return fChoiceLimits;
+}
+
+// -------------------------------------
+// Gets the closures array.
+
+const UBool*
+ChoiceFormat::getClosures(int32_t& cnt) const
+{
+ cnt = fCount;
+ return fClosures;
+}
+
+// -------------------------------------
+// Gets the format array.
+
+const UnicodeString*
+ChoiceFormat::getFormats(int32_t& cnt) const
+{
+ cnt = fCount;
+ return fChoiceFormats;
+}
+
+// -------------------------------------
+// Formats an int64 number, it's actually formatted as
+// a double. The returned format string may differ
+// from the input number because of this.
+
+UnicodeString&
+ChoiceFormat::format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& status) const
+{
+ return format((double) number, appendTo, status);
+}
+
+// -------------------------------------
+// Formats a long number, it's actually formatted as
+// a double. The returned format string may differ
+// from the input number because of this.
+
+UnicodeString&
+ChoiceFormat::format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& status) const
+{
+ return format((double) number, appendTo, status);
+}
+
+// -------------------------------------
+// Formats a double number.
+
+UnicodeString&
+ChoiceFormat::format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& /*pos*/) const
+{
+ // find the number
+ int32_t i;
+ for (i = 0; i < fCount; ++i) {
+ if (fClosures[i]) {
+ if (!(number > fChoiceLimits[i])) {
+ // same as number <= fChoiceLimits, except catches NaN
+ break;
+ }
+ } else if (!(number >= fChoiceLimits[i])) {
+ // same as number < fChoiceLimits, except catches NaN
+ break;
+ }
+ }
+ --i;
+ if (i < 0) {
+ i = 0;
+ }
+ // return either a formatted number, or a string
+ appendTo += fChoiceFormats[i];
+ return appendTo;
+}
+
+// -------------------------------------
+// Formats an array of objects. Checks if the data type of the objects
+// to get the right value for formatting.
+
+UnicodeString&
+ChoiceFormat::format(const Formattable* objs,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ if(cnt < 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+
+ UnicodeString buffer;
+ for (int32_t i = 0; i < cnt; i++) {
+ double objDouble = objs[i].getDouble(status);
+ if (U_SUCCESS(status)) {
+ buffer.remove();
+ appendTo += format(objDouble, buffer, pos);
+ }
+ }
+
+ return appendTo;
+}
+
+// -------------------------------------
+// Formats an array of objects. Checks if the data type of the objects
+// to get the right value for formatting.
+
+UnicodeString&
+ChoiceFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ return NumberFormat::format(obj, appendTo, pos, status);
+}
+// -------------------------------------
+
+void
+ChoiceFormat::parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& status) const
+{
+ // find the best number (defined as the one with the longest parse)
+ int32_t start = status.getIndex();
+ int32_t furthest = start;
+ double bestNumber = uprv_getNaN();
+ double tempNumber = 0.0;
+ for (int i = 0; i < fCount; ++i) {
+ int32_t len = fChoiceFormats[i].length();
+ if (text.compare(start, len, fChoiceFormats[i]) == 0) {
+ status.setIndex(start + len);
+ tempNumber = fChoiceLimits[i];
+ if (status.getIndex() > furthest) {
+ furthest = status.getIndex();
+ bestNumber = tempNumber;
+ if (furthest == text.length())
+ break;
+ }
+ }
+ }
+ status.setIndex(furthest);
+ if (status.getIndex() == start) {
+ status.setErrorIndex(furthest);
+ }
+ result.setDouble(bestNumber);
+}
+
+// -------------------------------------
+// Parses the text and return the Formattable object.
+
+void
+ChoiceFormat::parse(const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const
+{
+ NumberFormat::parse(text, result, status);
+}
+
+// -------------------------------------
+
+Format*
+ChoiceFormat::clone() const
+{
+ ChoiceFormat *aCopy = new ChoiceFormat(*this);
+ return aCopy;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/coleitr.cpp b/Build/source/libs/icu/icu-xetex/i18n/coleitr.cpp
new file mode 100644
index 00000000000..96aa9681264
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/coleitr.cpp
@@ -0,0 +1,493 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+/*
+* File coleitr.cpp
+*
+*
+*
+* Created by: Helena Shih
+*
+* Modification History:
+*
+* Date Name Description
+*
+* 6/23/97 helena Adding comments to make code more readable.
+* 08/03/98 erm Synched with 1.2 version of CollationElementIterator.java
+* 12/10/99 aliu Ported Thai collation support from Java.
+* 01/25/01 swquek Modified to a C++ wrapper calling C APIs (ucoliter.h)
+* 02/19/01 swquek Removed CollationElementsIterator() since it is
+* private constructor and no calls are made to it
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coleitr.h"
+#include "unicode/ustring.h"
+#include "ucol_imp.h"
+#include "cmemory.h"
+
+
+/* Constants --------------------------------------------------------------- */
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationElementIterator)
+
+/* CollationElementIterator public constructor/destructor ------------------ */
+
+CollationElementIterator::CollationElementIterator(
+ const CollationElementIterator& other)
+ : UObject(other), isDataOwned_(TRUE)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ m_data_ = ucol_openElements(other.m_data_->iteratordata_.coll, NULL, 0,
+ &status);
+
+ *this = other;
+}
+
+CollationElementIterator::~CollationElementIterator()
+{
+ if (isDataOwned_) {
+ ucol_closeElements(m_data_);
+ }
+}
+
+/* CollationElementIterator public methods --------------------------------- */
+
+int32_t CollationElementIterator::getOffset() const
+{
+ return ucol_getOffset(m_data_);
+}
+
+/**
+* Get the ordering priority of the next character in the string.
+* @return the next character's ordering. Returns NULLORDER if an error has
+* occured or if the end of string has been reached
+*/
+int32_t CollationElementIterator::next(UErrorCode& status)
+{
+ return ucol_next(m_data_, &status);
+}
+
+UBool CollationElementIterator::operator!=(
+ const CollationElementIterator& other) const
+{
+ return !(*this == other);
+}
+
+UBool CollationElementIterator::operator==(
+ const CollationElementIterator& that) const
+{
+ if (this == &that || m_data_ == that.m_data_) {
+ return TRUE;
+ }
+
+ // option comparison
+ if (m_data_->iteratordata_.coll != that.m_data_->iteratordata_.coll)
+ {
+ return FALSE;
+ }
+
+ // the constructor and setText always sets a length
+ // and we only compare the string not the contents of the normalization
+ // buffer
+ int thislength = m_data_->iteratordata_.endp -
+ m_data_->iteratordata_.string;
+ int thatlength = that.m_data_->iteratordata_.endp -
+ that.m_data_->iteratordata_.string;
+
+ if (thislength != thatlength) {
+ return FALSE;
+ }
+
+ if (uprv_memcmp(m_data_->iteratordata_.string,
+ that.m_data_->iteratordata_.string,
+ thislength * U_SIZEOF_UCHAR) != 0) {
+ return FALSE;
+ }
+ if (getOffset() != that.getOffset()) {
+ return FALSE;
+ }
+
+ // checking normalization buffer
+ if ((m_data_->iteratordata_.flags & UCOL_ITER_HASLEN) == 0) {
+ if ((that.m_data_->iteratordata_.flags & UCOL_ITER_HASLEN) != 0) {
+ return FALSE;
+ }
+ // both are in the normalization buffer
+ if (m_data_->iteratordata_.pos
+ - m_data_->iteratordata_.writableBuffer
+ != that.m_data_->iteratordata_.pos
+ - that.m_data_->iteratordata_.writableBuffer) {
+ // not in the same position in the normalization buffer
+ return FALSE;
+ }
+ }
+ else if ((that.m_data_->iteratordata_.flags & UCOL_ITER_HASLEN) == 0) {
+ return FALSE;
+ }
+ // checking ce position
+ return (m_data_->iteratordata_.CEpos - m_data_->iteratordata_.CEs)
+ == (that.m_data_->iteratordata_.CEpos
+ - that.m_data_->iteratordata_.CEs);
+}
+
+/**
+* Get the ordering priority of the previous collation element in the string.
+* @param status the error code status.
+* @return the previous element's ordering. Returns NULLORDER if an error has
+* occured or if the start of string has been reached.
+*/
+int32_t CollationElementIterator::previous(UErrorCode& status)
+{
+ return ucol_previous(m_data_, &status);
+}
+
+/**
+* Resets the cursor to the beginning of the string.
+*/
+void CollationElementIterator::reset()
+{
+ ucol_reset(m_data_);
+}
+
+void CollationElementIterator::setOffset(int32_t newOffset,
+ UErrorCode& status)
+{
+ ucol_setOffset(m_data_, newOffset, &status);
+}
+
+/**
+* Sets the source to the new source string.
+*/
+void CollationElementIterator::setText(const UnicodeString& source,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ int32_t length = source.length();
+ UChar *string = NULL;
+ if (m_data_->isWritable && m_data_->iteratordata_.string != NULL) {
+ uprv_free(m_data_->iteratordata_.string);
+ }
+ m_data_->isWritable = TRUE;
+ if (length > 0) {
+ string = (UChar *)uprv_malloc(U_SIZEOF_UCHAR * length);
+ /* test for NULL */
+ if (string == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ u_memcpy(string, source.getBuffer(), length);
+ }
+ else {
+ string = (UChar *)uprv_malloc(U_SIZEOF_UCHAR);
+ /* test for NULL */
+ if (string == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ *string = 0;
+ }
+ uprv_init_collIterate(m_data_->iteratordata_.coll, string, length,
+ &m_data_->iteratordata_);
+
+ m_data_->reset_ = TRUE;
+}
+
+// Sets the source to the new character iterator.
+void CollationElementIterator::setText(CharacterIterator& source,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status))
+ return;
+
+ int32_t length = source.getLength();
+ UChar *buffer = NULL;
+
+ if (length == 0) {
+ buffer = (UChar *)uprv_malloc(U_SIZEOF_UCHAR);
+ /* test for NULL */
+ if (buffer == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ *buffer = 0;
+ }
+ else {
+ buffer = (UChar *)uprv_malloc(U_SIZEOF_UCHAR * length);
+ /* test for NULL */
+ if (buffer == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ /*
+ Using this constructor will prevent buffer from being removed when
+ string gets removed
+ */
+ UnicodeString string;
+ source.getText(string);
+ u_memcpy(buffer, string.getBuffer(), length);
+ }
+
+ if (m_data_->isWritable && m_data_->iteratordata_.string != NULL) {
+ uprv_free(m_data_->iteratordata_.string);
+ }
+ m_data_->isWritable = TRUE;
+ uprv_init_collIterate(m_data_->iteratordata_.coll, buffer, length,
+ &m_data_->iteratordata_);
+ m_data_->reset_ = TRUE;
+}
+
+int32_t CollationElementIterator::strengthOrder(int32_t order) const
+{
+ UCollationStrength s = ucol_getStrength(m_data_->iteratordata_.coll);
+ // Mask off the unwanted differences.
+ if (s == UCOL_PRIMARY) {
+ order &= RuleBasedCollator::PRIMARYDIFFERENCEONLY;
+ }
+ else if (s == UCOL_SECONDARY) {
+ order &= RuleBasedCollator::SECONDARYDIFFERENCEONLY;
+ }
+
+ return order;
+}
+
+/* CollationElementIterator private constructors/destructors --------------- */
+
+/**
+* This is the "real" constructor for this class; it constructs an iterator
+* over the source text using the specified collator
+*/
+CollationElementIterator::CollationElementIterator(
+ const UnicodeString& sourceText,
+ const RuleBasedCollator* order,
+ UErrorCode& status)
+ : isDataOwned_(TRUE)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ int32_t length = sourceText.length();
+ UChar *string = NULL;
+
+ if (length > 0) {
+ string = (UChar *)uprv_malloc(U_SIZEOF_UCHAR * length);
+ /* test for NULL */
+ if (string == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ /*
+ Using this constructor will prevent buffer from being removed when
+ string gets removed
+ */
+ u_memcpy(string, sourceText.getBuffer(), length);
+ }
+ else {
+ string = (UChar *)uprv_malloc(U_SIZEOF_UCHAR);
+ /* test for NULL */
+ if (string == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ *string = 0;
+ }
+ m_data_ = ucol_openElements(order->ucollator, string, length, &status);
+
+ /* Test for buffer overflows */
+ if (U_FAILURE(status)) {
+ return;
+ }
+ m_data_->isWritable = TRUE;
+}
+
+/**
+* This is the "real" constructor for this class; it constructs an iterator over
+* the source text using the specified collator
+*/
+CollationElementIterator::CollationElementIterator(
+ const CharacterIterator& sourceText,
+ const RuleBasedCollator* order,
+ UErrorCode& status)
+ : isDataOwned_(TRUE)
+{
+ if (U_FAILURE(status))
+ return;
+
+ // **** should I just drop this test? ****
+ /*
+ if ( sourceText.endIndex() != 0 )
+ {
+ // A CollationElementIterator is really a two-layered beast.
+ // Internally it uses a Normalizer to munge the source text into a form
+ // where all "composed" Unicode characters (such as \u00FC) are split into a
+ // normal character and a combining accent character.
+ // Afterward, CollationElementIterator does its own processing to handle
+ // expanding and contracting collation sequences, ignorables, and so on.
+
+ Normalizer::EMode decomp = order->getStrength() == Collator::IDENTICAL
+ ? Normalizer::NO_OP : order->getDecomposition();
+
+ text = new Normalizer(sourceText, decomp);
+ if (text == NULL)
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ */
+ int32_t length = sourceText.getLength();
+ UChar *buffer;
+ if (length > 0) {
+ buffer = (UChar *)uprv_malloc(U_SIZEOF_UCHAR * length);
+ /* test for NULL */
+ if (buffer == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ /*
+ Using this constructor will prevent buffer from being removed when
+ string gets removed
+ */
+ UnicodeString string(buffer, length, length);
+ ((CharacterIterator &)sourceText).getText(string);
+ const UChar *temp = string.getBuffer();
+ u_memcpy(buffer, temp, length);
+ }
+ else {
+ buffer = (UChar *)uprv_malloc(U_SIZEOF_UCHAR);
+ /* test for NULL */
+ if (buffer == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ *buffer = 0;
+ }
+ m_data_ = ucol_openElements(order->ucollator, buffer, length, &status);
+
+ /* Test for buffer overflows */
+ if (U_FAILURE(status)) {
+ return;
+ }
+ m_data_->isWritable = TRUE;
+}
+
+/* CollationElementIterator protected methods ----------------------------- */
+
+const CollationElementIterator& CollationElementIterator::operator=(
+ const CollationElementIterator& other)
+{
+ if (this != &other)
+ {
+ UCollationElements *ucolelem = this->m_data_;
+ UCollationElements *otherucolelem = other.m_data_;
+ collIterate *coliter = &(ucolelem->iteratordata_);
+ collIterate *othercoliter = &(otherucolelem->iteratordata_);
+ int length = 0;
+
+ // checking only UCOL_ITER_HASLEN is not enough here as we may be in
+ // the normalization buffer
+ length = othercoliter->endp - othercoliter->string;
+
+ ucolelem->reset_ = otherucolelem->reset_;
+ ucolelem->isWritable = TRUE;
+
+ /* create a duplicate of string */
+ if (length > 0) {
+ coliter->string = (UChar *)uprv_malloc(length * U_SIZEOF_UCHAR);
+ if(coliter->string != NULL) {
+ uprv_memcpy(coliter->string, othercoliter->string,
+ length * U_SIZEOF_UCHAR);
+ } else { // Error: couldn't allocate memory. No copying should be done
+ length = 0;
+ }
+ }
+ else {
+ coliter->string = NULL;
+ }
+
+ /* start and end of string */
+ coliter->endp = coliter->string + length;
+
+ /* handle writable buffer here */
+
+ if (othercoliter->flags & UCOL_ITER_INNORMBUF) {
+ uint32_t wlength = u_strlen(othercoliter->writableBuffer) + 1;
+ if (wlength < coliter->writableBufSize) {
+ uprv_memcpy(coliter->stackWritableBuffer,
+ othercoliter->stackWritableBuffer,
+ wlength * U_SIZEOF_UCHAR);
+ }
+ else {
+ if (coliter->writableBuffer != coliter->stackWritableBuffer) {
+ uprv_free(coliter->writableBuffer);
+ }
+ coliter->writableBuffer = (UChar *)uprv_malloc(
+ wlength * U_SIZEOF_UCHAR);
+ if(coliter->writableBuffer != NULL) {
+ uprv_memcpy(coliter->writableBuffer,
+ othercoliter->writableBuffer,
+ wlength * U_SIZEOF_UCHAR);
+ coliter->writableBufSize = wlength;
+ } else { // Error: couldn't allocate memory for writableBuffer
+ coliter->writableBufSize = 0;
+ }
+ }
+ }
+
+ /* current position */
+ if (othercoliter->pos >= othercoliter->string &&
+ othercoliter->pos <= othercoliter->endp)
+ {
+ coliter->pos = coliter->string +
+ (othercoliter->pos - othercoliter->string);
+ }
+ else if (coliter->writableBuffer != NULL) {
+ coliter->pos = coliter->writableBuffer +
+ (othercoliter->pos - othercoliter->writableBuffer);
+ }
+ else {
+ // Error: couldn't allocate memory for writableBuffer
+ coliter->pos = NULL;
+ }
+
+ /* CE buffer */
+ int32_t CEsize = (int32_t)(othercoliter->CEpos - othercoliter->CEs);
+ if (CEsize > 0) {
+ uprv_memcpy(coliter->CEs, othercoliter->CEs, CEsize);
+ }
+ coliter->toReturn = coliter->CEs +
+ (othercoliter->toReturn - othercoliter->CEs);
+ coliter->CEpos = coliter->CEs + CEsize;
+
+ if (othercoliter->fcdPosition != NULL) {
+ coliter->fcdPosition = coliter->string +
+ (othercoliter->fcdPosition
+ - othercoliter->string);
+ }
+ else {
+ coliter->fcdPosition = NULL;
+ }
+ coliter->flags = othercoliter->flags/*| UCOL_ITER_HASLEN*/;
+ coliter->origFlags = othercoliter->origFlags;
+ coliter->coll = othercoliter->coll;
+ this->isDataOwned_ = TRUE;
+ }
+
+ return *this;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+/* eof */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/coll.cpp b/Build/source/libs/icu/icu-xetex/i18n/coll.cpp
new file mode 100644
index 00000000000..88229893de0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/coll.cpp
@@ -0,0 +1,809 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ ******************************************************************************
+ */
+
+/**
+ * File coll.cpp
+ *
+ * Created by: Helena Shih
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 2/5/97 aliu Modified createDefault to load collation data from
+ * binary files when possible. Added related methods
+ * createCollationFromFile, chopLocale, createPathName.
+ * 2/11/97 aliu Added methods addToCache, findInCache, which implement
+ * a Collation cache. Modified createDefault to look in
+ * cache first, and also to store newly created Collation
+ * objects in the cache. Modified to not use gLocPath.
+ * 2/12/97 aliu Modified to create objects from RuleBasedCollator cache.
+ * Moved cache out of Collation class.
+ * 2/13/97 aliu Moved several methods out of this class and into
+ * RuleBasedCollator, with modifications. Modified
+ * createDefault() to call new RuleBasedCollator(Locale&)
+ * constructor. General clean up and documentation.
+ * 2/20/97 helena Added clone, operator==, operator!=, operator=, and copy
+ * constructor.
+ * 05/06/97 helena Added memory allocation error detection.
+ * 05/08/97 helena Added createInstance().
+ * 6/20/97 helena Java class name change.
+ * 04/23/99 stephen Removed EDecompositionMode, merged with
+ * Normalizer::EMode
+ * 11/23/9 srl Inlining of some critical functions
+ * 01/29/01 synwee Modified into a C++ wrapper calling C APIs (ucol.h)
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "ucol_imp.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "umutex.h"
+#include "servloc.h"
+#include "ustrenum.h"
+#include "ucln_in.h"
+
+static U_NAMESPACE_QUALIFIER Locale* availableLocaleList = NULL;
+static int32_t availableLocaleListCount;
+static U_NAMESPACE_QUALIFIER ICULocaleService* gService = NULL;
+
+/**
+ * Release all static memory held by collator.
+ */
+U_CDECL_BEGIN
+static UBool U_CALLCONV collator_cleanup(void) {
+#if !UCONFIG_NO_SERVICE
+ if (gService) {
+ delete gService;
+ gService = NULL;
+ }
+#endif
+ if (availableLocaleList) {
+ delete []availableLocaleList;
+ availableLocaleList = NULL;
+ }
+ availableLocaleListCount = 0;
+
+ return TRUE;
+}
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+#if !UCONFIG_NO_SERVICE
+
+// ------------------------------------------
+//
+// Registration
+//
+
+//-------------------------------------------
+
+CollatorFactory::~CollatorFactory() {}
+
+//-------------------------------------------
+
+UBool
+CollatorFactory::visible(void) const {
+ return TRUE;
+}
+
+//-------------------------------------------
+
+UnicodeString&
+CollatorFactory::getDisplayName(const Locale& objectLocale,
+ const Locale& displayLocale,
+ UnicodeString& result)
+{
+ return objectLocale.getDisplayName(displayLocale, result);
+}
+
+// -------------------------------------
+
+class ICUCollatorFactory : public ICUResourceBundleFactory {
+ public:
+ ICUCollatorFactory(): ICUResourceBundleFactory(UnicodeString(U_ICUDATA_COLL, -1, US_INV)) { }
+ protected:
+ virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
+};
+
+UObject*
+ICUCollatorFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
+ if (handlesKey(key, status)) {
+ const LocaleKey& lkey = (const LocaleKey&)key;
+ Locale loc;
+ // make sure the requested locale is correct
+ // default LocaleFactory uses currentLocale since that's the one vetted by handlesKey
+ // but for ICU rb resources we use the actual one since it will fallback again
+ lkey.canonicalLocale(loc);
+
+ return Collator::makeInstance(loc, status);
+ }
+ return NULL;
+}
+
+// -------------------------------------
+
+class ICUCollatorService : public ICULocaleService {
+public:
+ ICUCollatorService()
+ : ICULocaleService(UNICODE_STRING_SIMPLE("Collator"))
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ registerFactory(new ICUCollatorFactory(), status);
+ }
+
+ virtual UObject* cloneInstance(UObject* instance) const {
+ return ((Collator*)instance)->clone();
+ }
+
+ virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* actualID, UErrorCode& status) const {
+ LocaleKey& lkey = (LocaleKey&)key;
+ if (actualID) {
+ // Ugly Hack Alert! We return an empty actualID to signal
+ // to callers that this is a default object, not a "real"
+ // service-created object. (TODO remove in 3.0) [aliu]
+ actualID->truncate(0);
+ }
+ Locale loc("");
+ lkey.canonicalLocale(loc);
+ return Collator::makeInstance(loc, status);
+ }
+
+ virtual UObject* getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const {
+ UnicodeString ar;
+ if (actualReturn == NULL) {
+ actualReturn = &ar;
+ }
+ Collator* result = (Collator*)ICULocaleService::getKey(key, actualReturn, status);
+ // Ugly Hack Alert! If the actualReturn length is zero, this
+ // means we got a default object, not a "real" service-created
+ // object. We don't call setLocales() on a default object,
+ // because that will overwrite its correct built-in locale
+ // metadata (valid & actual) with our incorrect data (all we
+ // have is the requested locale). (TODO remove in 3.0) [aliu]
+ if (result && actualReturn->length() > 0) {
+ const LocaleKey& lkey = (const LocaleKey&)key;
+ Locale canonicalLocale("");
+ Locale currentLocale("");
+
+ result->setLocales(lkey.canonicalLocale(canonicalLocale),
+ LocaleUtility::initLocaleFromName(*actualReturn, currentLocale));
+ }
+ return result;
+ }
+
+ virtual UBool isDefault() const {
+ return countFactories() == 1;
+ }
+};
+
+// -------------------------------------
+
+static ICULocaleService*
+getService(void)
+{
+ UBool needInit;
+ UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
+ if(needInit) {
+ ICULocaleService *newservice = new ICUCollatorService();
+ if(newservice) {
+ umtx_lock(NULL);
+ if(gService == NULL) {
+ gService = newservice;
+ newservice = NULL;
+ }
+ umtx_unlock(NULL);
+ }
+ if(newservice) {
+ delete newservice;
+ }
+ else {
+ ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
+ }
+ }
+ return gService;
+}
+
+// -------------------------------------
+
+static inline UBool
+hasService(void)
+{
+ UBool retVal;
+ UMTX_CHECK(NULL, gService != NULL, retVal);
+ return retVal;
+}
+
+// -------------------------------------
+
+UCollator*
+Collator::createUCollator(const char *loc,
+ UErrorCode *status)
+{
+ UCollator *result = 0;
+ if (status && U_SUCCESS(*status) && hasService()) {
+ Locale desiredLocale(loc);
+ Collator *col = (Collator*)gService->get(desiredLocale, *status);
+ if (col && col->getDynamicClassID() == RuleBasedCollator::getStaticClassID()) {
+ RuleBasedCollator *rbc = (RuleBasedCollator *)col;
+ if (!rbc->dataIsOwned) {
+ result = ucol_safeClone(rbc->ucollator, NULL, NULL, status);
+ } else {
+ result = rbc->ucollator;
+ rbc->ucollator = NULL; // to prevent free on delete
+ }
+ }
+ delete col;
+ }
+ return result;
+}
+#endif /* UCONFIG_NO_SERVICE */
+
+static UBool isAvailableLocaleListInitialized(UErrorCode &status) {
+ // for now, there is a hardcoded list, so just walk through that list and set it up.
+ UBool needInit;
+ UMTX_CHECK(NULL, availableLocaleList == NULL, needInit);
+
+ if (needInit) {
+ UResourceBundle *index = NULL;
+ UResourceBundle installed;
+ Locale * temp;
+ int32_t i = 0;
+ int32_t localeCount;
+
+ ures_initStackObject(&installed);
+ index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
+ ures_getByKey(index, "InstalledLocales", &installed, &status);
+
+ if(U_SUCCESS(status)) {
+ localeCount = ures_getSize(&installed);
+ temp = new Locale[localeCount];
+
+ if (temp != NULL) {
+ ures_resetIterator(&installed);
+ while(ures_hasNext(&installed)) {
+ const char *tempKey = NULL;
+ ures_getNextString(&installed, NULL, &tempKey, &status);
+ temp[i++] = Locale(tempKey);
+ }
+
+ umtx_lock(NULL);
+ if (availableLocaleList == NULL)
+ {
+ availableLocaleList = temp;
+ availableLocaleListCount = localeCount;
+ temp = NULL;
+ ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup);
+ }
+ umtx_unlock(NULL);
+
+ needInit = FALSE;
+ if (temp) {
+ delete []temp;
+ }
+ }
+
+ ures_close(&installed);
+ }
+ ures_close(index);
+ }
+ return !needInit;
+}
+
+// Collator public methods -----------------------------------------------
+
+Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success)
+{
+ return createInstance(Locale::getDefault(), success);
+}
+
+Collator* U_EXPORT2 Collator::createInstance(const Locale& desiredLocale,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status))
+ return 0;
+
+#if !UCONFIG_NO_SERVICE
+ if (hasService()) {
+ Locale actualLoc;
+ Collator *result =
+ (Collator*)gService->get(desiredLocale, &actualLoc, status);
+ // Ugly Hack Alert! If the returned locale is empty (not root,
+ // but empty -- getName() == "") then that means the service
+ // returned a default object, not a "real" service object. In
+ // that case, the locale metadata (valid & actual) is setup
+ // correctly already, and we don't want to overwrite it. (TODO
+ // remove in 3.0) [aliu]
+ if (*actualLoc.getName() != 0) {
+ result->setLocales(desiredLocale, actualLoc);
+ }
+ return result;
+ }
+#endif
+ return makeInstance(desiredLocale, status);
+}
+
+
+Collator* Collator::makeInstance(const Locale& desiredLocale,
+ UErrorCode& status)
+{
+ // A bit of explanation is required here. Although in the current
+ // implementation
+ // Collator::createInstance() is just turning around and calling
+ // RuleBasedCollator(Locale&), this will not necessarily always be the
+ // case. For example, suppose we modify this code to handle a
+ // non-table-based Collator, such as that for Thai. In this case,
+ // createInstance() will have to be modified to somehow determine this fact
+ // (perhaps a field in the resource bundle). Then it can construct the
+ // non-table-based Collator in some other way, when it sees that it needs
+ // to.
+ // The specific caution is this: RuleBasedCollator(Locale&) will ALWAYS
+ // return a valid collation object, if the system if functioning properly.
+ // The reason is that it will fall back, use the default locale, and even
+ // use the built-in default collation rules. THEREFORE, createInstance()
+ // should in general ONLY CALL RuleBasedCollator(Locale&) IF IT KNOWS IN
+ // ADVANCE that the given locale's collation is properly implemented as a
+ // RuleBasedCollator.
+ // Currently, we don't do this...we always return a RuleBasedCollator,
+ // whether it is strictly correct to do so or not, without checking, because
+ // we currently have no way of checking.
+
+ RuleBasedCollator* collation = new RuleBasedCollator(desiredLocale,
+ status);
+ /* test for NULL */
+ if (collation == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ if (U_FAILURE(status))
+ {
+ delete collation;
+ collation = 0;
+ }
+ return collation;
+}
+
+#ifdef U_USE_COLLATION_OBSOLETE_2_6
+// !!! dlf the following is obsolete, ignore registration for this
+
+Collator *
+Collator::createInstance(const Locale &loc,
+ UVersionInfo version,
+ UErrorCode &status)
+{
+ Collator *collator;
+ UVersionInfo info;
+
+ collator=new RuleBasedCollator(loc, status);
+ /* test for NULL */
+ if (collator == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ if(U_SUCCESS(status)) {
+ collator->getVersion(info);
+ if(0!=uprv_memcmp(version, info, sizeof(UVersionInfo))) {
+ delete collator;
+ status=U_MISSING_RESOURCE_ERROR;
+ return 0;
+ }
+ }
+ return collator;
+}
+#endif
+
+// implement deprecated, previously abstract method
+Collator::EComparisonResult Collator::compare(const UnicodeString& source,
+ const UnicodeString& target) const
+{
+ UErrorCode ec = U_ZERO_ERROR;
+ return (Collator::EComparisonResult)compare(source, target, ec);
+}
+
+// implement deprecated, previously abstract method
+Collator::EComparisonResult Collator::compare(const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length) const
+{
+ UErrorCode ec = U_ZERO_ERROR;
+ return (Collator::EComparisonResult)compare(source, target, length, ec);
+}
+
+// implement deprecated, previously abstract method
+Collator::EComparisonResult Collator::compare(const UChar* source, int32_t sourceLength,
+ const UChar* target, int32_t targetLength)
+ const
+{
+ UErrorCode ec = U_ZERO_ERROR;
+ return (Collator::EComparisonResult)compare(source, sourceLength, target, targetLength, ec);
+}
+
+UBool Collator::equals(const UnicodeString& source,
+ const UnicodeString& target) const
+{
+ UErrorCode ec = U_ZERO_ERROR;
+ return (compare(source, target, ec) == UCOL_EQUAL);
+}
+
+UBool Collator::greaterOrEqual(const UnicodeString& source,
+ const UnicodeString& target) const
+{
+ UErrorCode ec = U_ZERO_ERROR;
+ return (compare(source, target, ec) != UCOL_LESS);
+}
+
+UBool Collator::greater(const UnicodeString& source,
+ const UnicodeString& target) const
+{
+ UErrorCode ec = U_ZERO_ERROR;
+ return (compare(source, target, ec) == UCOL_GREATER);
+}
+
+// this API ignores registered collators, since it returns an
+// array of indefinite lifetime
+const Locale* U_EXPORT2 Collator::getAvailableLocales(int32_t& count)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Locale *result = NULL;
+ count = 0;
+ if (isAvailableLocaleListInitialized(status))
+ {
+ result = availableLocaleList;
+ count = availableLocaleListCount;
+ }
+ return result;
+}
+
+UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
+ const Locale& displayLocale,
+ UnicodeString& name)
+{
+#if !UCONFIG_NO_SERVICE
+ if (hasService()) {
+ UnicodeString locNameStr;
+ LocaleUtility::initNameFromLocale(objectLocale, locNameStr);
+ return gService->getDisplayName(locNameStr, name, displayLocale);
+ }
+#endif
+ return objectLocale.getDisplayName(displayLocale, name);
+}
+
+UnicodeString& U_EXPORT2 Collator::getDisplayName(const Locale& objectLocale,
+ UnicodeString& name)
+{
+ return getDisplayName(objectLocale, Locale::getDefault(), name);
+}
+
+/* This is useless information */
+/*void Collator::getVersion(UVersionInfo versionInfo) const
+{
+ if (versionInfo!=NULL)
+ uprv_memcpy(versionInfo, fVersion, U_MAX_VERSION_LENGTH);
+}
+*/
+
+// UCollator protected constructor destructor ----------------------------
+
+/**
+* Default constructor.
+* Constructor is different from the old default Collator constructor.
+* The task for determing the default collation strength and normalization mode
+* is left to the child class.
+*/
+Collator::Collator()
+: UObject()
+{
+}
+
+/**
+* Constructor.
+* Empty constructor, does not handle the arguments.
+* This constructor is done for backward compatibility with 1.7 and 1.8.
+* The task for handling the argument collation strength and normalization
+* mode is left to the child class.
+* @param collationStrength collation strength
+* @param decompositionMode
+* @deprecated 2.4 use the default constructor instead
+*/
+Collator::Collator(UCollationStrength, UNormalizationMode )
+: UObject()
+{
+}
+
+Collator::~Collator()
+{
+}
+
+Collator::Collator(const Collator &other)
+ : UObject(other)
+{
+}
+
+UBool Collator::operator==(const Collator& other) const
+{
+ return (UBool)(this == &other);
+}
+
+UBool Collator::operator!=(const Collator& other) const
+{
+ return (UBool)!(*this == other);
+}
+
+int32_t U_EXPORT2 Collator::getBound(const uint8_t *source,
+ int32_t sourceLength,
+ UColBoundMode boundType,
+ uint32_t noOfLevels,
+ uint8_t *result,
+ int32_t resultLength,
+ UErrorCode &status)
+{
+ return ucol_getBound(source, sourceLength, boundType, noOfLevels, result, resultLength, &status);
+}
+
+void
+Collator::setLocales(const Locale& /* requestedLocale */, const Locale& /* validLocale */) {
+}
+
+UnicodeSet *Collator::getTailoredSet(UErrorCode &status) const
+{
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+ // everything can be changed
+ return new UnicodeSet(0, 0x10FFFF);
+}
+
+// -------------------------------------
+
+#if !UCONFIG_NO_SERVICE
+URegistryKey U_EXPORT2
+Collator::registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status)
+{
+ if (U_SUCCESS(status)) {
+ return getService()->registerInstance(toAdopt, locale, status);
+ }
+ return NULL;
+}
+
+// -------------------------------------
+
+class CFactory : public LocaleKeyFactory {
+private:
+ CollatorFactory* _delegate;
+ Hashtable* _ids;
+
+public:
+ CFactory(CollatorFactory* delegate, UErrorCode& status)
+ : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
+ , _delegate(delegate)
+ , _ids(NULL)
+ {
+ if (U_SUCCESS(status)) {
+ int32_t count = 0;
+ _ids = new Hashtable(status);
+ if (_ids) {
+ const UnicodeString * idlist = _delegate->getSupportedIDs(count, status);
+ for (int i = 0; i < count; ++i) {
+ _ids->put(idlist[i], (void*)this, status);
+ if (U_FAILURE(status)) {
+ delete _ids;
+ _ids = NULL;
+ return;
+ }
+ }
+ } else {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ }
+
+ virtual ~CFactory()
+ {
+ delete _delegate;
+ delete _ids;
+ }
+
+ virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const;
+
+protected:
+ virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
+ {
+ if (U_SUCCESS(status)) {
+ return _ids;
+ }
+ return NULL;
+ }
+
+ virtual UnicodeString&
+ getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const;
+};
+
+UObject*
+CFactory::create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const
+{
+ if (handlesKey(key, status)) {
+ const LocaleKey& lkey = (const LocaleKey&)key;
+ Locale validLoc;
+ lkey.currentLocale(validLoc);
+ return _delegate->createCollator(validLoc);
+ }
+ return NULL;
+}
+
+UnicodeString&
+CFactory::getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
+{
+ if ((_coverage & 0x1) == 0) {
+ UErrorCode status = U_ZERO_ERROR;
+ const Hashtable* ids = getSupportedIDs(status);
+ if (ids && (ids->get(id) != NULL)) {
+ Locale loc;
+ LocaleUtility::initLocaleFromName(id, loc);
+ return _delegate->getDisplayName(loc, locale, result);
+ }
+ }
+ result.setToBogus();
+ return result;
+}
+
+URegistryKey U_EXPORT2
+Collator::registerFactory(CollatorFactory* toAdopt, UErrorCode& status)
+{
+ if (U_SUCCESS(status)) {
+ CFactory* f = new CFactory(toAdopt, status);
+ if (f) {
+ return getService()->registerFactory(f, status);
+ }
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return NULL;
+}
+
+// -------------------------------------
+
+UBool U_EXPORT2
+Collator::unregister(URegistryKey key, UErrorCode& status)
+{
+ if (U_SUCCESS(status)) {
+ if (hasService()) {
+ return gService->unregister(key, status);
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return FALSE;
+}
+#endif /* UCONFIG_NO_SERVICE */
+
+class CollationLocaleListEnumeration : public StringEnumeration {
+private:
+ int32_t index;
+public:
+ static UClassID U_EXPORT2 getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+public:
+ CollationLocaleListEnumeration()
+ : index(0)
+ {
+ // The global variables should already be initialized.
+ //isAvailableLocaleListInitialized(status);
+ }
+
+ virtual ~CollationLocaleListEnumeration() {
+ }
+
+ virtual StringEnumeration * clone() const
+ {
+ CollationLocaleListEnumeration *result = new CollationLocaleListEnumeration();
+ result->index = index;
+ return result;
+ }
+
+ virtual int32_t count(UErrorCode &/*status*/) const {
+ return availableLocaleListCount;
+ }
+
+ virtual const char* next(int32_t* resultLength, UErrorCode& /*status*/) {
+ const char* result;
+ if(index < availableLocaleListCount) {
+ result = availableLocaleList[index++].getName();
+ if(resultLength != NULL) {
+ *resultLength = uprv_strlen(result);
+ }
+ } else {
+ if(resultLength != NULL) {
+ *resultLength = 0;
+ }
+ result = NULL;
+ }
+ return result;
+ }
+
+ virtual const UnicodeString* snext(UErrorCode& status) {
+ int32_t resultLength = 0;
+ const char *s = next(&resultLength, status);
+ return setChars(s, resultLength, status);
+ }
+
+ virtual void reset(UErrorCode& /*status*/) {
+ index = 0;
+ }
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationLocaleListEnumeration)
+
+
+// -------------------------------------
+
+StringEnumeration* U_EXPORT2
+Collator::getAvailableLocales(void)
+{
+#if !UCONFIG_NO_SERVICE
+ if (hasService()) {
+ return getService()->getAvailableLocales();
+ }
+#endif /* UCONFIG_NO_SERVICE */
+ UErrorCode status = U_ZERO_ERROR;
+ if (isAvailableLocaleListInitialized(status)) {
+ return new CollationLocaleListEnumeration();
+ }
+ return NULL;
+}
+
+StringEnumeration* U_EXPORT2
+Collator::getKeywords(UErrorCode& status) {
+ // This is a wrapper over ucol_getKeywords
+ UEnumeration* uenum = ucol_getKeywords(&status);
+ if (U_FAILURE(status)) {
+ uenum_close(uenum);
+ return NULL;
+ }
+ return new UStringEnumeration(uenum);
+}
+
+StringEnumeration* U_EXPORT2
+Collator::getKeywordValues(const char *keyword, UErrorCode& status) {
+ // This is a wrapper over ucol_getKeywordValues
+ UEnumeration* uenum = ucol_getKeywordValues(keyword, &status);
+ if (U_FAILURE(status)) {
+ uenum_close(uenum);
+ return NULL;
+ }
+ return new UStringEnumeration(uenum);
+}
+
+Locale U_EXPORT2
+Collator::getFunctionalEquivalent(const char* keyword, const Locale& locale,
+ UBool& isAvailable, UErrorCode& status) {
+ // This is a wrapper over ucol_getFunctionalEquivalent
+ char loc[ULOC_FULLNAME_CAPACITY];
+ /*int32_t len =*/ ucol_getFunctionalEquivalent(loc, sizeof(loc),
+ keyword, locale.getName(), &isAvailable, &status);
+ if (U_FAILURE(status)) {
+ *loc = 0; // root
+ }
+ return Locale::createFromName(loc);
+}
+
+// UCollator private data members ----------------------------------------
+
+/* This is useless information */
+/*const UVersionInfo Collator::fVersion = {1, 1, 0, 0};*/
+
+// -------------------------------------
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+/* eof */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/cpdtrans.cpp b/Build/source/libs/icu/icu-xetex/i18n/cpdtrans.cpp
new file mode 100644
index 00000000000..afd1fdbf8bd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/cpdtrans.cpp
@@ -0,0 +1,578 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifilt.h"
+#include "unicode/uniset.h"
+#include "cpdtrans.h"
+#include "uvector.h"
+#include "tridpars.h"
+#include "cmemory.h"
+
+// keep in sync with Transliterator
+//static const UChar ID_SEP = 0x002D; /*-*/
+static const UChar ID_DELIM = 0x003B; /*;*/
+static const UChar NEWLINE = 10;
+
+// Empty string
+static const UChar EMPTY[] = {0}; //""
+static const UChar COLON_COLON[] = {0x3A, 0x3A, 0}; //"::"
+
+U_NAMESPACE_BEGIN
+
+const UChar CompoundTransliterator::PASS_STRING[] = { 0x0025, 0x0050, 0x0061, 0x0073, 0x0073, 0 }; // "%Pass"
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompoundTransliterator)
+
+/**
+ * Constructs a new compound transliterator given an array of
+ * transliterators. The array of transliterators may be of any
+ * length, including zero or one, however, useful compound
+ * transliterators have at least two components.
+ * @param transliterators array of <code>Transliterator</code>
+ * objects
+ * @param transliteratorCount The number of
+ * <code>Transliterator</code> objects in transliterators.
+ * @param filter the filter. Any character for which
+ * <tt>filter.contains()</tt> returns <tt>false</tt> will not be
+ * altered by this transliterator. If <tt>filter</tt> is
+ * <tt>null</tt> then no filtering is applied.
+ */
+CompoundTransliterator::CompoundTransliterator(
+ Transliterator* const transliterators[],
+ int32_t transliteratorCount,
+ UnicodeFilter* adoptedFilter) :
+ Transliterator(joinIDs(transliterators, transliteratorCount), adoptedFilter),
+ trans(0), count(0), numAnonymousRBTs(0) {
+ setTransliterators(transliterators, transliteratorCount);
+}
+
+/**
+ * Splits an ID of the form "ID;ID;..." into a compound using each
+ * of the IDs.
+ * @param id of above form
+ * @param forward if false, does the list in reverse order, and
+ * takes the inverse of each ID.
+ */
+CompoundTransliterator::CompoundTransliterator(const UnicodeString& id,
+ UTransDirection direction,
+ UnicodeFilter* adoptedFilter,
+ UParseError& /*parseError*/,
+ UErrorCode& status) :
+ Transliterator(id, adoptedFilter),
+ trans(0), numAnonymousRBTs(0) {
+ // TODO add code for parseError...currently unused, but
+ // later may be used by parsing code...
+ init(id, direction, TRUE, status);
+}
+
+CompoundTransliterator::CompoundTransliterator(const UnicodeString& id,
+ UParseError& /*parseError*/,
+ UErrorCode& status) :
+ Transliterator(id, 0), // set filter to 0 here!
+ trans(0), numAnonymousRBTs(0) {
+ // TODO add code for parseError...currently unused, but
+ // later may be used by parsing code...
+ init(id, UTRANS_FORWARD, TRUE, status);
+}
+
+
+/**
+ * Private constructor for use of TransliteratorAlias
+ */
+CompoundTransliterator::CompoundTransliterator(const UnicodeString& newID,
+ UVector& list,
+ UnicodeFilter* adoptedFilter,
+ int32_t anonymousRBTs,
+ UParseError& /*parseError*/,
+ UErrorCode& status) :
+ Transliterator(newID, adoptedFilter),
+ trans(0), numAnonymousRBTs(anonymousRBTs)
+{
+ init(list, UTRANS_FORWARD, FALSE, status);
+}
+
+/**
+ * Private constructor for Transliterator from a vector of
+ * transliterators. The caller is responsible for fixing up the
+ * ID.
+ */
+CompoundTransliterator::CompoundTransliterator(UVector& list,
+ UParseError& /*parseError*/,
+ UErrorCode& status) :
+ Transliterator(EMPTY, NULL),
+ trans(0), numAnonymousRBTs(0)
+{
+ // TODO add code for parseError...currently unused, but
+ // later may be used by parsing code...
+ init(list, UTRANS_FORWARD, FALSE, status);
+ // assume caller will fixup ID
+}
+
+CompoundTransliterator::CompoundTransliterator(UVector& list,
+ int32_t anonymousRBTs,
+ UParseError& /*parseError*/,
+ UErrorCode& status) :
+ Transliterator(EMPTY, NULL),
+ trans(0), numAnonymousRBTs(anonymousRBTs)
+{
+ init(list, UTRANS_FORWARD, FALSE, status);
+}
+
+/**
+ * Finish constructing a transliterator: only to be called by
+ * constructors. Before calling init(), set trans and filter to NULL.
+ * @param id the id containing ';'-separated entries
+ * @param direction either FORWARD or REVERSE
+ * @param idSplitPoint the index into id at which the
+ * adoptedSplitTransliterator should be inserted, if there is one, or
+ * -1 if there is none.
+ * @param adoptedSplitTransliterator a transliterator to be inserted
+ * before the entry at offset idSplitPoint in the id string. May be
+ * NULL to insert no entry.
+ * @param fixReverseID if TRUE, then reconstruct the ID of reverse
+ * entries by calling getID() of component entries. Some constructors
+ * do not require this because they apply a facade ID anyway.
+ * @param status the error code indicating success or failure
+ */
+void CompoundTransliterator::init(const UnicodeString& id,
+ UTransDirection direction,
+ UBool fixReverseID,
+ UErrorCode& status) {
+ // assert(trans == 0);
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UVector list(status);
+ UnicodeSet* compoundFilter = NULL;
+ UnicodeString regenID;
+ if (!TransliteratorIDParser::parseCompoundID(id, direction,
+ regenID, list, compoundFilter)) {
+ status = U_INVALID_ID;
+ delete compoundFilter;
+ return;
+ }
+
+ TransliteratorIDParser::instantiateList(list, status);
+
+ init(list, direction, fixReverseID, status);
+
+ if (compoundFilter != NULL) {
+ adoptFilter(compoundFilter);
+ }
+}
+
+/**
+ * Finish constructing a transliterator: only to be called by
+ * constructors. Before calling init(), set trans and filter to NULL.
+ * @param list a vector of transliterator objects to be adopted. It
+ * should NOT be empty. The list should be in declared order. That
+ * is, it should be in the FORWARD order; if direction is REVERSE then
+ * the list order will be reversed.
+ * @param direction either FORWARD or REVERSE
+ * @param fixReverseID if TRUE, then reconstruct the ID of reverse
+ * entries by calling getID() of component entries. Some constructors
+ * do not require this because they apply a facade ID anyway.
+ * @param status the error code indicating success or failure
+ */
+void CompoundTransliterator::init(UVector& list,
+ UTransDirection direction,
+ UBool fixReverseID,
+ UErrorCode& status) {
+ // assert(trans == 0);
+
+ // Allocate array
+ if (U_SUCCESS(status)) {
+ count = list.size();
+ trans = (Transliterator **)uprv_malloc(count * sizeof(Transliterator *));
+ /* test for NULL */
+ if (trans == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ if (U_FAILURE(status) || trans == 0) {
+ // assert(trans == 0);
+ return;
+ }
+
+ // Move the transliterators from the vector into an array.
+ // Reverse the order if necessary.
+ int32_t i;
+ for (i=0; i<count; ++i) {
+ int32_t j = (direction == UTRANS_FORWARD) ? i : count - 1 - i;
+ trans[i] = (Transliterator*) list.elementAt(j);
+ }
+
+ // If the direction is UTRANS_REVERSE then we may need to fix the
+ // ID.
+ if (direction == UTRANS_REVERSE && fixReverseID) {
+ UnicodeString newID;
+ for (i=0; i<count; ++i) {
+ if (i > 0) {
+ newID.append(ID_DELIM);
+ }
+ newID.append(trans[i]->getID());
+ }
+ setID(newID);
+ }
+
+ computeMaximumContextLength();
+}
+
+/**
+ * Return the IDs of the given list of transliterators, concatenated
+ * with ID_DELIM delimiting them. Equivalent to the perlish expression
+ * join(ID_DELIM, map($_.getID(), transliterators).
+ */
+UnicodeString CompoundTransliterator::joinIDs(Transliterator* const transliterators[],
+ int32_t transCount) {
+ UnicodeString id;
+ for (int32_t i=0; i<transCount; ++i) {
+ if (i > 0) {
+ id.append(ID_DELIM);
+ }
+ id.append(transliterators[i]->getID());
+ }
+ return id; // Return temporary
+}
+
+/**
+ * Copy constructor.
+ */
+CompoundTransliterator::CompoundTransliterator(const CompoundTransliterator& t) :
+ Transliterator(t), trans(0), count(0), numAnonymousRBTs(-1) {
+ *this = t;
+}
+
+/**
+ * Destructor
+ */
+CompoundTransliterator::~CompoundTransliterator() {
+ freeTransliterators();
+}
+
+void CompoundTransliterator::freeTransliterators(void) {
+ if (trans != 0) {
+ for (int32_t i=0; i<count; ++i) {
+ delete trans[i];
+ }
+ uprv_free(trans);
+ }
+ trans = 0;
+ count = 0;
+}
+
+/**
+ * Assignment operator.
+ */
+CompoundTransliterator& CompoundTransliterator::operator=(
+ const CompoundTransliterator& t) {
+ Transliterator::operator=(t);
+ int32_t i;
+ for (i=0; i<count; ++i) {
+ delete trans[i];
+ trans[i] = 0;
+ }
+ if (t.count > count) {
+ uprv_free(trans);
+ trans = (Transliterator **)uprv_malloc(t.count * sizeof(Transliterator *));
+ }
+ count = t.count;
+ for (i=0; i<count; ++i) {
+ trans[i] = t.trans[i]->clone();
+ }
+ numAnonymousRBTs = t.numAnonymousRBTs;
+ return *this;
+}
+
+/**
+ * Transliterator API.
+ */
+Transliterator* CompoundTransliterator::clone(void) const {
+ return new CompoundTransliterator(*this);
+}
+
+/**
+ * Returns the number of transliterators in this chain.
+ * @return number of transliterators in this chain.
+ */
+int32_t CompoundTransliterator::getCount(void) const {
+ return count;
+}
+
+/**
+ * Returns the transliterator at the given index in this chain.
+ * @param index index into chain, from 0 to <code>getCount() - 1</code>
+ * @return transliterator at the given index
+ */
+const Transliterator& CompoundTransliterator::getTransliterator(int32_t index) const {
+ return *trans[index];
+}
+
+void CompoundTransliterator::setTransliterators(Transliterator* const transliterators[],
+ int32_t transCount) {
+ Transliterator** a = (Transliterator **)uprv_malloc(transCount * sizeof(Transliterator *));
+ for (int32_t i=0; i<transCount; ++i) {
+ a[i] = transliterators[i]->clone();
+ }
+ adoptTransliterators(a, transCount);
+}
+
+void CompoundTransliterator::adoptTransliterators(Transliterator* adoptedTransliterators[],
+ int32_t transCount) {
+ // First free trans[] and set count to zero. Once this is done,
+ // orphan the filter. Set up the new trans[].
+ freeTransliterators();
+ trans = adoptedTransliterators;
+ count = transCount;
+ computeMaximumContextLength();
+ setID(joinIDs(trans, count));
+}
+
+/**
+ * Append c to buf, unless buf is empty or buf already ends in c.
+ */
+static void _smartAppend(UnicodeString& buf, UChar c) {
+ if (buf.length() != 0 &&
+ buf.charAt(buf.length() - 1) != c) {
+ buf.append(c);
+ }
+}
+
+UnicodeString& CompoundTransliterator::toRules(UnicodeString& rulesSource,
+ UBool escapeUnprintable) const {
+ // We do NOT call toRules() on our component transliterators, in
+ // general. If we have several rule-based transliterators, this
+ // yields a concatenation of the rules -- not what we want. We do
+ // handle compound RBT transliterators specially -- those for which
+ // compoundRBTIndex >= 0. For the transliterator at compoundRBTIndex,
+ // we do call toRules() recursively.
+ rulesSource.truncate(0);
+ if (numAnonymousRBTs >= 1 && getFilter() != NULL) {
+ // If we are a compound RBT and if we have a global
+ // filter, then emit it at the top.
+ UnicodeString pat;
+ rulesSource.append(COLON_COLON).append(getFilter()->toPattern(pat, escapeUnprintable)).append(ID_DELIM);
+ }
+ for (int32_t i=0; i<count; ++i) {
+ UnicodeString rule;
+
+ // Anonymous RuleBasedTransliterators (inline rules and
+ // ::BEGIN/::END blocks) are given IDs that begin with
+ // "%Pass": use toRules() to write all the rules to the output
+ // (and insert "::Null;" if we have two in a row)
+ if (trans[i]->getID().startsWith(PASS_STRING)) {
+ trans[i]->toRules(rule, escapeUnprintable);
+ if (numAnonymousRBTs > 1 && i > 0 && trans[i - 1]->getID().startsWith(PASS_STRING))
+ rule = UNICODE_STRING_SIMPLE("::Null;") + rule;
+
+ // we also use toRules() on CompoundTransliterators (which we
+ // check for by looking for a semicolon in the ID)-- this gets
+ // the list of their child transliterators output in the right
+ // format
+ } else if (trans[i]->getID().indexOf(ID_DELIM) >= 0) {
+ trans[i]->toRules(rule, escapeUnprintable);
+
+ // for everything else, use Transliterator::toRules()
+ } else {
+ trans[i]->Transliterator::toRules(rule, escapeUnprintable);
+ }
+ _smartAppend(rulesSource, NEWLINE);
+ rulesSource.append(rule);
+ _smartAppend(rulesSource, ID_DELIM);
+ }
+ return rulesSource;
+}
+
+/**
+ * Implement Transliterator framework
+ */
+void CompoundTransliterator::handleGetSourceSet(UnicodeSet& result) const {
+ UnicodeSet set;
+ result.clear();
+ for (int32_t i=0; i<count; ++i) {
+ result.addAll(trans[i]->getSourceSet(set));
+ // Take the example of Hiragana-Latin. This is really
+ // Hiragana-Katakana; Katakana-Latin. The source set of
+ // these two is roughly [:Hiragana:] and [:Katakana:].
+ // But the source set for the entire transliterator is
+ // actually [:Hiragana:] ONLY -- that is, the first
+ // non-empty source set.
+
+ // This is a heuristic, and not 100% reliable.
+ if (!result.isEmpty()) {
+ break;
+ }
+ }
+}
+
+/**
+ * Override Transliterator framework
+ */
+UnicodeSet& CompoundTransliterator::getTargetSet(UnicodeSet& result) const {
+ UnicodeSet set;
+ result.clear();
+ for (int32_t i=0; i<count; ++i) {
+ // This is a heuristic, and not 100% reliable.
+ result.addAll(trans[i]->getTargetSet(set));
+ }
+ return result;
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void CompoundTransliterator::handleTransliterate(Replaceable& text, UTransPosition& index,
+ UBool incremental) const {
+ /* Call each transliterator with the same contextStart and
+ * start, but with the limit as modified
+ * by preceding transliterators. The start index must be
+ * reset for each transliterator to give each a chance to
+ * transliterate the text. The initial contextStart index is known
+ * to still point to the same place after each transliterator
+ * is called because each transliterator will not change the
+ * text between contextStart and the initial start index.
+ *
+ * IMPORTANT: After the first transliterator, each subsequent
+ * transliterator only gets to transliterate text committed by
+ * preceding transliterators; that is, the start (output
+ * value) of transliterator i becomes the limit (input value)
+ * of transliterator i+1. Finally, the overall limit is fixed
+ * up before we return.
+ *
+ * Assumptions we make here:
+ * (1) contextStart <= start <= limit <= contextLimit <= text.length()
+ * (2) start <= start' <= limit' ;cursor doesn't move back
+ * (3) start <= limit' ;text before cursor unchanged
+ * - start' is the value of start after calling handleKT
+ * - limit' is the value of limit after calling handleKT
+ */
+
+ /**
+ * Example: 3 transliterators. This example illustrates the
+ * mechanics we need to implement. C, S, and L are the contextStart,
+ * start, and limit. gl is the globalLimit. contextLimit is
+ * equal to limit throughout.
+ *
+ * 1. h-u, changes hex to Unicode
+ *
+ * 4 7 a d 0 4 7 a
+ * abc/u0061/u => abca/u
+ * C S L C S L gl=f->a
+ *
+ * 2. upup, changes "x" to "XX"
+ *
+ * 4 7 a 4 7 a
+ * abca/u => abcAA/u
+ * C SL C S
+ * L gl=a->b
+ * 3. u-h, changes Unicode to hex
+ *
+ * 4 7 a 4 7 a d 0 3
+ * abcAA/u => abc/u0041/u0041/u
+ * C S L C S
+ * L gl=b->15
+ * 4. return
+ *
+ * 4 7 a d 0 3
+ * abc/u0041/u0041/u
+ * C S L
+ */
+
+ if (count < 1) {
+ index.start = index.limit;
+ return; // Short circuit for empty compound transliterators
+ }
+
+ // compoundLimit is the limit value for the entire compound
+ // operation. We overwrite index.limit with the previous
+ // index.start. After each transliteration, we update
+ // compoundLimit for insertions or deletions that have happened.
+ int32_t compoundLimit = index.limit;
+
+ // compoundStart is the start for the entire compound
+ // operation.
+ int32_t compoundStart = index.start;
+
+ int32_t delta = 0; // delta in length
+
+ // Give each transliterator a crack at the run of characters.
+ // See comments at the top of the method for more detail.
+ for (int32_t i=0; i<count; ++i) {
+ index.start = compoundStart; // Reset start
+ int32_t limit = index.limit;
+
+ if (index.start == index.limit) {
+ // Short circuit for empty range
+ break;
+ }
+
+ trans[i]->filteredTransliterate(text, index, incremental);
+
+ // In a properly written transliterator, start == limit after
+ // handleTransliterate() returns when incremental is false.
+ // Catch cases where the subclass doesn't do this, and throw
+ // an exception. (Just pinning start to limit is a bad idea,
+ // because what's probably happening is that the subclass
+ // isn't transliterating all the way to the end, and it should
+ // in non-incremental mode.)
+ if (!incremental && index.start != index.limit) {
+ // We can't throw an exception, so just fudge things
+ index.start = index.limit;
+ }
+
+ // Cumulative delta for insertions/deletions
+ delta += index.limit - limit;
+
+ if (incremental) {
+ // In the incremental case, only allow subsequent
+ // transliterators to modify what has already been
+ // completely processed by prior transliterators. In the
+ // non-incrmental case, allow each transliterator to
+ // process the entire text.
+ index.limit = index.start;
+ }
+ }
+
+ compoundLimit += delta;
+
+ // Start is good where it is -- where the last transliterator left
+ // it. Limit needs to be put back where it was, modulo
+ // adjustments for deletions/insertions.
+ index.limit = compoundLimit;
+}
+
+/**
+ * Sets the length of the longest context required by this transliterator.
+ * This is <em>preceding</em> context.
+ */
+void CompoundTransliterator::computeMaximumContextLength(void) {
+ int32_t max = 0;
+ for (int32_t i=0; i<count; ++i) {
+ int32_t len = trans[i]->getMaximumContextLength();
+ if (len > max) {
+ max = len;
+ }
+ }
+ setMaximumContextLength(max);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+/* eof */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/cpdtrans.h b/Build/source/libs/icu/icu-xetex/i18n/cpdtrans.h
new file mode 100644
index 00000000000..833b2cb8198
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/cpdtrans.h
@@ -0,0 +1,248 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+#ifndef CPDTRANS_H
+#define CPDTRANS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+
+U_NAMESPACE_BEGIN
+
+class U_COMMON_API UVector;
+class TransliteratorRegistry;
+
+/**
+ * A transliterator that is composed of two or more other
+ * transliterator objects linked together. For example, if one
+ * transliterator transliterates from script A to script B, and
+ * another transliterates from script B to script C, the two may be
+ * combined to form a new transliterator from A to C.
+ *
+ * <p>Composed transliterators may not behave as expected. For
+ * example, inverses may not combine to form the identity
+ * transliterator. See the class documentation for {@link
+ * Transliterator} for details.
+ *
+ * @author Alan Liu
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+class U_I18N_API CompoundTransliterator : public Transliterator {
+
+ Transliterator** trans;
+
+ int32_t count;
+
+ int32_t numAnonymousRBTs;
+
+public:
+
+ /**
+ * Constructs a new compound transliterator given an array of
+ * transliterators. The array of transliterators may be of any
+ * length, including zero or one, however, useful compound
+ * transliterators have at least two components.
+ * @param transliterators array of <code>Transliterator</code>
+ * objects
+ * @param transliteratorCount The number of
+ * <code>Transliterator</code> objects in transliterators.
+ * @param adoptedFilter the filter. Any character for which
+ * <tt>filter.contains()</tt> returns <tt>false</tt> will not be
+ * altered by this transliterator. If <tt>filter</tt> is
+ * <tt>null</tt> then no filtering is applied.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator(Transliterator* const transliterators[],
+ int32_t transliteratorCount,
+ UnicodeFilter* adoptedFilter = 0);
+
+ /**
+ * Constructs a new compound transliterator.
+ * @param id compound ID
+ * @param dir either UTRANS_FORWARD or UTRANS_REVERSE
+ * @param adoptedFilter a global filter for this compound transliterator
+ * or NULL
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator(const UnicodeString& id,
+ UTransDirection dir,
+ UnicodeFilter* adoptedFilter,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ /**
+ * Constructs a new compound transliterator in the FORWARD
+ * direction with a NULL filter.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator(const UnicodeString& id,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Destructor.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual ~CompoundTransliterator();
+
+ /**
+ * Copy constructor.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator(const CompoundTransliterator&);
+
+ /**
+ * Transliterator API.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * Returns the number of transliterators in this chain.
+ * @return number of transliterators in this chain.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual int32_t getCount(void) const;
+
+ /**
+ * Returns the transliterator at the given index in this chain.
+ * @param index index into chain, from 0 to <code>getCount() - 1</code>
+ * @return transliterator at the given index
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual const Transliterator& getTransliterator(int32_t index) const;
+
+ /**
+ * Sets the transliterators.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ void setTransliterators(Transliterator* const transliterators[],
+ int32_t count);
+
+ /**
+ * Adopts the transliterators.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ void adoptTransliterators(Transliterator* adoptedTransliterators[],
+ int32_t count);
+
+ /**
+ * Override Transliterator:
+ * Create a rule string that can be passed to createFromRules()
+ * to recreate this transliterator.
+ * @param result the string to receive the rules. Previous
+ * contents will be deleted.
+ * @param escapeUnprintable if TRUE then convert unprintable
+ * character to their hex escape representations, \uxxxx or
+ * \Uxxxxxxxx. Unprintable characters are those other than
+ * U+000A, U+0020..U+007E.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual UnicodeString& toRules(UnicodeString& result,
+ UBool escapeUnprintable) const;
+
+ protected:
+ /**
+ * Implement Transliterator framework
+ */
+ virtual void handleGetSourceSet(UnicodeSet& result) const;
+
+ public:
+ /**
+ * Override Transliterator framework
+ */
+ virtual UnicodeSet& getTargetSet(UnicodeSet& result) const;
+
+protected:
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& index,
+ UBool incremental) const;
+
+public:
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /* @internal */
+ static const UChar PASS_STRING[];
+
+private:
+
+ friend class Transliterator;
+ friend class TransliteratorAlias; // to access private ct
+
+ /**
+ * Assignment operator.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ CompoundTransliterator& operator=(const CompoundTransliterator&);
+
+ /**
+ * Private constructor for Transliterator.
+ */
+ CompoundTransliterator(const UnicodeString& ID,
+ UVector& list,
+ UnicodeFilter* adoptedFilter,
+ int32_t numAnonymousRBTs,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ CompoundTransliterator(UVector& list,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ CompoundTransliterator(UVector& list,
+ int32_t anonymousRBTs,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ void init(const UnicodeString& id,
+ UTransDirection direction,
+ UBool fixReverseID,
+ UErrorCode& status);
+
+ void init(UVector& list,
+ UTransDirection direction,
+ UBool fixReverseID,
+ UErrorCode& status);
+
+ /**
+ * Return the IDs of the given list of transliterators, concatenated
+ * with ';' delimiting them. Equivalent to the perlish expression
+ * join(';', map($_.getID(), transliterators).
+ */
+ UnicodeString joinIDs(Transliterator* const transliterators[],
+ int32_t transCount);
+
+ void freeTransliterators(void);
+
+ void computeMaximumContextLength(void);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csdetect.cpp b/Build/source/libs/icu/icu-xetex/i18n/csdetect.cpp
new file mode 100644
index 00000000000..08412477a0b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csdetect.cpp
@@ -0,0 +1,391 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "unicode/ucsdet.h"
+
+#include "csdetect.h"
+#include "csmatch.h"
+#include "uenumimp.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+#include "umutex.h"
+#include "ucln_in.h"
+#include "uarrsort.h"
+#include "inputext.h"
+#include "csrsbcs.h"
+#include "csrmbcs.h"
+#include "csrutf8.h"
+#include "csrucode.h"
+#include "csr2022.h"
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
+#define DELETE_ARRAY(array) uprv_free((void *) (array))
+
+U_CDECL_BEGIN
+static U_NAMESPACE_QUALIFIER CharsetRecognizer **fCSRecognizers = NULL;
+
+static int32_t fCSRecognizers_size = 0;
+
+static UBool U_CALLCONV csdet_cleanup(void)
+{
+ if (fCSRecognizers != NULL) {
+ for(int32_t r = 0; r < fCSRecognizers_size; r += 1) {
+ delete fCSRecognizers[r];
+ fCSRecognizers[r] = NULL;
+ }
+
+ DELETE_ARRAY(fCSRecognizers);
+ fCSRecognizers = NULL;
+ fCSRecognizers_size = 0;
+ }
+
+ return TRUE;
+}
+
+static int32_t U_CALLCONV
+charsetMatchComparator(const void * /*context*/, const void *left, const void *right)
+{
+ U_NAMESPACE_USE
+
+ const CharsetMatch **csm_l = (const CharsetMatch **) left;
+ const CharsetMatch **csm_r = (const CharsetMatch **) right;
+
+ // NOTE: compare is backwards to sort from highest to lowest.
+ return (*csm_r)->getConfidence() - (*csm_l)->getConfidence();
+}
+
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+void CharsetDetector::setRecognizers(UErrorCode &status)
+{
+ UBool needsInit;
+ CharsetRecognizer **recognizers;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UMTX_CHECK(NULL, (UBool) (fCSRecognizers == NULL), needsInit);
+
+ if (needsInit) {
+ CharsetRecognizer *tempArray[] = {
+ new CharsetRecog_UTF8(),
+
+ new CharsetRecog_UTF_16_BE(),
+ new CharsetRecog_UTF_16_LE(),
+ new CharsetRecog_UTF_32_BE(),
+ new CharsetRecog_UTF_32_LE(),
+
+ new CharsetRecog_8859_1_en(),
+ new CharsetRecog_8859_1_da(),
+ new CharsetRecog_8859_1_de(),
+ new CharsetRecog_8859_1_es(),
+ new CharsetRecog_8859_1_fr(),
+ new CharsetRecog_8859_1_it(),
+ new CharsetRecog_8859_1_nl(),
+ new CharsetRecog_8859_1_no(),
+ new CharsetRecog_8859_1_pt(),
+ new CharsetRecog_8859_1_sv(),
+ new CharsetRecog_8859_2_cs(),
+ new CharsetRecog_8859_2_hu(),
+ new CharsetRecog_8859_2_pl(),
+ new CharsetRecog_8859_2_ro(),
+ new CharsetRecog_8859_5_ru(),
+ new CharsetRecog_8859_6_ar(),
+ new CharsetRecog_8859_7_el(),
+ new CharsetRecog_8859_8_I_he(),
+ new CharsetRecog_8859_8_he(),
+ new CharsetRecog_windows_1251(),
+ new CharsetRecog_windows_1256(),
+ new CharsetRecog_KOI8_R(),
+ new CharsetRecog_8859_9_tr(),
+ new CharsetRecog_sjis(),
+ new CharsetRecog_gb_18030(),
+ new CharsetRecog_euc_jp(),
+ new CharsetRecog_euc_kr(),
+ new CharsetRecog_big5(),
+
+ new CharsetRecog_2022JP(),
+ new CharsetRecog_2022KR(),
+ new CharsetRecog_2022CN()
+ };
+ int32_t rCount = ARRAY_SIZE(tempArray);
+ int32_t r;
+
+ recognizers = NEW_ARRAY(CharsetRecognizer *, rCount);
+
+ if (recognizers == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ for (r = 0; r < rCount; r += 1) {
+ recognizers[r] = tempArray[r];
+
+ if (recognizers[r] == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ }
+ }
+
+ if (U_SUCCESS(status)) {
+ umtx_lock(NULL);
+ if (fCSRecognizers == NULL) {
+ fCSRecognizers = recognizers;
+ fCSRecognizers_size = rCount;
+ }
+ umtx_unlock(NULL);
+ }
+
+ if (fCSRecognizers != recognizers) {
+ for (r = 0; r < rCount; r += 1) {
+ delete recognizers[r];
+ recognizers[r] = NULL;
+ }
+
+ DELETE_ARRAY(recognizers);
+ }
+
+ recognizers = NULL;
+ ucln_i18n_registerCleanup(UCLN_I18N_CSDET, csdet_cleanup);
+ }
+}
+
+CharsetDetector::CharsetDetector(UErrorCode &status)
+ : textIn(new InputText()), resultCount(0), fStripTags(FALSE), fFreshTextSet(FALSE)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ setRecognizers(status);
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ resultArray = (CharsetMatch **)uprv_malloc(sizeof(CharsetMatch *)*fCSRecognizers_size);
+
+ if (resultArray == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ for(int32_t i = 0; i < fCSRecognizers_size; i += 1) {
+ resultArray[i] = new CharsetMatch();
+
+ if (resultArray[i] == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ }
+}
+
+CharsetDetector::~CharsetDetector()
+{
+ delete textIn;
+
+ for(int32_t i = 0; i < fCSRecognizers_size; i += 1) {
+ delete resultArray[i];
+ }
+
+ uprv_free(resultArray);
+}
+
+void CharsetDetector::setText(const char *in, int32_t len)
+{
+ textIn->setText(in, len);
+ fFreshTextSet = TRUE;
+}
+
+UBool CharsetDetector::setStripTagsFlag(UBool flag)
+{
+ UBool temp = fStripTags;
+ fStripTags = flag;
+ fFreshTextSet = TRUE;
+ return temp;
+}
+
+UBool CharsetDetector::getStripTagsFlag() const
+{
+ return fStripTags;
+}
+
+void CharsetDetector::setDeclaredEncoding(const char *encoding, int32_t len) const
+{
+ textIn->setDeclaredEncoding(encoding,len);
+}
+
+int32_t CharsetDetector::getDetectableCount()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ setRecognizers(status);
+
+ return fCSRecognizers_size;
+}
+
+const CharsetMatch *CharsetDetector::detect(UErrorCode &status)
+{
+ int32_t maxMatchesFound = 0;
+
+ detectAll(maxMatchesFound, status);
+
+ if(maxMatchesFound > 0) {
+ return resultArray[0];
+ } else {
+ return NULL;
+ }
+}
+
+const CharsetMatch * const *CharsetDetector::detectAll(int32_t &maxMatchesFound, UErrorCode &status)
+{
+ if(!textIn->isSet()) {
+ status = U_MISSING_RESOURCE_ERROR;// TODO: Need to set proper status code for input text not set
+
+ return NULL;
+ } else if(fFreshTextSet) {
+ CharsetRecognizer *csr;
+ int32_t detectResults;
+ int32_t confidence;
+ int32_t i;
+
+ textIn->MungeInput(fStripTags);
+
+ // Iterate over all possible charsets, remember all that
+ // give a match quality > 0.
+ resultCount = 0;
+ for (i = 0; i < fCSRecognizers_size; i += 1) {
+ csr = fCSRecognizers[i];
+ detectResults = csr->match(textIn);
+ confidence = detectResults;
+
+ if (confidence > 0) {
+ resultArray[resultCount++]->set(textIn, csr, confidence);
+ }
+ }
+
+ for(i = resultCount; i < fCSRecognizers_size; i += 1) {
+ resultArray[i]->set(textIn, 0, 0);
+ }
+
+ uprv_sortArray(resultArray, resultCount, sizeof resultArray[0], charsetMatchComparator, NULL, TRUE, &status);
+ ////Bubble sort
+ //for(int32_t i = resultCount; i > 1; i -= 1) {
+ // for(int32_t j = 0; j < i-1; j += 1) {
+ // if(resultArray[j]->getConfidence() < resultArray[j+1]->getConfidence()) {
+ // CharsetMatch *temp = resultArray[j];
+ // resultArray[j] = resultArray[j+1];
+ // resultArray[j+1] = temp;
+ // }
+ // }
+ //}
+
+ fFreshTextSet = FALSE;
+ }
+
+ maxMatchesFound = resultCount;
+
+ return resultArray;
+}
+
+/*const char *CharsetDetector::getCharsetName(int32_t index, UErrorCode &status) const
+{
+ if( index > fCSRecognizers_size-1 || index < 0) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+
+ return 0;
+ } else {
+ return fCSRecognizers[index]->getName();
+ }
+}*/
+
+U_NAMESPACE_END
+
+U_CDECL_BEGIN
+typedef struct {
+ int32_t currIndex;
+} Context;
+
+
+
+static void U_CALLCONV
+enumClose(UEnumeration *en) {
+ if(en->context != NULL) {
+ DELETE_ARRAY(en->context);
+ }
+
+ DELETE_ARRAY(en);
+}
+
+static int32_t U_CALLCONV
+enumCount(UEnumeration *, UErrorCode *) {
+ return fCSRecognizers_size;
+}
+
+static const char* U_CALLCONV
+enumNext(UEnumeration *en, int32_t *resultLength, UErrorCode * /*status*/) {
+ if(((Context *)en->context)->currIndex >= fCSRecognizers_size) {
+ if(resultLength != NULL) {
+ *resultLength = 0;
+ }
+ return NULL;
+ }
+ const char *currName = fCSRecognizers[((Context *)en->context)->currIndex]->getName();
+ if(resultLength != NULL) {
+ *resultLength = (int32_t)uprv_strlen(currName);
+ }
+ ((Context *)en->context)->currIndex++;
+
+ return currName;
+}
+
+static void U_CALLCONV
+enumReset(UEnumeration *en, UErrorCode *) {
+ ((Context *)en->context)->currIndex = 0;
+}
+
+static const UEnumeration gCSDetEnumeration = {
+ NULL,
+ NULL,
+ enumClose,
+ enumCount,
+ uenum_unextDefault,
+ enumNext,
+ enumReset
+};
+
+U_CAPI UEnumeration * U_EXPORT2
+ucsdet_getAllDetectableCharsets(const UCharsetDetector *ucsd, UErrorCode *status)
+{
+ U_NAMESPACE_USE
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ /* Initialize recognized charsets. */
+ CharsetDetector::getDetectableCount();
+
+ UEnumeration *en = NEW_ARRAY(UEnumeration, 1);
+ memcpy(en, &gCSDetEnumeration, sizeof(UEnumeration));
+ en->context = (void*)NEW_ARRAY(Context, 1);
+ uprv_memset(en->context, 0, sizeof(Context));
+ return en;
+}
+U_CDECL_END
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csdetect.h b/Build/source/libs/icu/icu-xetex/i18n/csdetect.h
new file mode 100644
index 00000000000..405e1f55800
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csdetect.h
@@ -0,0 +1,56 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __CSDETECT_H
+#define __CSDETECT_H
+
+#include "unicode/uobject.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+U_NAMESPACE_BEGIN
+
+class InputText;
+class CharsetRecognizer;
+class CharsetMatch;
+
+class CharsetDetector : public UMemory
+{
+private:
+ InputText *textIn;
+ CharsetMatch **resultArray;
+ int32_t resultCount;
+ UBool fStripTags; // If true, setText() will strip tags from input text.
+ UBool fFreshTextSet;
+ static void setRecognizers(UErrorCode &status);
+
+public:
+ CharsetDetector(UErrorCode &status);
+
+ ~CharsetDetector();
+
+ void setText(const char *in, int32_t len);
+
+ const CharsetMatch * const *detectAll(int32_t &maxMatchesFound, UErrorCode &status);
+
+ const CharsetMatch *detect(UErrorCode& status);
+
+ void setDeclaredEncoding(const char *encoding, int32_t len) const;
+
+ UBool setStripTagsFlag(UBool flag);
+
+ UBool getStripTagsFlag() const;
+
+// const char *getCharsetName(int32_t index, UErrorCode& status) const;
+
+ static int32_t getDetectableCount();
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __CSDETECT_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csmatch.cpp b/Build/source/libs/icu/icu-xetex/i18n/csmatch.cpp
new file mode 100644
index 00000000000..f1d25d2dde9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csmatch.cpp
@@ -0,0 +1,61 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+#include "unicode/unistr.h"
+#include "unicode/ucnv.h"
+
+#include "csmatch.h"
+
+#include "csrecog.h"
+#include "inputext.h"
+
+U_NAMESPACE_BEGIN
+
+CharsetMatch::CharsetMatch()
+ : csr(0), confidence(0)
+{
+ // nothing else to do.
+}
+
+void CharsetMatch::set(InputText *input, CharsetRecognizer *cr, int32_t conf)
+{
+ textIn = input;
+ csr = cr;
+ confidence = conf;
+}
+
+const char* CharsetMatch::getName()const
+{
+ return csr->getName();
+}
+
+const char* CharsetMatch::getLanguage()const
+{
+ return csr->getLanguage();
+}
+
+int32_t CharsetMatch::getConfidence()const
+{
+ return confidence;
+}
+
+int32_t CharsetMatch::getUChars(UChar *buf, int32_t cap, UErrorCode *status) const
+{
+ UConverter *conv = ucnv_open(getName(), status);
+ int32_t result = ucnv_toUChars(conv, buf, cap, (const char *) textIn->fRawInput, textIn->fRawLength, status);
+
+ ucnv_close(conv);
+
+ return result;
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csmatch.h b/Build/source/libs/icu/icu-xetex/i18n/csmatch.h
new file mode 100644
index 00000000000..50b78a3a1dc
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csmatch.h
@@ -0,0 +1,44 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __CSMATCH_H
+#define __CSMATCH_H
+
+#include "unicode/uobject.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+U_NAMESPACE_BEGIN
+
+class InputText;
+class CharsetRecognizer;
+
+class CharsetMatch : public UMemory
+{
+ private:
+ CharsetRecognizer *csr;
+ InputText *textIn;
+ int32_t confidence;
+
+ public:
+ CharsetMatch();
+
+ void set(InputText *input, CharsetRecognizer *cr, int32_t conf);
+
+ const char *getName()const;
+
+ const char *getLanguage()const;
+
+ int32_t getConfidence()const;
+
+ int32_t getUChars(UChar *buf, int32_t cap, UErrorCode *status) const;
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __CSMATCH_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csr2022.cpp b/Build/source/libs/icu/icu-xetex/i18n/csr2022.cpp
new file mode 100644
index 00000000000..c7165f1c0d3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csr2022.cpp
@@ -0,0 +1,172 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "cstring.h"
+
+#include "csr2022.h"
+
+U_NAMESPACE_BEGIN
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+/**
+ * Matching function shared among the 2022 detectors JP, CN and KR
+ * Counts up the number of legal an unrecognized escape sequences in
+ * the sample of text, and computes a score based on the total number &
+ * the proportion that fit the encoding.
+ *
+ *
+ * @param text the byte buffer containing text to analyse
+ * @param textLen the size of the text in the byte.
+ * @param escapeSequences the byte escape sequences to test for.
+ * @return match quality, in the range of 0-100.
+ */
+int32_t CharsetRecog_2022::match_2022(const uint8_t *text, int32_t textLen, const uint8_t escapeSequences[][5], int32_t escapeSequences_length)
+{
+ int32_t i, j;
+ int32_t escN;
+ int32_t hits = 0;
+ int32_t misses = 0;
+ int32_t shifts = 0;
+ int32_t quality;
+
+ i = 0;
+ while(i < textLen) {
+ if(text[i] == 0x1B) {
+ escN = 0;
+ while(escN < escapeSequences_length) {
+ int32_t seq_length = uprv_strlen((const char *) escapeSequences[escN]);
+ const uint8_t *seq = escapeSequences[escN];
+
+ j = 1;
+ while(j < seq_length) {
+ if(seq[j] != text[i+j]) {
+ goto checkEscapes;
+ }
+
+ j += 1;
+ }
+
+ hits += 1;
+ i += seq_length-1;
+ goto scanInput;
+checkEscapes:
+ escN += 1;
+ }
+
+ misses += 1;
+ }
+
+ if( text[i]== 0x0e || text[i] == 0x0f){
+ shifts += 1;
+ }
+
+scanInput:
+ i += 1;
+ }
+
+ if (hits == 0) {
+ return 0;
+ }
+
+ //
+ // Initial quality is based on relative proportion of recongized vs.
+ // unrecognized escape sequences.
+ // All good: quality = 100;
+ // half or less good: quality = 0;
+ // linear inbetween.
+ quality = (100*hits - 100*misses) / (hits + misses);
+
+ // Back off quality if there were too few escape sequences seen.
+ // Include shifts in this computation, so that KR does not get penalized
+ // for having only a single Escape sequence, but many shifts.
+ if (hits+shifts < 5) {
+ quality -= (5-(hits+shifts))*10;
+ }
+
+ if (quality < 0) {
+ quality = 0;
+ }
+
+ return quality;
+}
+
+
+static const uint8_t escapeSequences_2022JP[][5] = {
+ {0x1b, 0x24, 0x28, 0x43, 0x00}, // KS X 1001:1992
+ {0x1b, 0x24, 0x28, 0x44, 0x00}, // JIS X 212-1990
+ {0x1b, 0x24, 0x40, 0x00, 0x00}, // JIS C 6226-1978
+ {0x1b, 0x24, 0x41, 0x00, 0x00}, // GB 2312-80
+ {0x1b, 0x24, 0x42, 0x00, 0x00}, // JIS X 208-1983
+ {0x1b, 0x26, 0x40, 0x00, 0x00}, // JIS X 208 1990, 1997
+ {0x1b, 0x28, 0x42, 0x00, 0x00}, // ASCII
+ {0x1b, 0x28, 0x48, 0x00, 0x00}, // JIS-Roman
+ {0x1b, 0x28, 0x49, 0x00, 0x00}, // Half-width katakana
+ {0x1b, 0x28, 0x4a, 0x00, 0x00}, // JIS-Roman
+ {0x1b, 0x2e, 0x41, 0x00, 0x00}, // ISO 8859-1
+ {0x1b, 0x2e, 0x46, 0x00, 0x00} // ISO 8859-7
+};
+
+static const uint8_t escapeSequences_2022KR[][5] = {
+ {0x1b, 0x24, 0x29, 0x43, 0x00}
+};
+
+static const uint8_t escapeSequences_2022CN[][5] = {
+ {0x1b, 0x24, 0x29, 0x41, 0x00}, // GB 2312-80
+ {0x1b, 0x24, 0x29, 0x47, 0x00}, // CNS 11643-1992 Plane 1
+ {0x1b, 0x24, 0x2A, 0x48, 0x00}, // CNS 11643-1992 Plane 2
+ {0x1b, 0x24, 0x29, 0x45, 0x00}, // ISO-IR-165
+ {0x1b, 0x24, 0x2B, 0x49, 0x00}, // CNS 11643-1992 Plane 3
+ {0x1b, 0x24, 0x2B, 0x4A, 0x00}, // CNS 11643-1992 Plane 4
+ {0x1b, 0x24, 0x2B, 0x4B, 0x00}, // CNS 11643-1992 Plane 5
+ {0x1b, 0x24, 0x2B, 0x4C, 0x00}, // CNS 11643-1992 Plane 6
+ {0x1b, 0x24, 0x2B, 0x4D, 0x00}, // CNS 11643-1992 Plane 7
+ {0x1b, 0x4e, 0x00, 0x00, 0x00}, // SS2
+ {0x1b, 0x4f, 0x00, 0x00, 0x00}, // SS3
+};
+
+const char *CharsetRecog_2022JP::getName() const
+{
+ return "ISO-2022-JP";
+}
+
+int32_t CharsetRecog_2022JP::match(InputText *textIn)
+{
+ return match_2022(textIn->fInputBytes, textIn->fInputLen, escapeSequences_2022JP, ARRAY_SIZE(escapeSequences_2022JP));
+}
+
+const char *CharsetRecog_2022KR::getName() const
+{
+ return "ISO-2022-KR";
+}
+
+int32_t CharsetRecog_2022KR::match(InputText *textIn)
+{
+ return match_2022(textIn->fInputBytes, textIn->fInputLen, escapeSequences_2022KR, ARRAY_SIZE(escapeSequences_2022KR));
+}
+
+const char *CharsetRecog_2022CN::getName() const
+{
+ return "ISO-2022-CN";
+}
+
+int32_t CharsetRecog_2022CN::match(InputText *textIn)
+{
+ return match_2022(textIn->fInputBytes, textIn->fInputLen, escapeSequences_2022CN, ARRAY_SIZE(escapeSequences_2022CN));
+}
+
+CharsetRecog_2022::~CharsetRecog_2022()
+{
+ // nothing to do
+}
+
+U_NAMESPACE_END
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csr2022.h b/Build/source/libs/icu/icu-xetex/i18n/csr2022.h
new file mode 100644
index 00000000000..5d34711bdc3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csr2022.h
@@ -0,0 +1,86 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __CSR2022_H
+#define __CSR2022_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "csrecog.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * class CharsetRecog_2022 part of the ICU charset detection imlementation.
+ * This is a superclass for the individual detectors for
+ * each of the detectable members of the ISO 2022 family
+ * of encodings.
+ *
+ * The separate classes are nested within this class.
+ *
+ * @internal
+ */
+class CharsetRecog_2022 : public CharsetRecognizer
+{
+
+public:
+ virtual ~CharsetRecog_2022() = 0;
+
+protected:
+
+ /**
+ * Matching function shared among the 2022 detectors JP, CN and KR
+ * Counts up the number of legal an unrecognized escape sequences in
+ * the sample of text, and computes a score based on the total number &
+ * the proportion that fit the encoding.
+ *
+ *
+ * @param text the byte buffer containing text to analyse
+ * @param textLen the size of the text in the byte.
+ * @param escapeSequences the byte escape sequences to test for.
+ * @return match quality, in the range of 0-100.
+ */
+ int32_t match_2022(const uint8_t *text, int32_t textLen, const uint8_t escapeSequences[][5], int32_t escapeSequences_length);
+
+};
+
+class CharsetRecog_2022JP :public CharsetRecog_2022
+{
+public:
+ virtual ~CharsetRecog_2022JP() {}
+
+ const char *getName() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_2022KR :public CharsetRecog_2022 {
+public:
+ virtual ~CharsetRecog_2022KR() {}
+
+ const char *getName() const;
+
+ int32_t match(InputText *textIn);
+
+};
+
+class CharsetRecog_2022CN :public CharsetRecog_2022
+{
+public:
+ virtual ~CharsetRecog_2022CN() {}
+
+ const char* getName() const;
+
+ int32_t match(InputText *textIn);
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __CSR2022_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrecog.cpp b/Build/source/libs/icu/icu-xetex/i18n/csrecog.cpp
new file mode 100644
index 00000000000..ba70b1547f8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrecog.cpp
@@ -0,0 +1,28 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "csrecog.h"
+
+U_NAMESPACE_BEGIN
+
+CharsetRecognizer::~CharsetRecognizer()
+{
+ // nothing to do.
+}
+
+const char *CharsetRecognizer::getLanguage() const
+{
+ return "";
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrecog.h b/Build/source/libs/icu/icu-xetex/i18n/csrecog.h
new file mode 100644
index 00000000000..75cf94f49f4
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrecog.h
@@ -0,0 +1,42 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __CSRECOG_H
+#define __CSRECOG_H
+
+#include "unicode/uobject.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "inputext.h"
+
+U_NAMESPACE_BEGIN
+
+class CharsetRecognizer : public UMemory
+{
+ public:
+ /**
+ * Get the IANA name of this charset.
+ * @return the charset name.
+ */
+ virtual const char *getName() const = 0;
+
+ /**
+ * Get the ISO language code for this charset.
+ * @return the language code, or <code>null</code> if the language cannot be determined.
+ */
+ virtual const char *getLanguage() const;
+
+ virtual int32_t match(InputText *textIn) = 0;
+
+ virtual ~CharsetRecognizer();
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __CSRECOG_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrmbcs.cpp b/Build/source/libs/icu/icu-xetex/i18n/csrmbcs.cpp
new file mode 100644
index 00000000000..11f70a78861
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrmbcs.cpp
@@ -0,0 +1,517 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "csrmbcs.h"
+
+#include <math.h>
+
+U_NAMESPACE_BEGIN
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define min(x,y) (((x)<(y))?(x):(y))
+
+const int32_t commonChars_sjis [] = {
+// TODO: This set of data comes from the character frequency-
+// of-occurence analysis tool. The data needs to be moved
+// into a resource and loaded from there.
+0x8140, 0x8141, 0x8142, 0x8145, 0x815b, 0x8169, 0x816a, 0x8175, 0x8176, 0x82a0,
+0x82a2, 0x82a4, 0x82a9, 0x82aa, 0x82ab, 0x82ad, 0x82af, 0x82b1, 0x82b3, 0x82b5,
+0x82b7, 0x82bd, 0x82be, 0x82c1, 0x82c4, 0x82c5, 0x82c6, 0x82c8, 0x82c9, 0x82cc,
+0x82cd, 0x82dc, 0x82e0, 0x82e7, 0x82e8, 0x82e9, 0x82ea, 0x82f0, 0x82f1, 0x8341,
+0x8343, 0x834e, 0x834f, 0x8358, 0x835e, 0x8362, 0x8367, 0x8375, 0x8376, 0x8389,
+0x838a, 0x838b, 0x838d, 0x8393, 0x8e96, 0x93fa, 0x95aa};
+
+const int32_t commonChars_euc_jp[] = {
+// TODO: This set of data comes from the character frequency-
+// of-occurence analysis tool. The data needs to be moved
+// into a resource and loaded from there.
+0xa1a1, 0xa1a2, 0xa1a3, 0xa1a6, 0xa1bc, 0xa1ca, 0xa1cb, 0xa1d6, 0xa1d7, 0xa4a2,
+0xa4a4, 0xa4a6, 0xa4a8, 0xa4aa, 0xa4ab, 0xa4ac, 0xa4ad, 0xa4af, 0xa4b1, 0xa4b3,
+0xa4b5, 0xa4b7, 0xa4b9, 0xa4bb, 0xa4bd, 0xa4bf, 0xa4c0, 0xa4c1, 0xa4c3, 0xa4c4,
+0xa4c6, 0xa4c7, 0xa4c8, 0xa4c9, 0xa4ca, 0xa4cb, 0xa4ce, 0xa4cf, 0xa4d0, 0xa4de,
+0xa4df, 0xa4e1, 0xa4e2, 0xa4e4, 0xa4e8, 0xa4e9, 0xa4ea, 0xa4eb, 0xa4ec, 0xa4ef,
+0xa4f2, 0xa4f3, 0xa5a2, 0xa5a3, 0xa5a4, 0xa5a6, 0xa5a7, 0xa5aa, 0xa5ad, 0xa5af,
+0xa5b0, 0xa5b3, 0xa5b5, 0xa5b7, 0xa5b8, 0xa5b9, 0xa5bf, 0xa5c3, 0xa5c6, 0xa5c7,
+0xa5c8, 0xa5c9, 0xa5cb, 0xa5d0, 0xa5d5, 0xa5d6, 0xa5d7, 0xa5de, 0xa5e0, 0xa5e1,
+0xa5e5, 0xa5e9, 0xa5ea, 0xa5eb, 0xa5ec, 0xa5ed, 0xa5f3, 0xb8a9, 0xb9d4, 0xbaee,
+0xbbc8, 0xbef0, 0xbfb7, 0xc4ea, 0xc6fc, 0xc7bd, 0xcab8, 0xcaf3, 0xcbdc, 0xcdd1};
+
+const int32_t commonChars_euc_kr[] = {
+// TODO: This set of data comes from the character frequency-
+// of-occurence analysis tool. The data needs to be moved
+// into a resource and loaded from there.
+0xb0a1, 0xb0b3, 0xb0c5, 0xb0cd, 0xb0d4, 0xb0e6, 0xb0ed, 0xb0f8, 0xb0fa, 0xb0fc,
+0xb1b8, 0xb1b9, 0xb1c7, 0xb1d7, 0xb1e2, 0xb3aa, 0xb3bb, 0xb4c2, 0xb4cf, 0xb4d9,
+0xb4eb, 0xb5a5, 0xb5b5, 0xb5bf, 0xb5c7, 0xb5e9, 0xb6f3, 0xb7af, 0xb7c2, 0xb7ce,
+0xb8a6, 0xb8ae, 0xb8b6, 0xb8b8, 0xb8bb, 0xb8e9, 0xb9ab, 0xb9ae, 0xb9cc, 0xb9ce,
+0xb9fd, 0xbab8, 0xbace, 0xbad0, 0xbaf1, 0xbbe7, 0xbbf3, 0xbbfd, 0xbcad, 0xbcba,
+0xbcd2, 0xbcf6, 0xbdba, 0xbdc0, 0xbdc3, 0xbdc5, 0xbec6, 0xbec8, 0xbedf, 0xbeee,
+0xbef8, 0xbefa, 0xbfa1, 0xbfa9, 0xbfc0, 0xbfe4, 0xbfeb, 0xbfec, 0xbff8, 0xc0a7,
+0xc0af, 0xc0b8, 0xc0ba, 0xc0bb, 0xc0bd, 0xc0c7, 0xc0cc, 0xc0ce, 0xc0cf, 0xc0d6,
+0xc0da, 0xc0e5, 0xc0fb, 0xc0fc, 0xc1a4, 0xc1a6, 0xc1b6, 0xc1d6, 0xc1df, 0xc1f6,
+0xc1f8, 0xc4a1, 0xc5cd, 0xc6ae, 0xc7cf, 0xc7d1, 0xc7d2, 0xc7d8, 0xc7e5, 0xc8ad};
+
+const int32_t commonChars_big5[] = {
+// TODO: This set of data comes from the character frequency-
+// of-occurence analysis tool. The data needs to be moved
+// into a resource and loaded from there.
+0xa140, 0xa141, 0xa142, 0xa143, 0xa147, 0xa149, 0xa175, 0xa176, 0xa440, 0xa446,
+0xa447, 0xa448, 0xa451, 0xa454, 0xa457, 0xa464, 0xa46a, 0xa46c, 0xa477, 0xa4a3,
+0xa4a4, 0xa4a7, 0xa4c1, 0xa4ce, 0xa4d1, 0xa4df, 0xa4e8, 0xa4fd, 0xa540, 0xa548,
+0xa558, 0xa569, 0xa5cd, 0xa5e7, 0xa657, 0xa661, 0xa662, 0xa668, 0xa670, 0xa6a8,
+0xa6b3, 0xa6b9, 0xa6d3, 0xa6db, 0xa6e6, 0xa6f2, 0xa740, 0xa751, 0xa759, 0xa7da,
+0xa8a3, 0xa8a5, 0xa8ad, 0xa8d1, 0xa8d3, 0xa8e4, 0xa8fc, 0xa9c0, 0xa9d2, 0xa9f3,
+0xaa6b, 0xaaba, 0xaabe, 0xaacc, 0xaafc, 0xac47, 0xac4f, 0xacb0, 0xacd2, 0xad59,
+0xaec9, 0xafe0, 0xb0ea, 0xb16f, 0xb2b3, 0xb2c4, 0xb36f, 0xb44c, 0xb44e, 0xb54c,
+0xb5a5, 0xb5bd, 0xb5d0, 0xb5d8, 0xb671, 0xb7ed, 0xb867, 0xb944, 0xbad8, 0xbb44,
+0xbba1, 0xbdd1, 0xc2c4, 0xc3b9, 0xc440, 0xc45f};
+
+const int32_t commonChars_gb_18030[] = {
+// TODO: This set of data comes from the character frequency-
+// of-occurence analysis tool. The data needs to be moved
+// into a resource and loaded from there.
+0xa1a1, 0xa1a2, 0xa1a3, 0xa1a4, 0xa1b0, 0xa1b1, 0xa1f1, 0xa1f3, 0xa3a1, 0xa3ac,
+0xa3ba, 0xb1a8, 0xb1b8, 0xb1be, 0xb2bb, 0xb3c9, 0xb3f6, 0xb4f3, 0xb5bd, 0xb5c4,
+0xb5e3, 0xb6af, 0xb6d4, 0xb6e0, 0xb7a2, 0xb7a8, 0xb7bd, 0xb7d6, 0xb7dd, 0xb8b4,
+0xb8df, 0xb8f6, 0xb9ab, 0xb9c9, 0xb9d8, 0xb9fa, 0xb9fd, 0xbacd, 0xbba7, 0xbbd6,
+0xbbe1, 0xbbfa, 0xbcbc, 0xbcdb, 0xbcfe, 0xbdcc, 0xbecd, 0xbedd, 0xbfb4, 0xbfc6,
+0xbfc9, 0xc0b4, 0xc0ed, 0xc1cb, 0xc2db, 0xc3c7, 0xc4dc, 0xc4ea, 0xc5cc, 0xc6f7,
+0xc7f8, 0xc8ab, 0xc8cb, 0xc8d5, 0xc8e7, 0xc9cf, 0xc9fa, 0xcab1, 0xcab5, 0xcac7,
+0xcad0, 0xcad6, 0xcaf5, 0xcafd, 0xccec, 0xcdf8, 0xceaa, 0xcec4, 0xced2, 0xcee5,
+0xcfb5, 0xcfc2, 0xcfd6, 0xd0c2, 0xd0c5, 0xd0d0, 0xd0d4, 0xd1a7, 0xd2aa, 0xd2b2,
+0xd2b5, 0xd2bb, 0xd2d4, 0xd3c3, 0xd3d0, 0xd3fd, 0xd4c2, 0xd4da, 0xd5e2, 0xd6d0};
+
+static int32_t binarySearch(const int32_t *array, int32_t len, int32_t value)
+{
+ int32_t start = 0, end = len-1;
+ int32_t mid = (start+end)/2;
+
+ while(start <= end) {
+ if(array[mid] == value) {
+ return mid;
+ }
+
+ if(array[mid] < value){
+ start = mid+1;
+ } else {
+ end = mid-1;
+ }
+
+ mid = (start+end)/2;
+ }
+
+ return -1;
+}
+
+IteratedChar::IteratedChar():charValue(0), index(0), nextIndex(0), error(FALSE), done(FALSE)
+{
+ // nothing else to do.
+}
+
+void IteratedChar::reset()
+{
+ charValue = 0;
+ index = -1;
+ nextIndex = 0;
+ error = FALSE;
+ done = FALSE;
+}
+
+int32_t IteratedChar::nextByte(InputText *det)
+{
+ if (nextIndex >= det->fRawLength) {
+ done = TRUE;
+
+ return -1;
+ }
+
+ return det->fRawInput[nextIndex++];
+}
+
+CharsetRecog_mbcs::~CharsetRecog_mbcs()
+{
+ // nothing to do.
+}
+
+int32_t CharsetRecog_mbcs::match_mbcs(InputText *det, const int32_t commonChars[], int32_t commonCharsLen) {
+ int singleByteCharCount = 0;
+ int doubleByteCharCount = 0;
+ int commonCharCount = 0;
+ int badCharCount = 0;
+ int totalCharCount = 0;
+ int confidence = 0;
+ IteratedChar *iter = new IteratedChar();
+
+ // {
+ for (iter->reset(); nextChar(iter, det);) {
+ totalCharCount += 1;
+
+ if (iter->error) {
+ badCharCount += 1;
+ } else {
+ if (iter->charValue <= 0xFF) {
+ singleByteCharCount += 1;
+ } else {
+ doubleByteCharCount += 1;
+
+ if (commonChars != 0) {
+ if (binarySearch(commonChars, commonCharsLen, iter->charValue) >= 0){
+ commonCharCount += 1;
+ }
+ }
+ }
+ }
+
+
+ if (badCharCount >= 2 && badCharCount*5 >= doubleByteCharCount) {
+ // Bail out early if the byte data is not matching the encoding scheme.
+ // break detectBlock;
+ delete iter;
+ return confidence;
+ }
+ }
+
+ delete iter;
+
+ if (doubleByteCharCount <= 10 && badCharCount == 0) {
+ // Not many multi-byte chars.
+ // ASCII or ISO file? It's probably not our encoding,
+ // but is not incompatible with our encoding, so don't give it a zero.
+ confidence = 10;
+
+ return confidence;
+ }
+
+ //
+ // No match if there are too many characters that don't fit the encoding scheme.
+ // (should we have zero tolerance for these?)
+ //
+ if (doubleByteCharCount < 20*badCharCount) {
+ confidence = 0;
+
+ return confidence;
+ }
+
+ if (commonChars == 0) {
+ // We have no statistics on frequently occuring characters.
+ // Assess confidence purely on having a reasonable number of
+ // multi-byte characters (the more the better)
+ confidence = 30 + doubleByteCharCount - 20*badCharCount;
+
+ if (confidence > 100) {
+ confidence = 100;
+ }
+ } else {
+ //
+ // Frequency of occurence statistics exist.
+ //
+
+ double maxVal = log10((double)doubleByteCharCount / 4); /*(float)?*/
+ double scaleFactor = 90.0 / maxVal;
+ confidence = (int32_t)(log10((double)commonCharCount+1) * scaleFactor + 10.0);
+
+ confidence = min(confidence, 100);
+ }
+
+ if (confidence < 0) {
+ confidence = 0;
+ }
+
+ return confidence;
+}
+
+CharsetRecog_sjis::~CharsetRecog_sjis()
+{
+ // nothing to do
+}
+
+UBool CharsetRecog_sjis::nextChar(IteratedChar* it, InputText* det) {
+ it->index = it->nextIndex;
+ it->error = FALSE;
+
+ int32_t firstByte = it->charValue = it->nextByte(det);
+
+ if (firstByte < 0) {
+ return FALSE;
+ }
+
+ if (firstByte <= 0x7F || (firstByte > 0xA0 && firstByte <= 0xDF)) {
+ return TRUE;
+ }
+
+ int32_t secondByte = it->nextByte(det);
+
+ if (secondByte < 0) {
+ return FALSE;
+ }
+ it->charValue = (firstByte << 8) | secondByte;
+ if (! ((secondByte >= 0x40 && secondByte <= 0x7F) || (secondByte >= 0x80 && secondByte <= 0xFE))) {
+ // Illegal second byte value.
+ it->error = TRUE;
+ }
+
+ return TRUE;
+}
+
+int32_t CharsetRecog_sjis::match(InputText* det)
+{
+ return match_mbcs(det, commonChars_sjis, ARRAY_SIZE(commonChars_sjis));
+}
+
+const char *CharsetRecog_sjis::getName() const
+{
+ return "Shift_JIS";
+}
+
+const char *CharsetRecog_sjis::getLanguage() const
+{
+ return "ja";
+}
+
+CharsetRecog_euc::~CharsetRecog_euc()
+{
+ // nothing to do
+}
+
+UBool CharsetRecog_euc::nextChar(IteratedChar* it, InputText* det) {
+ int32_t firstByte = 0;
+ int32_t secondByte = 0;
+ int32_t thirdByte = 0;
+ // int32_t fourthByte = 0;
+
+ it->index = it->nextIndex;
+ it->error = FALSE;
+ firstByte = it->charValue = it->nextByte(det);
+
+ if (firstByte < 0) {
+ // Ran off the end of the input data
+ it->done = TRUE;
+
+ return (! it->done);
+ }
+
+ if (firstByte <= 0x8D) {
+ // single byte char
+ return (! it->done);
+ }
+
+ secondByte = it->nextByte(det);
+ it->charValue = (it->charValue << 8) | secondByte;
+
+ if (firstByte >= 0xA1 && firstByte <= 0xFE) {
+ // Two byte Char
+ if (secondByte < 0xA1) {
+ it->error = TRUE;
+ }
+
+ return (! it->done);
+ }
+
+ if (firstByte == 0x8E) {
+ // Code Set 2.
+ // In EUC-JP, total char size is 2 bytes, only one byte of actual char value.
+ // In EUC-TW, total char size is 4 bytes, three bytes contribute to char value.
+ // We don't know which we've got.
+ // Treat it like EUC-JP. If the data really was EUC-TW, the following two
+ // bytes will look like a well formed 2 byte char.
+ if (secondByte < 0xA1) {
+ it->error = TRUE;
+ }
+
+ return (! it->done);
+ }
+
+ if (firstByte == 0x8F) {
+ // Code set 3.
+ // Three byte total char size, two bytes of actual char value.
+ thirdByte = it->nextByte(det);
+ it->charValue = (it->charValue << 8) | thirdByte;
+
+ if (thirdByte < 0xa1) {
+ it->error = TRUE;
+ }
+ }
+
+ return (! it->done);
+
+}
+
+CharsetRecog_euc_jp::~CharsetRecog_euc_jp()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_euc_jp::getName() const
+{
+ return "EUC-JP";
+}
+
+const char *CharsetRecog_euc_jp::getLanguage() const
+{
+ return "ja";
+}
+
+int32_t CharsetRecog_euc_jp::match(InputText *det)
+{
+ return match_mbcs(det, commonChars_euc_jp, ARRAY_SIZE(commonChars_euc_jp));
+}
+
+CharsetRecog_euc_kr::~CharsetRecog_euc_kr()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_euc_kr::getName() const
+{
+ return "EUC-KR";
+}
+
+const char *CharsetRecog_euc_kr::getLanguage() const
+{
+ return "ko";
+}
+
+int32_t CharsetRecog_euc_kr::match(InputText *det)
+{
+ return match_mbcs(det, commonChars_euc_kr, ARRAY_SIZE(commonChars_euc_kr));
+}
+
+CharsetRecog_big5::~CharsetRecog_big5()
+{
+ // nothing to do
+}
+
+UBool CharsetRecog_big5::nextChar(IteratedChar* it, InputText* det)
+{
+ int32_t firstByte;
+
+ it->index = it->nextIndex;
+ it->error = FALSE;
+ firstByte = it->charValue = it->nextByte(det);
+
+ if (firstByte < 0) {
+ return FALSE;
+ }
+
+ if (firstByte <= 0x7F || firstByte == 0xFF) {
+ // single byte character.
+ return TRUE;
+ }
+
+ int32_t secondByte = it->nextByte(det);
+
+ if (secondByte < 0) {
+ return FALSE;
+ }
+
+ it->charValue = (it->charValue << 8) | secondByte;
+
+ if (secondByte < 0x40 ||
+ secondByte == 0x7F ||
+ secondByte == 0xFF) {
+ it->error = TRUE;
+ }
+
+ return TRUE;
+}
+
+const char *CharsetRecog_big5::getName() const
+{
+ return "Big5";
+}
+
+const char *CharsetRecog_big5::getLanguage() const
+{
+ return "zh";
+}
+
+int32_t CharsetRecog_big5::match(InputText *det)
+{
+ return match_mbcs(det, commonChars_big5, ARRAY_SIZE(commonChars_big5));
+}
+
+CharsetRecog_gb_18030::~CharsetRecog_gb_18030()
+{
+ // nothing to do
+}
+
+UBool CharsetRecog_gb_18030::nextChar(IteratedChar* it, InputText* det) {
+ int32_t firstByte = 0;
+ int32_t secondByte = 0;
+ int32_t thirdByte = 0;
+ int32_t fourthByte = 0;
+
+ it->index = it->nextIndex;
+ it->error = FALSE;
+ firstByte = it->charValue = it->nextByte(det);
+
+ if (firstByte < 0) {
+ // Ran off the end of the input data
+ it->done = TRUE;
+
+ return (! it->done);
+ }
+
+ if (firstByte <= 0x80) {
+ // single byte char
+ return (! it->done);
+ }
+
+ secondByte = it->nextByte(det);
+ it->charValue = (it->charValue << 8) | secondByte;
+
+ if (firstByte >= 0x81 && firstByte <= 0xFE) {
+ // Two byte Char
+ if ((secondByte >= 0x40 && secondByte <= 0x7E) || (secondByte >=80 && secondByte <= 0xFE)) {
+ return (! it->done);
+ }
+
+ // Four byte char
+ if (secondByte >= 0x30 && secondByte <= 0x39) {
+ thirdByte = it->nextByte(det);
+
+ if (thirdByte >= 0x81 && thirdByte <= 0xFE) {
+ fourthByte = it->nextByte(det);
+
+ if (fourthByte >= 0x30 && fourthByte <= 0x39) {
+ it->charValue = (it->charValue << 16) | (thirdByte << 8) | fourthByte;
+
+ return (! it->done);
+ }
+ }
+ }
+
+ it->error = TRUE;
+
+ return (! it->done);
+ }
+
+ return (! it->done);
+}
+
+const char *CharsetRecog_gb_18030::getName() const
+{
+ return "GB18030";
+}
+
+const char *CharsetRecog_gb_18030::getLanguage() const
+{
+ return "zh";
+}
+
+int32_t CharsetRecog_gb_18030::match(InputText *det)
+{
+ return match_mbcs(det, commonChars_gb_18030, ARRAY_SIZE(commonChars_gb_18030));
+}
+
+U_NAMESPACE_END
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrmbcs.h b/Build/source/libs/icu/icu-xetex/i18n/csrmbcs.h
new file mode 100644
index 00000000000..4a5f1e63f20
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrmbcs.h
@@ -0,0 +1,205 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __CSRMBCS_H
+#define __CSRMBCS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "csrecog.h"
+
+U_NAMESPACE_BEGIN
+
+// "Character" iterated character class.
+// Recognizers for specific mbcs encodings make their "characters" available
+// by providing a nextChar() function that fills in an instance of IteratedChar
+// with the next char from the input.
+// The returned characters are not converted to Unicode, but remain as the raw
+// bytes (concatenated into an int) from the codepage data.
+//
+// For Asian charsets, use the raw input rather than the input that has been
+// stripped of markup. Detection only considers multi-byte chars, effectively
+// stripping markup anyway, and double byte chars do occur in markup too.
+//
+class IteratedChar : public UMemory
+{
+public:
+ uint32_t charValue; // 1-4 bytes from the raw input data
+ int32_t index;
+ int32_t nextIndex;
+ UBool error;
+ UBool done;
+
+public:
+ IteratedChar();
+ void reset();
+ int32_t nextByte(InputText* det);
+};
+
+
+class CharsetRecog_mbcs : public CharsetRecognizer {
+
+protected:
+ /**
+ * Test the match of this charset with the input text data
+ * which is obtained via the CharsetDetector object.
+ *
+ * @param det The CharsetDetector, which contains the input text
+ * to be checked for being in this charset.
+ * @return Two values packed into one int (Damn java, anyhow)
+ * <br/>
+ * bits 0-7: the match confidence, ranging from 0-100
+ * <br/>
+ * bits 8-15: The match reason, an enum-like value.
+ */
+ int32_t match_mbcs(InputText* det, const int32_t commonChars[], int32_t commonCharsLen);
+
+public:
+
+ virtual ~CharsetRecog_mbcs();
+
+ /**
+ * Get the IANA name of this charset.
+ * @return the charset name.
+ */
+
+ const char *getName() const = 0;
+ const char *getLanguage() const = 0;
+ int32_t match(InputText* det) = 0;
+
+ /**
+ * Get the next character (however many bytes it is) from the input data
+ * Subclasses for specific charset encodings must implement this function
+ * to get characters according to the rules of their encoding scheme.
+ *
+ * This function is not a method of class IteratedChar only because
+ * that would require a lot of extra derived classes, which is awkward.
+ * @param it The IteratedChar "struct" into which the returned char is placed.
+ * @param det The charset detector, which is needed to get at the input byte data
+ * being iterated over.
+ * @return True if a character was returned, false at end of input.
+ */
+ virtual UBool nextChar(IteratedChar *it, InputText *textIn) = 0;
+
+};
+
+
+/**
+ * Shift-JIS charset recognizer.
+ *
+ */
+class CharsetRecog_sjis : public CharsetRecog_mbcs {
+public:
+ virtual ~CharsetRecog_sjis();
+
+ UBool nextChar(IteratedChar *it, InputText *det);
+
+ int32_t match(InputText *det);
+
+ const char *getName() const;
+ const char *getLanguage() const;
+
+};
+
+
+/**
+ * EUC charset recognizers. One abstract class that provides the common function
+ * for getting the next character according to the EUC encoding scheme,
+ * and nested derived classes for EUC_KR, EUC_JP, EUC_CN.
+ *
+ */
+class CharsetRecog_euc : public CharsetRecog_mbcs
+{
+public:
+ virtual ~CharsetRecog_euc();
+
+ const char *getName() const = 0;
+ const char *getLanguage() const = 0;
+
+ int32_t match(InputText* det) = 0;
+ /*
+ * (non-Javadoc)
+ * Get the next character value for EUC based encodings.
+ * Character "value" is simply the raw bytes that make up the character
+ * packed into an int.
+ */
+ UBool nextChar(IteratedChar *it, InputText *det);
+};
+
+/**
+ * The charset recognize for EUC-JP. A singleton instance of this class
+ * is created and kept by the public CharsetDetector class
+ */
+class CharsetRecog_euc_jp : public CharsetRecog_euc
+{
+public:
+ virtual ~CharsetRecog_euc_jp();
+
+ const char *getName() const;
+ const char *getLanguage() const;
+
+ int32_t match(InputText *det);
+};
+
+/**
+ * The charset recognize for EUC-KR. A singleton instance of this class
+ * is created and kept by the public CharsetDetector class
+ */
+class CharsetRecog_euc_kr : public CharsetRecog_euc
+{
+public:
+ virtual ~CharsetRecog_euc_kr();
+
+ const char *getName() const;
+ const char *getLanguage() const;
+
+ int32_t match(InputText *det);
+};
+
+/**
+ *
+ * Big5 charset recognizer.
+ *
+ */
+class CharsetRecog_big5 : public CharsetRecog_mbcs
+{
+public:
+ virtual ~CharsetRecog_big5();
+
+ UBool nextChar(IteratedChar* it, InputText* det);
+
+ const char *getName() const;
+ const char *getLanguage() const;
+
+ int32_t match(InputText *det);
+};
+
+
+/**
+ *
+ * GB-18030 recognizer. Uses simplified Chinese statistics.
+ *
+ */
+class CharsetRecog_gb_18030 : public CharsetRecog_mbcs
+{
+public:
+ virtual ~CharsetRecog_gb_18030();
+
+ UBool nextChar(IteratedChar* it, InputText* det);
+
+ const char *getName() const;
+ const char *getLanguage() const;
+
+ int32_t match(InputText *det);
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __CSRMBCS_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrsbcs.cpp b/Build/source/libs/icu/icu-xetex/i18n/csrsbcs.cpp
new file mode 100644
index 00000000000..ddf5aedf520
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrsbcs.cpp
@@ -0,0 +1,1099 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+#include "csrsbcs.h"
+
+#include <stdio.h>
+
+#define N_GRAM_SIZE 3
+#define N_GRAM_MASK 0xFFFFFF
+
+U_NAMESPACE_BEGIN
+
+NGramParser::NGramParser(const int32_t *theNgramList, const uint8_t *theCharMap)
+ :byteIndex(0), ngram(0)
+{
+ ngramList = theNgramList;
+ charMap = theCharMap;
+
+ ngramCount = hitCount = 0;
+}
+
+/*
+ * Binary search for value in table, which must have exactly 64 entries.
+ */
+
+int32_t NGramParser::search(const int32_t *table, int32_t value)
+{
+ int32_t index = 0;
+
+ if (table[index + 32] <= value) {
+ index += 32;
+ }
+
+ if (table[index + 16] <= value) {
+ index += 16;
+ }
+
+ if (table[index + 8] <= value) {
+ index += 8;
+ }
+
+ if (table[index + 4] <= value) {
+ index += 4;
+ }
+
+ if (table[index + 2] <= value) {
+ index += 2;
+ }
+
+ if (table[index + 1] <= value) {
+ index += 1;
+ }
+
+ if (table[index] > value) {
+ index -= 1;
+ }
+
+ if (index < 0 || table[index] != value) {
+ return -1;
+ }
+
+ return index;
+}
+
+void NGramParser::lookup(int32_t thisNgram)
+{
+ ngramCount += 1;
+
+ if (search(ngramList, thisNgram) >= 0) {
+ hitCount += 1;
+ }
+
+}
+
+void NGramParser::addByte(int32_t b)
+{
+ ngram = ((ngram << 8) + b) & N_GRAM_MASK;
+ lookup(ngram);
+}
+
+int32_t NGramParser::nextByte(InputText *det)
+{
+ if (byteIndex >= det->fInputLen) {
+ return -1;
+ }
+
+ return det->fInputBytes[byteIndex++];
+}
+
+int32_t NGramParser::parse(InputText *det)
+{
+ int32_t b;
+ bool ignoreSpace = FALSE;
+
+ while ((b = nextByte(det)) >= 0) {
+ uint8_t mb = charMap[b];
+
+ // TODO: 0x20 might not be a space in all character sets...
+ if (mb != 0) {
+ if (!(mb == 0x20 && ignoreSpace)) {
+ addByte(mb);
+ }
+
+ ignoreSpace = (mb == 0x20);
+ }
+ }
+
+ // TODO: Is this OK? The buffer could have ended in the middle of a word...
+ addByte(0x20);
+
+ double rawPercent = (double) hitCount / (double) ngramCount;
+
+ // if (rawPercent <= 2.0) {
+ // return 0;
+ // }
+
+ // TODO - This is a bit of a hack to take care of a case
+ // were we were getting a confidence of 135...
+ if (rawPercent > 0.33) {
+ return 98;
+ }
+
+ return (int32_t) (rawPercent * 300.0);
+}
+
+CharsetRecog_sbcs::CharsetRecog_sbcs()
+: haveC1Bytes(FALSE)
+{
+ // nothing else to do
+}
+
+CharsetRecog_sbcs::~CharsetRecog_sbcs()
+{
+ // nothing to do
+}
+
+int32_t CharsetRecog_sbcs::match_sbcs(InputText *det, const int32_t ngrams[], const uint8_t byteMap[])
+{
+ NGramParser *parser = new NGramParser(ngrams, byteMap);
+ int32_t result;
+
+ haveC1Bytes = det->fC1Bytes;
+ result = parser->parse(det);
+ delete parser;
+
+ return result;
+}
+
+static const uint8_t charMap_8859_1[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0xAA, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0xB5, 0x20, 0x20,
+ 0x20, 0x20, 0xBA, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0x20,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0x20,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
+};
+
+static const uint8_t charMap_8859_2[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0xB1, 0x20, 0xB3, 0x20, 0xB5, 0xB6, 0x20,
+ 0x20, 0xB9, 0xBA, 0xBB, 0xBC, 0x20, 0xBE, 0xBF,
+ 0x20, 0xB1, 0x20, 0xB3, 0x20, 0xB5, 0xB6, 0xB7,
+ 0x20, 0xB9, 0xBA, 0xBB, 0xBC, 0x20, 0xBE, 0xBF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0x20,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0x20,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x20,
+};
+
+static const uint8_t charMap_8859_5[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0x20, 0xFE, 0xFF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0x20, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0x20, 0xFE, 0xFF,
+};
+
+static const uint8_t charMap_8859_6[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+};
+
+static const uint8_t charMap_8859_7[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0xA1, 0xA2, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xDC, 0x20,
+ 0xDD, 0xDE, 0xDF, 0x20, 0xFC, 0x20, 0xFD, 0xFE,
+ 0xC0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0x20, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x20,
+};
+
+static const uint8_t charMap_8859_8[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0xB5, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0x20, 0x20, 0x20, 0x20, 0x20,
+};
+
+static const uint8_t charMap_8859_9[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0xAA, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0xB5, 0x20, 0x20,
+ 0x20, 0x20, 0xBA, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0x20,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0x69, 0xFE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0x20,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
+};
+
+static const int32_t ngrams_windows_1251[] = {
+ 0x20E220, 0x20E2EE, 0x20E4EE, 0x20E7E0, 0x20E820, 0x20EAE0, 0x20EAEE, 0x20EDE0, 0x20EDE5, 0x20EEE1, 0x20EFEE, 0x20EFF0, 0x20F0E0, 0x20F1EE, 0x20F1F2, 0x20F2EE,
+ 0x20F7F2, 0x20FDF2, 0xE0EDE8, 0xE0F2FC, 0xE3EE20, 0xE5EBFC, 0xE5EDE8, 0xE5F1F2, 0xE5F220, 0xE820EF, 0xE8E520, 0xE8E820, 0xE8FF20, 0xEBE5ED, 0xEBE820, 0xEBFCED,
+ 0xEDE020, 0xEDE520, 0xEDE8E5, 0xEDE8FF, 0xEDEE20, 0xEDEEE2, 0xEE20E2, 0xEE20EF, 0xEE20F1, 0xEEE220, 0xEEE2E0, 0xEEE3EE, 0xEEE920, 0xEEEBFC, 0xEEEC20, 0xEEF1F2,
+ 0xEFEEEB, 0xEFF0E5, 0xEFF0E8, 0xEFF0EE, 0xF0E0E2, 0xF0E5E4, 0xF1F2E0, 0xF1F2E2, 0xF1F2E8, 0xF1FF20, 0xF2E5EB, 0xF2EE20, 0xF2EEF0, 0xF2FC20, 0xF7F2EE, 0xFBF520,
+};
+
+static const uint8_t charMap_windows_1251[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x90, 0x83, 0x20, 0x83, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x9A, 0x20, 0x9C, 0x9D, 0x9E, 0x9F,
+ 0x90, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x9A, 0x20, 0x9C, 0x9D, 0x9E, 0x9F,
+ 0x20, 0xA2, 0xA2, 0xBC, 0x20, 0xB4, 0x20, 0x20,
+ 0xB8, 0x20, 0xBA, 0x20, 0x20, 0x20, 0x20, 0xBF,
+ 0x20, 0x20, 0xB3, 0xB3, 0xB4, 0xB5, 0x20, 0x20,
+ 0xB8, 0x20, 0xBA, 0x20, 0xBC, 0xBE, 0xBE, 0xBF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
+};
+
+static const int32_t ngrams_windows_1256[] = {
+ 0x20C7E1, 0x20C7E4, 0x20C8C7, 0x20DAE1, 0x20DDED, 0x20E1E1, 0x20E3E4, 0x20E6C7, 0xC720C7, 0xC7C120, 0xC7CA20, 0xC7D120, 0xC7E120, 0xC7E1C3, 0xC7E1C7, 0xC7E1C8,
+ 0xC7E1CA, 0xC7E1CC, 0xC7E1CD, 0xC7E1CF, 0xC7E1D3, 0xC7E1DA, 0xC7E1DE, 0xC7E1E3, 0xC7E1E6, 0xC7E1ED, 0xC7E320, 0xC7E420, 0xC7E4CA, 0xC820C7, 0xC920C7, 0xC920DD,
+ 0xC920E1, 0xC920E3, 0xC920E6, 0xCA20C7, 0xCF20C7, 0xCFC920, 0xD120C7, 0xD1C920, 0xD320C7, 0xDA20C7, 0xDAE1EC, 0xDDED20, 0xE120C7, 0xE1C920, 0xE1EC20, 0xE1ED20,
+ 0xE320C7, 0xE3C720, 0xE3C920, 0xE3E420, 0xE420C7, 0xE520C7, 0xE5C720, 0xE6C7E1, 0xE6E420, 0xEC20C7, 0xED20C7, 0xED20E3, 0xED20E6, 0xEDC920, 0xEDD120, 0xEDE420,
+};
+
+static const uint8_t charMap_windows_1256[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x81, 0x20, 0x83, 0x20, 0x20, 0x20, 0x20,
+ 0x88, 0x20, 0x8A, 0x20, 0x9C, 0x8D, 0x8E, 0x8F,
+ 0x90, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x98, 0x20, 0x9A, 0x20, 0x9C, 0x20, 0x20, 0x9F,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0xAA, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0xB5, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0x20,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0x20, 0x20, 0x20, 0x20, 0xF4, 0x20, 0x20, 0x20,
+ 0x20, 0xF9, 0x20, 0xFB, 0xFC, 0x20, 0x20, 0xFF,
+};
+
+static const int32_t ngrams_KOI8_R[] = {
+ 0x20C4CF, 0x20C920, 0x20CBC1, 0x20CBCF, 0x20CEC1, 0x20CEC5, 0x20CFC2, 0x20D0CF, 0x20D0D2, 0x20D2C1, 0x20D3CF, 0x20D3D4, 0x20D4CF, 0x20D720, 0x20D7CF, 0x20DAC1,
+ 0x20DCD4, 0x20DED4, 0xC1CEC9, 0xC1D4D8, 0xC5CCD8, 0xC5CEC9, 0xC5D3D4, 0xC5D420, 0xC7CF20, 0xC920D0, 0xC9C520, 0xC9C920, 0xC9D120, 0xCCC5CE, 0xCCC920, 0xCCD8CE,
+ 0xCEC120, 0xCEC520, 0xCEC9C5, 0xCEC9D1, 0xCECF20, 0xCECFD7, 0xCF20D0, 0xCF20D3, 0xCF20D7, 0xCFC7CF, 0xCFCA20, 0xCFCCD8, 0xCFCD20, 0xCFD3D4, 0xCFD720, 0xCFD7C1,
+ 0xD0CFCC, 0xD0D2C5, 0xD0D2C9, 0xD0D2CF, 0xD2C1D7, 0xD2C5C4, 0xD3D120, 0xD3D4C1, 0xD3D4C9, 0xD3D4D7, 0xD4C5CC, 0xD4CF20, 0xD4CFD2, 0xD4D820, 0xD9C820, 0xDED4CF,
+};
+
+static const uint8_t charMap_KOI8_R[] = {
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0xA3, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0xA3, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+};
+
+//ISO-8859-1,2,5,6,7,8,9 Ngrams
+static const int32_t ngrams_8859_1_en[] = {
+ 0x206120, 0x20616E, 0x206265, 0x20636F, 0x20666F, 0x206861, 0x206865, 0x20696E, 0x206D61, 0x206F66, 0x207072, 0x207265, 0x207361, 0x207374, 0x207468, 0x20746F,
+ 0x207768, 0x616964, 0x616C20, 0x616E20, 0x616E64, 0x617320, 0x617420, 0x617465, 0x617469, 0x642061, 0x642074, 0x652061, 0x652073, 0x652074, 0x656420, 0x656E74,
+ 0x657220, 0x657320, 0x666F72, 0x686174, 0x686520, 0x686572, 0x696420, 0x696E20, 0x696E67, 0x696F6E, 0x697320, 0x6E2061, 0x6E2074, 0x6E6420, 0x6E6720, 0x6E7420,
+ 0x6F6620, 0x6F6E20, 0x6F7220, 0x726520, 0x727320, 0x732061, 0x732074, 0x736169, 0x737420, 0x742074, 0x746572, 0x746861, 0x746865, 0x74696F, 0x746F20, 0x747320,
+};
+
+static const int32_t ngrams_8859_1_da[] = {
+ 0x206166, 0x206174, 0x206465, 0x20656E, 0x206572, 0x20666F, 0x206861, 0x206920, 0x206D65, 0x206F67, 0x2070E5, 0x207369, 0x207374, 0x207469, 0x207669, 0x616620,
+ 0x616E20, 0x616E64, 0x617220, 0x617420, 0x646520, 0x64656E, 0x646572, 0x646574, 0x652073, 0x656420, 0x656465, 0x656E20, 0x656E64, 0x657220, 0x657265, 0x657320,
+ 0x657420, 0x666F72, 0x676520, 0x67656E, 0x676572, 0x696765, 0x696C20, 0x696E67, 0x6B6520, 0x6B6B65, 0x6C6572, 0x6C6967, 0x6C6C65, 0x6D6564, 0x6E6465, 0x6E6520,
+ 0x6E6720, 0x6E6765, 0x6F6720, 0x6F6D20, 0x6F7220, 0x70E520, 0x722064, 0x722065, 0x722073, 0x726520, 0x737465, 0x742073, 0x746520, 0x746572, 0x74696C, 0x766572,
+};
+
+static const int32_t ngrams_8859_1_de[] = {
+ 0x20616E, 0x206175, 0x206265, 0x206461, 0x206465, 0x206469, 0x206569, 0x206765, 0x206861, 0x20696E, 0x206D69, 0x207363, 0x207365, 0x20756E, 0x207665, 0x20766F,
+ 0x207765, 0x207A75, 0x626572, 0x636820, 0x636865, 0x636874, 0x646173, 0x64656E, 0x646572, 0x646965, 0x652064, 0x652073, 0x65696E, 0x656974, 0x656E20, 0x657220,
+ 0x657320, 0x67656E, 0x68656E, 0x687420, 0x696368, 0x696520, 0x696E20, 0x696E65, 0x697420, 0x6C6963, 0x6C6C65, 0x6E2061, 0x6E2064, 0x6E2073, 0x6E6420, 0x6E6465,
+ 0x6E6520, 0x6E6720, 0x6E6765, 0x6E7465, 0x722064, 0x726465, 0x726569, 0x736368, 0x737465, 0x742064, 0x746520, 0x74656E, 0x746572, 0x756E64, 0x756E67, 0x766572,
+};
+
+static const int32_t ngrams_8859_1_es[] = {
+ 0x206120, 0x206361, 0x20636F, 0x206465, 0x20656C, 0x20656E, 0x206573, 0x20696E, 0x206C61, 0x206C6F, 0x207061, 0x20706F, 0x207072, 0x207175, 0x207265, 0x207365,
+ 0x20756E, 0x207920, 0x612063, 0x612064, 0x612065, 0x61206C, 0x612070, 0x616369, 0x61646F, 0x616C20, 0x617220, 0x617320, 0x6369F3, 0x636F6E, 0x646520, 0x64656C,
+ 0x646F20, 0x652064, 0x652065, 0x65206C, 0x656C20, 0x656E20, 0x656E74, 0x657320, 0x657374, 0x69656E, 0x69F36E, 0x6C6120, 0x6C6F73, 0x6E2065, 0x6E7465, 0x6F2064,
+ 0x6F2065, 0x6F6E20, 0x6F7220, 0x6F7320, 0x706172, 0x717565, 0x726120, 0x726573, 0x732064, 0x732065, 0x732070, 0x736520, 0x746520, 0x746F20, 0x756520, 0xF36E20,
+};
+
+static const int32_t ngrams_8859_1_fr[] = {
+ 0x206175, 0x20636F, 0x206461, 0x206465, 0x206475, 0x20656E, 0x206574, 0x206C61, 0x206C65, 0x207061, 0x20706F, 0x207072, 0x207175, 0x207365, 0x20736F, 0x20756E,
+ 0x20E020, 0x616E74, 0x617469, 0x636520, 0x636F6E, 0x646520, 0x646573, 0x647520, 0x652061, 0x652063, 0x652064, 0x652065, 0x65206C, 0x652070, 0x652073, 0x656E20,
+ 0x656E74, 0x657220, 0x657320, 0x657420, 0x657572, 0x696F6E, 0x697320, 0x697420, 0x6C6120, 0x6C6520, 0x6C6573, 0x6D656E, 0x6E2064, 0x6E6520, 0x6E7320, 0x6E7420,
+ 0x6F6E20, 0x6F6E74, 0x6F7572, 0x717565, 0x72206C, 0x726520, 0x732061, 0x732064, 0x732065, 0x73206C, 0x732070, 0x742064, 0x746520, 0x74696F, 0x756520, 0x757220,
+};
+
+static const int32_t ngrams_8859_1_it[] = {
+ 0x20616C, 0x206368, 0x20636F, 0x206465, 0x206469, 0x206520, 0x20696C, 0x20696E, 0x206C61, 0x207065, 0x207072, 0x20756E, 0x612063, 0x612064, 0x612070, 0x612073,
+ 0x61746F, 0x636865, 0x636F6E, 0x64656C, 0x646920, 0x652061, 0x652063, 0x652064, 0x652069, 0x65206C, 0x652070, 0x652073, 0x656C20, 0x656C6C, 0x656E74, 0x657220,
+ 0x686520, 0x692061, 0x692063, 0x692064, 0x692073, 0x696120, 0x696C20, 0x696E20, 0x696F6E, 0x6C6120, 0x6C6520, 0x6C6920, 0x6C6C61, 0x6E6520, 0x6E6920, 0x6E6F20,
+ 0x6E7465, 0x6F2061, 0x6F2064, 0x6F2069, 0x6F2073, 0x6F6E20, 0x6F6E65, 0x706572, 0x726120, 0x726520, 0x736920, 0x746120, 0x746520, 0x746920, 0x746F20, 0x7A696F,
+};
+
+static const int32_t ngrams_8859_1_nl[] = {
+ 0x20616C, 0x206265, 0x206461, 0x206465, 0x206469, 0x206565, 0x20656E, 0x206765, 0x206865, 0x20696E, 0x206D61, 0x206D65, 0x206F70, 0x207465, 0x207661, 0x207665,
+ 0x20766F, 0x207765, 0x207A69, 0x61616E, 0x616172, 0x616E20, 0x616E64, 0x617220, 0x617420, 0x636874, 0x646520, 0x64656E, 0x646572, 0x652062, 0x652076, 0x65656E,
+ 0x656572, 0x656E20, 0x657220, 0x657273, 0x657420, 0x67656E, 0x686574, 0x696520, 0x696E20, 0x696E67, 0x697320, 0x6E2062, 0x6E2064, 0x6E2065, 0x6E2068, 0x6E206F,
+ 0x6E2076, 0x6E6465, 0x6E6720, 0x6F6E64, 0x6F6F72, 0x6F7020, 0x6F7220, 0x736368, 0x737465, 0x742064, 0x746520, 0x74656E, 0x746572, 0x76616E, 0x766572, 0x766F6F,
+};
+
+static const int32_t ngrams_8859_1_no[] = {
+ 0x206174, 0x206176, 0x206465, 0x20656E, 0x206572, 0x20666F, 0x206861, 0x206920, 0x206D65, 0x206F67, 0x2070E5, 0x207365, 0x20736B, 0x20736F, 0x207374, 0x207469,
+ 0x207669, 0x20E520, 0x616E64, 0x617220, 0x617420, 0x646520, 0x64656E, 0x646574, 0x652073, 0x656420, 0x656E20, 0x656E65, 0x657220, 0x657265, 0x657420, 0x657474,
+ 0x666F72, 0x67656E, 0x696B6B, 0x696C20, 0x696E67, 0x6B6520, 0x6B6B65, 0x6C6520, 0x6C6C65, 0x6D6564, 0x6D656E, 0x6E2073, 0x6E6520, 0x6E6720, 0x6E6765, 0x6E6E65,
+ 0x6F6720, 0x6F6D20, 0x6F7220, 0x70E520, 0x722073, 0x726520, 0x736F6D, 0x737465, 0x742073, 0x746520, 0x74656E, 0x746572, 0x74696C, 0x747420, 0x747465, 0x766572,
+};
+
+static const int32_t ngrams_8859_1_pt[] = {
+ 0x206120, 0x20636F, 0x206461, 0x206465, 0x20646F, 0x206520, 0x206573, 0x206D61, 0x206E6F, 0x206F20, 0x207061, 0x20706F, 0x207072, 0x207175, 0x207265, 0x207365,
+ 0x20756D, 0x612061, 0x612063, 0x612064, 0x612070, 0x616465, 0x61646F, 0x616C20, 0x617220, 0x617261, 0x617320, 0x636F6D, 0x636F6E, 0x646120, 0x646520, 0x646F20,
+ 0x646F73, 0x652061, 0x652064, 0x656D20, 0x656E74, 0x657320, 0x657374, 0x696120, 0x696361, 0x6D656E, 0x6E7465, 0x6E746F, 0x6F2061, 0x6F2063, 0x6F2064, 0x6F2065,
+ 0x6F2070, 0x6F7320, 0x706172, 0x717565, 0x726120, 0x726573, 0x732061, 0x732064, 0x732065, 0x732070, 0x737461, 0x746520, 0x746F20, 0x756520, 0xE36F20, 0xE7E36F,
+};
+
+static const int32_t ngrams_8859_1_sv[] = {
+ 0x206174, 0x206176, 0x206465, 0x20656E, 0x2066F6, 0x206861, 0x206920, 0x20696E, 0x206B6F, 0x206D65, 0x206F63, 0x2070E5, 0x20736B, 0x20736F, 0x207374, 0x207469,
+ 0x207661, 0x207669, 0x20E472, 0x616465, 0x616E20, 0x616E64, 0x617220, 0x617474, 0x636820, 0x646520, 0x64656E, 0x646572, 0x646574, 0x656420, 0x656E20, 0x657220,
+ 0x657420, 0x66F672, 0x67656E, 0x696C6C, 0x696E67, 0x6B6120, 0x6C6C20, 0x6D6564, 0x6E2073, 0x6E6120, 0x6E6465, 0x6E6720, 0x6E6765, 0x6E696E, 0x6F6368, 0x6F6D20,
+ 0x6F6E20, 0x70E520, 0x722061, 0x722073, 0x726120, 0x736B61, 0x736F6D, 0x742073, 0x746120, 0x746520, 0x746572, 0x74696C, 0x747420, 0x766172, 0xE47220, 0xF67220,
+};
+
+static const int32_t ngrams_8859_2_cs[] = {
+ 0x206120, 0x206279, 0x20646F, 0x206A65, 0x206E61, 0x206E65, 0x206F20, 0x206F64, 0x20706F, 0x207072, 0x2070F8, 0x20726F, 0x207365, 0x20736F, 0x207374, 0x20746F,
+ 0x207620, 0x207679, 0x207A61, 0x612070, 0x636520, 0x636820, 0x652070, 0x652073, 0x652076, 0x656D20, 0x656EED, 0x686F20, 0x686F64, 0x697374, 0x6A6520, 0x6B7465,
+ 0x6C6520, 0x6C6920, 0x6E6120, 0x6EE920, 0x6EEC20, 0x6EED20, 0x6F2070, 0x6F646E, 0x6F6A69, 0x6F7374, 0x6F7520, 0x6F7661, 0x706F64, 0x706F6A, 0x70726F, 0x70F865,
+ 0x736520, 0x736F75, 0x737461, 0x737469, 0x73746E, 0x746572, 0x746EED, 0x746F20, 0x752070, 0xBE6520, 0xE16EED, 0xE9686F, 0xED2070, 0xED2073, 0xED6D20, 0xF86564,
+};
+
+static const int32_t ngrams_8859_2_hu[] = {
+ 0x206120, 0x20617A, 0x206265, 0x206567, 0x20656C, 0x206665, 0x206861, 0x20686F, 0x206973, 0x206B65, 0x206B69, 0x206BF6, 0x206C65, 0x206D61, 0x206D65, 0x206D69,
+ 0x206E65, 0x20737A, 0x207465, 0x20E973, 0x612061, 0x61206B, 0x61206D, 0x612073, 0x616B20, 0x616E20, 0x617A20, 0x62616E, 0x62656E, 0x656779, 0x656B20, 0x656C20,
+ 0x656C65, 0x656D20, 0x656E20, 0x657265, 0x657420, 0x657465, 0x657474, 0x677920, 0x686F67, 0x696E74, 0x697320, 0x6B2061, 0x6BF67A, 0x6D6567, 0x6D696E, 0x6E2061,
+ 0x6E616B, 0x6E656B, 0x6E656D, 0x6E7420, 0x6F6779, 0x732061, 0x737A65, 0x737A74, 0x737AE1, 0x73E967, 0x742061, 0x747420, 0x74E173, 0x7A6572, 0xE16E20, 0xE97320,
+};
+
+static const int32_t ngrams_8859_2_pl[] = {
+ 0x20637A, 0x20646F, 0x206920, 0x206A65, 0x206B6F, 0x206D61, 0x206D69, 0x206E61, 0x206E69, 0x206F64, 0x20706F, 0x207072, 0x207369, 0x207720, 0x207769, 0x207779,
+ 0x207A20, 0x207A61, 0x612070, 0x612077, 0x616E69, 0x636820, 0x637A65, 0x637A79, 0x646F20, 0x647A69, 0x652070, 0x652073, 0x652077, 0x65207A, 0x65676F, 0x656A20,
+ 0x656D20, 0x656E69, 0x676F20, 0x696120, 0x696520, 0x69656A, 0x6B6120, 0x6B6920, 0x6B6965, 0x6D6965, 0x6E6120, 0x6E6961, 0x6E6965, 0x6F2070, 0x6F7761, 0x6F7769,
+ 0x706F6C, 0x707261, 0x70726F, 0x70727A, 0x727A65, 0x727A79, 0x7369EA, 0x736B69, 0x737461, 0x776965, 0x796368, 0x796D20, 0x7A6520, 0x7A6965, 0x7A7920, 0xF37720,
+};
+
+static const int32_t ngrams_8859_2_ro[] = {
+ 0x206120, 0x206163, 0x206361, 0x206365, 0x20636F, 0x206375, 0x206465, 0x206469, 0x206C61, 0x206D61, 0x207065, 0x207072, 0x207365, 0x2073E3, 0x20756E, 0x20BA69,
+ 0x20EE6E, 0x612063, 0x612064, 0x617265, 0x617420, 0x617465, 0x617520, 0x636172, 0x636F6E, 0x637520, 0x63E320, 0x646520, 0x652061, 0x652063, 0x652064, 0x652070,
+ 0x652073, 0x656120, 0x656920, 0x656C65, 0x656E74, 0x657374, 0x692061, 0x692063, 0x692064, 0x692070, 0x696520, 0x696920, 0x696E20, 0x6C6120, 0x6C6520, 0x6C6F72,
+ 0x6C7569, 0x6E6520, 0x6E7472, 0x6F7220, 0x70656E, 0x726520, 0x726561, 0x727520, 0x73E320, 0x746520, 0x747275, 0x74E320, 0x756920, 0x756C20, 0xBA6920, 0xEE6E20,
+};
+
+static const int32_t ngrams_8859_5_ru[] = {
+ 0x20D220, 0x20D2DE, 0x20D4DE, 0x20D7D0, 0x20D820, 0x20DAD0, 0x20DADE, 0x20DDD0, 0x20DDD5, 0x20DED1, 0x20DFDE, 0x20DFE0, 0x20E0D0, 0x20E1DE, 0x20E1E2, 0x20E2DE,
+ 0x20E7E2, 0x20EDE2, 0xD0DDD8, 0xD0E2EC, 0xD3DE20, 0xD5DBEC, 0xD5DDD8, 0xD5E1E2, 0xD5E220, 0xD820DF, 0xD8D520, 0xD8D820, 0xD8EF20, 0xDBD5DD, 0xDBD820, 0xDBECDD,
+ 0xDDD020, 0xDDD520, 0xDDD8D5, 0xDDD8EF, 0xDDDE20, 0xDDDED2, 0xDE20D2, 0xDE20DF, 0xDE20E1, 0xDED220, 0xDED2D0, 0xDED3DE, 0xDED920, 0xDEDBEC, 0xDEDC20, 0xDEE1E2,
+ 0xDFDEDB, 0xDFE0D5, 0xDFE0D8, 0xDFE0DE, 0xE0D0D2, 0xE0D5D4, 0xE1E2D0, 0xE1E2D2, 0xE1E2D8, 0xE1EF20, 0xE2D5DB, 0xE2DE20, 0xE2DEE0, 0xE2EC20, 0xE7E2DE, 0xEBE520,
+};
+
+static const int32_t ngrams_8859_6_ar[] = {
+ 0x20C7E4, 0x20C7E6, 0x20C8C7, 0x20D9E4, 0x20E1EA, 0x20E4E4, 0x20E5E6, 0x20E8C7, 0xC720C7, 0xC7C120, 0xC7CA20, 0xC7D120, 0xC7E420, 0xC7E4C3, 0xC7E4C7, 0xC7E4C8,
+ 0xC7E4CA, 0xC7E4CC, 0xC7E4CD, 0xC7E4CF, 0xC7E4D3, 0xC7E4D9, 0xC7E4E2, 0xC7E4E5, 0xC7E4E8, 0xC7E4EA, 0xC7E520, 0xC7E620, 0xC7E6CA, 0xC820C7, 0xC920C7, 0xC920E1,
+ 0xC920E4, 0xC920E5, 0xC920E8, 0xCA20C7, 0xCF20C7, 0xCFC920, 0xD120C7, 0xD1C920, 0xD320C7, 0xD920C7, 0xD9E4E9, 0xE1EA20, 0xE420C7, 0xE4C920, 0xE4E920, 0xE4EA20,
+ 0xE520C7, 0xE5C720, 0xE5C920, 0xE5E620, 0xE620C7, 0xE720C7, 0xE7C720, 0xE8C7E4, 0xE8E620, 0xE920C7, 0xEA20C7, 0xEA20E5, 0xEA20E8, 0xEAC920, 0xEAD120, 0xEAE620,
+};
+
+static const int32_t ngrams_8859_7_el[] = {
+ 0x20E1ED, 0x20E1F0, 0x20E3E9, 0x20E4E9, 0x20E5F0, 0x20E720, 0x20EAE1, 0x20ECE5, 0x20EDE1, 0x20EF20, 0x20F0E1, 0x20F0EF, 0x20F0F1, 0x20F3F4, 0x20F3F5, 0x20F4E7,
+ 0x20F4EF, 0xDFE120, 0xE120E1, 0xE120F4, 0xE1E920, 0xE1ED20, 0xE1F0FC, 0xE1F220, 0xE3E9E1, 0xE5E920, 0xE5F220, 0xE720F4, 0xE7ED20, 0xE7F220, 0xE920F4, 0xE9E120,
+ 0xE9EADE, 0xE9F220, 0xEAE1E9, 0xEAE1F4, 0xECE520, 0xED20E1, 0xED20E5, 0xED20F0, 0xEDE120, 0xEFF220, 0xEFF520, 0xF0EFF5, 0xF0F1EF, 0xF0FC20, 0xF220E1, 0xF220E5,
+ 0xF220EA, 0xF220F0, 0xF220F4, 0xF3E520, 0xF3E720, 0xF3F4EF, 0xF4E120, 0xF4E1E9, 0xF4E7ED, 0xF4E7F2, 0xF4E9EA, 0xF4EF20, 0xF4EFF5, 0xF4F9ED, 0xF9ED20, 0xFEED20,
+};
+
+static const int32_t ngrams_8859_8_I_he[] = {
+ 0x20E0E5, 0x20E0E7, 0x20E0E9, 0x20E0FA, 0x20E1E9, 0x20E1EE, 0x20E4E0, 0x20E4E5, 0x20E4E9, 0x20E4EE, 0x20E4F2, 0x20E4F9, 0x20E4FA, 0x20ECE0, 0x20ECE4, 0x20EEE0,
+ 0x20F2EC, 0x20F9EC, 0xE0FA20, 0xE420E0, 0xE420E1, 0xE420E4, 0xE420EC, 0xE420EE, 0xE420F9, 0xE4E5E0, 0xE5E020, 0xE5ED20, 0xE5EF20, 0xE5F820, 0xE5FA20, 0xE920E4,
+ 0xE9E420, 0xE9E5FA, 0xE9E9ED, 0xE9ED20, 0xE9EF20, 0xE9F820, 0xE9FA20, 0xEC20E0, 0xEC20E4, 0xECE020, 0xECE420, 0xED20E0, 0xED20E1, 0xED20E4, 0xED20EC, 0xED20EE,
+ 0xED20F9, 0xEEE420, 0xEF20E4, 0xF0E420, 0xF0E920, 0xF0E9ED, 0xF2EC20, 0xF820E4, 0xF8E9ED, 0xF9EC20, 0xFA20E0, 0xFA20E1, 0xFA20E4, 0xFA20EC, 0xFA20EE, 0xFA20F9,
+};
+
+static const int32_t ngrams_8859_8_he[] = {
+ 0x20E0E5, 0x20E0EC, 0x20E4E9, 0x20E4EC, 0x20E4EE, 0x20E4F0, 0x20E9F0, 0x20ECF2, 0x20ECF9, 0x20EDE5, 0x20EDE9, 0x20EFE5, 0x20EFE9, 0x20F8E5, 0x20F8E9, 0x20FAE0,
+ 0x20FAE5, 0x20FAE9, 0xE020E4, 0xE020EC, 0xE020ED, 0xE020FA, 0xE0E420, 0xE0E5E4, 0xE0EC20, 0xE0EE20, 0xE120E4, 0xE120ED, 0xE120FA, 0xE420E4, 0xE420E9, 0xE420EC,
+ 0xE420ED, 0xE420EF, 0xE420F8, 0xE420FA, 0xE4EC20, 0xE5E020, 0xE5E420, 0xE7E020, 0xE9E020, 0xE9E120, 0xE9E420, 0xEC20E4, 0xEC20ED, 0xEC20FA, 0xECF220, 0xECF920,
+ 0xEDE9E9, 0xEDE9F0, 0xEDE9F8, 0xEE20E4, 0xEE20ED, 0xEE20FA, 0xEEE120, 0xEEE420, 0xF2E420, 0xF920E4, 0xF920ED, 0xF920FA, 0xF9E420, 0xFAE020, 0xFAE420, 0xFAE5E9,
+};
+
+static const int32_t ngrams_8859_9_tr[] = {
+ 0x206261, 0x206269, 0x206275, 0x206461, 0x206465, 0x206765, 0x206861, 0x20696C, 0x206B61, 0x206B6F, 0x206D61, 0x206F6C, 0x207361, 0x207461, 0x207665, 0x207961,
+ 0x612062, 0x616B20, 0x616C61, 0x616D61, 0x616E20, 0x616EFD, 0x617220, 0x617261, 0x6172FD, 0x6173FD, 0x617961, 0x626972, 0x646120, 0x646520, 0x646920, 0x652062,
+ 0x65206B, 0x656469, 0x656E20, 0x657220, 0x657269, 0x657369, 0x696C65, 0x696E20, 0x696E69, 0x697220, 0x6C616E, 0x6C6172, 0x6C6520, 0x6C6572, 0x6E2061, 0x6E2062,
+ 0x6E206B, 0x6E6461, 0x6E6465, 0x6E6520, 0x6E6920, 0x6E696E, 0x6EFD20, 0x72696E, 0x72FD6E, 0x766520, 0x796120, 0x796F72, 0xFD6E20, 0xFD6E64, 0xFD6EFD, 0xFDF0FD,
+};
+
+CharsetRecog_8859_1::~CharsetRecog_8859_1()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_1::getName() const
+{
+ return haveC1Bytes? "windows-1252" : "ISO-8859-1";
+}
+
+const char *CharsetRecog_8859_1_en::getLanguage() const
+{
+ return "en";
+}
+
+CharsetRecog_8859_1_en::~CharsetRecog_8859_1_en()
+{
+ // nothing to do
+}
+
+int32_t CharsetRecog_8859_1_en::match(InputText *textIn)
+{
+ int32_t result = match_sbcs(textIn, ngrams_8859_1_en, charMap_8859_1);
+
+ // printf("8859_1_en: result = %d\n", result);
+ return result; //match_sbcs(textIn, ngrams, charMap);
+}
+
+CharsetRecog_8859_1_da::~CharsetRecog_8859_1_da()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_1_da::getLanguage() const
+{
+ return "da";
+}
+
+int32_t CharsetRecog_8859_1_da::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_1_da, charMap_8859_1);
+}
+
+CharsetRecog_8859_1_de::~CharsetRecog_8859_1_de() {}
+
+const char *CharsetRecog_8859_1_de::getLanguage() const
+{
+ return "de";
+}
+
+int32_t CharsetRecog_8859_1_de::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_1_de, charMap_8859_1);
+}
+
+CharsetRecog_8859_1_es::~CharsetRecog_8859_1_es()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_1_es::getLanguage() const
+{
+ return "es";
+}
+
+int32_t CharsetRecog_8859_1_es::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_1_es, charMap_8859_1);
+}
+
+CharsetRecog_8859_1_fr::~CharsetRecog_8859_1_fr()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_1_fr::getLanguage() const
+{
+ return "fr";
+}
+
+int32_t CharsetRecog_8859_1_fr::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_1_fr, charMap_8859_1);
+}
+
+CharsetRecog_8859_1_it::~CharsetRecog_8859_1_it()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_1_it::getLanguage() const
+{
+ return "it";
+}
+
+int32_t CharsetRecog_8859_1_it::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_1_it, charMap_8859_1);
+}
+
+CharsetRecog_8859_1_nl::~CharsetRecog_8859_1_nl()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_1_nl::getLanguage() const
+{
+ return "nl";
+}
+
+int32_t CharsetRecog_8859_1_nl::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_1_nl, charMap_8859_1);
+}
+
+CharsetRecog_8859_1_no::~CharsetRecog_8859_1_no() {}
+
+const char *CharsetRecog_8859_1_no::getLanguage() const
+{
+ return "no";
+}
+
+int32_t CharsetRecog_8859_1_no::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_1_no, charMap_8859_1);
+}
+
+CharsetRecog_8859_1_pt::~CharsetRecog_8859_1_pt()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_1_pt::getLanguage() const
+{
+ return "pt";
+}
+
+int32_t CharsetRecog_8859_1_pt::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_1_pt, charMap_8859_1);
+}
+
+CharsetRecog_8859_1_sv::~CharsetRecog_8859_1_sv() {}
+
+const char *CharsetRecog_8859_1_sv::getLanguage() const
+{
+ return "sv";
+}
+
+int32_t CharsetRecog_8859_1_sv::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_1_sv, charMap_8859_1);
+}
+
+CharsetRecog_8859_2::~CharsetRecog_8859_2()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_2::getName() const
+{
+ return haveC1Bytes? "windows-1250" : "ISO-8859-2";
+}
+
+CharsetRecog_8859_2_cs::~CharsetRecog_8859_2_cs()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_2_cs::getLanguage() const
+{
+ return "cs";
+}
+
+int32_t CharsetRecog_8859_2_cs::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_2_cs, charMap_8859_2);
+}
+
+CharsetRecog_8859_2_hu::~CharsetRecog_8859_2_hu()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_2_hu::getLanguage() const
+{
+ return "hu";
+}
+
+int32_t CharsetRecog_8859_2_hu::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_2_hu, charMap_8859_2);
+}
+
+CharsetRecog_8859_2_pl::~CharsetRecog_8859_2_pl()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_2_pl::getLanguage() const
+{
+ return "pl";
+}
+
+int32_t CharsetRecog_8859_2_pl::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_2_pl, charMap_8859_2);
+}
+
+CharsetRecog_8859_2_ro::~CharsetRecog_8859_2_ro()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_2_ro::getLanguage() const
+{
+ return "ro";
+}
+
+int32_t CharsetRecog_8859_2_ro::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_2_ro, charMap_8859_2);
+}
+
+CharsetRecog_8859_5::~CharsetRecog_8859_5()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_5::getName() const
+{
+ return "ISO-8859-5";
+}
+
+CharsetRecog_8859_5_ru::~CharsetRecog_8859_5_ru()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_5_ru::getLanguage() const
+{
+ return "ru";
+}
+
+int32_t CharsetRecog_8859_5_ru::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_5_ru, charMap_8859_5);
+}
+
+CharsetRecog_8859_6::~CharsetRecog_8859_6()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_6::getName() const
+{
+ return "ISO-8859-6";
+}
+
+CharsetRecog_8859_6_ar::~CharsetRecog_8859_6_ar()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_6_ar::getLanguage() const
+{
+ return "ar";
+}
+
+int32_t CharsetRecog_8859_6_ar::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_6_ar, charMap_8859_6);
+}
+
+CharsetRecog_8859_7::~CharsetRecog_8859_7()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_7::getName() const
+{
+ return haveC1Bytes? "windows-1253" : "ISO-8859-7";
+}
+
+CharsetRecog_8859_7_el::~CharsetRecog_8859_7_el()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_7_el::getLanguage() const
+{
+ return "el";
+}
+
+int32_t CharsetRecog_8859_7_el::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_7_el, charMap_8859_7);
+}
+
+CharsetRecog_8859_8::~CharsetRecog_8859_8()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_8::getName() const
+{
+ return haveC1Bytes? "windows-1255" : "ISO-8859-8";
+}
+
+CharsetRecog_8859_8_I_he::~CharsetRecog_8859_8_I_he ()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_8_I_he::getName() const
+{
+ return haveC1Bytes? "windows-1255" : "ISO-8859-8-I";
+}
+
+const char *CharsetRecog_8859_8_I_he::getLanguage() const
+{
+ return "he";
+}
+
+int32_t CharsetRecog_8859_8_I_he::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_8_I_he, charMap_8859_8);
+}
+
+CharsetRecog_8859_8_he::~CharsetRecog_8859_8_he()
+{
+ // od ot gnihton
+}
+
+const char *CharsetRecog_8859_8_he::getLanguage() const
+{
+ return "he";
+}
+
+int32_t CharsetRecog_8859_8_he::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_8_he, charMap_8859_8);
+}
+
+CharsetRecog_8859_9::~CharsetRecog_8859_9()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_9::getName() const
+{
+ return haveC1Bytes? "windows-1254" : "ISO-8859-9";
+}
+
+CharsetRecog_8859_9_tr::~CharsetRecog_8859_9_tr ()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_8859_9_tr::getLanguage() const
+{
+ return "tr";
+}
+
+int32_t CharsetRecog_8859_9_tr::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_8859_9_tr, charMap_8859_9);
+}
+
+CharsetRecog_windows_1256::~CharsetRecog_windows_1256()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_windows_1256::getName() const
+{
+ return "windows-1256";
+}
+
+const char *CharsetRecog_windows_1256::getLanguage() const
+{
+ return "ar";
+}
+
+int32_t CharsetRecog_windows_1256::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_windows_1256, charMap_windows_1256);
+}
+
+CharsetRecog_windows_1251::~CharsetRecog_windows_1251()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_windows_1251::getName() const
+{
+ return "windows-1251";
+}
+
+const char *CharsetRecog_windows_1251::getLanguage() const
+{
+ return "ru";
+}
+
+int32_t CharsetRecog_windows_1251::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_windows_1251, charMap_windows_1251);
+}
+
+CharsetRecog_KOI8_R::~CharsetRecog_KOI8_R()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_KOI8_R::getName() const
+{
+ return "KOI8-R";
+}
+
+const char *CharsetRecog_KOI8_R::getLanguage() const
+{
+ return "ru";
+}
+
+int32_t CharsetRecog_KOI8_R::match(InputText *textIn)
+{
+ return match_sbcs(textIn, ngrams_KOI8_R, charMap_KOI8_R);
+}
+
+U_NAMESPACE_END
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrsbcs.h b/Build/source/libs/icu/icu-xetex/i18n/csrsbcs.h
new file mode 100644
index 00000000000..456fc4dff43
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrsbcs.h
@@ -0,0 +1,364 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __CSRSBCS_H
+#define __CSRSBCS_H
+
+#include "unicode/uobject.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "csrecog.h"
+
+U_NAMESPACE_BEGIN
+
+class NGramParser : public UMemory
+{
+private:
+ int32_t byteIndex;
+ int32_t ngram;
+
+ const int32_t *ngramList;
+ const uint8_t *charMap;
+
+ int32_t ngramCount;
+ int32_t hitCount;
+
+public:
+ NGramParser(const int32_t *theNgramList, const uint8_t *theCharMap);
+
+private:
+ /*
+ * Binary search for value in table, which must have exactly 64 entries.
+ */
+ int32_t search(const int32_t *table, int32_t value);
+
+ void lookup(int32_t thisNgram);
+ void addByte(int32_t b);
+ int32_t nextByte(InputText *det);
+
+public:
+ int32_t parse(InputText *det);
+
+};
+
+class CharsetRecog_sbcs : public CharsetRecognizer
+{
+protected:
+ UBool haveC1Bytes;
+
+public:
+ CharsetRecog_sbcs();
+
+ virtual ~CharsetRecog_sbcs();
+
+ virtual const char *getName() const = 0;
+
+ virtual int32_t match(InputText *det) = 0;
+
+ int32_t match_sbcs(InputText *det, const int32_t ngrams[], const uint8_t charMap[]);
+};
+
+class CharsetRecog_8859_1 : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_8859_1();
+
+ const char *getName() const;
+};
+
+class CharsetRecog_8859_2 : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_8859_2();
+
+ const char *getName() const;
+};
+
+class CharsetRecog_8859_5 : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_8859_5();
+
+ const char *getName() const;
+};
+
+class CharsetRecog_8859_6 : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_8859_6();
+
+ const char *getName() const;
+};
+
+class CharsetRecog_8859_7 : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_8859_7();
+
+ const char *getName() const;
+};
+
+class CharsetRecog_8859_8 : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_8859_8();
+
+ virtual const char *getName() const;
+};
+
+class CharsetRecog_8859_9 : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_8859_9();
+
+ const char *getName() const;
+};
+
+class CharsetRecog_8859_1_en : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_en();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_1_da : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_da();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_1_de : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_de();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_1_es : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_es();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_1_fr : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_fr();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_1_it : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_it();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_1_nl : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_nl();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_1_no : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_no();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_1_pt : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_pt();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_1_sv : public CharsetRecog_8859_1
+{
+public:
+ virtual ~CharsetRecog_8859_1_sv();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_2_cs : public CharsetRecog_8859_2
+{
+public:
+ virtual ~CharsetRecog_8859_2_cs();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_2_hu : public CharsetRecog_8859_2
+{
+public:
+ virtual ~CharsetRecog_8859_2_hu();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_2_pl : public CharsetRecog_8859_2
+{
+public:
+ virtual ~CharsetRecog_8859_2_pl();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_2_ro : public CharsetRecog_8859_2
+{
+public:
+ virtual ~CharsetRecog_8859_2_ro();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_5_ru : public CharsetRecog_8859_5
+{
+public:
+ virtual ~CharsetRecog_8859_5_ru();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_6_ar : public CharsetRecog_8859_6
+{
+public:
+ virtual ~CharsetRecog_8859_6_ar();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_7_el : public CharsetRecog_8859_7
+{
+public:
+ virtual ~CharsetRecog_8859_7_el();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_8_I_he : public CharsetRecog_8859_8
+{
+public:
+ virtual ~CharsetRecog_8859_8_I_he();
+
+ const char *getName() const;
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_8_he : public CharsetRecog_8859_8
+{
+public:
+ virtual ~CharsetRecog_8859_8_he ();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_8859_9_tr : public CharsetRecog_8859_9
+{
+public:
+ virtual ~CharsetRecog_8859_9_tr ();
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_windows_1256 : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_windows_1256();
+
+ const char *getName() const;
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+class CharsetRecog_windows_1251 : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_windows_1251();
+
+ const char *getName() const;
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+
+class CharsetRecog_KOI8_R : public CharsetRecog_sbcs
+{
+public:
+ virtual ~CharsetRecog_KOI8_R();
+
+ const char *getName() const;
+
+ const char *getLanguage() const;
+
+ int32_t match(InputText *textIn);
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __CSRSBCS_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrucode.cpp b/Build/source/libs/icu/icu-xetex/i18n/csrucode.cpp
new file mode 100644
index 00000000000..99a76d850e6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrucode.cpp
@@ -0,0 +1,146 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "csrucode.h"
+
+U_NAMESPACE_BEGIN
+
+CharsetRecog_Unicode::~CharsetRecog_Unicode()
+{
+ // nothing to do
+}
+
+CharsetRecog_UTF_16_BE::~CharsetRecog_UTF_16_BE()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_UTF_16_BE::getName() const
+{
+ return "UTF-16BE";
+}
+
+int32_t CharsetRecog_UTF_16_BE::match(InputText* textIn)
+{
+ const uint8_t *input = textIn->fRawInput;
+
+ if (input[0] == 0xFE && input[1] == 0xFF) {
+ return 100;
+ }
+
+ // TODO: Do some statastics to check for unsigned UTF-16BE
+ return 0;
+}
+
+CharsetRecog_UTF_16_LE::~CharsetRecog_UTF_16_LE()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_UTF_16_LE::getName() const
+{
+ return "UTF-16LE";
+}
+
+int32_t CharsetRecog_UTF_16_LE::match(InputText* textIn)
+{
+ const uint8_t *input = textIn->fRawInput;
+
+ if (input[0] == 0xFF && input[1] == 0xFE && (input[2] != 0x00 || input[3] != 0x00)) {
+ return 100;
+ }
+
+ // TODO: Do some statastics to check for unsigned UTF-16LE
+ return 0;
+}
+
+CharsetRecog_UTF_32::~CharsetRecog_UTF_32()
+{
+ // nothing to do
+}
+
+int32_t CharsetRecog_UTF_32::match(InputText* textIn)
+{
+ const uint8_t *input = textIn->fRawInput;
+ int32_t limit = (textIn->fRawLength / 4) * 4;
+ int32_t numValid = 0;
+ int32_t numInvalid = 0;
+ bool hasBOM = FALSE;
+ int32_t confidence = 0;
+
+ if (getChar(input, 0) == 0x0000FEFFUL) {
+ hasBOM = TRUE;
+ }
+
+ for(int32_t i = 0; i < limit; i += 4) {
+ int32_t ch = getChar(input, i);
+
+ if (ch < 0 || ch >= 0x10FFFF || (ch >= 0xD800 && ch <= 0xDFFF)) {
+ numInvalid += 1;
+ } else {
+ numValid += 1;
+ }
+ }
+
+
+ // Cook up some sort of confidence score, based on presense of a BOM
+ // and the existence of valid and/or invalid multi-byte sequences.
+ if (hasBOM && numInvalid==0) {
+ confidence = 100;
+ } else if (hasBOM && numValid > numInvalid*10) {
+ confidence = 80;
+ } else if (numValid > 3 && numInvalid == 0) {
+ confidence = 100;
+ } else if (numValid > 0 && numInvalid == 0) {
+ confidence = 80;
+ } else if (numValid > numInvalid*10) {
+ // Probably corruput UTF-32BE data. Valid sequences aren't likely by chance.
+ confidence = 25;
+ }
+
+ return confidence;
+}
+
+CharsetRecog_UTF_32_BE::~CharsetRecog_UTF_32_BE()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_UTF_32_BE::getName() const
+{
+ return "UTF-32BE";
+}
+
+int32_t CharsetRecog_UTF_32_BE::getChar(const uint8_t *input, int32_t index) const
+{
+ return input[index + 0] << 24 | input[index + 1] << 16 |
+ input[index + 2] << 8 | input[index + 3];
+}
+
+CharsetRecog_UTF_32_LE::~CharsetRecog_UTF_32_LE()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_UTF_32_LE::getName() const
+{
+ return "UTF-32LE";
+}
+
+int32_t CharsetRecog_UTF_32_LE::getChar(const uint8_t *input, int32_t index) const
+{
+ return input[index + 3] << 24 | input[index + 2] << 16 |
+ input[index + 1] << 8 | input[index + 0];
+}
+
+U_NAMESPACE_END
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrucode.h b/Build/source/libs/icu/icu-xetex/i18n/csrucode.h
new file mode 100644
index 00000000000..315bad6b25e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrucode.h
@@ -0,0 +1,106 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __CSRUCODE_H
+#define __CSRUCODE_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "csrecog.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * This class matches UTF-16 and UTF-32, both big- and little-endian. The
+ * BOM will be used if it is present.
+ *
+ * @internal
+ */
+class CharsetRecog_Unicode : public CharsetRecognizer
+{
+
+public:
+
+ virtual ~CharsetRecog_Unicode();
+ /* (non-Javadoc)
+ * @see com.ibm.icu.text.CharsetRecognizer#getName()
+ */
+ const char* getName() const = 0;
+
+ /* (non-Javadoc)
+ * @see com.ibm.icu.text.CharsetRecognizer#match(com.ibm.icu.text.CharsetDetector)
+ */
+ int32_t match(InputText* textIn) = 0;
+};
+
+
+class CharsetRecog_UTF_16_BE : public CharsetRecog_Unicode
+{
+public:
+
+ virtual ~CharsetRecog_UTF_16_BE();
+
+ const char *getName() const;
+
+ int32_t match(InputText* textIn);
+};
+
+class CharsetRecog_UTF_16_LE : public CharsetRecog_Unicode
+{
+public:
+
+ virtual ~CharsetRecog_UTF_16_LE();
+
+ const char *getName() const;
+
+ int32_t match(InputText* textIn);
+};
+
+class CharsetRecog_UTF_32 : public CharsetRecog_Unicode
+{
+protected:
+ virtual int32_t getChar(const uint8_t *input, int32_t index) const = 0;
+public:
+
+ virtual ~CharsetRecog_UTF_32();
+
+ const char* getName() const = 0;
+
+ int32_t match(InputText* textIn);
+};
+
+
+class CharsetRecog_UTF_32_BE : public CharsetRecog_UTF_32
+{
+protected:
+ int32_t getChar(const uint8_t *input, int32_t index) const;
+
+public:
+
+ virtual ~CharsetRecog_UTF_32_BE();
+
+ const char *getName() const;
+};
+
+
+class CharsetRecog_UTF_32_LE : public CharsetRecog_UTF_32
+{
+protected:
+ int32_t getChar(const uint8_t *input, int32_t index) const;
+
+public:
+ virtual ~CharsetRecog_UTF_32_LE();
+
+ const char* getName() const;
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __CSRUCODE_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrutf8.cpp b/Build/source/libs/icu/icu-xetex/i18n/csrutf8.cpp
new file mode 100644
index 00000000000..8af5307bdc3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrutf8.cpp
@@ -0,0 +1,111 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "csrutf8.h"
+
+U_NAMESPACE_BEGIN
+
+CharsetRecog_UTF8::~CharsetRecog_UTF8()
+{
+ // nothing to do
+}
+
+const char *CharsetRecog_UTF8::getName() const
+{
+ return "UTF-8";
+}
+
+int32_t CharsetRecog_UTF8::match(InputText* det) {
+ bool hasBOM = FALSE;
+ int32_t numValid = 0;
+ int32_t numInvalid = 0;
+ const uint8_t *input = det->fRawInput;
+ int32_t i;
+ int32_t trailBytes = 0;
+ int32_t confidence;
+
+ if (det->fRawLength >= 3 &&
+ input[0] == 0xEF && input[1] == 0xBB && input[2] == 0xBF) {
+ hasBOM = TRUE;
+ }
+
+ // Scan for multi-byte sequences
+ for (i=0; i < det->fRawLength; i += 1) {
+ int32_t b = input[i];
+
+ if ((b & 0x80) == 0) {
+ continue; // ASCII
+ }
+
+ // Hi bit on char found. Figure out how long the sequence should be
+ if ((b & 0x0E0) == 0x0C0) {
+ trailBytes = 1;
+ } else if ((b & 0x0F0) == 0x0E0) {
+ trailBytes = 2;
+ } else if ((b & 0x0F8) == 0xF0) {
+ trailBytes = 3;
+ } else {
+ numInvalid += 1;
+
+ if (numInvalid > 5) {
+ break;
+ }
+
+ trailBytes = 0;
+ }
+
+ // Verify that we've got the right number of trail bytes in the sequence
+ for (;;) {
+ i += 1;
+
+ if (i >= det->fRawLength) {
+ break;
+ }
+
+ b = input[i];
+
+ if ((b & 0xC0) != 0x080) {
+ numInvalid += 1;
+ break;
+ }
+
+ if (--trailBytes == 0) {
+ numValid += 1;
+ break;
+ }
+ }
+
+ }
+
+ // Cook up some sort of confidence score, based on presense of a BOM
+ // and the existence of valid and/or invalid multi-byte sequences.
+ confidence = 0;
+ if (hasBOM && numInvalid == 0) {
+ confidence = 100;
+ } else if (hasBOM && numValid > numInvalid*10) {
+ confidence = 80;
+ } else if (numValid > 3 && numInvalid == 0) {
+ confidence = 100;
+ } else if (numValid > 0 && numInvalid == 0) {
+ confidence = 80;
+ } else if (numValid == 0 && numInvalid == 0) {
+ // Plain ASCII.
+ confidence = 10;
+ } else if (numValid > numInvalid*10) {
+ // Probably corruput utf-8 data. Valid sequences aren't likely by chance.
+ confidence = 25;
+ }
+
+ return confidence;
+}
+
+U_NAMESPACE_END
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/csrutf8.h b/Build/source/libs/icu/icu-xetex/i18n/csrutf8.h
new file mode 100644
index 00000000000..10fe287a435
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/csrutf8.h
@@ -0,0 +1,42 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __CSRUTF8_H
+#define __CSRUTF8_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "csrecog.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Charset recognizer for UTF-8
+ *
+ * @internal
+ */
+class CharsetRecog_UTF8: public CharsetRecognizer {
+
+ public:
+
+ virtual ~CharsetRecog_UTF8();
+
+ const char *getName() const;
+
+ /* (non-Javadoc)
+ * @see com.ibm.icu.text.CharsetRecognizer#match(com.ibm.icu.text.CharsetDetector)
+ */
+ int32_t match(InputText *det);
+
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __CSRUTF8_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/curramt.cpp b/Build/source/libs/icu/icu-xetex/i18n/curramt.cpp
new file mode 100644
index 00000000000..f4e1abb0572
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/curramt.cpp
@@ -0,0 +1,50 @@
+/*
+**********************************************************************
+* Copyright (c) 2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 26, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/curramt.h"
+#include "unicode/currunit.h"
+
+U_NAMESPACE_BEGIN
+
+CurrencyAmount::CurrencyAmount(const Formattable& amount, const UChar* isoCode,
+ UErrorCode& ec) :
+ Measure(amount, new CurrencyUnit(isoCode, ec), ec) {
+}
+
+CurrencyAmount::CurrencyAmount(double amount, const UChar* isoCode,
+ UErrorCode& ec) :
+ Measure(Formattable(amount), new CurrencyUnit(isoCode, ec), ec) {
+}
+
+CurrencyAmount::CurrencyAmount(const CurrencyAmount& other) :
+ Measure(other) {
+}
+
+CurrencyAmount& CurrencyAmount::operator=(const CurrencyAmount& other) {
+ Measure::operator=(other);
+ return *this;
+}
+
+UObject* CurrencyAmount::clone() const {
+ return new CurrencyAmount(*this);
+}
+
+CurrencyAmount::~CurrencyAmount() {
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyAmount)
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
diff --git a/Build/source/libs/icu/icu-xetex/i18n/currfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/currfmt.cpp
new file mode 100644
index 00000000000..e2fc5a8f202
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/currfmt.cpp
@@ -0,0 +1,66 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 20, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "currfmt.h"
+#include "unicode/numfmt.h"
+
+U_NAMESPACE_BEGIN
+
+CurrencyFormat::CurrencyFormat(const Locale& locale, UErrorCode& ec) :
+ fmt(NULL) {
+ fmt = NumberFormat::createCurrencyInstance(locale, ec);
+}
+
+CurrencyFormat::CurrencyFormat(const CurrencyFormat& other) :
+ MeasureFormat(other), fmt(NULL) {
+ fmt = (NumberFormat*) other.fmt->clone();
+}
+
+CurrencyFormat::~CurrencyFormat() {
+ delete fmt;
+}
+
+UBool CurrencyFormat::operator==(const Format& other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ if (other.getDynamicClassID() != CurrencyFormat::getStaticClassID()) {
+ return FALSE;
+ }
+ const CurrencyFormat* c = (const CurrencyFormat*) &other;
+ return *fmt == *c->fmt;
+}
+
+Format* CurrencyFormat::clone() const {
+ return new CurrencyFormat(*this);
+}
+
+UnicodeString& CurrencyFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& ec) const {
+ return fmt->format(obj, appendTo, pos, ec);
+}
+
+void CurrencyFormat::parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& pos) const {
+ fmt->parseCurrency(source, result, pos);
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyFormat)
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/currfmt.h b/Build/source/libs/icu/icu-xetex/i18n/currfmt.h
new file mode 100644
index 00000000000..b9e8dd89686
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/currfmt.h
@@ -0,0 +1,98 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 20, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#ifndef CURRENCYFORMAT_H
+#define CURRENCYFORMAT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/measfmt.h"
+
+U_NAMESPACE_BEGIN
+
+class NumberFormat;
+
+/**
+ * Temporary internal concrete subclass of MeasureFormat implementing
+ * parsing and formatting of currency amount objects. This class is
+ * likely to be redesigned and rewritten in the near future.
+ *
+ * <p>This class currently delegates to DecimalFormat for parsing and
+ * formatting.
+ *
+ * @see MeasureFormat
+ * @author Alan Liu
+ * @internal
+ */
+class U_I18N_API CurrencyFormat : public MeasureFormat {
+
+ public:
+
+ /**
+ * Construct a CurrencyFormat for the given locale.
+ */
+ CurrencyFormat(const Locale& locale, UErrorCode& ec);
+
+ /**
+ * Copy constructor.
+ */
+ CurrencyFormat(const CurrencyFormat& other);
+
+ /**
+ * Destructor.
+ */
+ virtual ~CurrencyFormat();
+
+ /**
+ * Override Format API.
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Override Format API.
+ */
+ virtual Format* clone() const;
+
+ /**
+ * Override Format API.
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& ec) const;
+
+ /**
+ * Override Format API.
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& pos) const;
+
+ /**
+ * Override Format API.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * Returns the class ID for this class.
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ private:
+
+ NumberFormat* fmt;
+};
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_FORMATTING
+#endif // #ifndef CURRENCYFORMAT_H
diff --git a/Build/source/libs/icu/icu-xetex/i18n/currunit.cpp b/Build/source/libs/icu/icu-xetex/i18n/currunit.cpp
new file mode 100644
index 00000000000..0ba2631d480
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/currunit.cpp
@@ -0,0 +1,60 @@
+/*
+**********************************************************************
+* Copyright (c) 2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 26, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/currunit.h"
+#include "unicode/ustring.h"
+
+U_NAMESPACE_BEGIN
+
+CurrencyUnit::CurrencyUnit(const UChar* _isoCode, UErrorCode& ec) {
+ *isoCode = 0;
+ if (U_SUCCESS(ec)) {
+ if (_isoCode && u_strlen(_isoCode)==3) {
+ u_strcpy(isoCode, _isoCode);
+ } else {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ }
+}
+
+CurrencyUnit::CurrencyUnit(const CurrencyUnit& other) :
+ MeasureUnit(other) {
+ *this = other;
+}
+
+CurrencyUnit& CurrencyUnit::operator=(const CurrencyUnit& other) {
+ if (this != &other) {
+ u_strcpy(isoCode, other.isoCode);
+ }
+ return *this;
+}
+
+UObject* CurrencyUnit::clone() const {
+ return new CurrencyUnit(*this);
+}
+
+CurrencyUnit::~CurrencyUnit() {
+}
+
+UBool CurrencyUnit::operator==(const UObject& other) const {
+ const CurrencyUnit& c = (const CurrencyUnit&) other;
+ return other.getDynamicClassID() == CurrencyUnit::getStaticClassID() &&
+ u_strcmp(isoCode, c.isoCode) == 0;
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyUnit)
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
diff --git a/Build/source/libs/icu/icu-xetex/i18n/datefmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/datefmt.cpp
new file mode 100644
index 00000000000..f49ca94cc50
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/datefmt.cpp
@@ -0,0 +1,428 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ *
+ * File DATEFMT.CPP
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 02/19/97 aliu Converted from java.
+ * 03/31/97 aliu Modified extensively to work with 50 locales.
+ * 04/01/97 aliu Added support for centuries.
+ * 08/12/97 aliu Fixed operator== to use Calendar::equivalentTo.
+ * 07/20/98 stephen Changed ParsePosition initialization
+ ********************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ures.h"
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "reldtfmt.h"
+
+#include "cstring.h"
+#include "windtfmt.h"
+
+#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
+#include <stdio.h>
+#endif
+
+// *****************************************************************************
+// class DateFormat
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+DateFormat::DateFormat()
+: fCalendar(0),
+ fNumberFormat(0)
+{
+}
+
+//----------------------------------------------------------------------
+
+DateFormat::DateFormat(const DateFormat& other)
+: Format(other),
+ fCalendar(0),
+ fNumberFormat(0)
+{
+ *this = other;
+}
+
+//----------------------------------------------------------------------
+
+DateFormat& DateFormat::operator=(const DateFormat& other)
+{
+ if (this != &other)
+ {
+ delete fCalendar;
+ delete fNumberFormat;
+ if(other.fCalendar) {
+ fCalendar = other.fCalendar->clone();
+ } else {
+ fCalendar = NULL;
+ }
+ if(other.fNumberFormat) {
+ fNumberFormat = (NumberFormat*)other.fNumberFormat->clone();
+ } else {
+ fNumberFormat = NULL;
+ }
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+
+DateFormat::~DateFormat()
+{
+ delete fCalendar;
+ delete fNumberFormat;
+}
+
+//----------------------------------------------------------------------
+
+UBool
+DateFormat::operator==(const Format& other) const
+{
+ // This protected comparison operator should only be called by subclasses
+ // which have confirmed that the other object being compared against is
+ // an instance of a sublcass of DateFormat. THIS IS IMPORTANT.
+
+ // Format::operator== guarantees that this cast is safe
+ DateFormat* fmt = (DateFormat*)&other;
+
+ return (this == fmt) ||
+ (Format::operator==(other) &&
+ fCalendar&&(fCalendar->isEquivalentTo(*fmt->fCalendar)) &&
+ (fNumberFormat && *fNumberFormat == *fmt->fNumberFormat));
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+DateFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return appendTo;
+
+ // if the type of the Formattable is double or long, treat it as if it were a Date
+ UDate date = 0;
+ switch (obj.getType())
+ {
+ case Formattable::kDate:
+ date = obj.getDate();
+ break;
+ case Formattable::kDouble:
+ date = (UDate)obj.getDouble();
+ break;
+ case Formattable::kLong:
+ date = (UDate)obj.getLong();
+ break;
+ default:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+
+ // Is this right?
+ //if (fieldPosition.getBeginIndex() == fieldPosition.getEndIndex())
+ // status = U_ILLEGAL_ARGUMENT_ERROR;
+
+ return format(date, appendTo, fieldPosition);
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const {
+ if (fCalendar != NULL) {
+ // Use our calendar instance
+ UErrorCode ec = U_ZERO_ERROR;
+ fCalendar->setTime(date, ec);
+ if (U_SUCCESS(ec)) {
+ return format(*fCalendar, appendTo, fieldPosition);
+ }
+ }
+ return appendTo;
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+DateFormat::format(UDate date, UnicodeString& appendTo) const
+{
+ // Note that any error information is just lost. That's okay
+ // for this convenience method.
+ FieldPosition fpos(0);
+ return format(date, appendTo, fpos);
+}
+
+//----------------------------------------------------------------------
+
+UDate
+DateFormat::parse(const UnicodeString& text,
+ ParsePosition& pos) const
+{
+ UDate d = 0; // Error return UDate is 0 (the epoch)
+ if (fCalendar != NULL) {
+ int32_t start = pos.getIndex();
+
+ // Parse may update TimeZone used by the calendar.
+ TimeZone *tzsav = (TimeZone*)fCalendar->getTimeZone().clone();
+
+ fCalendar->clear();
+ parse(text, *fCalendar, pos);
+ if (pos.getIndex() != start) {
+ UErrorCode ec = U_ZERO_ERROR;
+ d = fCalendar->getTime(ec);
+ if (U_FAILURE(ec)) {
+ // We arrive here if fCalendar is non-lenient and there
+ // is an out-of-range field. We don't know which field
+ // was illegal so we set the error index to the start.
+ pos.setIndex(start);
+ pos.setErrorIndex(start);
+ d = 0;
+ }
+ }
+
+ // Restore TimeZone
+ fCalendar->adoptTimeZone(tzsav);
+ }
+ return d;
+}
+
+//----------------------------------------------------------------------
+
+UDate
+DateFormat::parse(const UnicodeString& text,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return 0;
+
+ ParsePosition pos(0);
+ UDate result = parse(text, pos);
+ if (pos.getIndex() == 0) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d - - failed to parse - err index %d\n"
+ , __FILE__, __LINE__, pos.getErrorIndex() );
+#endif
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return result;
+}
+
+//----------------------------------------------------------------------
+
+void
+DateFormat::parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& pos) const
+{
+ result.setDate(parse(source, pos));
+}
+
+//----------------------------------------------------------------------
+
+DateFormat* U_EXPORT2
+DateFormat::createTimeInstance(DateFormat::EStyle style,
+ const Locale& aLocale)
+{
+ return create(style, kNone, aLocale);
+}
+
+//----------------------------------------------------------------------
+
+DateFormat* U_EXPORT2
+DateFormat::createDateInstance(DateFormat::EStyle style,
+ const Locale& aLocale)
+{
+ // +4 to set the correct index for getting data out of
+ // LocaleElements.
+ if(style != kNone)
+ {
+ style = (EStyle) (style + kDateOffset);
+ }
+ return create(kNone, (EStyle) (style), aLocale);
+}
+
+//----------------------------------------------------------------------
+
+DateFormat* U_EXPORT2
+DateFormat::createDateTimeInstance(EStyle dateStyle,
+ EStyle timeStyle,
+ const Locale& aLocale)
+{
+ if(dateStyle != kNone)
+ {
+ dateStyle = (EStyle) (dateStyle + kDateOffset);
+ }
+ return create(timeStyle, dateStyle, aLocale);
+}
+
+//----------------------------------------------------------------------
+
+DateFormat* U_EXPORT2
+DateFormat::createInstance()
+{
+ return create(kShort, (EStyle) (kShort + kDateOffset), Locale::getDefault());
+}
+
+//----------------------------------------------------------------------
+
+DateFormat* U_EXPORT2
+DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
+{
+ UErrorCode status = U_ZERO_ERROR;
+#ifdef U_WINDOWS
+ char buffer[8];
+ int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status);
+
+ // if the locale has "@compat=host", create a host-specific DateFormat...
+ if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
+ Win32DateFormat *f = new Win32DateFormat(timeStyle, dateStyle, locale, status);
+
+ if (U_SUCCESS(status)) {
+ return f;
+ }
+
+ delete f;
+ }
+#endif
+
+ // is it relative?
+ if(/*((timeStyle!=UDAT_NONE)&&(timeStyle & UDAT_RELATIVE)) || */((dateStyle!=kNone)&&((dateStyle-kDateOffset) & UDAT_RELATIVE))) {
+ RelativeDateFormat *r = new RelativeDateFormat((UDateFormatStyle)timeStyle, (UDateFormatStyle)(dateStyle-kDateOffset), locale, status);
+ if(U_SUCCESS(status)) return r;
+ delete r;
+ status = U_ZERO_ERROR;
+ }
+
+ // Try to create a SimpleDateFormat of the desired style.
+ SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status);
+ if (U_SUCCESS(status)) return f;
+ delete f;
+
+ // If that fails, try to create a format using the default pattern and
+ // the DateFormatSymbols for this locale.
+ status = U_ZERO_ERROR;
+ f = new SimpleDateFormat(locale, status);
+ if (U_SUCCESS(status)) return f;
+ delete f;
+
+ // This should never really happen, because the preceding constructor
+ // should always succeed. If the resource data is unavailable, a last
+ // resort object should be returned.
+ return 0;
+}
+
+//----------------------------------------------------------------------
+
+const Locale* U_EXPORT2
+DateFormat::getAvailableLocales(int32_t& count)
+{
+ // Get the list of installed locales.
+ // Even if root has the correct date format for this locale,
+ // it's still a valid locale (we don't worry about data fallbacks).
+ return Locale::getAvailableLocales(count);
+}
+
+//----------------------------------------------------------------------
+
+void
+DateFormat::adoptCalendar(Calendar* newCalendar)
+{
+ delete fCalendar;
+ fCalendar = newCalendar;
+}
+
+//----------------------------------------------------------------------
+void
+DateFormat::setCalendar(const Calendar& newCalendar)
+{
+ adoptCalendar(newCalendar.clone());
+}
+
+//----------------------------------------------------------------------
+
+const Calendar*
+DateFormat::getCalendar() const
+{
+ return fCalendar;
+}
+
+//----------------------------------------------------------------------
+
+void
+DateFormat::adoptNumberFormat(NumberFormat* newNumberFormat)
+{
+ delete fNumberFormat;
+ fNumberFormat = newNumberFormat;
+ newNumberFormat->setParseIntegerOnly(TRUE);
+}
+//----------------------------------------------------------------------
+
+void
+DateFormat::setNumberFormat(const NumberFormat& newNumberFormat)
+{
+ adoptNumberFormat((NumberFormat*)newNumberFormat.clone());
+}
+
+//----------------------------------------------------------------------
+
+const NumberFormat*
+DateFormat::getNumberFormat() const
+{
+ return fNumberFormat;
+}
+
+//----------------------------------------------------------------------
+
+void
+DateFormat::adoptTimeZone(TimeZone* zone)
+{
+ fCalendar->adoptTimeZone(zone);
+}
+//----------------------------------------------------------------------
+
+void
+DateFormat::setTimeZone(const TimeZone& zone)
+{
+ fCalendar->setTimeZone(zone);
+}
+
+//----------------------------------------------------------------------
+
+const TimeZone&
+DateFormat::getTimeZone() const
+{
+ return fCalendar->getTimeZone();
+}
+
+//----------------------------------------------------------------------
+
+void
+DateFormat::setLenient(UBool lenient)
+{
+ fCalendar->setLenient(lenient);
+}
+
+//----------------------------------------------------------------------
+
+UBool
+DateFormat::isLenient() const
+{
+ return fCalendar->isLenient();
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/dcfmtsym.cpp b/Build/source/libs/icu/icu-xetex/i18n/dcfmtsym.cpp
new file mode 100644
index 00000000000..34074750ad2
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/dcfmtsym.cpp
@@ -0,0 +1,298 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File DCFMTSYM.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/18/97 clhuang Implemented with C++ APIs.
+* 03/27/97 helena Updated to pass the simple test after code review.
+* 08/26/97 aliu Added currency/intl currency symbol support.
+* 07/20/98 stephen Slightly modified initialization of monetarySeparator
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/dcfmtsym.h"
+#include "unicode/ures.h"
+#include "unicode/decimfmt.h"
+#include "unicode/ucurr.h"
+#include "unicode/choicfmt.h"
+#include "ucurrimp.h"
+#include "cstring.h"
+#include "locbased.h"
+#include "uresimp.h"
+// *****************************************************************************
+// class DecimalFormatSymbols
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormatSymbols)
+
+static const char gNumberElements[] = "NumberElements";
+
+static const UChar INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0};
+
+// -------------------------------------
+// Initializes this with the decimal format symbols in the default locale.
+
+DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status)
+ : UObject(),
+ locale()
+{
+ initialize(locale, status, TRUE);
+}
+
+// -------------------------------------
+// Initializes this with the decimal format symbols in the desired locale.
+
+DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status)
+ : UObject(),
+ locale(loc)
+{
+ initialize(locale, status);
+}
+
+// -------------------------------------
+
+DecimalFormatSymbols::~DecimalFormatSymbols()
+{
+}
+
+// -------------------------------------
+// copy constructor
+
+DecimalFormatSymbols::DecimalFormatSymbols(const DecimalFormatSymbols &source)
+ : UObject(source)
+{
+ *this = source;
+}
+
+// -------------------------------------
+// assignment operator
+
+DecimalFormatSymbols&
+DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs)
+{
+ if (this != &rhs) {
+ for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) {
+ // fastCopyFrom is safe, see docs on fSymbols
+ fSymbols[(ENumberFormatSymbol)i].fastCopyFrom(rhs.fSymbols[(ENumberFormatSymbol)i]);
+ }
+ locale = rhs.locale;
+ uprv_strcpy(validLocale, rhs.validLocale);
+ uprv_strcpy(actualLocale, rhs.actualLocale);
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+UBool
+DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const
+{
+ if (this == &that) {
+ return TRUE;
+ }
+ for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) {
+ if(fSymbols[(ENumberFormatSymbol)i] != that.fSymbols[(ENumberFormatSymbol)i]) {
+ return FALSE;
+ }
+ }
+ return locale == that.locale &&
+ uprv_strcmp(validLocale, that.validLocale) == 0 &&
+ uprv_strcmp(actualLocale, that.actualLocale) == 0;
+}
+
+// -------------------------------------
+
+void
+DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status,
+ UBool useLastResortData)
+{
+ *validLocale = *actualLocale = 0;
+ currPattern = NULL;
+ if (U_FAILURE(status))
+ return;
+
+ const char* locStr = loc.getName();
+ UResourceBundle *resource = ures_open((char *)0, locStr, &status);
+ UResourceBundle *numberElementsRes = ures_getByKey(resource, gNumberElements, NULL, &status);
+ if (U_FAILURE(status))
+ {
+ // Initializes with last resort data if necessary.
+ if (useLastResortData)
+ {
+ status = U_USING_FALLBACK_WARNING;
+ initialize();
+ }
+ }
+ else {
+ // Gets the number element array.
+ int32_t numberElementsLength = ures_getSize(numberElementsRes);
+
+ if (numberElementsLength > (int32_t)kFormatSymbolCount) {
+ /* Warning: Invalid format. Array too large. */
+ numberElementsLength = (int32_t)kFormatSymbolCount;
+ }
+ // If the array size is too small, something is wrong with the resource
+ // bundle, returns the failure error code.
+ if (numberElementsLength != 12 || U_FAILURE(status)) {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ else {
+ const UChar *numberElements[kFormatSymbolCount];
+ int32_t numberElementsStrLen[kFormatSymbolCount];
+ int32_t i = 0;
+ for(i = 0; i<numberElementsLength; i++) {
+ numberElements[i] = ures_getStringByIndex(numberElementsRes, i, &numberElementsStrLen[i], &status);
+ }
+
+ if (U_SUCCESS(status)) {
+ initialize(numberElements, numberElementsStrLen, numberElementsLength);
+
+ // Obtain currency data from the currency API. This is strictly
+ // for backward compatibility; we don't use DecimalFormatSymbols
+ // for currency data anymore.
+ UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out
+ UChar curriso[4];
+ UnicodeString tempStr;
+ ucurr_forLocale(locStr, curriso, 4, &internalStatus);
+
+ // Reuse numberElements[0] as a temporary buffer
+ uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus);
+ if (U_SUCCESS(internalStatus)) {
+ fSymbols[kIntlCurrencySymbol] = curriso;
+ fSymbols[kCurrencySymbol] = tempStr;
+ }
+ /* else use the default values. */
+ }
+
+ U_LOCALE_BASED(locBased, *this);
+ locBased.setLocaleIDs(ures_getLocaleByType(numberElementsRes,
+ ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(numberElementsRes,
+ ULOC_ACTUAL_LOCALE, &status));
+ }
+ //load the currency data
+ UChar ucc[4]={0}; //Currency Codes are always 3 chars long
+ int32_t uccLen = 4;
+ const char* locName = loc.getName();
+ uccLen = ucurr_forLocale(locName, ucc, uccLen, &status);
+ if(U_SUCCESS(status) && uccLen > 0) {
+ char cc[4]={0};
+ u_UCharsToChars(ucc, cc, uccLen);
+ /* An explicit currency was requested */
+ UErrorCode localStatus = U_ZERO_ERROR;
+ UResourceBundle *currency = ures_getByKeyWithFallback(resource, "Currencies", NULL, &localStatus);
+ currency = ures_getByKeyWithFallback(currency, cc, currency, &localStatus);
+ if(U_SUCCESS(localStatus) && ures_getSize(currency)>2) { // the length is 3 if more data is present
+ currency = ures_getByIndex(currency, 2, currency, &localStatus);
+ int32_t currPatternLen = 0;
+ currPattern = ures_getStringByIndex(currency, (int32_t)0, &currPatternLen, &localStatus);
+ UnicodeString decimalSep = ures_getStringByIndex(currency, (int32_t)1, NULL, &localStatus);
+ UnicodeString groupingSep = ures_getStringByIndex(currency, (int32_t)2, NULL, &localStatus);
+ if(U_SUCCESS(localStatus)){
+ fSymbols[kMonetaryGroupingSeparatorSymbol] = groupingSep;
+ fSymbols[kMonetarySeparatorSymbol] = decimalSep;
+ //pattern.setTo(TRUE, currPattern, currPatternLen);
+ status = localStatus;
+ }
+ }
+ ures_close(currency);
+ /* else An explicit currency was requested and is unknown or locale data is malformed. */
+ /* ucurr_* API will get the correct value later on. */
+ }else{
+ // ignore the error if no currency
+ status = U_ZERO_ERROR;
+ }
+ }
+ ures_close(resource);
+ ures_close(numberElementsRes);
+}
+
+// Initializes the DecimalFormatSymbol instance with the data obtained
+// from ResourceBundle in the desired locale.
+
+void
+DecimalFormatSymbols::initialize(const UChar** numberElements, int32_t *numberElementsStrLen, int32_t numberElementsLength)
+{
+ static const int32_t TYPE_MAPPING[][2] = {
+ {kDecimalSeparatorSymbol, 0},
+ {kGroupingSeparatorSymbol, 1},
+ {kPatternSeparatorSymbol, 2},
+ {kPercentSymbol, 3},
+ {kZeroDigitSymbol, 4},
+ {kDigitSymbol, 5},
+ {kMinusSignSymbol, 6},
+ {kExponentialSymbol, 7},
+ {kPerMillSymbol, 8},
+ {kInfinitySymbol, 9},
+ {kNaNSymbol, 10},
+ {kPlusSignSymbol, 11},
+ {kMonetarySeparatorSymbol, 0}
+ };
+ int32_t idx;
+
+ for (idx = 0; idx < (int32_t)(sizeof(TYPE_MAPPING)/sizeof(TYPE_MAPPING[0])); idx++) {
+ if (TYPE_MAPPING[idx][1] < numberElementsLength) {
+ fSymbols[TYPE_MAPPING[idx][0]].setTo(TRUE, numberElements[TYPE_MAPPING[idx][1]], numberElementsStrLen[TYPE_MAPPING[idx][1]]);
+ }
+ }
+
+ // Default values until it's set later on.
+ fSymbols[kCurrencySymbol] = (UChar)0xa4; // 'OX' currency symbol
+ fSymbols[kIntlCurrencySymbol] = INTL_CURRENCY_SYMBOL_STR;
+ // TODO: read from locale data, if this makes it into CLDR
+ fSymbols[kSignificantDigitSymbol] = (UChar)0x0040; // '@' significant digit
+ fSymbols[kPadEscapeSymbol] = (UChar)0x002a; // TODO: '*' Hard coded for now; get from resource later
+ fSymbols[kMonetaryGroupingSeparatorSymbol] = fSymbols[kGroupingSeparatorSymbol];
+}
+
+// initialize with default values
+void
+DecimalFormatSymbols::initialize() {
+ /*
+ * These strings used to be in static arrays, but the HP/UX aCC compiler
+ * cannot initialize a static array with class constructors.
+ * markus 2000may25
+ */
+ fSymbols[kDecimalSeparatorSymbol] = (UChar)0x2e; // '.' decimal separator
+ fSymbols[kGroupingSeparatorSymbol].remove(); // group (thousands) separator
+ fSymbols[kPatternSeparatorSymbol] = (UChar)0x3b; // ';' pattern separator
+ fSymbols[kPercentSymbol] = (UChar)0x25; // '%' percent sign
+ fSymbols[kZeroDigitSymbol] = (UChar)0x30; // '0' native 0 digit
+ fSymbols[kDigitSymbol] = (UChar)0x23; // '#' pattern digit
+ fSymbols[kPlusSignSymbol] = (UChar)0x002b; // '+' plus sign
+ fSymbols[kMinusSignSymbol] = (UChar)0x2d; // '-' minus sign
+ fSymbols[kCurrencySymbol] = (UChar)0xa4; // 'OX' currency symbol
+ fSymbols[kIntlCurrencySymbol] = INTL_CURRENCY_SYMBOL_STR;
+ fSymbols[kMonetarySeparatorSymbol] = (UChar)0x2e; // '.' monetary decimal separator
+ fSymbols[kExponentialSymbol] = (UChar)0x45; // 'E' exponential
+ fSymbols[kPerMillSymbol] = (UChar)0x2030; // '%o' per mill
+ fSymbols[kPadEscapeSymbol] = (UChar)0x2a; // '*' pad escape symbol
+ fSymbols[kInfinitySymbol] = (UChar)0x221e; // 'oo' infinite
+ fSymbols[kNaNSymbol] = (UChar)0xfffd; // SUB NaN
+ fSymbols[kSignificantDigitSymbol] = (UChar)0x0040; // '@' significant digit
+}
+
+Locale
+DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
+ U_LOCALE_BASED(locBased, *this);
+ return locBased.getLocale(type, status);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/decimfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/decimfmt.cpp
new file mode 100644
index 00000000000..0598bbbd0b5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/decimfmt.cpp
@@ -0,0 +1,3748 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File DECIMFMT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/20/97 clhuang Implemented with new APIs.
+* 03/31/97 aliu Moved isLONG_MIN to DigitList, and fixed it.
+* 04/3/97 aliu Rewrote parsing and formatting completely, and
+* cleaned up and debugged. Actually works now.
+* Implemented NAN and INF handling, for both parsing
+* and formatting. Extensive testing & debugging.
+* 04/10/97 aliu Modified to compile on AIX.
+* 04/16/97 aliu Rewrote to use DigitList, which has been resurrected.
+* Changed DigitCount to int per code review.
+* 07/09/97 helena Made ParsePosition into a class.
+* 08/26/97 aliu Extensive changes to applyPattern; completely
+* rewritten from the Java.
+* 09/09/97 aliu Ported over support for exponential formats.
+* 07/20/98 stephen JDK 1.2 sync up.
+* Various instances of '0' replaced with 'NULL'
+* Check for grouping size in subFormat()
+* Brought subParse() in line with Java 1.2
+* Added method appendAffix()
+* 08/24/1998 srl Removed Mutex calls. This is not a thread safe class!
+* 02/22/99 stephen Removed character literals for EBCDIC safety
+* 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
+* 06/28/99 stephen Fixed bugs in toPattern().
+* 06/29/99 stephen Fixed operator= to copy fFormatWidth, fPad,
+* fPadPosition
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/decimfmt.h"
+#include "unicode/choicfmt.h"
+#include "unicode/ucurr.h"
+#include "unicode/ustring.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/ures.h"
+#include "unicode/uchar.h"
+#include "unicode/curramt.h"
+#include "ucurrimp.h"
+#include "util.h"
+#include "digitlst.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "umutex.h"
+#include "uassert.h"
+#include "putilimp.h"
+
+U_NAMESPACE_BEGIN
+
+//#define FMT_DEBUG
+
+#ifdef FMT_DEBUG
+#include <stdio.h>
+static void debugout(UnicodeString s) {
+ char buf[2000];
+ s.extract((int32_t) 0, s.length(), buf);
+ printf("%s", buf);
+}
+#define debug(x) printf("%s", x);
+#else
+#define debugout(x)
+#define debug(x)
+#endif
+
+// *****************************************************************************
+// class DecimalFormat
+// *****************************************************************************
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
+
+// Constants for characters used in programmatic (unlocalized) patterns.
+#define kPatternZeroDigit ((UChar)0x0030) /*'0'*/
+#define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/
+#define kPatternGroupingSeparator ((UChar)0x002C) /*','*/
+#define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/
+#define kPatternPerMill ((UChar)0x2030)
+#define kPatternPercent ((UChar)0x0025) /*'%'*/
+#define kPatternDigit ((UChar)0x0023) /*'#'*/
+#define kPatternSeparator ((UChar)0x003B) /*';'*/
+#define kPatternExponent ((UChar)0x0045) /*'E'*/
+#define kPatternPlus ((UChar)0x002B) /*'+'*/
+#define kPatternMinus ((UChar)0x002D) /*'-'*/
+#define kPatternPadEscape ((UChar)0x002A) /*'*'*/
+#define kQuote ((UChar)0x0027) /*'\''*/
+/**
+ * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
+ * is used in patterns and substitued with either the currency symbol,
+ * or if it is doubled, with the international currency symbol. If the
+ * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
+ * replaced with the monetary decimal separator.
+ */
+#define kCurrencySign ((UChar)0x00A4)
+#define kDefaultPad ((UChar)0x0020) /* */
+
+const int32_t DecimalFormat::kDoubleIntegerDigits = 309;
+const int32_t DecimalFormat::kDoubleFractionDigits = 340;
+
+const int32_t DecimalFormat::kMaxScientificIntegerDigits = 8;
+
+/**
+ * These are the tags we expect to see in normal resource bundle files associated
+ * with a locale.
+ */
+const char DecimalFormat::fgNumberPatterns[]="NumberPatterns";
+
+inline int32_t _min(int32_t a, int32_t b) { return (a<b) ? a : b; }
+inline int32_t _max(int32_t a, int32_t b) { return (a<b) ? b : a; }
+
+//------------------------------------------------------------------------------
+// Constructs a DecimalFormat instance in the default locale.
+
+DecimalFormat::DecimalFormat(UErrorCode& status)
+: NumberFormat(),
+ fPosPrefixPattern(0),
+ fPosSuffixPattern(0),
+ fNegPrefixPattern(0),
+ fNegSuffixPattern(0),
+ fCurrencyChoice(0),
+ fMultiplier(0),
+ fGroupingSize(0),
+ fGroupingSize2(0),
+ fSymbols(0),
+ fUseSignificantDigits(FALSE),
+ fMinSignificantDigits(1),
+ fMaxSignificantDigits(6),
+ fMinExponentDigits(0),
+ fRoundingIncrement(0),
+ fPad(0),
+ fFormatWidth(0)
+{
+ UParseError parseError;
+ construct(status, parseError);
+}
+
+//------------------------------------------------------------------------------
+// Constructs a DecimalFormat instance with the specified number format
+// pattern in the default locale.
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern,
+ UErrorCode& status)
+: NumberFormat(),
+ fPosPrefixPattern(0),
+ fPosSuffixPattern(0),
+ fNegPrefixPattern(0),
+ fNegSuffixPattern(0),
+ fCurrencyChoice(0),
+ fMultiplier(0),
+ fGroupingSize(0),
+ fGroupingSize2(0),
+ fSymbols(0),
+ fUseSignificantDigits(FALSE),
+ fMinSignificantDigits(1),
+ fMaxSignificantDigits(6),
+ fMinExponentDigits(0),
+ fRoundingIncrement(0),
+ fPad(0),
+ fFormatWidth(0)
+{
+ UParseError parseError;
+ construct(status, parseError, &pattern);
+}
+
+//------------------------------------------------------------------------------
+// Constructs a DecimalFormat instance with the specified number format
+// pattern and the number format symbols in the default locale. The
+// created instance owns the symbols.
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern,
+ DecimalFormatSymbols* symbolsToAdopt,
+ UErrorCode& status)
+: NumberFormat(),
+ fPosPrefixPattern(0),
+ fPosSuffixPattern(0),
+ fNegPrefixPattern(0),
+ fNegSuffixPattern(0),
+ fCurrencyChoice(0),
+ fMultiplier(0),
+ fGroupingSize(0),
+ fGroupingSize2(0),
+ fSymbols(0),
+ fUseSignificantDigits(FALSE),
+ fMinSignificantDigits(1),
+ fMaxSignificantDigits(6),
+ fMinExponentDigits(0),
+ fRoundingIncrement(0),
+ fPad(0),
+ fFormatWidth(0)
+{
+ UParseError parseError;
+ if (symbolsToAdopt == NULL)
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ construct(status, parseError, &pattern, symbolsToAdopt);
+}
+
+DecimalFormat::DecimalFormat( const UnicodeString& pattern,
+ DecimalFormatSymbols* symbolsToAdopt,
+ UParseError& parseErr,
+ UErrorCode& status)
+: NumberFormat(),
+ fPosPrefixPattern(0),
+ fPosSuffixPattern(0),
+ fNegPrefixPattern(0),
+ fNegSuffixPattern(0),
+ fCurrencyChoice(0),
+ fMultiplier(0),
+ fGroupingSize(0),
+ fGroupingSize2(0),
+ fSymbols(0),
+ fUseSignificantDigits(FALSE),
+ fMinSignificantDigits(1),
+ fMaxSignificantDigits(6),
+ fMinExponentDigits(0),
+ fRoundingIncrement(0),
+ fPad(0),
+ fFormatWidth(0)
+{
+ if (symbolsToAdopt == NULL)
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ construct(status,parseErr, &pattern, symbolsToAdopt);
+}
+//------------------------------------------------------------------------------
+// Constructs a DecimalFormat instance with the specified number format
+// pattern and the number format symbols in the default locale. The
+// created instance owns the clone of the symbols.
+
+DecimalFormat::DecimalFormat(const UnicodeString& pattern,
+ const DecimalFormatSymbols& symbols,
+ UErrorCode& status)
+: NumberFormat(),
+ fPosPrefixPattern(0),
+ fPosSuffixPattern(0),
+ fNegPrefixPattern(0),
+ fNegSuffixPattern(0),
+ fCurrencyChoice(0),
+ fMultiplier(0),
+ fGroupingSize(0),
+ fGroupingSize2(0),
+ fSymbols(0),
+ fUseSignificantDigits(FALSE),
+ fMinSignificantDigits(1),
+ fMaxSignificantDigits(6),
+ fMinExponentDigits(0),
+ fRoundingIncrement(0),
+ fPad(0),
+ fFormatWidth(0)
+{
+ UParseError parseError;
+ construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols));
+}
+
+//------------------------------------------------------------------------------
+// Constructs a DecimalFormat instance with the specified number format
+// pattern and the number format symbols in the desired locale. The
+// created instance owns the symbols.
+
+void
+DecimalFormat::construct(UErrorCode& status,
+ UParseError& parseErr,
+ const UnicodeString* pattern,
+ DecimalFormatSymbols* symbolsToAdopt)
+{
+ fSymbols = symbolsToAdopt; // Do this BEFORE aborting on status failure!!!
+// fDigitList = new DigitList(); // Do this BEFORE aborting on status failure!!!
+ fRoundingIncrement = NULL;
+ fRoundingDouble = 0.0;
+ fRoundingMode = kRoundHalfEven;
+ fPad = kPatternPadEscape;
+ fPadPosition = kPadBeforePrefix;
+ if (U_FAILURE(status))
+ return;
+
+ fPosPrefixPattern = fPosSuffixPattern = NULL;
+ fNegPrefixPattern = fNegSuffixPattern = NULL;
+ fMultiplier = 1;
+ fGroupingSize = 3;
+ fGroupingSize2 = 0;
+ fDecimalSeparatorAlwaysShown = FALSE;
+ fIsCurrencyFormat = FALSE;
+ fUseExponentialNotation = FALSE;
+ fMinExponentDigits = 0;
+
+ if (fSymbols == NULL)
+ {
+ fSymbols = new DecimalFormatSymbols(Locale::getDefault(), status);
+ /* test for NULL */
+ if (fSymbols == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ UnicodeString str;
+ // Uses the default locale's number format pattern if there isn't
+ // one specified.
+ if (pattern == NULL)
+ {
+ int32_t len = 0;
+ UResourceBundle *resource = ures_open(NULL, Locale::getDefault().getName(), &status);
+
+ resource = ures_getByKey(resource, fgNumberPatterns, resource, &status);
+ const UChar *resStr = ures_getStringByIndex(resource, (int32_t)0, &len, &status);
+ str.setTo(TRUE, resStr, len);
+ pattern = &str;
+ ures_close(resource);
+ }
+
+ if (U_FAILURE(status))
+ {
+ return;
+ }
+
+ if (pattern->indexOf((UChar)kCurrencySign) >= 0) {
+ // If it looks like we are going to use a currency pattern
+ // then do the time consuming lookup.
+ setCurrencyForSymbols();
+ } else {
+ setCurrency(NULL, status);
+ }
+
+ applyPattern(*pattern, FALSE /*not localized*/,parseErr, status);
+
+ // If it was a currency format, apply the appropriate rounding by
+ // resetting the currency. NOTE: this copies fCurrency on top of itself.
+ if (fIsCurrencyFormat) {
+ setCurrency(getCurrency(), status);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+DecimalFormat::~DecimalFormat()
+{
+// delete fDigitList;
+ delete fPosPrefixPattern;
+ delete fPosSuffixPattern;
+ delete fNegPrefixPattern;
+ delete fNegSuffixPattern;
+ delete fCurrencyChoice;
+ delete fSymbols;
+ delete fRoundingIncrement;
+}
+
+//------------------------------------------------------------------------------
+// copy constructor
+
+DecimalFormat::DecimalFormat(const DecimalFormat &source)
+: NumberFormat(source),
+// fDigitList(NULL),
+ fPosPrefixPattern(NULL),
+ fPosSuffixPattern(NULL),
+ fNegPrefixPattern(NULL),
+ fNegSuffixPattern(NULL),
+ fCurrencyChoice(NULL),
+ fSymbols(NULL),
+ fRoundingIncrement(NULL)
+{
+ *this = source;
+}
+
+//------------------------------------------------------------------------------
+// assignment operator
+// Note that fDigitList is not considered a significant part of the
+// DecimalFormat because it's used as a buffer to process the numbers.
+
+static void _copy_us_ptr(UnicodeString** pdest, const UnicodeString* source) {
+ if (source == NULL) {
+ delete *pdest;
+ *pdest = NULL;
+ } else if (*pdest == NULL) {
+ *pdest = new UnicodeString(*source);
+ } else {
+ **pdest = *source;
+ }
+}
+
+DecimalFormat&
+DecimalFormat::operator=(const DecimalFormat& rhs)
+{
+ if(this != &rhs) {
+ NumberFormat::operator=(rhs);
+ fPositivePrefix = rhs.fPositivePrefix;
+ fPositiveSuffix = rhs.fPositiveSuffix;
+ fNegativePrefix = rhs.fNegativePrefix;
+ fNegativeSuffix = rhs.fNegativeSuffix;
+ _copy_us_ptr(&fPosPrefixPattern, rhs.fPosPrefixPattern);
+ _copy_us_ptr(&fPosSuffixPattern, rhs.fPosSuffixPattern);
+ _copy_us_ptr(&fNegPrefixPattern, rhs.fNegPrefixPattern);
+ _copy_us_ptr(&fNegSuffixPattern, rhs.fNegSuffixPattern);
+ if (rhs.fCurrencyChoice == 0) {
+ delete fCurrencyChoice;
+ fCurrencyChoice = 0;
+ } else {
+ fCurrencyChoice = (ChoiceFormat*) rhs.fCurrencyChoice->clone();
+ }
+ if(rhs.fRoundingIncrement == NULL) {
+ delete fRoundingIncrement;
+ fRoundingIncrement = NULL;
+ }
+ else if(fRoundingIncrement == NULL) {
+ fRoundingIncrement = new DigitList(*rhs.fRoundingIncrement);
+ }
+ else {
+ *fRoundingIncrement = *rhs.fRoundingIncrement;
+ }
+ fRoundingDouble = rhs.fRoundingDouble;
+ fRoundingMode = rhs.fRoundingMode;
+ fMultiplier = rhs.fMultiplier;
+ fGroupingSize = rhs.fGroupingSize;
+ fGroupingSize2 = rhs.fGroupingSize2;
+ fDecimalSeparatorAlwaysShown = rhs.fDecimalSeparatorAlwaysShown;
+ if(fSymbols == NULL) {
+ fSymbols = new DecimalFormatSymbols(*rhs.fSymbols);
+ } else {
+ *fSymbols = *rhs.fSymbols;
+ }
+ fUseExponentialNotation = rhs.fUseExponentialNotation;
+ fExponentSignAlwaysShown = rhs.fExponentSignAlwaysShown;
+ /*Bertrand A. D. Update 98.03.17*/
+ fIsCurrencyFormat = rhs.fIsCurrencyFormat;
+ /*end of Update*/
+ fMinExponentDigits = rhs.fMinExponentDigits;
+ // if (fDigitList == NULL)
+ // fDigitList = new DigitList();
+
+ /* sfb 990629 */
+ fFormatWidth = rhs.fFormatWidth;
+ fPad = rhs.fPad;
+ fPadPosition = rhs.fPadPosition;
+ /* end sfb */
+ fMinSignificantDigits = rhs.fMinSignificantDigits;
+ fMaxSignificantDigits = rhs.fMaxSignificantDigits;
+ fUseSignificantDigits = rhs.fUseSignificantDigits;
+ }
+ return *this;
+}
+
+//------------------------------------------------------------------------------
+
+UBool
+DecimalFormat::operator==(const Format& that) const
+{
+ if (this == &that)
+ return TRUE;
+
+ // NumberFormat::operator== guarantees this cast is safe
+ const DecimalFormat* other = (DecimalFormat*)&that;
+
+#ifdef FMT_DEBUG
+ // This code makes it easy to determine why two format objects that should
+ // be equal aren't.
+ UBool first = TRUE;
+ if (!NumberFormat::operator==(that)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("NumberFormat::!=");
+ }
+ if (!((fPosPrefixPattern == other->fPosPrefixPattern && // both null
+ fPositivePrefix == other->fPositivePrefix)
+ || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 &&
+ *fPosPrefixPattern == *other->fPosPrefixPattern))) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Pos Prefix !=");
+ }
+ if (!((fPosSuffixPattern == other->fPosSuffixPattern && // both null
+ fPositiveSuffix == other->fPositiveSuffix)
+ || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 &&
+ *fPosSuffixPattern == *other->fPosSuffixPattern))) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Pos Suffix !=");
+ }
+ if (!((fNegPrefixPattern == other->fNegPrefixPattern && // both null
+ fNegativePrefix == other->fNegativePrefix)
+ || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 &&
+ *fNegPrefixPattern == *other->fNegPrefixPattern))) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Neg Prefix ");
+ if (fNegPrefixPattern == NULL) {
+ debug("NULL(");
+ debugout(fNegativePrefix);
+ debug(")");
+ } else {
+ debugout(*fNegPrefixPattern);
+ }
+ debug(" != ");
+ if (other->fNegPrefixPattern == NULL) {
+ debug("NULL(");
+ debugout(other->fNegativePrefix);
+ debug(")");
+ } else {
+ debugout(*other->fNegPrefixPattern);
+ }
+ }
+ if (!((fNegSuffixPattern == other->fNegSuffixPattern && // both null
+ fNegativeSuffix == other->fNegativeSuffix)
+ || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 &&
+ *fNegSuffixPattern == *other->fNegSuffixPattern))) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Neg Suffix ");
+ if (fNegSuffixPattern == NULL) {
+ debug("NULL(");
+ debugout(fNegativeSuffix);
+ debug(")");
+ } else {
+ debugout(*fNegSuffixPattern);
+ }
+ debug(" != ");
+ if (other->fNegSuffixPattern == NULL) {
+ debug("NULL(");
+ debugout(other->fNegativeSuffix);
+ debug(")");
+ } else {
+ debugout(*other->fNegSuffixPattern);
+ }
+ }
+ if (!((fRoundingIncrement == other->fRoundingIncrement) // both null
+ || (fRoundingIncrement != NULL &&
+ other->fRoundingIncrement != NULL &&
+ *fRoundingIncrement == *other->fRoundingIncrement))) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Rounding Increment !=");
+ }
+ if (fMultiplier != other->fMultiplier) {
+ if (first) { printf("[ "); first = FALSE; }
+ printf("Multiplier %ld != %ld", fMultiplier, other->fMultiplier);
+ }
+ if (fGroupingSize != other->fGroupingSize) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ printf("Grouping Size %ld != %ld", fGroupingSize, other->fGroupingSize);
+ }
+ if (fGroupingSize2 != other->fGroupingSize2) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ printf("Secondary Grouping Size %ld != %ld", fGroupingSize2, other->fGroupingSize2);
+ }
+ if (fDecimalSeparatorAlwaysShown != other->fDecimalSeparatorAlwaysShown) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ printf("Dec Sep Always %d != %d", fDecimalSeparatorAlwaysShown, other->fDecimalSeparatorAlwaysShown);
+ }
+ if (fUseExponentialNotation != other->fUseExponentialNotation) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Use Exp !=");
+ }
+ if (!(!fUseExponentialNotation ||
+ fMinExponentDigits != other->fMinExponentDigits)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Exp Digits !=");
+ }
+ if (*fSymbols != *(other->fSymbols)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Symbols !=");
+ }
+ // TODO Add debug stuff for significant digits here
+ if (!first) { printf(" ]"); }
+#endif
+
+ return (NumberFormat::operator==(that) &&
+ ((fPosPrefixPattern == other->fPosPrefixPattern && // both null
+ fPositivePrefix == other->fPositivePrefix)
+ || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 &&
+ *fPosPrefixPattern == *other->fPosPrefixPattern)) &&
+ ((fPosSuffixPattern == other->fPosSuffixPattern && // both null
+ fPositiveSuffix == other->fPositiveSuffix)
+ || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 &&
+ *fPosSuffixPattern == *other->fPosSuffixPattern)) &&
+ ((fNegPrefixPattern == other->fNegPrefixPattern && // both null
+ fNegativePrefix == other->fNegativePrefix)
+ || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 &&
+ *fNegPrefixPattern == *other->fNegPrefixPattern)) &&
+ ((fNegSuffixPattern == other->fNegSuffixPattern && // both null
+ fNegativeSuffix == other->fNegativeSuffix)
+ || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 &&
+ *fNegSuffixPattern == *other->fNegSuffixPattern)) &&
+ ((fRoundingIncrement == other->fRoundingIncrement) // both null
+ || (fRoundingIncrement != NULL &&
+ other->fRoundingIncrement != NULL &&
+ *fRoundingIncrement == *other->fRoundingIncrement)) &&
+ fMultiplier == other->fMultiplier &&
+ fGroupingSize == other->fGroupingSize &&
+ fGroupingSize2 == other->fGroupingSize2 &&
+ fDecimalSeparatorAlwaysShown == other->fDecimalSeparatorAlwaysShown &&
+ fUseExponentialNotation == other->fUseExponentialNotation &&
+ (!fUseExponentialNotation ||
+ fMinExponentDigits == other->fMinExponentDigits) &&
+ *fSymbols == *(other->fSymbols) &&
+ fUseSignificantDigits == other->fUseSignificantDigits &&
+ (!fUseSignificantDigits ||
+ (fMinSignificantDigits == other->fMinSignificantDigits &&
+ fMaxSignificantDigits == other->fMaxSignificantDigits)));
+}
+
+//------------------------------------------------------------------------------
+
+Format*
+DecimalFormat::clone() const
+{
+ return new DecimalFormat(*this);
+}
+
+//------------------------------------------------------------------------------
+
+UnicodeString&
+DecimalFormat::format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition) const
+{
+ return format((int64_t)number, appendTo, fieldPosition);
+}
+
+//------------------------------------------------------------------------------
+
+UnicodeString&
+DecimalFormat::format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition) const
+{
+ DigitList digits;
+
+ // Clears field positions.
+ fieldPosition.setBeginIndex(0);
+ fieldPosition.setEndIndex(0);
+
+ // If we are to do rounding, we need to move into the BigDecimal
+ // domain in order to do divide/multiply correctly.
+ // ||
+ // In general, long values always represent real finite numbers, so
+ // we don't have to check for +/- Infinity or NaN. However, there
+ // is one case we have to be careful of: The multiplier can push
+ // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
+ // check for this before multiplying, and if it happens we use doubles
+ // instead, trading off accuracy for range.
+ if (fRoundingIncrement != NULL
+ || (fMultiplier != 0 && (number > (U_INT64_MAX / fMultiplier)
+ || number < (U_INT64_MIN / fMultiplier))))
+ {
+ digits.set(((double)number) * fMultiplier,
+ precision(FALSE),
+ !fUseExponentialNotation && !areSignificantDigitsUsed());
+ }
+ else
+ {
+ digits.set(number * fMultiplier, precision(TRUE));
+ }
+
+ return subformat(appendTo, fieldPosition, digits, TRUE);
+}
+
+//------------------------------------------------------------------------------
+
+UnicodeString&
+DecimalFormat::format( double number,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition) const
+{
+ // Clears field positions.
+ fieldPosition.setBeginIndex(0);
+ fieldPosition.setEndIndex(0);
+
+ // Special case for NaN, sets the begin and end index to be the
+ // the string length of localized name of NaN.
+ if (uprv_isNaN(number))
+ {
+ if (fieldPosition.getField() == NumberFormat::kIntegerField)
+ fieldPosition.setBeginIndex(appendTo.length());
+
+ appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
+
+ if (fieldPosition.getField() == NumberFormat::kIntegerField)
+ fieldPosition.setEndIndex(appendTo.length());
+
+ addPadding(appendTo, fieldPosition, 0, 0);
+ return appendTo;
+ }
+
+ /* Detecting whether a double is negative is easy with the exception of
+ * the value -0.0. This is a double which has a zero mantissa (and
+ * exponent), but a negative sign bit. It is semantically distinct from
+ * a zero with a positive sign bit, and this distinction is important
+ * to certain kinds of computations. However, it's a little tricky to
+ * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
+ * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
+ * -Infinity. Proper detection of -0.0 is needed to deal with the
+ * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
+ */
+ UBool isNegative = uprv_isNegative(number);
+
+ // Do this BEFORE checking to see if value is infinite! Sets the
+ // begin and end index to be length of the string composed of
+ // localized name of Infinite and the positive/negative localized
+ // signs.
+
+ number *= fMultiplier;
+
+ // Apply rounding after multiplier
+ if (fRoundingIncrement != NULL) {
+ if (isNegative) // For rounding in the correct direction
+ number = -number;
+ number = fRoundingDouble
+ * round(number / fRoundingDouble, fRoundingMode, isNegative);
+ if (isNegative)
+ number = -number;
+ }
+
+ // Special case for INFINITE,
+ if (uprv_isInfinite(number))
+ {
+ int32_t prefixLen = appendAffix(appendTo, number, isNegative, TRUE);
+
+ if (fieldPosition.getField() == NumberFormat::kIntegerField)
+ fieldPosition.setBeginIndex(appendTo.length());
+
+ appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
+
+ if (fieldPosition.getField() == NumberFormat::kIntegerField)
+ fieldPosition.setEndIndex(appendTo.length());
+
+ int32_t suffixLen = appendAffix(appendTo, number, isNegative, FALSE);
+
+ addPadding(appendTo, fieldPosition, prefixLen, suffixLen);
+ return appendTo;
+ }
+
+ DigitList digits;
+
+ // This detects negativity too.
+ if (fRoundingIncrement == NULL) {
+ // If we did not round in binary space, round in decimal space
+ digits.fRoundingMode = fRoundingMode;
+ }
+ digits.set(number, precision(FALSE),
+ !fUseExponentialNotation && !areSignificantDigitsUsed());
+
+ return subformat(appendTo, fieldPosition, digits, FALSE);
+}
+
+/**
+ * Round a double value to the nearest integer according to the
+ * given mode.
+ * @param a the absolute value of the number to be rounded
+ * @param mode a BigDecimal rounding mode
+ * @param isNegative true if the number to be rounded is negative
+ * @return the absolute value of the rounded result
+ */
+double DecimalFormat::round(double a, ERoundingMode mode, UBool isNegative) {
+ switch (mode) {
+ case kRoundCeiling:
+ return isNegative ? uprv_floor(a) : uprv_ceil(a);
+ case kRoundFloor:
+ return isNegative ? uprv_ceil(a) : uprv_floor(a);
+ case kRoundDown:
+ return uprv_floor(a);
+ case kRoundUp:
+ return uprv_ceil(a);
+ case kRoundHalfEven:
+ {
+ double f = uprv_floor(a);
+ if ((a - f) != 0.5) {
+ return uprv_floor(a + 0.5);
+ }
+ double g = f / 2.0;
+ return (g == uprv_floor(g)) ? f : (f + 1.0);
+ }
+ case kRoundHalfDown:
+ return ((a - uprv_floor(a)) <= 0.5) ? uprv_floor(a) : uprv_ceil(a);
+ case kRoundHalfUp:
+ return ((a - uprv_floor(a)) < 0.5) ? uprv_floor(a) : uprv_ceil(a);
+ }
+ return 1.0;
+}
+
+UnicodeString&
+DecimalFormat::format( const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ UErrorCode& status) const
+{
+ return NumberFormat::format(obj, appendTo, fieldPosition, status);
+}
+
+/**
+ * Return true if a grouping separator belongs at the given
+ * position, based on whether grouping is in use and the values of
+ * the primary and secondary grouping interval.
+ * @param pos the number of integer digits to the right of
+ * the current position. Zero indicates the position after the
+ * rightmost integer digit.
+ * @return true if a grouping character belongs at the current
+ * position.
+ */
+UBool DecimalFormat::isGroupingPosition(int32_t pos) const {
+ UBool result = FALSE;
+ if (isGroupingUsed() && (pos > 0) && (fGroupingSize > 0)) {
+ if ((fGroupingSize2 > 0) && (pos > fGroupingSize)) {
+ result = ((pos - fGroupingSize) % fGroupingSize2) == 0;
+ } else {
+ result = pos % fGroupingSize == 0;
+ }
+ }
+ return result;
+}
+
+//------------------------------------------------------------------------------
+
+/**
+ * Complete the formatting of a finite number. On entry, the fDigitList must
+ * be filled in with the correct digits.
+ */
+UnicodeString&
+DecimalFormat::subformat(UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ DigitList& digits,
+ UBool isInteger) const
+{
+ // Gets the localized zero Unicode character.
+ UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
+ int32_t zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
+ const UnicodeString *grouping ;
+ if(fIsCurrencyFormat) {
+ grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
+ }else{
+ grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+ }
+ const UnicodeString *decimal;
+ if(fIsCurrencyFormat) {
+ decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
+ } else {
+ decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ }
+ UBool useSigDig = areSignificantDigitsUsed();
+ int32_t maxIntDig = getMaximumIntegerDigits();
+ int32_t minIntDig = getMinimumIntegerDigits();
+
+ /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
+ * format as zero. This allows sensible computations and preserves
+ * relations such as signum(1/x) = signum(x), where x is +Infinity or
+ * -Infinity. Prior to this fix, we always formatted zero values as if
+ * they were positive. Liu 7/6/98.
+ */
+ if (digits.isZero())
+ {
+ digits.fDecimalAt = digits.fCount = 0; // Normalize
+ }
+
+ // Appends the prefix.
+ double doubleValue = digits.getDouble();
+ int32_t prefixLen = appendAffix(appendTo, doubleValue, !digits.fIsPositive, TRUE);
+
+ if (fUseExponentialNotation)
+ {
+ // Record field information for caller.
+ if (fieldPosition.getField() == NumberFormat::kIntegerField)
+ {
+ fieldPosition.setBeginIndex(appendTo.length());
+ fieldPosition.setEndIndex(-1);
+ }
+ else if (fieldPosition.getField() == NumberFormat::kFractionField)
+ {
+ fieldPosition.setBeginIndex(-1);
+ }
+
+ int32_t minFracDig = 0;
+ if (useSigDig) {
+ maxIntDig = minIntDig = 1;
+ minFracDig = getMinimumSignificantDigits() - 1;
+ } else {
+ minFracDig = getMinimumFractionDigits();
+ if (maxIntDig > kMaxScientificIntegerDigits) {
+ maxIntDig = 1;
+ if (maxIntDig < minIntDig) {
+ maxIntDig = minIntDig;
+ }
+ }
+ if (maxIntDig > minIntDig) {
+ minIntDig = 1;
+ }
+ }
+
+ // Minimum integer digits are handled in exponential format by
+ // adjusting the exponent. For example, 0.01234 with 3 minimum
+ // integer digits is "123.4E-4".
+
+ // Maximum integer digits are interpreted as indicating the
+ // repeating range. This is useful for engineering notation, in
+ // which the exponent is restricted to a multiple of 3. For
+ // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
+ // If maximum integer digits are defined and are larger than
+ // minimum integer digits, then minimum integer digits are
+ // ignored.
+ int32_t exponent = digits.fDecimalAt;
+ if (maxIntDig > 1 && maxIntDig != minIntDig) {
+ // A exponent increment is defined; adjust to it.
+ exponent = (exponent > 0) ? (exponent - 1) / maxIntDig
+ : (exponent / maxIntDig) - 1;
+ exponent *= maxIntDig;
+ } else {
+ // No exponent increment is defined; use minimum integer digits.
+ // If none is specified, as in "#E0", generate 1 integer digit.
+ exponent -= (minIntDig > 0 || minFracDig > 0)
+ ? minIntDig : 1;
+ }
+
+ // We now output a minimum number of digits, and more if there
+ // are more digits, up to the maximum number of digits. We
+ // place the decimal point after the "integer" digits, which
+ // are the first (decimalAt - exponent) digits.
+ int32_t minimumDigits = minIntDig + minFracDig;
+ // The number of integer digits is handled specially if the number
+ // is zero, since then there may be no digits.
+ int32_t integerDigits = digits.isZero() ? minIntDig :
+ digits.fDecimalAt - exponent;
+ int32_t totalDigits = digits.fCount;
+ if (minimumDigits > totalDigits)
+ totalDigits = minimumDigits;
+ if (integerDigits > totalDigits)
+ totalDigits = integerDigits;
+
+ // totalDigits records total number of digits needs to be processed
+ int32_t i;
+ for (i=0; i<totalDigits; ++i)
+ {
+ if (i == integerDigits)
+ {
+ // Record field information for caller.
+ if (fieldPosition.getField() == NumberFormat::kIntegerField)
+ fieldPosition.setEndIndex(appendTo.length());
+
+ appendTo += *decimal;
+
+ // Record field information for caller.
+ if (fieldPosition.getField() == NumberFormat::kFractionField)
+ fieldPosition.setBeginIndex(appendTo.length());
+ }
+ // Restores the digit character or pads the buffer with zeros.
+ UChar32 c = (UChar32)((i < digits.fCount) ?
+ (digits.fDigits[i] + zeroDelta) :
+ zero);
+ appendTo += c;
+ }
+
+ // Record field information
+ if (fieldPosition.getField() == NumberFormat::kIntegerField)
+ {
+ if (fieldPosition.getEndIndex() < 0)
+ fieldPosition.setEndIndex(appendTo.length());
+ }
+ else if (fieldPosition.getField() == NumberFormat::kFractionField)
+ {
+ if (fieldPosition.getBeginIndex() < 0)
+ fieldPosition.setBeginIndex(appendTo.length());
+ fieldPosition.setEndIndex(appendTo.length());
+ }
+
+ // The exponent is output using the pattern-specified minimum
+ // exponent digits. There is no maximum limit to the exponent
+ // digits, since truncating the exponent would appendTo in an
+ // unacceptable inaccuracy.
+ appendTo += getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
+
+ // For zero values, we force the exponent to zero. We
+ // must do this here, and not earlier, because the value
+ // is used to determine integer digit count above.
+ if (digits.isZero())
+ exponent = 0;
+
+ if (exponent < 0) {
+ appendTo += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ } else if (fExponentSignAlwaysShown) {
+ appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
+ }
+
+ DigitList expDigits;
+ expDigits.set(exponent);
+ {
+ int expDig = fMinExponentDigits;
+ if (fUseExponentialNotation && expDig < 1) {
+ expDig = 1;
+ }
+ for (i=expDigits.fDecimalAt; i<expDig; ++i)
+ appendTo += (zero);
+ }
+ for (i=0; i<expDigits.fDecimalAt; ++i)
+ {
+ UChar32 c = (UChar32)((i < expDigits.fCount) ?
+ (expDigits.fDigits[i] + zeroDelta) : zero);
+ appendTo += c;
+ }
+ }
+ else // Not using exponential notation
+ {
+ // Record field information for caller.
+ if (fieldPosition.getField() == NumberFormat::kIntegerField)
+ fieldPosition.setBeginIndex(appendTo.length());
+
+ int32_t sigCount = 0;
+ int32_t minSigDig = getMinimumSignificantDigits();
+ int32_t maxSigDig = getMaximumSignificantDigits();
+ if (!useSigDig) {
+ minSigDig = 0;
+ maxSigDig = INT32_MAX;
+ }
+
+ // Output the integer portion. Here 'count' is the total
+ // number of integer digits we will display, including both
+ // leading zeros required to satisfy getMinimumIntegerDigits,
+ // and actual digits present in the number.
+ int32_t count = useSigDig ?
+ _max(1, digits.fDecimalAt) : minIntDig;
+ if (digits.fDecimalAt > 0 && count < digits.fDecimalAt) {
+ count = digits.fDecimalAt;
+ }
+
+ // Handle the case where getMaximumIntegerDigits() is smaller
+ // than the real number of integer digits. If this is so, we
+ // output the least significant max integer digits. For example,
+ // the value 1997 printed with 2 max integer digits is just "97".
+
+ int32_t digitIndex = 0; // Index into digitList.fDigits[]
+ if (count > maxIntDig && maxIntDig >= 0) {
+ count = maxIntDig;
+ digitIndex = digits.fDecimalAt - count;
+ }
+
+ int32_t sizeBeforeIntegerPart = appendTo.length();
+
+ int32_t i;
+ for (i=count-1; i>=0; --i)
+ {
+ if (i < digits.fDecimalAt && digitIndex < digits.fCount &&
+ sigCount < maxSigDig) {
+ // Output a real digit
+ appendTo += ((UChar32)(digits.fDigits[digitIndex++] + zeroDelta));
+ ++sigCount;
+ }
+ else
+ {
+ // Output a zero (leading or trailing)
+ appendTo += (zero);
+ if (sigCount > 0) {
+ ++sigCount;
+ }
+ }
+
+ // Output grouping separator if necessary.
+ if (isGroupingPosition(i)) {
+ appendTo.append(*grouping);
+ }
+ }
+
+ // Record field information for caller.
+ if (fieldPosition.getField() == NumberFormat::kIntegerField)
+ fieldPosition.setEndIndex(appendTo.length());
+
+ // Determine whether or not there are any printable fractional
+ // digits. If we've used up the digits we know there aren't.
+ UBool fractionPresent = (!isInteger && digitIndex < digits.fCount) ||
+ (useSigDig ? (sigCount < minSigDig) : (getMinimumFractionDigits() > 0));
+
+ // If there is no fraction present, and we haven't printed any
+ // integer digits, then print a zero. Otherwise we won't print
+ // _any_ digits, and we won't be able to parse this string.
+ if (!fractionPresent && appendTo.length() == sizeBeforeIntegerPart)
+ appendTo += (zero);
+
+ // Output the decimal separator if we always do so.
+ if (fDecimalSeparatorAlwaysShown || fractionPresent)
+ appendTo += *decimal;
+
+ // Record field information for caller.
+ if (fieldPosition.getField() == NumberFormat::kFractionField)
+ fieldPosition.setBeginIndex(appendTo.length());
+
+ count = useSigDig ? INT32_MAX : getMaximumFractionDigits();
+ if (useSigDig && (sigCount == maxSigDig ||
+ (sigCount >= minSigDig && digitIndex == digits.fCount))) {
+ count = 0;
+ }
+
+ for (i=0; i < count; ++i) {
+ // Here is where we escape from the loop. We escape
+ // if we've output the maximum fraction digits
+ // (specified in the for expression above). We also
+ // stop when we've output the minimum digits and
+ // either: we have an integer, so there is no
+ // fractional stuff to display, or we're out of
+ // significant digits.
+ if (!useSigDig && i >= getMinimumFractionDigits() &&
+ (isInteger || digitIndex >= digits.fCount)) {
+ break;
+ }
+
+ // Output leading fractional zeros. These are zeros
+ // that come after the decimal but before any
+ // significant digits. These are only output if
+ // abs(number being formatted) < 1.0.
+ if (-1-i > (digits.fDecimalAt-1)) {
+ appendTo += zero;
+ continue;
+ }
+
+ // Output a digit, if we have any precision left, or a
+ // zero if we don't. We don't want to output noise digits.
+ if (!isInteger && digitIndex < digits.fCount) {
+ appendTo += ((UChar32)(digits.fDigits[digitIndex++] + zeroDelta));
+ } else {
+ appendTo += zero;
+ }
+
+ // If we reach the maximum number of significant
+ // digits, or if we output all the real digits and
+ // reach the minimum, then we are done.
+ ++sigCount;
+ if (useSigDig &&
+ (sigCount == maxSigDig ||
+ (digitIndex == digits.fCount && sigCount >= minSigDig))) {
+ break;
+ }
+ }
+
+ // Record field information for caller.
+ if (fieldPosition.getField() == NumberFormat::kFractionField)
+ fieldPosition.setEndIndex(appendTo.length());
+ }
+
+ int32_t suffixLen = appendAffix(appendTo, doubleValue, !digits.fIsPositive, FALSE);
+
+ addPadding(appendTo, fieldPosition, prefixLen, suffixLen);
+ return appendTo;
+}
+
+/**
+ * Inserts the character fPad as needed to expand result to fFormatWidth.
+ * @param result the string to be padded
+ */
+void DecimalFormat::addPadding(UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ int32_t prefixLen,
+ int32_t suffixLen) const
+{
+ if (fFormatWidth > 0) {
+ int32_t len = fFormatWidth - appendTo.length();
+ if (len > 0) {
+ UnicodeString padding;
+ for (int32_t i=0; i<len; ++i) {
+ padding += fPad;
+ }
+ switch (fPadPosition) {
+ case kPadAfterPrefix:
+ appendTo.insert(prefixLen, padding);
+ break;
+ case kPadBeforePrefix:
+ appendTo.insert(0, padding);
+ break;
+ case kPadBeforeSuffix:
+ appendTo.insert(appendTo.length() - suffixLen, padding);
+ break;
+ case kPadAfterSuffix:
+ appendTo += padding;
+ break;
+ }
+ if (fPadPosition == kPadBeforePrefix ||
+ fPadPosition == kPadAfterPrefix) {
+ fieldPosition.setBeginIndex(len + fieldPosition.getBeginIndex());
+ fieldPosition.setEndIndex(len + fieldPosition.getEndIndex());
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void
+DecimalFormat::parse(const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const
+{
+ NumberFormat::parse(text, result, status);
+}
+
+void
+DecimalFormat::parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& parsePosition) const {
+ parse(text, result, parsePosition, FALSE);
+}
+
+Formattable& DecimalFormat::parseCurrency(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& pos) const {
+ parse(text, result, pos, TRUE);
+ return result;
+}
+
+/**
+ * Parses the given text as either a number or a currency amount.
+ * @param text the string to parse
+ * @param result output parameter for the result
+ * @param parsePosition input-output position; on input, the
+ * position within text to match; must have 0 <= pos.getIndex() <
+ * text.length(); on output, the position after the last matched
+ * character. If the parse fails, the position in unchanged upon
+ * output.
+ * @param parseCurrency if true, a currency amount is parsed;
+ * otherwise a Number is parsed
+ */
+void DecimalFormat::parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& parsePosition,
+ UBool parseCurrency) const {
+ int32_t backup;
+ int32_t i = backup = parsePosition.getIndex();
+
+ // Handle NaN as a special case:
+
+ // Skip padding characters, if around prefix
+ if (fFormatWidth > 0 && (fPadPosition == kPadBeforePrefix ||
+ fPadPosition == kPadAfterPrefix)) {
+ i = skipPadding(text, i);
+ }
+ // If the text is composed of the representation of NaN, returns NaN.length
+ const UnicodeString *nan = &getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
+ int32_t nanLen = (text.compare(i, nan->length(), *nan)
+ ? 0 : nan->length());
+ if (nanLen) {
+ i += nanLen;
+ if (fFormatWidth > 0 && (fPadPosition == kPadBeforeSuffix ||
+ fPadPosition == kPadAfterSuffix)) {
+ i = skipPadding(text, i);
+ }
+ parsePosition.setIndex(i);
+ result.setDouble(uprv_getNaN());
+ return;
+ }
+
+ // NaN parse failed; start over
+ i = backup;
+
+ // status is used to record whether a number is infinite.
+ UBool status[fgStatusLength];
+ UChar curbuf[4];
+ UChar* currency = parseCurrency ? curbuf : NULL;
+ DigitList digits;
+
+ if (!subparse(text, parsePosition, digits, status, currency)) {
+ parsePosition.setIndex(backup);
+ return;
+ }
+
+ // Handle infinity
+ if (status[fgStatusInfinite]) {
+ double inf = uprv_getInfinity();
+ result.setDouble(digits.fIsPositive ? inf : -inf);
+ }
+
+ else {
+ // Do as much of the multiplier conversion as possible without
+ // losing accuracy.
+ int32_t mult = fMultiplier; // Don't modify this.multiplier
+ while (mult % 10 == 0) {
+ mult /= 10;
+ --digits.fDecimalAt;
+ }
+
+ // Handle integral values. We want to return the most
+ // parsimonious type that will accommodate all of the result's
+ // precision. We therefore only return a long if the result fits
+ // entirely within a long (taking into account the multiplier) --
+ // otherwise we fall through and return a double. When more
+ // numeric types are supported by Formattable (e.g., 64-bit
+ // integers, bignums) we will extend this logic to include them.
+ if (digits.fitsIntoLong(isParseIntegerOnly())) {
+ int32_t n = digits.getLong();
+ if (n % mult == 0) {
+ result.setLong(n / mult);
+ }
+ else { // else handle the remainder
+ result.setDouble(((double)n) / mult);
+ }
+ }
+ else if (digits.fitsIntoInt64(isParseIntegerOnly())) {
+ int64_t n = digits.getInt64();
+ if (n % mult == 0) {
+ result.setInt64(n / mult);
+ }
+ else { // else handle the remainder
+ result.setDouble(((double)n) / mult);
+ }
+ }
+ else {
+ // Handle non-integral or very large values
+ // Dividing by one is okay and not that costly.
+ result.setDouble(digits.getDouble() / mult);
+ }
+ }
+
+ if (parseCurrency) {
+ UErrorCode ec = U_ZERO_ERROR;
+ Formattable n(result);
+ result.adoptObject(new CurrencyAmount(n, curbuf, ec));
+ U_ASSERT(U_SUCCESS(ec)); // should always succeed
+ }
+}
+
+
+/*
+This is an old implimentation that was preparing for 64-bit numbers in ICU.
+It is very slow, and 64-bit numbers are not ANSI-C compatible. This code
+is here if we change our minds.
+
+^^^ what is this referring to? remove? ^^^ [alan]
+*/
+
+/**
+ * Parse the given text into a number. The text is parsed beginning at
+ * parsePosition, until an unparseable character is seen.
+ * @param text the string to parse.
+ * @param parsePosition The position at which to being parsing. Upon
+ * return, the first unparsed character.
+ * @param digits the DigitList to set to the parsed value.
+ * @param status output param containing boolean status flags indicating
+ * whether the value was infinite and whether it was positive.
+ * @param currency return value for parsed currency, for generic
+ * currency parsing mode, or NULL for normal parsing. In generic
+ * currency parsing mode, any currency is parsed, not just the
+ * currency that this formatter is set to.
+ */
+UBool DecimalFormat::subparse(const UnicodeString& text, ParsePosition& parsePosition,
+ DigitList& digits, UBool* status,
+ UChar* currency) const
+{
+ int32_t position = parsePosition.getIndex();
+ int32_t oldStart = position;
+
+ // Match padding before prefix
+ if (fFormatWidth > 0 && fPadPosition == kPadBeforePrefix) {
+ position = skipPadding(text, position);
+ }
+
+ // Match positive and negative prefixes; prefer longest match.
+ int32_t posMatch = compareAffix(text, position, FALSE, TRUE, currency);
+ int32_t negMatch = compareAffix(text, position, TRUE, TRUE, currency);
+ if (posMatch >= 0 && negMatch >= 0) {
+ if (posMatch > negMatch) {
+ negMatch = -1;
+ } else if (negMatch > posMatch) {
+ posMatch = -1;
+ }
+ }
+ if (posMatch >= 0) {
+ position += posMatch;
+ } else if (negMatch >= 0) {
+ position += negMatch;
+ } else {
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+
+ // Match padding before prefix
+ if (fFormatWidth > 0 && fPadPosition == kPadAfterPrefix) {
+ position = skipPadding(text, position);
+ }
+
+ // process digits or Inf, find decimal position
+ const UnicodeString *inf = &getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
+ int32_t infLen = (text.compare(position, inf->length(), *inf)
+ ? 0 : inf->length());
+ position += infLen; // infLen is non-zero when it does equal to infinity
+ status[fgStatusInfinite] = (UBool)infLen;
+ if (!infLen)
+ {
+ // We now have a string of digits, possibly with grouping symbols,
+ // and decimal points. We want to process these into a DigitList.
+ // We don't want to put a bunch of leading zeros into the DigitList
+ // though, so we keep track of the location of the decimal point,
+ // put only significant digits into the DigitList, and adjust the
+ // exponent as needed.
+
+ digits.fDecimalAt = digits.fCount = 0;
+ UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
+
+ const UnicodeString *decimal;
+ if(fIsCurrencyFormat) {
+ decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
+ } else {
+ decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ }
+ const UnicodeString *grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+ UBool sawDecimal = FALSE;
+ UBool sawDigit = FALSE;
+ int32_t backup = -1;
+ int32_t digit;
+ int32_t textLength = text.length(); // One less pointer to follow
+ int32_t groupingLen = grouping->length();
+ int32_t decimalLen = decimal->length();
+
+ // We have to track digitCount ourselves, because digits.fCount will
+ // pin when the maximum allowable digits is reached.
+ int32_t digitCount = 0;
+
+ for (; position < textLength; )
+ {
+ UChar32 ch = text.char32At(position);
+
+ /* We recognize all digit ranges, not only the Latin digit range
+ * '0'..'9'. We do so by using the Character.digit() method,
+ * which converts a valid Unicode digit to the range 0..9.
+ *
+ * The character 'ch' may be a digit. If so, place its value
+ * from 0 to 9 in 'digit'. First try using the locale digit,
+ * which may or MAY NOT be a standard Unicode digit range. If
+ * this fails, try using the standard Unicode digit ranges by
+ * calling Character.digit(). If this also fails, digit will
+ * have a value outside the range 0..9.
+ */
+ digit = ch - zero;
+ if (digit < 0 || digit > 9)
+ {
+ digit = u_charDigitValue(ch);
+ }
+
+ if (digit > 0 && digit <= 9)
+ {
+ // Cancel out backup setting (see grouping handler below)
+ backup = -1;
+
+ sawDigit = TRUE;
+ // output a regular non-zero digit.
+ ++digitCount;
+ digits.append((char)(digit + '0'));
+ position += U16_LENGTH(ch);
+ }
+ else if (digit == 0)
+ {
+ // Cancel out backup setting (see grouping handler below)
+ backup = -1;
+ sawDigit = TRUE;
+
+ // Check for leading zeros
+ if (digits.fCount != 0)
+ {
+ // output a regular zero digit.
+ ++digitCount;
+ digits.append((char)(digit + '0'));
+ }
+ else if (sawDecimal)
+ {
+ // If we have seen the decimal, but no significant digits yet,
+ // then we account for leading zeros by decrementing the
+ // digits.fDecimalAt into negative values.
+ --digits.fDecimalAt;
+ }
+ // else ignore leading zeros in integer part of number.
+ position += U16_LENGTH(ch);
+ }
+ else if (!text.compare(position, groupingLen, *grouping) && isGroupingUsed())
+ {
+ // Ignore grouping characters, if we are using them, but require
+ // that they be followed by a digit. Otherwise we backup and
+ // reprocess them.
+ backup = position;
+ position += groupingLen;
+ }
+ else if (!text.compare(position, decimalLen, *decimal) && !isParseIntegerOnly() && !sawDecimal)
+ {
+ // If we're only parsing integers, or if we ALREADY saw the
+ // decimal, then don't parse this one.
+
+ digits.fDecimalAt = digitCount; // Not digits.fCount!
+ sawDecimal = TRUE;
+ position += decimalLen;
+ }
+ else {
+ const UnicodeString *tmp;
+ tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
+ if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit
+ {
+ // Parse sign, if present
+ int32_t pos = position + tmp->length();
+ DigitList exponentDigits;
+
+ if (pos < textLength)
+ {
+ tmp = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
+ if (!text.compare(pos, tmp->length(), *tmp))
+ {
+ pos += tmp->length();
+ }
+ else {
+ tmp = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ if (!text.compare(pos, tmp->length(), *tmp))
+ {
+ pos += tmp->length();
+ exponentDigits.fIsPositive = FALSE;
+ }
+ }
+ }
+
+ while (pos < textLength) {
+ ch = text[(int32_t)pos];
+ digit = ch - zero;
+
+ if (digit < 0 || digit > 9) {
+ digit = u_charDigitValue(ch);
+ }
+ if (0 <= digit && digit <= 9) {
+ ++pos;
+ exponentDigits.append((char)(digit + '0'));
+ } else {
+ break;
+ }
+ }
+
+ if (exponentDigits.fCount > 0) {
+ exponentDigits.fDecimalAt = exponentDigits.fCount;
+ digits.fDecimalAt += exponentDigits.getLong();
+ position = pos; // Advance past the exponent
+ }
+
+ break; // Whether we fail or succeed, we exit this loop
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ if (backup != -1)
+ {
+ position = backup;
+ }
+
+ // If there was no decimal point we have an integer
+ if (!sawDecimal)
+ {
+ digits.fDecimalAt += digitCount; // Not digits.fCount!
+ }
+
+ // If none of the text string was recognized. For example, parse
+ // "x" with pattern "#0.00" (return index and error index both 0)
+ // parse "$" with pattern "$#0.00". (return index 0 and error index
+ // 1).
+ if (!sawDigit && digitCount == 0) {
+ parsePosition.setIndex(oldStart);
+ parsePosition.setErrorIndex(oldStart);
+ return FALSE;
+ }
+ }
+
+ // Match padding before suffix
+ if (fFormatWidth > 0 && fPadPosition == kPadBeforeSuffix) {
+ position = skipPadding(text, position);
+ }
+
+ // Match positive and negative suffixes; prefer longest match.
+ if (posMatch >= 0) {
+ posMatch = compareAffix(text, position, FALSE, FALSE, currency);
+ }
+ if (negMatch >= 0) {
+ negMatch = compareAffix(text, position, TRUE, FALSE, currency);
+ }
+ if (posMatch >= 0 && negMatch >= 0) {
+ if (posMatch > negMatch) {
+ negMatch = -1;
+ } else if (negMatch > posMatch) {
+ posMatch = -1;
+ }
+ }
+
+ // Fail if neither or both
+ if ((posMatch >= 0) == (negMatch >= 0)) {
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+
+ position += (posMatch>=0 ? posMatch : negMatch);
+
+ // Match padding before suffix
+ if (fFormatWidth > 0 && fPadPosition == kPadAfterSuffix) {
+ position = skipPadding(text, position);
+ }
+
+ parsePosition.setIndex(position);
+
+ digits.fIsPositive = (posMatch >= 0);
+
+ if(parsePosition.getIndex() == oldStart)
+ {
+ parsePosition.setErrorIndex(position);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Starting at position, advance past a run of pad characters, if any.
+ * Return the index of the first character after position that is not a pad
+ * character. Result is >= position.
+ */
+int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position) const {
+ int32_t padLen = U16_LENGTH(fPad);
+ while (position < text.length() &&
+ text.char32At(position) == fPad) {
+ position += padLen;
+ }
+ return position;
+}
+
+/**
+ * Return the length matched by the given affix, or -1 if none.
+ * Runs of white space in the affix, match runs of white space in
+ * the input. Pattern white space and input white space are
+ * determined differently; see code.
+ * @param text input text
+ * @param pos offset into input at which to begin matching
+ * @param isNegative
+ * @param isPrefix
+ * @param currency return value for parsed currency, for generic
+ * currency parsing mode, or null for normal parsing. In generic
+ * currency parsing mode, any currency is parsed, not just the
+ * currency that this formatter is set to.
+ * @return length of input that matches, or -1 if match failure
+ */
+int32_t DecimalFormat::compareAffix(const UnicodeString& text,
+ int32_t pos,
+ UBool isNegative,
+ UBool isPrefix,
+ UChar* currency) const
+{
+ const UnicodeString *patternToCompare;
+ if (fCurrencyChoice != NULL || currency != NULL) {
+ if (isNegative) {
+ if (isPrefix) {
+ patternToCompare = fNegPrefixPattern;
+ }
+ else {
+ patternToCompare = fNegSuffixPattern;
+ }
+ }
+ else {
+ if (isPrefix) {
+ patternToCompare = fPosPrefixPattern;
+ }
+ else {
+ patternToCompare = fPosSuffixPattern;
+ }
+ }
+ if (patternToCompare != NULL) {
+ return compareComplexAffix(*patternToCompare, text, pos, currency);
+ }
+ /* else the caller modified the pattern. Fallback to normal behavior. */
+ }
+
+ if (isNegative) {
+ if (isPrefix) {
+ patternToCompare = &fNegativePrefix;
+ }
+ else {
+ patternToCompare = &fNegativeSuffix;
+ }
+ }
+ else {
+ if (isPrefix) {
+ patternToCompare = &fPositivePrefix;
+ }
+ else {
+ patternToCompare = &fPositiveSuffix;
+ }
+ }
+ return compareSimpleAffix(*patternToCompare, text, pos);
+}
+
+/**
+ * Return the length matched by the given affix, or -1 if none.
+ * Runs of white space in the affix, match runs of white space in
+ * the input. Pattern white space and input white space are
+ * determined differently; see code.
+ * @param affix pattern string, taken as a literal
+ * @param input input text
+ * @param pos offset into input at which to begin matching
+ * @return length of input that matches, or -1 if match failure
+ */
+int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
+ const UnicodeString& input,
+ int32_t pos) {
+ int32_t start = pos;
+ for (int32_t i=0; i<affix.length(); ) {
+ UChar32 c = affix.char32At(i);
+ int32_t len = U16_LENGTH(c);
+ if (uprv_isRuleWhiteSpace(c)) {
+ // We may have a pattern like: \u200F \u0020
+ // and input text like: \u200F \u0020
+ // Note that U+200F and U+0020 are RuleWhiteSpace but only
+ // U+0020 is UWhiteSpace. So we have to first do a direct
+ // match of the run of RULE whitespace in the pattern,
+ // then match any extra characters.
+ UBool literalMatch = FALSE;
+ while (pos < input.length() &&
+ input.char32At(pos) == c) {
+ literalMatch = TRUE;
+ i += len;
+ pos += len;
+ if (i == affix.length()) {
+ break;
+ }
+ c = affix.char32At(i);
+ len = U16_LENGTH(c);
+ if (!uprv_isRuleWhiteSpace(c)) {
+ break;
+ }
+ }
+
+ // Advance over run in pattern
+ i = skipRuleWhiteSpace(affix, i);
+
+ // Advance over run in input text
+ // Must see at least one white space char in input,
+ // unless we've already matched some characters literally.
+ int32_t s = pos;
+ pos = skipUWhiteSpace(input, pos);
+ if (pos == s && !literalMatch) {
+ return -1;
+ }
+ } else {
+ if (pos < input.length() &&
+ input.char32At(pos) == c) {
+ i += len;
+ pos += len;
+ } else {
+ return -1;
+ }
+ }
+ }
+ return pos - start;
+}
+
+/**
+ * Skip over a run of zero or more isRuleWhiteSpace() characters at
+ * pos in text.
+ */
+int32_t DecimalFormat::skipRuleWhiteSpace(const UnicodeString& text, int32_t pos) {
+ while (pos < text.length()) {
+ UChar32 c = text.char32At(pos);
+ if (!uprv_isRuleWhiteSpace(c)) {
+ break;
+ }
+ pos += U16_LENGTH(c);
+ }
+ return pos;
+}
+
+/**
+ * Skip over a run of zero or more isUWhiteSpace() characters at pos
+ * in text.
+ */
+int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
+ while (pos < text.length()) {
+ UChar32 c = text.char32At(pos);
+ if (!u_isUWhiteSpace(c)) {
+ break;
+ }
+ pos += U16_LENGTH(c);
+ }
+ return pos;
+}
+
+/**
+ * Return the length matched by the given affix, or -1 if none.
+ * @param affixPat pattern string
+ * @param input input text
+ * @param pos offset into input at which to begin matching
+ * @param currency return value for parsed currency, for generic
+ * currency parsing mode, or null for normal parsing. In generic
+ * currency parsing mode, any currency is parsed, not just the
+ * currency that this formatter is set to.
+ * @return length of input that matches, or -1 if match failure
+ */
+int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
+ const UnicodeString& text,
+ int32_t pos,
+ UChar* currency) const
+{
+ int32_t start = pos;
+ U_ASSERT(currency != NULL ||
+ (fCurrencyChoice != NULL && *getCurrency() != 0));
+
+ for (int32_t i=0; i<affixPat.length() && pos >= 0; ) {
+ UChar32 c = affixPat.char32At(i);
+ i += U16_LENGTH(c);
+
+ if (c == kQuote) {
+ U_ASSERT(i <= affixPat.length());
+ c = affixPat.char32At(i);
+ i += U16_LENGTH(c);
+
+ const UnicodeString* affix = NULL;
+
+ switch (c) {
+ case kCurrencySign: {
+ // If currency != null, then perform generic currency matching.
+ // Otherwise, do currency choice parsing.
+ UBool intl = i<affixPat.length() &&
+ affixPat.char32At(i) == kCurrencySign;
+ // Parse generic currency -- anything for which we
+ // have a display name, or any 3-letter ISO code.
+ if (currency != NULL) {
+ // Try to parse display name for our locale; first
+ // determine our locale.
+ UErrorCode ec = U_ZERO_ERROR;
+ const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec);
+ if (U_FAILURE(ec) || loc == NULL || *loc == 0) {
+ // applyPattern has been called; use the symbols
+ loc = fSymbols->getLocale().getName();
+ ec = U_ZERO_ERROR;
+ }
+ // Delegate parse of display name => ISO code to Currency
+ ParsePosition ppos(pos);
+ UChar curr[4];
+ uprv_parseCurrency(loc, text, ppos, curr, ec);
+
+ // If parse succeeds, populate currency[0]
+ if (U_SUCCESS(ec) && ppos.getIndex() != pos) {
+ u_strcpy(currency, curr);
+ pos = ppos.getIndex();
+ } else {
+ pos = -1;
+ }
+ } else {
+ if (intl) {
+ ++i;
+ pos = match(text, pos, getCurrency());
+ } else {
+ ParsePosition ppos(pos);
+ Formattable result;
+ fCurrencyChoice->parse(text, result, ppos);
+ pos = (ppos.getIndex() == pos) ? -1 : ppos.getIndex();
+ }
+ }
+ continue;
+ }
+ case kPatternPercent:
+ affix = &getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
+ break;
+ case kPatternPerMill:
+ affix = &getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
+ break;
+ case kPatternPlus:
+ affix = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
+ break;
+ case kPatternMinus:
+ affix = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ break;
+ default:
+ // fall through to affix!=0 test, which will fail
+ break;
+ }
+
+ if (affix != NULL) {
+ pos = match(text, pos, *affix);
+ continue;
+ }
+ }
+
+ pos = match(text, pos, c);
+ if (uprv_isRuleWhiteSpace(c)) {
+ i = skipRuleWhiteSpace(affixPat, i);
+ }
+ }
+ return pos - start;
+}
+
+/**
+ * Match a single character at text[pos] and return the index of the
+ * next character upon success. Return -1 on failure. If
+ * isRuleWhiteSpace(ch) then match a run of white space in text.
+ */
+int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch) {
+ if (uprv_isRuleWhiteSpace(ch)) {
+ // Advance over run of white space in input text
+ // Must see at least one white space char in input
+ int32_t s = pos;
+ pos = skipUWhiteSpace(text, pos);
+ if (pos == s) {
+ return -1;
+ }
+ return pos;
+ }
+ return (pos >= 0 && text.char32At(pos) == ch) ?
+ (pos + U16_LENGTH(ch)) : -1;
+}
+
+/**
+ * Match a string at text[pos] and return the index of the next
+ * character upon success. Return -1 on failure. Match a run of
+ * white space in str with a run of white space in text.
+ */
+int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, const UnicodeString& str) {
+ for (int32_t i=0; i<str.length() && pos >= 0; ) {
+ UChar32 ch = str.char32At(i);
+ i += U16_LENGTH(ch);
+ if (uprv_isRuleWhiteSpace(ch)) {
+ i = skipRuleWhiteSpace(str, i);
+ }
+ pos = match(text, pos, ch);
+ }
+ return pos;
+}
+
+//------------------------------------------------------------------------------
+// Gets the pointer to the localized decimal format symbols
+
+const DecimalFormatSymbols*
+DecimalFormat::getDecimalFormatSymbols() const
+{
+ return fSymbols;
+}
+
+//------------------------------------------------------------------------------
+// De-owning the current localized symbols and adopt the new symbols.
+
+void
+DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt)
+{
+ if (symbolsToAdopt == NULL) {
+ return; // do not allow caller to set fSymbols to NULL
+ }
+
+ UBool sameSymbols = FALSE;
+ if (fSymbols != NULL) {
+ sameSymbols = (UBool)(getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) ==
+ symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) &&
+ getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol) ==
+ symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol));
+ delete fSymbols;
+ }
+
+ fSymbols = symbolsToAdopt;
+ if (!sameSymbols) {
+ // If the currency symbols are the same, there is no need to recalculate.
+ setCurrencyForSymbols();
+ }
+ expandAffixes();
+}
+//------------------------------------------------------------------------------
+// Setting the symbols is equlivalent to adopting a newly created localized
+// symbols.
+
+void
+DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
+{
+ adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
+}
+
+/**
+ * Update the currency object to match the symbols. This method
+ * is used only when the caller has passed in a symbols object
+ * that may not be the default object for its locale.
+ */
+void
+DecimalFormat::setCurrencyForSymbols() {
+ /*Bug 4212072
+ Update the affix strings accroding to symbols in order to keep
+ the affix strings up to date.
+ [Richard/GCL]
+ */
+
+ // With the introduction of the Currency object, the currency
+ // symbols in the DFS object are ignored. For backward
+ // compatibility, we check any explicitly set DFS object. If it
+ // is a default symbols object for its locale, we change the
+ // currency object to one for that locale. If it is custom,
+ // we set the currency to null.
+ UErrorCode ec = U_ZERO_ERROR;
+ const UChar* c = NULL;
+ const char* loc = fSymbols->getLocale().getName();
+ UChar intlCurrencySymbol[4];
+ ucurr_forLocale(loc, intlCurrencySymbol, 4, &ec);
+ UnicodeString currencySymbol;
+
+ uprv_getStaticCurrencyName(intlCurrencySymbol, loc, currencySymbol, ec);
+ if (U_SUCCESS(ec)
+ && getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) == currencySymbol
+ && getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol) == intlCurrencySymbol)
+ {
+ // Trap an error in mapping locale to currency. If we can't
+ // map, then don't fail and set the currency to "".
+ c = intlCurrencySymbol;
+ }
+ ec = U_ZERO_ERROR; // reset local error code!
+ setCurrency(c, ec);
+}
+
+
+//------------------------------------------------------------------------------
+// Gets the positive prefix of the number pattern.
+
+UnicodeString&
+DecimalFormat::getPositivePrefix(UnicodeString& result) const
+{
+ result = fPositivePrefix;
+ return result;
+}
+
+//------------------------------------------------------------------------------
+// Sets the positive prefix of the number pattern.
+
+void
+DecimalFormat::setPositivePrefix(const UnicodeString& newValue)
+{
+ fPositivePrefix = newValue;
+ delete fPosPrefixPattern;
+ fPosPrefixPattern = 0;
+}
+
+//------------------------------------------------------------------------------
+// Gets the negative prefix of the number pattern.
+
+UnicodeString&
+DecimalFormat::getNegativePrefix(UnicodeString& result) const
+{
+ result = fNegativePrefix;
+ return result;
+}
+
+//------------------------------------------------------------------------------
+// Gets the negative prefix of the number pattern.
+
+void
+DecimalFormat::setNegativePrefix(const UnicodeString& newValue)
+{
+ fNegativePrefix = newValue;
+ delete fNegPrefixPattern;
+ fNegPrefixPattern = 0;
+}
+
+//------------------------------------------------------------------------------
+// Gets the positive suffix of the number pattern.
+
+UnicodeString&
+DecimalFormat::getPositiveSuffix(UnicodeString& result) const
+{
+ result = fPositiveSuffix;
+ return result;
+}
+
+//------------------------------------------------------------------------------
+// Sets the positive suffix of the number pattern.
+
+void
+DecimalFormat::setPositiveSuffix(const UnicodeString& newValue)
+{
+ fPositiveSuffix = newValue;
+ delete fPosSuffixPattern;
+ fPosSuffixPattern = 0;
+}
+
+//------------------------------------------------------------------------------
+// Gets the negative suffix of the number pattern.
+
+UnicodeString&
+DecimalFormat::getNegativeSuffix(UnicodeString& result) const
+{
+ result = fNegativeSuffix;
+ return result;
+}
+
+//------------------------------------------------------------------------------
+// Sets the negative suffix of the number pattern.
+
+void
+DecimalFormat::setNegativeSuffix(const UnicodeString& newValue)
+{
+ fNegativeSuffix = newValue;
+ delete fNegSuffixPattern;
+ fNegSuffixPattern = 0;
+}
+
+//------------------------------------------------------------------------------
+// Gets the multiplier of the number pattern.
+
+int32_t DecimalFormat::getMultiplier() const
+{
+ return fMultiplier;
+}
+
+//------------------------------------------------------------------------------
+// Sets the multiplier of the number pattern.
+void
+DecimalFormat::setMultiplier(int32_t newValue)
+{
+// if (newValue <= 0) {
+// throw new IllegalArgumentException("Bad multiplier: " + newValue);
+// }
+ if (newValue > 0) {
+ fMultiplier = newValue;
+ }
+ // else No way to return an error.
+}
+
+/**
+ * Get the rounding increment.
+ * @return A positive rounding increment, or 0.0 if rounding
+ * is not in effect.
+ * @see #setRoundingIncrement
+ * @see #getRoundingMode
+ * @see #setRoundingMode
+ */
+double DecimalFormat::getRoundingIncrement() const {
+ return fRoundingDouble;
+}
+
+/**
+ * Set the rounding increment. This method also controls whether
+ * rounding is enabled.
+ * @param newValue A positive rounding increment, or 0.0 to disable rounding.
+ * Negative increments are equivalent to 0.0.
+ * @see #getRoundingIncrement
+ * @see #getRoundingMode
+ * @see #setRoundingMode
+ */
+void DecimalFormat::setRoundingIncrement(double newValue) {
+ if (newValue > 0.0) {
+ if (fRoundingIncrement == NULL) {
+ fRoundingIncrement = new DigitList();
+ }
+ fRoundingIncrement->set((int32_t)newValue);
+ fRoundingDouble = newValue;
+ } else {
+ delete fRoundingIncrement;
+ fRoundingIncrement = NULL;
+ fRoundingDouble = 0.0;
+ }
+}
+
+/**
+ * Get the rounding mode.
+ * @return A rounding mode
+ * @see #setRoundingIncrement
+ * @see #getRoundingIncrement
+ * @see #setRoundingMode
+ */
+DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const {
+ return fRoundingMode;
+}
+
+/**
+ * Set the rounding mode. This has no effect unless the rounding
+ * increment is greater than zero.
+ * @param roundingMode A rounding mode
+ * @see #setRoundingIncrement
+ * @see #getRoundingIncrement
+ * @see #getRoundingMode
+ */
+void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
+ fRoundingMode = roundingMode;
+}
+
+/**
+ * Get the width to which the output of <code>format()</code> is padded.
+ * @return the format width, or zero if no padding is in effect
+ * @see #setFormatWidth
+ * @see #getPadCharacter
+ * @see #setPadCharacter
+ * @see #getPadPosition
+ * @see #setPadPosition
+ */
+int32_t DecimalFormat::getFormatWidth() const {
+ return fFormatWidth;
+}
+
+/**
+ * Set the width to which the output of <code>format()</code> is padded.
+ * This method also controls whether padding is enabled.
+ * @param width the width to which to pad the result of
+ * <code>format()</code>, or zero to disable padding. A negative
+ * width is equivalent to 0.
+ * @see #getFormatWidth
+ * @see #getPadCharacter
+ * @see #setPadCharacter
+ * @see #getPadPosition
+ * @see #setPadPosition
+ */
+void DecimalFormat::setFormatWidth(int32_t width) {
+ fFormatWidth = (width > 0) ? width : 0;
+}
+
+UnicodeString DecimalFormat::getPadCharacterString() const {
+ return fPad;
+}
+
+void DecimalFormat::setPadCharacter(const UnicodeString &padChar) {
+ if (padChar.length() > 0) {
+ fPad = padChar.char32At(0);
+ }
+ else {
+ fPad = kDefaultPad;
+ }
+}
+
+/**
+ * Get the position at which padding will take place. This is the location
+ * at which padding will be inserted if the result of <code>format()</code>
+ * is shorter than the format width.
+ * @return the pad position, one of <code>kPadBeforePrefix</code>,
+ * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or
+ * <code>kPadAfterSuffix</code>.
+ * @see #setFormatWidth
+ * @see #getFormatWidth
+ * @see #setPadCharacter
+ * @see #getPadCharacter
+ * @see #setPadPosition
+ * @see #kPadBeforePrefix
+ * @see #kPadAfterPrefix
+ * @see #kPadBeforeSuffix
+ * @see #kPadAfterSuffix
+ */
+DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const {
+ return fPadPosition;
+}
+
+/**
+ * <strong><font face=helvetica color=red>NEW</font></strong>
+ * Set the position at which padding will take place. This is the location
+ * at which padding will be inserted if the result of <code>format()</code>
+ * is shorter than the format width. This has no effect unless padding is
+ * enabled.
+ * @param padPos the pad position, one of <code>kPadBeforePrefix</code>,
+ * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or
+ * <code>kPadAfterSuffix</code>.
+ * @see #setFormatWidth
+ * @see #getFormatWidth
+ * @see #setPadCharacter
+ * @see #getPadCharacter
+ * @see #getPadPosition
+ * @see #kPadBeforePrefix
+ * @see #kPadAfterPrefix
+ * @see #kPadBeforeSuffix
+ * @see #kPadAfterSuffix
+ */
+void DecimalFormat::setPadPosition(EPadPosition padPos) {
+ fPadPosition = padPos;
+}
+
+/**
+ * Return whether or not scientific notation is used.
+ * @return TRUE if this object formats and parses scientific notation
+ * @see #setScientificNotation
+ * @see #getMinimumExponentDigits
+ * @see #setMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ * @see #setExponentSignAlwaysShown
+ */
+UBool DecimalFormat::isScientificNotation() {
+ return fUseExponentialNotation;
+}
+
+/**
+ * Set whether or not scientific notation is used.
+ * @param useScientific TRUE if this object formats and parses scientific
+ * notation
+ * @see #isScientificNotation
+ * @see #getMinimumExponentDigits
+ * @see #setMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ * @see #setExponentSignAlwaysShown
+ */
+void DecimalFormat::setScientificNotation(UBool useScientific) {
+ fUseExponentialNotation = useScientific;
+}
+
+/**
+ * Return the minimum exponent digits that will be shown.
+ * @return the minimum exponent digits that will be shown
+ * @see #setScientificNotation
+ * @see #isScientificNotation
+ * @see #setMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ * @see #setExponentSignAlwaysShown
+ */
+int8_t DecimalFormat::getMinimumExponentDigits() const {
+ return fMinExponentDigits;
+}
+
+/**
+ * Set the minimum exponent digits that will be shown. This has no
+ * effect unless scientific notation is in use.
+ * @param minExpDig a value >= 1 indicating the fewest exponent digits
+ * that will be shown. Values less than 1 will be treated as 1.
+ * @see #setScientificNotation
+ * @see #isScientificNotation
+ * @see #getMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ * @see #setExponentSignAlwaysShown
+ */
+void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
+ fMinExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1);
+}
+
+/**
+ * Return whether the exponent sign is always shown.
+ * @return TRUE if the exponent is always prefixed with either the
+ * localized minus sign or the localized plus sign, false if only negative
+ * exponents are prefixed with the localized minus sign.
+ * @see #setScientificNotation
+ * @see #isScientificNotation
+ * @see #setMinimumExponentDigits
+ * @see #getMinimumExponentDigits
+ * @see #setExponentSignAlwaysShown
+ */
+UBool DecimalFormat::isExponentSignAlwaysShown() {
+ return fExponentSignAlwaysShown;
+}
+
+/**
+ * Set whether the exponent sign is always shown. This has no effect
+ * unless scientific notation is in use.
+ * @param expSignAlways TRUE if the exponent is always prefixed with either
+ * the localized minus sign or the localized plus sign, false if only
+ * negative exponents are prefixed with the localized minus sign.
+ * @see #setScientificNotation
+ * @see #isScientificNotation
+ * @see #setMinimumExponentDigits
+ * @see #getMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ */
+void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
+ fExponentSignAlwaysShown = expSignAlways;
+}
+
+//------------------------------------------------------------------------------
+// Gets the grouping size of the number pattern. For example, thousand or 10
+// thousand groupings.
+
+int32_t
+DecimalFormat::getGroupingSize() const
+{
+ return fGroupingSize;
+}
+
+//------------------------------------------------------------------------------
+// Gets the grouping size of the number pattern.
+
+void
+DecimalFormat::setGroupingSize(int32_t newValue)
+{
+ fGroupingSize = newValue;
+}
+
+//------------------------------------------------------------------------------
+
+int32_t
+DecimalFormat::getSecondaryGroupingSize() const
+{
+ return fGroupingSize2;
+}
+
+//------------------------------------------------------------------------------
+
+void
+DecimalFormat::setSecondaryGroupingSize(int32_t newValue)
+{
+ fGroupingSize2 = newValue;
+}
+
+//------------------------------------------------------------------------------
+// Checks if to show the decimal separator.
+
+UBool
+DecimalFormat::isDecimalSeparatorAlwaysShown() const
+{
+ return fDecimalSeparatorAlwaysShown;
+}
+
+//------------------------------------------------------------------------------
+// Sets to always show the decimal separator.
+
+void
+DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue)
+{
+ fDecimalSeparatorAlwaysShown = newValue;
+}
+
+//------------------------------------------------------------------------------
+// Emits the pattern of this DecimalFormat instance.
+
+UnicodeString&
+DecimalFormat::toPattern(UnicodeString& result) const
+{
+ return toPattern(result, FALSE);
+}
+
+//------------------------------------------------------------------------------
+// Emits the localized pattern this DecimalFormat instance.
+
+UnicodeString&
+DecimalFormat::toLocalizedPattern(UnicodeString& result) const
+{
+ return toPattern(result, TRUE);
+}
+
+//------------------------------------------------------------------------------
+/**
+ * Expand the affix pattern strings into the expanded affix strings. If any
+ * affix pattern string is null, do not expand it. This method should be
+ * called any time the symbols or the affix patterns change in order to keep
+ * the expanded affix strings up to date.
+ */
+void DecimalFormat::expandAffixes() {
+ if (fPosPrefixPattern != 0) {
+ expandAffix(*fPosPrefixPattern, fPositivePrefix, 0, FALSE);
+ }
+ if (fPosSuffixPattern != 0) {
+ expandAffix(*fPosSuffixPattern, fPositiveSuffix, 0, FALSE);
+ }
+ if (fNegPrefixPattern != 0) {
+ expandAffix(*fNegPrefixPattern, fNegativePrefix, 0, FALSE);
+ }
+ if (fNegSuffixPattern != 0) {
+ expandAffix(*fNegSuffixPattern, fNegativeSuffix, 0, FALSE);
+ }
+#ifdef FMT_DEBUG
+ UnicodeString s;
+ s.append("[")
+ .append(*fPosPrefixPattern).append("|").append(*fPosSuffixPattern)
+ .append(";") .append(*fNegPrefixPattern).append("|").append(*fNegSuffixPattern)
+ .append("]->[")
+ .append(fPositivePrefix).append("|").append(fPositiveSuffix)
+ .append(";") .append(fNegativePrefix).append("|").append(fNegativeSuffix)
+ .append("]\n");
+ debugout(s);
+#endif
+}
+
+/**
+ * Expand an affix pattern into an affix string. All characters in the
+ * pattern are literal unless prefixed by kQuote. The following characters
+ * after kQuote are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
+ * PATTERN_MINUS, and kCurrencySign. If kCurrencySign is doubled (kQuote +
+ * kCurrencySign + kCurrencySign), it is interpreted as an international
+ * currency sign. Any other character after a kQuote represents itself.
+ * kQuote must be followed by another character; kQuote may not occur by
+ * itself at the end of the pattern.
+ *
+ * This method is used in two distinct ways. First, it is used to expand
+ * the stored affix patterns into actual affixes. For this usage, doFormat
+ * must be false. Second, it is used to expand the stored affix patterns
+ * given a specific number (doFormat == true), for those rare cases in
+ * which a currency format references a ChoiceFormat (e.g., en_IN display
+ * name for INR). The number itself is taken from digitList.
+ *
+ * When used in the first way, this method has a side effect: It sets
+ * currencyChoice to a ChoiceFormat object, if the currency's display name
+ * in this locale is a ChoiceFormat pattern (very rare). It only does this
+ * if currencyChoice is null to start with.
+ *
+ * @param pattern the non-null, fPossibly empty pattern
+ * @param affix string to receive the expanded equivalent of pattern.
+ * Previous contents are deleted.
+ * @param doFormat if false, then the pattern will be expanded, and if a
+ * currency symbol is encountered that expands to a ChoiceFormat, the
+ * currencyChoice member variable will be initialized if it is null. If
+ * doFormat is true, then it is assumed that the currencyChoice has been
+ * created, and it will be used to format the value in digitList.
+ */
+void DecimalFormat::expandAffix(const UnicodeString& pattern,
+ UnicodeString& affix,
+ double number,
+ UBool doFormat) const {
+ affix.remove();
+ for (int i=0; i<pattern.length(); ) {
+ UChar32 c = pattern.char32At(i);
+ i += U16_LENGTH(c);
+ if (c == kQuote) {
+ c = pattern.char32At(i);
+ i += U16_LENGTH(c);
+ switch (c) {
+ case kCurrencySign: {
+ // As of ICU 2.2 we use the currency object, and
+ // ignore the currency symbols in the DFS, unless
+ // we have a null currency object. This occurs if
+ // resurrecting a pre-2.2 object or if the user
+ // sets a custom DFS.
+ UBool intl = i<pattern.length() &&
+ pattern.char32At(i) == kCurrencySign;
+ if (intl) {
+ ++i;
+ }
+ const UChar* currencyUChars = getCurrency();
+ if (currencyUChars[0] != 0) {
+ UErrorCode ec = U_ZERO_ERROR;
+ if(intl) {
+ affix += currencyUChars;
+ } else {
+ int32_t len;
+ UBool isChoiceFormat;
+ const UChar* s = ucurr_getName(currencyUChars, fSymbols->getLocale().getName(),
+ UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec);
+ if (isChoiceFormat) {
+ // Two modes here: If doFormat is false, we set up
+ // currencyChoice. If doFormat is true, we use the
+ // previously created currencyChoice to format the
+ // value in digitList.
+ if (!doFormat) {
+ // If the currency is handled by a ChoiceFormat,
+ // then we're not going to use the expanded
+ // patterns. Instantiate the ChoiceFormat and
+ // return.
+ if (fCurrencyChoice == NULL) {
+ // TODO Replace double-check with proper thread-safe code
+ ChoiceFormat* fmt = new ChoiceFormat(s, ec);
+ if (U_SUCCESS(ec)) {
+ umtx_lock(NULL);
+ if (fCurrencyChoice == NULL) {
+ // Cast away const
+ ((DecimalFormat*)this)->fCurrencyChoice = fmt;
+ fmt = NULL;
+ }
+ umtx_unlock(NULL);
+ delete fmt;
+ }
+ }
+ // We could almost return null or "" here, since the
+ // expanded affixes are almost not used at all
+ // in this situation. However, one method --
+ // toPattern() -- still does use the expanded
+ // affixes, in order to set up a padding
+ // pattern. We use the CURRENCY_SIGN as a
+ // placeholder.
+ affix.append(kCurrencySign);
+ } else {
+ if (fCurrencyChoice != NULL) {
+ FieldPosition pos(0); // ignored
+ if (number < 0) {
+ number = -number;
+ }
+ fCurrencyChoice->format(number, affix, pos);
+ } else {
+ // We only arrive here if the currency choice
+ // format in the locale data is INVALID.
+ affix += currencyUChars;
+ }
+ }
+ continue;
+ }
+ affix += UnicodeString(s, len);
+ }
+ } else {
+ if(intl) {
+ affix += getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
+ } else {
+ affix += getConstSymbol(DecimalFormatSymbols::kCurrencySymbol);
+ }
+ }
+ break;
+ }
+ case kPatternPercent:
+ affix += getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
+ break;
+ case kPatternPerMill:
+ affix += getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
+ break;
+ case kPatternPlus:
+ affix += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
+ break;
+ case kPatternMinus:
+ affix += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ break;
+ default:
+ affix.append(c);
+ break;
+ }
+ }
+ else {
+ affix.append(c);
+ }
+ }
+}
+
+/**
+ * Append an affix to the given StringBuffer.
+ * @param buf buffer to append to
+ * @param isNegative
+ * @param isPrefix
+ */
+int32_t DecimalFormat::appendAffix(UnicodeString& buf, double number,
+ UBool isNegative, UBool isPrefix) const {
+ if (fCurrencyChoice != 0) {
+ const UnicodeString* affixPat;
+ if (isPrefix) {
+ affixPat = isNegative ? fNegPrefixPattern : fPosPrefixPattern;
+ } else {
+ affixPat = isNegative ? fNegSuffixPattern : fPosSuffixPattern;
+ }
+ if (affixPat) {
+ UnicodeString affixBuf;
+ expandAffix(*affixPat, affixBuf, number, TRUE);
+ buf.append(affixBuf);
+ return affixBuf.length();
+ }
+ // else someone called a function that reset the pattern.
+ }
+
+ const UnicodeString* affix;
+ if (isPrefix) {
+ affix = isNegative ? &fNegativePrefix : &fPositivePrefix;
+ } else {
+ affix = isNegative ? &fNegativeSuffix : &fPositiveSuffix;
+ }
+ buf.append(*affix);
+ return affix->length();
+}
+
+/**
+ * Appends an affix pattern to the given StringBuffer, quoting special
+ * characters as needed. Uses the internal affix pattern, if that exists,
+ * or the literal affix, if the internal affix pattern is null. The
+ * appended string will generate the same affix pattern (or literal affix)
+ * when passed to toPattern().
+ *
+ * @param appendTo the affix string is appended to this
+ * @param affixPattern a pattern such as fPosPrefixPattern; may be null
+ * @param expAffix a corresponding expanded affix, such as fPositivePrefix.
+ * Ignored unless affixPattern is null. If affixPattern is null, then
+ * expAffix is appended as a literal affix.
+ * @param localized true if the appended pattern should contain localized
+ * pattern characters; otherwise, non-localized pattern chars are appended
+ */
+void DecimalFormat::appendAffixPattern(UnicodeString& appendTo,
+ const UnicodeString* affixPattern,
+ const UnicodeString& expAffix,
+ UBool localized) const {
+ if (affixPattern == 0) {
+ appendAffixPattern(appendTo, expAffix, localized);
+ } else {
+ int i;
+ for (int pos=0; pos<affixPattern->length(); pos=i) {
+ i = affixPattern->indexOf(kQuote, pos);
+ if (i < 0) {
+ UnicodeString s;
+ affixPattern->extractBetween(pos, affixPattern->length(), s);
+ appendAffixPattern(appendTo, s, localized);
+ break;
+ }
+ if (i > pos) {
+ UnicodeString s;
+ affixPattern->extractBetween(pos, i, s);
+ appendAffixPattern(appendTo, s, localized);
+ }
+ UChar32 c = affixPattern->char32At(++i);
+ ++i;
+ if (c == kQuote) {
+ appendTo.append(c).append(c);
+ // Fall through and append another kQuote below
+ } else if (c == kCurrencySign &&
+ i<affixPattern->length() &&
+ affixPattern->char32At(i) == kCurrencySign) {
+ ++i;
+ appendTo.append(c).append(c);
+ } else if (localized) {
+ switch (c) {
+ case kPatternPercent:
+ appendTo += getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
+ break;
+ case kPatternPerMill:
+ appendTo += getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
+ break;
+ case kPatternPlus:
+ appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
+ break;
+ case kPatternMinus:
+ appendTo += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ break;
+ default:
+ appendTo.append(c);
+ }
+ } else {
+ appendTo.append(c);
+ }
+ }
+ }
+}
+
+/**
+ * Append an affix to the given StringBuffer, using quotes if
+ * there are special characters. Single quotes themselves must be
+ * escaped in either case.
+ */
+void
+DecimalFormat::appendAffixPattern(UnicodeString& appendTo,
+ const UnicodeString& affix,
+ UBool localized) const {
+ UBool needQuote;
+ if(localized) {
+ needQuote = affix.indexOf(getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol)) >= 0
+ || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol)) >= 0
+ || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol)) >= 0
+ || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPercentSymbol)) >= 0
+ || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol)) >= 0
+ || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kDigitSymbol)) >= 0
+ || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol)) >= 0
+ || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol)) >= 0
+ || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol)) >= 0
+ || affix.indexOf(kCurrencySign) >= 0;
+ }
+ else {
+ needQuote = affix.indexOf(kPatternZeroDigit) >= 0
+ || affix.indexOf(kPatternGroupingSeparator) >= 0
+ || affix.indexOf(kPatternDecimalSeparator) >= 0
+ || affix.indexOf(kPatternPercent) >= 0
+ || affix.indexOf(kPatternPerMill) >= 0
+ || affix.indexOf(kPatternDigit) >= 0
+ || affix.indexOf(kPatternSeparator) >= 0
+ || affix.indexOf(kPatternExponent) >= 0
+ || affix.indexOf(kPatternPlus) >= 0
+ || affix.indexOf(kPatternMinus) >= 0
+ || affix.indexOf(kCurrencySign) >= 0;
+ }
+ if (needQuote)
+ appendTo += (UChar)0x0027 /*'\''*/;
+ if (affix.indexOf((UChar)0x0027 /*'\''*/) < 0)
+ appendTo += affix;
+ else {
+ for (int32_t j = 0; j < affix.length(); ) {
+ UChar32 c = affix.char32At(j);
+ j += U16_LENGTH(c);
+ appendTo += c;
+ if (c == 0x0027 /*'\''*/)
+ appendTo += c;
+ }
+ }
+ if (needQuote)
+ appendTo += (UChar)0x0027 /*'\''*/;
+}
+
+//------------------------------------------------------------------------------
+
+UnicodeString&
+DecimalFormat::toPattern(UnicodeString& result, UBool localized) const
+{
+ result.remove();
+ UChar32 zero, sigDigit = kPatternSignificantDigit;
+ UnicodeString digit, group;
+ int32_t i;
+ int32_t roundingDecimalPos = 0; // Pos of decimal in roundingDigits
+ UnicodeString roundingDigits;
+ int32_t padPos = (fFormatWidth > 0) ? fPadPosition : -1;
+ UnicodeString padSpec;
+ UBool useSigDig = areSignificantDigitsUsed();
+
+ if (localized) {
+ digit.append(getConstSymbol(DecimalFormatSymbols::kDigitSymbol));
+ group.append(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
+ zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
+ if (useSigDig) {
+ sigDigit = getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
+ }
+ }
+ else {
+ digit.append((UChar)kPatternDigit);
+ group.append((UChar)kPatternGroupingSeparator);
+ zero = (UChar32)kPatternZeroDigit;
+ }
+ if (fFormatWidth > 0) {
+ if (localized) {
+ padSpec.append(getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol));
+ }
+ else {
+ padSpec.append((UChar)kPatternPadEscape);
+ }
+ padSpec.append(fPad);
+ }
+ if (fRoundingIncrement != NULL) {
+ for(i=0; i<fRoundingIncrement->fCount; ++i) {
+ roundingDigits.append((UChar)fRoundingIncrement->fDigits[i]);
+ }
+ roundingDecimalPos = fRoundingIncrement->fDecimalAt;
+ }
+ for (int32_t part=0; part<2; ++part) {
+ if (padPos == kPadBeforePrefix) {
+ result.append(padSpec);
+ }
+ appendAffixPattern(result,
+ (part==0 ? fPosPrefixPattern : fNegPrefixPattern),
+ (part==0 ? fPositivePrefix : fNegativePrefix),
+ localized);
+ if (padPos == kPadAfterPrefix && ! padSpec.isEmpty()) {
+ result.append(padSpec);
+ }
+ int32_t sub0Start = result.length();
+ int32_t g = isGroupingUsed() ? _max(0, fGroupingSize) : 0;
+ if (g > 0 && fGroupingSize2 > 0 && fGroupingSize2 != fGroupingSize) {
+ g += fGroupingSize2;
+ }
+ int32_t maxDig = 0, minDig = 0, maxSigDig = 0;
+ if (useSigDig) {
+ minDig = getMinimumSignificantDigits();
+ maxDig = maxSigDig = getMaximumSignificantDigits();
+ } else {
+ minDig = getMinimumIntegerDigits();
+ maxDig = getMaximumIntegerDigits();
+ }
+ if (fUseExponentialNotation) {
+ if (maxDig > kMaxScientificIntegerDigits) {
+ maxDig = 1;
+ }
+ } else if (useSigDig) {
+ maxDig = _max(maxDig, g+1);
+ } else {
+ maxDig = _max(_max(g, getMinimumIntegerDigits()),
+ roundingDecimalPos) + 1;
+ }
+ for (i = maxDig; i > 0; --i) {
+ if (!fUseExponentialNotation && i<maxDig &&
+ isGroupingPosition(i)) {
+ result.append(group);
+ }
+ if (useSigDig) {
+ // #@,@### (maxSigDig == 5, minSigDig == 2)
+ // 65 4321 (1-based pos, count from the right)
+ // Use # if pos > maxSigDig or 1 <= pos <= (maxSigDig - minSigDig)
+ // Use @ if (maxSigDig - minSigDig) < pos <= maxSigDig
+ if (maxSigDig >= i && i > (maxSigDig - minDig)) {
+ result.append(sigDigit);
+ } else {
+ result.append(digit);
+ }
+ } else {
+ if (! roundingDigits.isEmpty()) {
+ int32_t pos = roundingDecimalPos - i;
+ if (pos >= 0 && pos < roundingDigits.length()) {
+ result.append((UChar) (roundingDigits.char32At(pos) - kPatternZeroDigit + zero));
+ continue;
+ }
+ }
+ if (i<=minDig) {
+ result.append(zero);
+ } else {
+ result.append(digit);
+ }
+ }
+ }
+ if (!useSigDig) {
+ if (getMaximumFractionDigits() > 0 || fDecimalSeparatorAlwaysShown) {
+ if (localized) {
+ result += getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ }
+ else {
+ result.append((UChar)kPatternDecimalSeparator);
+ }
+ }
+ int32_t pos = roundingDecimalPos;
+ for (i = 0; i < getMaximumFractionDigits(); ++i) {
+ if (! roundingDigits.isEmpty() && pos < roundingDigits.length()) {
+ if (pos < 0) {
+ result.append(zero);
+ }
+ else {
+ result.append((UChar)(roundingDigits.char32At(pos) - kPatternZeroDigit + zero));
+ }
+ ++pos;
+ continue;
+ }
+ if (i<getMinimumFractionDigits()) {
+ result.append(zero);
+ }
+ else {
+ result.append(digit);
+ }
+ }
+ }
+ if (fUseExponentialNotation) {
+ if (localized) {
+ result += getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
+ }
+ else {
+ result.append((UChar)kPatternExponent);
+ }
+ if (fExponentSignAlwaysShown) {
+ if (localized) {
+ result += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
+ }
+ else {
+ result.append((UChar)kPatternPlus);
+ }
+ }
+ for (i=0; i<fMinExponentDigits; ++i) {
+ result.append(zero);
+ }
+ }
+ if (! padSpec.isEmpty() && !fUseExponentialNotation) {
+ int32_t add = fFormatWidth - result.length() + sub0Start
+ - ((part == 0)
+ ? fPositivePrefix.length() + fPositiveSuffix.length()
+ : fNegativePrefix.length() + fNegativeSuffix.length());
+ while (add > 0) {
+ result.insert(sub0Start, digit);
+ ++maxDig;
+ --add;
+ // Only add a grouping separator if we have at least
+ // 2 additional characters to be added, so we don't
+ // end up with ",###".
+ if (add>1 && isGroupingPosition(maxDig)) {
+ result.insert(sub0Start, group);
+ --add;
+ }
+ }
+ }
+ if (fPadPosition == kPadBeforeSuffix && ! padSpec.isEmpty()) {
+ result.append(padSpec);
+ }
+ if (part == 0) {
+ appendAffixPattern(result, fPosSuffixPattern, fPositiveSuffix, localized);
+ if (fPadPosition == kPadAfterSuffix && ! padSpec.isEmpty()) {
+ result.append(padSpec);
+ }
+ UBool isDefault = FALSE;
+ if ((fNegSuffixPattern == fPosSuffixPattern && // both null
+ fNegativeSuffix == fPositiveSuffix)
+ || (fNegSuffixPattern != 0 && fPosSuffixPattern != 0 &&
+ *fNegSuffixPattern == *fPosSuffixPattern))
+ {
+ if (fNegPrefixPattern != NULL && fPosPrefixPattern != NULL)
+ {
+ int32_t length = fPosPrefixPattern->length();
+ isDefault = fNegPrefixPattern->length() == (length+2) &&
+ (*fNegPrefixPattern)[(int32_t)0] == kQuote &&
+ (*fNegPrefixPattern)[(int32_t)1] == kPatternMinus &&
+ fNegPrefixPattern->compare(2, length, *fPosPrefixPattern, 0, length) == 0;
+ }
+ if (!isDefault &&
+ fNegPrefixPattern == NULL && fPosPrefixPattern == NULL)
+ {
+ int32_t length = fPositivePrefix.length();
+ isDefault = fNegativePrefix.length() == (length+1) &&
+ fNegativePrefix.compare(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol)) == 0 &&
+ fNegativePrefix.compare(1, length, fPositivePrefix, 0, length) == 0;
+ }
+ }
+ if (isDefault) {
+ break; // Don't output default negative subpattern
+ } else {
+ if (localized) {
+ result += getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol);
+ }
+ else {
+ result.append((UChar)kPatternSeparator);
+ }
+ }
+ } else {
+ appendAffixPattern(result, fNegSuffixPattern, fNegativeSuffix, localized);
+ if (fPadPosition == kPadAfterSuffix && ! padSpec.isEmpty()) {
+ result.append(padSpec);
+ }
+ }
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------
+
+void
+DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status)
+{
+ UParseError parseError;
+ applyPattern(pattern, FALSE, parseError, status);
+}
+
+//------------------------------------------------------------------------------
+
+void
+DecimalFormat::applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status)
+{
+ applyPattern(pattern, FALSE, parseError, status);
+}
+//------------------------------------------------------------------------------
+
+void
+DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status)
+{
+ UParseError parseError;
+ applyPattern(pattern, TRUE,parseError,status);
+}
+
+//------------------------------------------------------------------------------
+
+void
+DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status)
+{
+ applyPattern(pattern, TRUE,parseError,status);
+}
+
+//------------------------------------------------------------------------------
+
+void
+DecimalFormat::applyPattern(const UnicodeString& pattern,
+ UBool localized,
+ UParseError& parseError,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status))
+ {
+ return;
+ }
+ // Clear error struct
+ parseError.offset = -1;
+ parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
+
+ // Set the significant pattern symbols
+ UChar32 zeroDigit = kPatternZeroDigit; // '0'
+ UChar32 sigDigit = kPatternSignificantDigit; // '@'
+ UnicodeString groupingSeparator ((UChar)kPatternGroupingSeparator);
+ UnicodeString decimalSeparator ((UChar)kPatternDecimalSeparator);
+ UnicodeString percent ((UChar)kPatternPercent);
+ UnicodeString perMill ((UChar)kPatternPerMill);
+ UnicodeString digit ((UChar)kPatternDigit); // '#'
+ UnicodeString separator ((UChar)kPatternSeparator);
+ UnicodeString exponent ((UChar)kPatternExponent);
+ UnicodeString plus ((UChar)kPatternPlus);
+ UnicodeString minus ((UChar)kPatternMinus);
+ UnicodeString padEscape ((UChar)kPatternPadEscape);
+ // Substitute with the localized symbols if necessary
+ if (localized) {
+ zeroDigit = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
+ sigDigit = getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
+ groupingSeparator. remove().append(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
+ decimalSeparator. remove().append(getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol));
+ percent. remove().append(getConstSymbol(DecimalFormatSymbols::kPercentSymbol));
+ perMill. remove().append(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol));
+ digit. remove().append(getConstSymbol(DecimalFormatSymbols::kDigitSymbol));
+ separator. remove().append(getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol));
+ exponent. remove().append(getConstSymbol(DecimalFormatSymbols::kExponentialSymbol));
+ plus. remove().append(getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol));
+ minus. remove().append(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol));
+ padEscape. remove().append(getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol));
+ }
+ UChar nineDigit = (UChar)(zeroDigit + 9);
+ int32_t digitLen = digit.length();
+ int32_t groupSepLen = groupingSeparator.length();
+ int32_t decimalSepLen = decimalSeparator.length();
+
+ int32_t pos = 0;
+ int32_t patLen = pattern.length();
+ // Part 0 is the positive pattern. Part 1, if present, is the negative
+ // pattern.
+ for (int32_t part=0; part<2 && pos<patLen; ++part) {
+ // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix,
+ // 2=suffix, 3=prefix in quote, 4=suffix in quote. Subpart 0 is
+ // between the prefix and suffix, and consists of pattern
+ // characters. In the prefix and suffix, percent, perMill, and
+ // currency symbols are recognized and translated.
+ int32_t subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0;
+
+ // It's important that we don't change any fields of this object
+ // prematurely. We set the following variables for the multiplier,
+ // grouping, etc., and then only change the actual object fields if
+ // everything parses correctly. This also lets us register
+ // the data from part 0 and ignore the part 1, except for the
+ // prefix and suffix.
+ UnicodeString prefix;
+ UnicodeString suffix;
+ int32_t decimalPos = -1;
+ int32_t multiplier = 1;
+ int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
+ int8_t groupingCount = -1;
+ int8_t groupingCount2 = -1;
+ int32_t padPos = -1;
+ UChar32 padChar = 0;
+ int32_t roundingPos = -1;
+ DigitList roundingInc;
+ int8_t expDigits = -1;
+ UBool expSignAlways = FALSE;
+ UBool isCurrency = FALSE;
+
+ // The affix is either the prefix or the suffix.
+ UnicodeString* affix = &prefix;
+
+ int32_t start = pos;
+ UBool isPartDone = FALSE;
+ UChar32 ch;
+
+ for (; !isPartDone && pos < patLen; ) {
+ // Todo: account for surrogate pairs
+ ch = pattern.char32At(pos);
+ switch (subpart) {
+ case 0: // Pattern proper subpart (between prefix & suffix)
+ // Process the digits, decimal, and grouping characters. We
+ // record five pieces of information. We expect the digits
+ // to occur in the pattern ####00.00####, and we record the
+ // number of left digits, zero (central) digits, and right
+ // digits. The position of the last grouping character is
+ // recorded (should be somewhere within the first two blocks
+ // of characters), as is the position of the decimal point,
+ // if any (should be in the zero digits). If there is no
+ // decimal point, then there should be no right digits.
+ if (pattern.compare(pos, digitLen, digit) == 0) {
+ if (zeroDigitCount > 0 || sigDigitCount > 0) {
+ ++digitRightCount;
+ } else {
+ ++digitLeftCount;
+ }
+ if (groupingCount >= 0 && decimalPos < 0) {
+ ++groupingCount;
+ }
+ pos += digitLen;
+ } else if ((ch >= zeroDigit && ch <= nineDigit) ||
+ ch == sigDigit) {
+ if (digitRightCount > 0) {
+ // Unexpected '0'
+ debug("Unexpected '0'")
+ status = U_UNEXPECTED_TOKEN;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ if (ch == sigDigit) {
+ ++sigDigitCount;
+ } else {
+ ++zeroDigitCount;
+ if (ch != zeroDigit && roundingPos < 0) {
+ roundingPos = digitLeftCount + zeroDigitCount;
+ }
+ if (roundingPos >= 0) {
+ roundingInc.append((char)(ch - zeroDigit + '0'));
+ }
+ }
+ if (groupingCount >= 0 && decimalPos < 0) {
+ ++groupingCount;
+ }
+ pos += U16_LENGTH(ch);
+ } else if (pattern.compare(pos, groupSepLen, groupingSeparator) == 0) {
+ if (decimalPos >= 0) {
+ // Grouping separator after decimal
+ debug("Grouping separator after decimal")
+ status = U_UNEXPECTED_TOKEN;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ groupingCount2 = groupingCount;
+ groupingCount = 0;
+ pos += groupSepLen;
+ } else if (pattern.compare(pos, decimalSepLen, decimalSeparator) == 0) {
+ if (decimalPos >= 0) {
+ // Multiple decimal separators
+ debug("Multiple decimal separators")
+ status = U_MULTIPLE_DECIMAL_SEPARATORS;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ // Intentionally incorporate the digitRightCount,
+ // even though it is illegal for this to be > 0
+ // at this point. We check pattern syntax below.
+ decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
+ pos += decimalSepLen;
+ } else {
+ if (pattern.compare(pos, exponent.length(), exponent) == 0) {
+ if (expDigits >= 0) {
+ // Multiple exponential symbols
+ debug("Multiple exponential symbols")
+ status = U_MULTIPLE_EXPONENTIAL_SYMBOLS;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ if (groupingCount >= 0) {
+ // Grouping separator in exponential pattern
+ debug("Grouping separator in exponential pattern")
+ status = U_MALFORMED_EXPONENTIAL_PATTERN;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ pos += exponent.length();
+ // Check for positive prefix
+ if (pos < patLen
+ && pattern.compare(pos, plus.length(), plus) == 0) {
+ expSignAlways = TRUE;
+ pos += plus.length();
+ }
+ // Use lookahead to parse out the exponential part of the
+ // pattern, then jump into suffix subpart.
+ expDigits = 0;
+ while (pos < patLen &&
+ pattern.char32At(pos) == zeroDigit) {
+ ++expDigits;
+ pos += U16_LENGTH(zeroDigit);
+ }
+
+ // 1. Require at least one mantissa pattern digit
+ // 2. Disallow "#+ @" in mantissa
+ // 3. Require at least one exponent pattern digit
+ if (((digitLeftCount + zeroDigitCount) < 1 &&
+ (sigDigitCount + digitRightCount) < 1) ||
+ (sigDigitCount > 0 && digitLeftCount > 0) ||
+ expDigits < 1) {
+ // Malformed exponential pattern
+ debug("Malformed exponential pattern")
+ status = U_MALFORMED_EXPONENTIAL_PATTERN;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ }
+ // Transition to suffix subpart
+ subpart = 2; // suffix subpart
+ affix = &suffix;
+ sub0Limit = pos;
+ continue;
+ }
+ break;
+ case 1: // Prefix subpart
+ case 2: // Suffix subpart
+ // Process the prefix / suffix characters
+ // Process unquoted characters seen in prefix or suffix
+ // subpart.
+
+ // Several syntax characters implicitly begins the
+ // next subpart if we are in the prefix; otherwise
+ // they are illegal if unquoted.
+ if (!pattern.compare(pos, digitLen, digit) ||
+ !pattern.compare(pos, groupSepLen, groupingSeparator) ||
+ !pattern.compare(pos, decimalSepLen, decimalSeparator) ||
+ (ch >= zeroDigit && ch <= nineDigit) ||
+ ch == sigDigit) {
+ if (subpart == 1) { // prefix subpart
+ subpart = 0; // pattern proper subpart
+ sub0Start = pos; // Reprocess this character
+ continue;
+ } else {
+ status = U_UNQUOTED_SPECIAL;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ } else if (ch == kCurrencySign) {
+ affix->append(kQuote); // Encode currency
+ // Use lookahead to determine if the currency sign is
+ // doubled or not.
+ U_ASSERT(U16_LENGTH(kCurrencySign) == 1);
+ if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) {
+ affix->append(kCurrencySign);
+ ++pos; // Skip over the doubled character
+ }
+ isCurrency = TRUE;
+ // Fall through to append(ch)
+ } else if (ch == kQuote) {
+ // A quote outside quotes indicates either the opening
+ // quote or two quotes, which is a quote literal. That is,
+ // we have the first quote in 'do' or o''clock.
+ U_ASSERT(U16_LENGTH(kQuote) == 1);
+ ++pos;
+ if (pos < pattern.length() && pattern[pos] == kQuote) {
+ affix->append(kQuote); // Encode quote
+ // Fall through to append(ch)
+ } else {
+ subpart += 2; // open quote
+ continue;
+ }
+ } else if (pattern.compare(pos, separator.length(), separator) == 0) {
+ // Don't allow separators in the prefix, and don't allow
+ // separators in the second pattern (part == 1).
+ if (subpart == 1 || part == 1) {
+ // Unexpected separator
+ debug("Unexpected separator")
+ status = U_UNEXPECTED_TOKEN;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ sub2Limit = pos;
+ isPartDone = TRUE; // Go to next part
+ pos += separator.length();
+ break;
+ } else if (pattern.compare(pos, percent.length(), percent) == 0) {
+ // Next handle characters which are appended directly.
+ if (multiplier != 1) {
+ // Too many percent/perMill characters
+ debug("Too many percent characters")
+ status = U_MULTIPLE_PERCENT_SYMBOLS;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ affix->append(kQuote); // Encode percent/perMill
+ affix->append(kPatternPercent); // Use unlocalized pattern char
+ multiplier = 100;
+ pos += percent.length();
+ break;
+ } else if (pattern.compare(pos, perMill.length(), perMill) == 0) {
+ // Next handle characters which are appended directly.
+ if (multiplier != 1) {
+ // Too many percent/perMill characters
+ debug("Too many perMill characters")
+ status = U_MULTIPLE_PERMILL_SYMBOLS;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ affix->append(kQuote); // Encode percent/perMill
+ affix->append(kPatternPerMill); // Use unlocalized pattern char
+ multiplier = 1000;
+ pos += perMill.length();
+ break;
+ } else if (pattern.compare(pos, padEscape.length(), padEscape) == 0) {
+ if (padPos >= 0 || // Multiple pad specifiers
+ (pos+1) == pattern.length()) { // Nothing after padEscape
+ debug("Multiple pad specifiers")
+ status = U_MULTIPLE_PAD_SPECIFIERS;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ padPos = pos;
+ pos += padEscape.length();
+ padChar = pattern.char32At(pos);
+ pos += U16_LENGTH(padChar);
+ break;
+ } else if (pattern.compare(pos, minus.length(), minus) == 0) {
+ affix->append(kQuote); // Encode minus
+ affix->append(kPatternMinus);
+ pos += minus.length();
+ break;
+ } else if (pattern.compare(pos, plus.length(), plus) == 0) {
+ affix->append(kQuote); // Encode plus
+ affix->append(kPatternPlus);
+ pos += plus.length();
+ break;
+ }
+ // Unquoted, non-special characters fall through to here, as
+ // well as other code which needs to append something to the
+ // affix.
+ affix->append(ch);
+ pos += U16_LENGTH(ch);
+ break;
+ case 3: // Prefix subpart, in quote
+ case 4: // Suffix subpart, in quote
+ // A quote within quotes indicates either the closing
+ // quote or two quotes, which is a quote literal. That is,
+ // we have the second quote in 'do' or 'don''t'.
+ if (ch == kQuote) {
+ ++pos;
+ if (pos < pattern.length() && pattern[pos] == kQuote) {
+ affix->append(kQuote); // Encode quote
+ // Fall through to append(ch)
+ } else {
+ subpart -= 2; // close quote
+ continue;
+ }
+ }
+ affix->append(ch);
+ pos += U16_LENGTH(ch);
+ break;
+ }
+ }
+
+ if (sub0Limit == 0) {
+ sub0Limit = pattern.length();
+ }
+
+ if (sub2Limit == 0) {
+ sub2Limit = pattern.length();
+ }
+
+ /* Handle patterns with no '0' pattern character. These patterns
+ * are legal, but must be recodified to make sense. "##.###" ->
+ * "#0.###". ".###" -> ".0##".
+ *
+ * We allow patterns of the form "####" to produce a zeroDigitCount
+ * of zero (got that?); although this seems like it might make it
+ * possible for format() to produce empty strings, format() checks
+ * for this condition and outputs a zero digit in this situation.
+ * Having a zeroDigitCount of zero yields a minimum integer digits
+ * of zero, which allows proper round-trip patterns. We don't want
+ * "#" to become "#0" when toPattern() is called (even though that's
+ * what it really is, semantically).
+ */
+ if (zeroDigitCount == 0 && sigDigitCount == 0 &&
+ digitLeftCount > 0 && decimalPos >= 0) {
+ // Handle "###.###" and "###." and ".###"
+ int n = decimalPos;
+ if (n == 0)
+ ++n; // Handle ".###"
+ digitRightCount = digitLeftCount - n;
+ digitLeftCount = n - 1;
+ zeroDigitCount = 1;
+ }
+
+ // Do syntax checking on the digits, decimal points, and quotes.
+ if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) ||
+ (decimalPos >= 0 &&
+ (sigDigitCount > 0 ||
+ decimalPos < digitLeftCount ||
+ decimalPos > (digitLeftCount + zeroDigitCount))) ||
+ groupingCount == 0 || groupingCount2 == 0 ||
+ (sigDigitCount > 0 && zeroDigitCount > 0) ||
+ subpart > 2)
+ { // subpart > 2 == unmatched quote
+ debug("Syntax error")
+ status = U_PATTERN_SYNTAX_ERROR;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+
+ // Make sure pad is at legal position before or after affix.
+ if (padPos >= 0) {
+ if (padPos == start) {
+ padPos = kPadBeforePrefix;
+ } else if (padPos+2 == sub0Start) {
+ padPos = kPadAfterPrefix;
+ } else if (padPos == sub0Limit) {
+ padPos = kPadBeforeSuffix;
+ } else if (padPos+2 == sub2Limit) {
+ padPos = kPadAfterSuffix;
+ } else {
+ // Illegal pad position
+ debug("Illegal pad position")
+ status = U_ILLEGAL_PAD_POSITION;
+ syntaxError(pattern,pos,parseError);
+ return;
+ }
+ }
+
+ if (part == 0) {
+ delete fPosPrefixPattern;
+ delete fPosSuffixPattern;
+ delete fNegPrefixPattern;
+ delete fNegSuffixPattern;
+ fPosPrefixPattern = new UnicodeString(prefix);
+ /* test for NULL */
+ if (fPosPrefixPattern == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fPosSuffixPattern = new UnicodeString(suffix);
+ /* test for NULL */
+ if (fPosSuffixPattern == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete fPosPrefixPattern;
+ return;
+ }
+ fNegPrefixPattern = 0;
+ fNegSuffixPattern = 0;
+
+ fUseExponentialNotation = (expDigits >= 0);
+ if (fUseExponentialNotation) {
+ fMinExponentDigits = expDigits;
+ }
+ fExponentSignAlwaysShown = expSignAlways;
+ fIsCurrencyFormat = isCurrency;
+ int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
+ // The effectiveDecimalPos is the position the decimal is at or
+ // would be at if there is no decimal. Note that if
+ // decimalPos<0, then digitTotalCount == digitLeftCount +
+ // zeroDigitCount.
+ int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
+ UBool isSigDig = (sigDigitCount > 0);
+ setSignificantDigitsUsed(isSigDig);
+ if (isSigDig) {
+ setMinimumSignificantDigits(sigDigitCount);
+ setMaximumSignificantDigits(sigDigitCount + digitRightCount);
+ } else {
+ int32_t minInt = effectiveDecimalPos - digitLeftCount;
+ setMinimumIntegerDigits(minInt);
+ setMaximumIntegerDigits(fUseExponentialNotation
+ ? digitLeftCount + getMinimumIntegerDigits()
+ : kDoubleIntegerDigits);
+ setMaximumFractionDigits(decimalPos >= 0
+ ? (digitTotalCount - decimalPos) : 0);
+ setMinimumFractionDigits(decimalPos >= 0
+ ? (digitLeftCount + zeroDigitCount - decimalPos) : 0);
+ }
+ setGroupingUsed(groupingCount > 0);
+ fGroupingSize = (groupingCount > 0) ? groupingCount : 0;
+ fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
+ ? groupingCount2 : 0;
+ fMultiplier = multiplier;
+ setDecimalSeparatorAlwaysShown(decimalPos == 0
+ || decimalPos == digitTotalCount);
+ if (padPos >= 0) {
+ fPadPosition = (EPadPosition) padPos;
+ // To compute the format width, first set up sub0Limit -
+ // sub0Start. Add in prefix/suffix length later.
+
+ // fFormatWidth = prefix.length() + suffix.length() +
+ // sub0Limit - sub0Start;
+ fFormatWidth = sub0Limit - sub0Start;
+ fPad = padChar;
+ } else {
+ fFormatWidth = 0;
+ }
+ if (roundingPos >= 0) {
+ roundingInc.fDecimalAt = effectiveDecimalPos - roundingPos;
+ if (fRoundingIncrement != NULL) {
+ *fRoundingIncrement = roundingInc;
+ } else {
+ fRoundingIncrement = new DigitList(roundingInc);
+ /* test for NULL */
+ if (fRoundingIncrement == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete fPosPrefixPattern;
+ delete fPosSuffixPattern;
+ return;
+ }
+ }
+ fRoundingDouble = fRoundingIncrement->getDouble();
+ fRoundingMode = kRoundHalfEven;
+ } else {
+ setRoundingIncrement(0.0);
+ }
+ } else {
+ fNegPrefixPattern = new UnicodeString(prefix);
+ /* test for NULL */
+ if (fNegPrefixPattern == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ fNegSuffixPattern = new UnicodeString(suffix);
+ /* test for NULL */
+ if (fNegSuffixPattern == 0) {
+ delete fNegPrefixPattern;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+ }
+
+ if (pattern.length() == 0) {
+ delete fNegPrefixPattern;
+ delete fNegSuffixPattern;
+ fNegPrefixPattern = NULL;
+ fNegSuffixPattern = NULL;
+ if (fPosPrefixPattern != NULL) {
+ fPosPrefixPattern->remove();
+ } else {
+ fPosPrefixPattern = new UnicodeString();
+ /* test for NULL */
+ if (fPosPrefixPattern == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+ if (fPosSuffixPattern != NULL) {
+ fPosSuffixPattern->remove();
+ } else {
+ fPosSuffixPattern = new UnicodeString();
+ /* test for NULL */
+ if (fPosSuffixPattern == 0) {
+ delete fPosPrefixPattern;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ setMinimumIntegerDigits(0);
+ setMaximumIntegerDigits(kDoubleIntegerDigits);
+ setMinimumFractionDigits(0);
+ setMaximumFractionDigits(kDoubleFractionDigits);
+
+ fUseExponentialNotation = FALSE;
+ fIsCurrencyFormat = FALSE;
+ setGroupingUsed(FALSE);
+ fGroupingSize = 0;
+ fGroupingSize2 = 0;
+ fMultiplier = 1;
+ setDecimalSeparatorAlwaysShown(FALSE);
+ fFormatWidth = 0;
+ setRoundingIncrement(0.0);
+ }
+
+ // If there was no negative pattern, or if the negative pattern is
+ // identical to the positive pattern, then prepend the minus sign to the
+ // positive pattern to form the negative pattern.
+ if (fNegPrefixPattern == NULL ||
+ (*fNegPrefixPattern == *fPosPrefixPattern
+ && *fNegSuffixPattern == *fPosSuffixPattern)) {
+ _copy_us_ptr(&fNegSuffixPattern, fPosSuffixPattern);
+ if (fNegPrefixPattern == NULL) {
+ fNegPrefixPattern = new UnicodeString();
+ /* test for NULL */
+ if (fNegPrefixPattern == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ } else {
+ fNegPrefixPattern->remove();
+ }
+ fNegPrefixPattern->append(kQuote).append(kPatternMinus)
+ .append(*fPosPrefixPattern);
+ }
+#ifdef FMT_DEBUG
+ UnicodeString s;
+ s.append("\"").append(pattern).append("\"->");
+ debugout(s);
+#endif
+ expandAffixes();
+ if (fFormatWidth > 0) {
+ // Finish computing format width (see above)
+ fFormatWidth += fPositivePrefix.length() + fPositiveSuffix.length();
+ }
+}
+
+/**
+ * Sets the maximum number of digits allowed in the integer portion of a
+ * number. This override limits the integer digit count to 309.
+ * @see NumberFormat#setMaximumIntegerDigits
+ */
+void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
+ NumberFormat::setMaximumIntegerDigits(_min(newValue, kDoubleIntegerDigits));
+}
+
+/**
+ * Sets the minimum number of digits allowed in the integer portion of a
+ * number. This override limits the integer digit count to 309.
+ * @see NumberFormat#setMinimumIntegerDigits
+ */
+void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
+ NumberFormat::setMinimumIntegerDigits(_min(newValue, kDoubleIntegerDigits));
+}
+
+/**
+ * Sets the maximum number of digits allowed in the fraction portion of a
+ * number. This override limits the fraction digit count to 340.
+ * @see NumberFormat#setMaximumFractionDigits
+ */
+void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
+ NumberFormat::setMaximumFractionDigits(_min(newValue, kDoubleFractionDigits));
+}
+
+/**
+ * Sets the minimum number of digits allowed in the fraction portion of a
+ * number. This override limits the fraction digit count to 340.
+ * @see NumberFormat#setMinimumFractionDigits
+ */
+void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {
+ NumberFormat::setMinimumFractionDigits(_min(newValue, kDoubleFractionDigits));
+}
+
+int32_t DecimalFormat::getMinimumSignificantDigits() const {
+ return fMinSignificantDigits;
+}
+
+int32_t DecimalFormat::getMaximumSignificantDigits() const {
+ return fMaxSignificantDigits;
+}
+
+void DecimalFormat::setMinimumSignificantDigits(int32_t min) {
+ if (min < 1) {
+ min = 1;
+ }
+ // pin max sig dig to >= min
+ int32_t max = _max(fMaxSignificantDigits, min);
+ fMinSignificantDigits = min;
+ fMaxSignificantDigits = max;
+}
+
+void DecimalFormat::setMaximumSignificantDigits(int32_t max) {
+ if (max < 1) {
+ max = 1;
+ }
+ // pin min sig dig to 1..max
+ U_ASSERT(fMinSignificantDigits >= 1);
+ int32_t min = _min(fMinSignificantDigits, max);
+ fMinSignificantDigits = min;
+ fMaxSignificantDigits = max;
+}
+
+UBool DecimalFormat::areSignificantDigitsUsed() const {
+ return fUseSignificantDigits;
+}
+
+void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
+ fUseSignificantDigits = useSignificantDigits;
+}
+
+void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
+ // If we are a currency format, then modify our affixes to
+ // encode the currency symbol for the given currency in our
+ // locale, and adjust the decimal digits and rounding for the
+ // given currency.
+
+ // Note: The code is ordered so that this object is *not changed*
+ // until we are sure we are going to succeed.
+
+ // NULL or empty currency is *legal* and indicates no currency.
+ UBool isCurr = (theCurrency && *theCurrency);
+
+ double rounding = 0.0;
+ int32_t frac = 0;
+ if (fIsCurrencyFormat && isCurr) {
+ rounding = ucurr_getRoundingIncrement(theCurrency, &ec);
+ frac = ucurr_getDefaultFractionDigits(theCurrency, &ec);
+ }
+
+ NumberFormat::setCurrency(theCurrency, ec);
+ if (U_FAILURE(ec)) return;
+
+ if (fIsCurrencyFormat) {
+ // NULL or empty currency is *legal* and indicates no currency.
+ if (isCurr) {
+ setRoundingIncrement(rounding);
+ setMinimumFractionDigits(frac);
+ setMaximumFractionDigits(frac);
+ }
+ expandAffixes();
+ }
+}
+
+// Deprecated variant with no UErrorCode parameter
+void DecimalFormat::setCurrency(const UChar* theCurrency) {
+ UErrorCode ec = U_ZERO_ERROR;
+ setCurrency(theCurrency, ec);
+}
+
+void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& /*ec*/) const {
+ const UChar* c = getCurrency();
+ if (*c == 0) {
+ const UnicodeString &intl =
+ fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
+ c = intl.getBuffer(); // ok for intl to go out of scope
+ }
+ u_strncpy(result, c, 3);
+ result[3] = 0;
+}
+
+/**
+ * Return the number of fraction digits to display, or the total
+ * number of digits for significant digit formats and exponential
+ * formats.
+ */
+int32_t
+DecimalFormat::precision(UBool isIntegral) const {
+ if (areSignificantDigitsUsed()) {
+ return getMaximumSignificantDigits();
+ } else if (fUseExponentialNotation) {
+ return getMinimumIntegerDigits() + getMaximumFractionDigits();
+ } else {
+ return isIntegral ? 0 : getMaximumFractionDigits();
+ }
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/digitlst.cpp b/Build/source/libs/icu/icu-xetex/i18n/digitlst.cpp
new file mode 100644
index 00000000000..39e69fd7998
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/digitlst.cpp
@@ -0,0 +1,674 @@
+/*
+**********************************************************************
+* Copyright (C) 1997-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*
+* File DIGITLST.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 03/21/97 clhuang Converted from java.
+* 03/21/97 clhuang Implemented with new APIs.
+* 03/27/97 helena Updated to pass the simple test after code review.
+* 03/31/97 aliu Moved isLONG_MIN to here, and fixed it.
+* 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char.
+* Reworked representation by replacing fDecimalAt
+* with fExponent.
+* 04/16/97 aliu Rewrote set() and getDouble() to use sprintf/atof
+* to do digit conversion.
+* 09/09/97 aliu Modified for exponential notation support.
+* 08/02/98 stephen Added nearest/even rounding
+* Fixed bug in fitsIntoLong
+******************************************************************************
+*/
+
+#include "digitlst.h"
+
+#if !UCONFIG_NO_FORMATTING
+#include "unicode/putil.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include "uassert.h"
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+
+// ***************************************************************************
+// class DigitList
+// This class handles the transcoding between numeric values and strings of
+// characters. Only handles as non-negative numbers.
+// ***************************************************************************
+
+/**
+ * This is the zero digit. Array elements fDigits[i] have values from
+ * kZero to kZero + 9. Typically, this is '0'.
+ */
+#define kZero '0'
+
+static char gDecimal = 0;
+
+/* Only for 32 bit numbers. Ignore the negative sign. */
+static const char LONG_MIN_REP[] = "2147483648";
+static const char I64_MIN_REP[] = "9223372036854775808";
+
+enum {
+ LONG_MIN_REP_LENGTH = sizeof(LONG_MIN_REP) - 1, //Ignore the NULL at the end
+ I64_MIN_REP_LENGTH = sizeof(I64_MIN_REP) - 1 //Ignore the NULL at the end
+};
+
+U_NAMESPACE_BEGIN
+
+
+// -------------------------------------
+// default constructor
+
+DigitList::DigitList()
+{
+ fDigits = fDecimalDigits + 1; // skip the decimal
+ clear();
+}
+
+// -------------------------------------
+
+DigitList::~DigitList()
+{
+}
+
+// -------------------------------------
+// copy constructor
+
+DigitList::DigitList(const DigitList &other)
+{
+ fDigits = fDecimalDigits + 1; // skip the decimal
+ *this = other;
+}
+
+// -------------------------------------
+// assignment operator
+
+DigitList&
+DigitList::operator=(const DigitList& other)
+{
+ if (this != &other)
+ {
+ fDecimalAt = other.fDecimalAt;
+ fCount = other.fCount;
+ fIsPositive = other.fIsPositive;
+ fRoundingMode = other.fRoundingMode;
+ uprv_strncpy(fDigits, other.fDigits, fCount);
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+UBool
+DigitList::operator==(const DigitList& that) const
+{
+ return ((this == &that) ||
+ (fDecimalAt == that.fDecimalAt &&
+ fCount == that.fCount &&
+ fIsPositive == that.fIsPositive &&
+ fRoundingMode == that.fRoundingMode &&
+ uprv_strncmp(fDigits, that.fDigits, fCount) == 0));
+}
+
+// -------------------------------------
+// Resets the digit list; sets all the digits to zero.
+
+void
+DigitList::clear()
+{
+ fDecimalAt = 0;
+ fCount = 0;
+ fIsPositive = TRUE;
+ fRoundingMode = DecimalFormat::kRoundHalfEven;
+
+ // Don't bother initializing fDigits because fCount is 0.
+}
+
+
+
+// -------------------------------------
+
+/**
+ * Formats a number into a base 10 string representation, and NULL terminates it.
+ * @param number The number to format
+ * @param outputStr The string to output to
+ * @param outputLen The maximum number of characters to put into outputStr
+ * (including NULL).
+ * @return the number of digits written, not including the sign.
+ */
+static int32_t
+formatBase10(int64_t number, char *outputStr, int32_t outputLen)
+{
+ char buffer[MAX_DIGITS + 1];
+ int32_t bufferLen;
+ int32_t result;
+
+ if (outputLen > MAX_DIGITS) {
+ outputLen = MAX_DIGITS; // Ignore NULL
+ }
+ else if (outputLen < 3) {
+ return 0; // Not enough room
+ }
+
+ bufferLen = outputLen;
+
+ if (number < 0) { // Negative numbers are slightly larger than a postive
+ buffer[bufferLen--] = (char)(-(number % 10) + kZero);
+ number /= -10;
+ *(outputStr++) = '-';
+ }
+ else {
+ *(outputStr++) = '+'; // allow +0
+ }
+ while (bufferLen >= 0 && number) { // Output the number
+ buffer[bufferLen--] = (char)(number % 10 + kZero);
+ number /= 10;
+ }
+
+ result = outputLen - bufferLen++;
+
+ while (bufferLen <= outputLen) { // Copy the number to output
+ *(outputStr++) = buffer[bufferLen++];
+ }
+ *outputStr = 0; // NULL terminate.
+ return result;
+}
+
+/**
+ * Currently, getDouble() depends on atof() to do its conversion.
+ *
+ * WARNING!!
+ * This is an extremely costly function. ~1/2 of the conversion time
+ * can be linked to this function.
+ */
+double
+DigitList::getDouble() /*const*/
+{
+ double value;
+
+ if (fCount == 0) {
+ value = 0.0;
+ }
+ else {
+ char* end = NULL;
+ if (!gDecimal) {
+ char rep[MAX_DIGITS];
+ // For machines that decide to change the decimal on you,
+ // and try to be too smart with localization.
+ // This normally should be just a '.'.
+ sprintf(rep, "%+1.1f", 1.0);
+ gDecimal = rep[2];
+ }
+
+ *fDecimalDigits = gDecimal;
+ *(fDigits+fCount) = 'e'; // add an e after the digits.
+ formatBase10(fDecimalAt,
+ fDigits + fCount + 1, // skip the 'e'
+ MAX_DEC_DIGITS - fCount - 3); // skip the 'e' and '.'
+ value = uprv_strtod(fDecimalDigits, &end);
+ }
+
+ return fIsPositive ? value : -value;
+}
+
+// -------------------------------------
+
+/**
+ * Make sure that fitsIntoLong() is called before calling this function.
+ */
+int32_t DigitList::getLong() /*const*/
+{
+ if (fCount == fDecimalAt) {
+ int32_t value;
+
+ fDigits[fCount] = 0; // NULL terminate
+
+ // This conversion is bad on 64-bit platforms when we want to
+ // be able to return a 64-bit number [grhoten]
+ *fDecimalDigits = fIsPositive ? '+' : '-';
+ value = (int32_t)atol(fDecimalDigits);
+ return value;
+ }
+ else {
+ // This is 100% accurate in c++ because if we are representing
+ // an integral value, we suffer nothing in the conversion to
+ // double. If we are to support 64-bit longs later, getLong()
+ // must be rewritten. [LIU]
+ return (int32_t)getDouble();
+ }
+}
+
+
+/**
+ * Make sure that fitsIntoInt64() is called before calling this function.
+ */
+int64_t DigitList::getInt64() /*const*/
+{
+ if (fCount == fDecimalAt) {
+ uint64_t value;
+
+ fDigits[fCount] = 0; // NULL terminate
+
+ // This conversion is bad on 64-bit platforms when we want to
+ // be able to return a 64-bit number [grhoten]
+ *fDecimalDigits = fIsPositive ? '+' : '-';
+
+ // emulate a platform independent atoi64()
+ value = 0;
+ for (int i = 0; i < fCount; ++i) {
+ int v = fDigits[i] - kZero;
+ value = value * (uint64_t)10 + (uint64_t)v;
+ }
+ if (!fIsPositive) {
+ value = ~value;
+ value += 1;
+ }
+ int64_t svalue = (int64_t)value;
+ return svalue;
+ }
+ else {
+ // TODO: figure out best approach
+
+ // This is 100% accurate in c++ because if we are representing
+ // an integral value, we suffer nothing in the conversion to
+ // double. If we are to support 64-bit longs later, getLong()
+ // must be rewritten. [LIU]
+ return (int64_t)getDouble();
+ }
+}
+
+/**
+ * Return true if the number represented by this object can fit into
+ * a long.
+ */
+UBool
+DigitList::fitsIntoLong(UBool ignoreNegativeZero) /*const*/
+{
+ // Figure out if the result will fit in a long. We have to
+ // first look for nonzero digits after the decimal point;
+ // then check the size.
+
+ // Trim trailing zeros after the decimal point. This does not change
+ // the represented value.
+ while (fCount > fDecimalAt && fCount > 0 && fDigits[fCount - 1] == kZero)
+ --fCount;
+
+ if (fCount == 0) {
+ // Positive zero fits into a long, but negative zero can only
+ // be represented as a double. - bug 4162852
+ return fIsPositive || ignoreNegativeZero;
+ }
+
+ // If the digit list represents a double or this number is too
+ // big for a long.
+ if (fDecimalAt < fCount || fDecimalAt > LONG_MIN_REP_LENGTH)
+ return FALSE;
+
+ // If number is small enough to fit in a long
+ if (fDecimalAt < LONG_MIN_REP_LENGTH)
+ return TRUE;
+
+ // At this point we have fDecimalAt == fCount, and fCount == LONG_MIN_REP_LENGTH.
+ // The number will overflow if it is larger than LONG_MAX
+ // or smaller than LONG_MIN.
+ for (int32_t i=0; i<fCount; ++i)
+ {
+ char dig = fDigits[i],
+ max = LONG_MIN_REP[i];
+ if (dig > max)
+ return FALSE;
+ if (dig < max)
+ return TRUE;
+ }
+
+ // At this point the first count digits match. If fDecimalAt is less
+ // than count, then the remaining digits are zero, and we return true.
+ if (fCount < fDecimalAt)
+ return TRUE;
+
+ // Now we have a representation of Long.MIN_VALUE, without the leading
+ // negative sign. If this represents a positive value, then it does
+ // not fit; otherwise it fits.
+ return !fIsPositive;
+}
+
+/**
+ * Return true if the number represented by this object can fit into
+ * a long.
+ */
+UBool
+DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/
+{
+ // Figure out if the result will fit in a long. We have to
+ // first look for nonzero digits after the decimal point;
+ // then check the size.
+
+ // Trim trailing zeros after the decimal point. This does not change
+ // the represented value.
+ while (fCount > fDecimalAt && fCount > 0 && fDigits[fCount - 1] == kZero)
+ --fCount;
+
+ if (fCount == 0) {
+ // Positive zero fits into a long, but negative zero can only
+ // be represented as a double. - bug 4162852
+ return fIsPositive || ignoreNegativeZero;
+ }
+
+ // If the digit list represents a double or this number is too
+ // big for a long.
+ if (fDecimalAt < fCount || fDecimalAt > I64_MIN_REP_LENGTH)
+ return FALSE;
+
+ // If number is small enough to fit in an int64
+ if (fDecimalAt < I64_MIN_REP_LENGTH)
+ return TRUE;
+
+ // At this point we have fDecimalAt == fCount, and fCount == INT64_MIN_REP_LENGTH.
+ // The number will overflow if it is larger than U_INT64_MAX
+ // or smaller than U_INT64_MIN.
+ for (int32_t i=0; i<fCount; ++i)
+ {
+ char dig = fDigits[i],
+ max = I64_MIN_REP[i];
+ if (dig > max)
+ return FALSE;
+ if (dig < max)
+ return TRUE;
+ }
+
+ // At this point the first count digits match. If fDecimalAt is less
+ // than count, then the remaining digits are zero, and we return true.
+ if (fCount < fDecimalAt)
+ return TRUE;
+
+ // Now we have a representation of INT64_MIN_VALUE, without the leading
+ // negative sign. If this represents a positive value, then it does
+ // not fit; otherwise it fits.
+ return !fIsPositive;
+}
+
+
+// -------------------------------------
+
+void
+DigitList::set(int32_t source, int32_t maximumDigits)
+{
+ set((int64_t)source, maximumDigits);
+}
+
+// -------------------------------------
+/**
+ * @param maximumDigits The maximum digits to be generated. If zero,
+ * there is no maximum -- generate all digits.
+ */
+void
+DigitList::set(int64_t source, int32_t maximumDigits)
+{
+ fCount = fDecimalAt = formatBase10(source, fDecimalDigits, MAX_DIGITS);
+
+ fIsPositive = (*fDecimalDigits == '+');
+
+ // Don't copy trailing zeros
+ while (fCount > 1 && fDigits[fCount - 1] == kZero)
+ --fCount;
+
+ if(maximumDigits > 0)
+ round(maximumDigits);
+}
+
+/**
+ * Set the digit list to a representation of the given double value.
+ * This method supports both fixed-point and exponential notation.
+ * @param source Value to be converted; must not be Inf, -Inf, Nan,
+ * or a value <= 0.
+ * @param maximumDigits The most fractional or total digits which should
+ * be converted. If total digits, and the value is zero, then
+ * there is no maximum -- generate all digits.
+ * @param fixedPoint If true, then maximumDigits is the maximum
+ * fractional digits to be converted. If false, total digits.
+ */
+void
+DigitList::set(double source, int32_t maximumDigits, UBool fixedPoint)
+{
+ // for now, simple implementation; later, do proper IEEE stuff
+ char rep[MAX_DIGITS + 8]; // Extra space for '+', '.', e+NNN, and '\0' (actually +8 is enough)
+ char *digitPtr = fDigits;
+ char *repPtr = rep + 2; // +2 to skip the sign and decimal
+ int32_t exponent = 0;
+
+ fIsPositive = !uprv_isNegative(source); // Allow +0 and -0
+
+ // Generate a representation of the form /[+-][0-9]+e[+-][0-9]+/
+ sprintf(rep, "%+1.*e", MAX_DBL_DIGITS - 1, source);
+ fDecimalAt = 0;
+ rep[2] = rep[1]; // remove decimal
+
+ while (*repPtr == kZero) {
+ repPtr++;
+ fDecimalAt--; // account for leading zeros
+ }
+
+ while (*repPtr != 'e') {
+ *(digitPtr++) = *(repPtr++);
+ }
+ fCount = MAX_DBL_DIGITS + fDecimalAt;
+
+ // Parse an exponent of the form /[eE][+-][0-9]+/
+ UBool negExp = (*(++repPtr) == '-');
+ while (*(++repPtr) != 0) {
+ exponent = 10*exponent + *repPtr - kZero;
+ }
+ if (negExp) {
+ exponent = -exponent;
+ }
+ fDecimalAt += exponent + 1; // +1 for decimal removal
+
+ // The negative of the exponent represents the number of leading
+ // zeros between the decimal and the first non-zero digit, for
+ // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
+ // is more than the maximum fraction digits, then we have an underflow
+ // for the printed representation.
+ if (fixedPoint && -fDecimalAt >= maximumDigits)
+ {
+ // If we round 0.0009 to 3 fractional digits, then we have to
+ // create a new one digit in the least significant location.
+ if (-fDecimalAt == maximumDigits && shouldRoundUp(0)) {
+ fCount = 1;
+ ++fDecimalAt;
+ fDigits[0] = (char)'1';
+ } else {
+ // Handle an underflow to zero when we round something like
+ // 0.0009 to 2 fractional digits.
+ fCount = 0;
+ }
+ return;
+ }
+
+
+ // Eliminate digits beyond maximum digits to be displayed.
+ // Round up if appropriate. Do NOT round in the special
+ // case where maximumDigits == 0 and fixedPoint is FALSE.
+ if (fixedPoint || (0 < maximumDigits && maximumDigits < fCount)) {
+ round(fixedPoint ? (maximumDigits + fDecimalAt) : maximumDigits);
+ }
+ else {
+ // Eliminate trailing zeros.
+ while (fCount > 1 && fDigits[fCount - 1] == kZero)
+ --fCount;
+ }
+}
+
+// -------------------------------------
+
+/**
+ * Round the representation to the given number of digits.
+ * @param maximumDigits The maximum number of digits to be shown.
+ * Upon return, count will be less than or equal to maximumDigits.
+ */
+void
+DigitList::round(int32_t maximumDigits)
+{
+ // Eliminate digits beyond maximum digits to be displayed.
+ // Round up if appropriate.
+ if (maximumDigits >= 0 && maximumDigits < fCount)
+ {
+ if (shouldRoundUp(maximumDigits)) {
+ // Rounding up involved incrementing digits from LSD to MSD.
+ // In most cases this is simple, but in a worst case situation
+ // (9999..99) we have to adjust the decimalAt value.
+ while (--maximumDigits >= 0 && ++fDigits[maximumDigits] > '9')
+ ;
+
+ if (maximumDigits < 0)
+ {
+ // We have all 9's, so we increment to a single digit
+ // of one and adjust the exponent.
+ fDigits[0] = (char) '1';
+ ++fDecimalAt;
+ maximumDigits = 1; // Adjust the count
+ }
+ else
+ {
+ ++maximumDigits; // Increment for use as count
+ }
+ }
+ fCount = maximumDigits;
+ }
+
+ // Eliminate trailing zeros.
+ while (fCount > 1 && fDigits[fCount-1] == kZero) {
+ --fCount;
+ }
+}
+
+/**
+ * Return true if truncating the representation to the given number
+ * of digits will result in an increment to the last digit. This
+ * method implements the requested rounding mode.
+ * [bnf]
+ * @param maximumDigits the number of digits to keep, from 0 to
+ * <code>count-1</code>. If 0, then all digits are rounded away, and
+ * this method returns true if a one should be generated (e.g., formatting
+ * 0.09 with "#.#").
+ * @return true if digit <code>maximumDigits-1</code> should be
+ * incremented
+ */
+UBool DigitList::shouldRoundUp(int32_t maximumDigits) const {
+ int i = 0;
+ if (fRoundingMode == DecimalFormat::kRoundDown ||
+ fRoundingMode == DecimalFormat::kRoundFloor && fIsPositive ||
+ fRoundingMode == DecimalFormat::kRoundCeiling && !fIsPositive) {
+ return FALSE;
+ }
+
+ if (fRoundingMode == DecimalFormat::kRoundHalfEven ||
+ fRoundingMode == DecimalFormat::kRoundHalfDown ||
+ fRoundingMode == DecimalFormat::kRoundHalfUp) {
+ if (fDigits[maximumDigits] == '5' ) {
+ for (i=maximumDigits+1; i<fCount; ++i) {
+ if (fDigits[i] != kZero) {
+ return TRUE;
+ }
+ }
+ switch (fRoundingMode) {
+ case DecimalFormat::kRoundHalfEven:
+ default:
+ // Implement IEEE half-even rounding
+ return maximumDigits > 0 && (fDigits[maximumDigits-1] % 2 != 0);
+ case DecimalFormat::kRoundHalfDown:
+ return FALSE;
+ case DecimalFormat::kRoundHalfUp:
+ return TRUE;
+ }
+ }
+ return (fDigits[maximumDigits] > '5');
+ }
+
+ U_ASSERT(fRoundingMode == DecimalFormat::kRoundUp ||
+ fRoundingMode == DecimalFormat::kRoundFloor && !fIsPositive ||
+ fRoundingMode == DecimalFormat::kRoundCeiling && fIsPositive);
+
+ for (i=maximumDigits; i<fCount; ++i) {
+ if (fDigits[i] != kZero) {
+ return TRUE;
+ }
+ }
+ return false;
+}
+
+// -------------------------------------
+
+// In the Java implementation, we need a separate set(long) because 64-bit longs
+// have too much precision to fit into a 64-bit double. In C++, longs can just
+// be passed to set(double) as long as they are 32 bits in size. We currently
+// don't implement 64-bit longs in C++, although the code below would work for
+// that with slight modifications. [LIU]
+/*
+void
+DigitList::set(long source)
+{
+ // handle the special case of zero using a standard exponent of 0.
+ // mathematically, the exponent can be any value.
+ if (source == 0)
+ {
+ fcount = 0;
+ fDecimalAt = 0;
+ return;
+ }
+
+ // we don't accept negative numbers, with the exception of long_min.
+ // long_min is treated specially by being represented as long_max+1,
+ // which is actually an impossible signed long value, so there is no
+ // ambiguity. we do this for convenience, so digitlist can easily
+ // represent the digits of a long.
+ bool islongmin = (source == long_min);
+ if (islongmin)
+ {
+ source = -(source + 1); // that is, long_max
+ islongmin = true;
+ }
+ sprintf(fdigits, "%d", source);
+
+ // now we need to compute the exponent. it's easy in this case; it's
+ // just the same as the count. e.g., 0.123 * 10^3 = 123.
+ fcount = strlen(fdigits);
+ fDecimalAt = fcount;
+
+ // here's how we represent long_max + 1. note that we always know
+ // that the last digit of long_max will not be 9, because long_max
+ // is of the form (2^n)-1.
+ if (islongmin)
+ ++fdigits[fcount-1];
+
+ // finally, we trim off trailing zeros. we don't alter fDecimalAt,
+ // so this has no effect on the represented value. we know the first
+ // digit is non-zero (see code above), so we only have to check down
+ // to fdigits[1].
+ while (fcount > 1 && fdigits[fcount-1] == kzero)
+ --fcount;
+}
+*/
+
+/**
+ * Return true if this object represents the value zero. Anything with
+ * no digits, or all zero digits, is zero, regardless of fDecimalAt.
+ */
+UBool
+DigitList::isZero() const
+{
+ for (int32_t i=0; i<fCount; ++i)
+ if (fDigits[i] != kZero)
+ return FALSE;
+ return TRUE;
+}
+
+U_NAMESPACE_END
+#endif // #if !UCONFIG_NO_FORMATTING
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/digitlst.h b/Build/source/libs/icu/icu-xetex/i18n/digitlst.h
new file mode 100644
index 00000000000..e6266ddb471
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/digitlst.h
@@ -0,0 +1,267 @@
+/*
+******************************************************************************
+*
+* Copyright (C) 1997-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+******************************************************************************
+*
+* File DIGITLST.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/25/97 aliu Converted from java.
+* 03/21/97 clhuang Updated per C++ implementation.
+* 04/15/97 aliu Changed MAX_COUNT to DBL_DIG. Changed Digit to char.
+* 09/09/97 aliu Adapted for exponential notation support.
+* 08/02/98 stephen Added nearest/even rounding
+* 06/29/99 stephen Made LONG_DIGITS a macro to satisfy SUN compiler
+* 07/09/99 stephen Removed kMaxCount (unused, for HP compiler)
+******************************************************************************
+*/
+
+#ifndef DIGITLST_H
+#define DIGITLST_H
+
+#include "unicode/uobject.h"
+
+#if !UCONFIG_NO_FORMATTING
+#include "unicode/decimfmt.h"
+#include <float.h>
+
+// Decimal digits in a 64-bit int
+//#define LONG_DIGITS 19
+#define INT64_DIGITS 19
+
+typedef enum EDigitListValues {
+ MAX_DBL_DIGITS = DBL_DIG,
+ MAX_I64_DIGITS = INT64_DIGITS,
+ MAX_DIGITS = MAX_I64_DIGITS,
+ MAX_EXPONENT = DBL_DIG,
+ DIGIT_PADDING = 3,
+
+ // "+." + fDigits + "e" + fDecimalAt
+ MAX_DEC_DIGITS = MAX_DIGITS + DIGIT_PADDING + MAX_EXPONENT
+} EDigitListValues;
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Digit List utility class. Private to DecimalFormat. Handles the transcoding
+ * between numeric values and strings of characters. Only handles
+ * non-negative numbers. The division of labor between DigitList and
+ * DecimalFormat is that DigitList handles the radix 10 representation
+ * issues; DecimalFormat handles the locale-specific issues such as
+ * positive/negative, grouping, decimal point, currency, and so on.
+ * <P>
+ * A DigitList is really a representation of a floating point value.
+ * It may be an integer value; we assume that a double has sufficient
+ * precision to represent all digits of a long.
+ * <P>
+ * The DigitList representation consists of a string of characters,
+ * which are the digits radix 10, from '0' to '9'. It also has a radix
+ * 10 exponent associated with it. The value represented by a DigitList
+ * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
+ * derived by placing all the digits of the list to the right of the
+ * decimal point, by 10^exponent.
+ */
+class DigitList : public UMemory { // Declare external to make compiler happy
+public:
+ DigitList();
+ ~DigitList();
+
+ /* copy constructor
+ * @param DigitList The object to be copied.
+ * @return the newly created object.
+ */
+ DigitList(const DigitList&); // copy constructor
+
+ /* assignment operator
+ * @param DigitList The object to be copied.
+ * @return the newly created object.
+ */
+ DigitList& operator=(const DigitList&); // assignment operator
+
+ /**
+ * Return true if another object is semantically equal to this one.
+ * @param other The DigitList to be compared for equality
+ * @return true if another object is semantically equal to this one.
+ * return false otherwise.
+ */
+ UBool operator==(const DigitList& other) const;
+
+private:
+ /**
+ * Commented out due to lack of usage and low code coverage.
+ */
+ inline UBool operator!=(const DigitList& other) const;
+public:
+
+ /**
+ * Clears out the digits.
+ * Use before appending them.
+ * Typically, you set a series of digits with append, then at the point
+ * you hit the decimal point, you set myDigitList.fDecimalAt = myDigitList.fCount;
+ * then go on appending digits.
+ */
+ void clear(void);
+
+ /**
+ * Appends digits to the list. Ignores all digits beyond the first DBL_DIG,
+ * since they are not significant for either longs or doubles.
+ * @param digit The digit to be appended.
+ */
+ inline void append(char digit);
+
+ /**
+ * Utility routine to get the value of the digit list
+ * Returns 0.0 if zero length.
+ * @return the value of the digit list.
+ */
+ double getDouble(void) /*const*/;
+
+ /**
+ * Utility routine to get the value of the digit list
+ * Make sure that fitsIntoLong() is called before calling this function.
+ * Returns 0 if zero length.
+ * @return the value of the digit list, return 0 if it is zero length
+ */
+ int32_t getLong(void) /*const*/;
+
+ /**
+ * Utility routine to get the value of the digit list
+ * Make sure that fitsIntoInt64() is called before calling this function.
+ * Returns 0 if zero length.
+ * @return the value of the digit list, return 0 if it is zero length
+ */
+ int64_t getInt64(void) /*const*/;
+
+ /**
+ * Return true if the number represented by this object can fit into
+ * a long.
+ * @param ignoreNegativeZero True if negative zero is ignored.
+ * @return true if the number represented by this object can fit into
+ * a long, return false otherwise.
+ */
+ UBool fitsIntoLong(UBool ignoreNegativeZero) /*const*/;
+
+ /**
+ * Return true if the number represented by this object can fit into
+ * an int64_t.
+ * @param ignoreNegativeZero True if negative zero is ignored.
+ * @return true if the number represented by this object can fit into
+ * a long, return false otherwise.
+ */
+ UBool fitsIntoInt64(UBool ignoreNegativeZero) /*const*/;
+
+ /**
+ * Utility routine to set the value of the digit list from a double
+ * Input must be non-negative, and must not be Inf, -Inf, or NaN.
+ * The maximum fraction digits helps us round properly.
+ * @param source The value to be set
+ * @param maximunDigits The maximum number of digits to be shown
+ * @param fixedPoint True if the point is fixed
+ */
+ void set(double source, int32_t maximumDigits, UBool fixedPoint = TRUE);
+
+ /**
+ * Utility routine to set the value of the digit list from a long.
+ * If a non-zero maximumDigits is specified, no more than that number of
+ * significant digits will be produced.
+ * @param source The value to be set
+ * @param maximunDigits The maximum number of digits to be shown
+ */
+ void set(int32_t source, int32_t maximumDigits = 0);
+
+ /**
+ * Utility routine to set the value of the digit list from an int64.
+ * If a non-zero maximumDigits is specified, no more than that number of
+ * significant digits will be produced.
+ * @param source The value to be set
+ * @param maximunDigits The maximum number of digits to be shown
+ */
+ void set(int64_t source, int32_t maximumDigits = 0);
+
+ /**
+ * Return true if this is a representation of zero.
+ * @return true if this is a representation of zero.
+ */
+ UBool isZero(void) const;
+
+ /**
+ * Return true if this is a representation of LONG_MIN. You must use
+ * this method to determine if this is so; you cannot check directly,
+ * because a special format is used to handle this.
+ */
+ // This code is unused.
+ //UBool isLONG_MIN(void) const;
+
+public:
+ /**
+ * These data members are intentionally public and can be set directly.
+ *<P>
+ * The value represented is given by placing the decimal point before
+ * fDigits[fDecimalAt]. If fDecimalAt is < 0, then leading zeros between
+ * the decimal point and the first nonzero digit are implied. If fDecimalAt
+ * is > fCount, then trailing zeros between the fDigits[fCount-1] and the
+ * decimal point are implied.
+ * <P>
+ * Equivalently, the represented value is given by f * 10^fDecimalAt. Here
+ * f is a value 0.1 <= f < 1 arrived at by placing the digits in fDigits to
+ * the right of the decimal.
+ * <P>
+ * DigitList is normalized, so if it is non-zero, fDigits[0] is non-zero. We
+ * don't allow denormalized numbers because our exponent is effectively of
+ * unlimited magnitude. The fCount value contains the number of significant
+ * digits present in fDigits[].
+ * <P>
+ * Zero is represented by any DigitList with fCount == 0 or with each fDigits[i]
+ * for all i <= fCount == '0'.
+ */
+ int32_t fDecimalAt;
+ int32_t fCount;
+ UBool fIsPositive;
+ char *fDigits;
+ DecimalFormat::ERoundingMode fRoundingMode;
+
+private:
+
+ /* One character before fDigits for the decimal*/
+ char fDecimalDigits[MAX_DEC_DIGITS + 1];
+
+ /**
+ * Round the representation to the given number of digits.
+ * @param maximumDigits The maximum number of digits to be shown.
+ * Upon return, count will be less than or equal to maximumDigits.
+ */
+ void round(int32_t maximumDigits);
+
+ UBool shouldRoundUp(int32_t maximumDigits) const;
+};
+
+// -------------------------------------
+// Appends the digit to the digit list if it's not out of scope.
+// Ignores the digit, otherwise.
+
+inline void
+DigitList::append(char digit)
+{
+ // Ignore digits which exceed the precision we can represent
+ if (fCount < MAX_DIGITS)
+ fDigits[fCount++] = digit;
+}
+
+#if 0
+inline UBool
+DigitList::operator!=(const DigitList& other) const {
+ return !operator==(other);
+}
+#endif
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_FORMATTING
+#endif // _DIGITLST
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/dtfmtsym.cpp b/Build/source/libs/icu/icu-xetex/i18n/dtfmtsym.cpp
new file mode 100644
index 00000000000..8614493701e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/dtfmtsym.cpp
@@ -0,0 +1,1520 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File DTFMTSYM.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 07/21/98 stephen Added getZoneIndex
+* Changed weekdays/short weekdays to be one-based
+* 06/14/99 stephen Removed SimpleDateFormat::fgTimeZoneDataSuffix
+* 11/16/99 weiv Added 'Y' and 'e' to fgPatternChars
+* 03/27/00 weiv Keeping resource bundle around!
+* 06/30/05 emmons Added eraNames, narrow month/day, standalone context
+* 10/12/05 emmons Added setters for eraNames, month/day by width/context
+*******************************************************************************
+*/
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+#include "unicode/ustring.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/msgfmt.h"
+#include "cpputils.h"
+#include "ucln_in.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "locbased.h"
+#include "gregoimp.h"
+#include "hash.h"
+#include "uresimp.h"
+#include "zstrfmt.h"
+
+// *****************************************************************************
+// class DateFormatSymbols
+// *****************************************************************************
+/**
+ * These are static arrays we use only in the case where we have no
+ * resource data.
+ */
+
+#define PATTERN_CHARS_LEN 30
+
+/**
+ * Unlocalized date-time pattern characters. For example: 'y', 'd', etc. All
+ * locales use the same these unlocalized pattern characters.
+ */
+static const UChar gPatternChars[] = {
+ // GyMdkHmsSEDFwWahKzYeugAZvcLQqV
+ 0x47, 0x79, 0x4D, 0x64, 0x6B, 0x48, 0x6D, 0x73, 0x53, 0x45,
+ 0x44, 0x46, 0x77, 0x57, 0x61, 0x68, 0x4B, 0x7A, 0x59, 0x65,
+ 0x75, 0x67, 0x41, 0x5A, 0x76, 0x63, 0x4c, 0x51, 0x71, 0x56, 0
+};
+
+/* length of an array */
+#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
+
+//------------------------------------------------------
+// Strings of last resort. These are only used if we have no resource
+// files. They aren't designed for actual use, just for backup.
+
+// These are the month names and abbreviations of last resort.
+static const UChar gLastResortMonthNames[13][3] =
+{
+ {0x0030, 0x0031, 0x0000}, /* "01" */
+ {0x0030, 0x0032, 0x0000}, /* "02" */
+ {0x0030, 0x0033, 0x0000}, /* "03" */
+ {0x0030, 0x0034, 0x0000}, /* "04" */
+ {0x0030, 0x0035, 0x0000}, /* "05" */
+ {0x0030, 0x0036, 0x0000}, /* "06" */
+ {0x0030, 0x0037, 0x0000}, /* "07" */
+ {0x0030, 0x0038, 0x0000}, /* "08" */
+ {0x0030, 0x0039, 0x0000}, /* "09" */
+ {0x0031, 0x0030, 0x0000}, /* "10" */
+ {0x0031, 0x0031, 0x0000}, /* "11" */
+ {0x0031, 0x0032, 0x0000}, /* "12" */
+ {0x0031, 0x0033, 0x0000} /* "13" */
+};
+
+// These are the weekday names and abbreviations of last resort.
+static const UChar gLastResortDayNames[8][2] =
+{
+ {0x0030, 0x0000}, /* "0" */
+ {0x0031, 0x0000}, /* "1" */
+ {0x0032, 0x0000}, /* "2" */
+ {0x0033, 0x0000}, /* "3" */
+ {0x0034, 0x0000}, /* "4" */
+ {0x0035, 0x0000}, /* "5" */
+ {0x0036, 0x0000}, /* "6" */
+ {0x0037, 0x0000} /* "7" */
+};
+
+// These are the quarter names and abbreviations of last resort.
+static const UChar gLastResortQuarters[4][2] =
+{
+ {0x0031, 0x0000}, /* "1" */
+ {0x0032, 0x0000}, /* "2" */
+ {0x0033, 0x0000}, /* "3" */
+ {0x0034, 0x0000}, /* "4" */
+};
+
+// These are the am/pm and BC/AD markers of last resort.
+static const UChar gLastResortAmPmMarkers[2][3] =
+{
+ {0x0041, 0x004D, 0x0000}, /* "AM" */
+ {0x0050, 0x004D, 0x0000} /* "PM" */
+};
+
+static const UChar gLastResortEras[2][3] =
+{
+ {0x0042, 0x0043, 0x0000}, /* "BC" */
+ {0x0041, 0x0044, 0x0000} /* "AD" */
+};
+
+
+// These are the zone strings of last resort.
+static const UChar gLastResortZoneStrings[7][4] =
+{
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000}, /* "GMT" */
+ {0x0047, 0x004D, 0x0054, 0x0000} /* "GMT" */
+};
+
+static const UChar gLastResortGmtFormat[] =
+ {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */
+
+static const UChar gLastResortGmtHourFormats[4][10] =
+{
+ {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}, /* -HH:mm:ss */
+ {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000, 0x0000, 0x0000, 0x0000}, /* -HH:mm */
+ {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}, /* +HH:mm:ss */
+ {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000, 0x0000, 0x0000, 0x0000} /* +HH:mm */
+};
+
+/* Sizes for the last resort string arrays */
+typedef enum LastResortSize {
+ kMonthNum = 13,
+ kMonthLen = 3,
+
+ kDayNum = 8,
+ kDayLen = 2,
+
+ kAmPmNum = 2,
+ kAmPmLen = 3,
+
+ kQuarterNum = 4,
+ kQuarterLen = 2,
+
+ kEraNum = 2,
+ kEraLen = 3,
+
+ kZoneNum = 5,
+ kZoneLen = 4,
+
+ kGmtHourNum = 4,
+ kGmtHourLen = 10
+} LastResortSize;
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols)
+
+#define kSUPPLEMENTAL "supplementalData"
+
+/**
+ * These are the tags we expect to see in normal resource bundle files associated
+ * with a locale and calendar
+ */
+static const char gErasTag[]="eras";
+static const char gAbbreviatedTag[] = "abbreviated";
+static const char gMonthNamesTag[]="monthNames";
+static const char gDayNamesTag[]="dayNames";
+static const char gNamesWideTag[]="wide";
+static const char gNamesAbbrTag[]="abbreviated";
+static const char gNamesNarrowTag[]="narrow";
+static const char gNamesStandaloneTag[]="stand-alone";
+static const char gAmPmMarkersTag[]="AmPmMarkers";
+static const char gQuartersTag[]="quarters";
+
+static const char gZoneStringsTag[]="zoneStrings";
+static const char gGmtFormatTag[]="gmtFormat";
+static const char gHourFormatTag[]="hourFormat";
+
+static const char gLocalPatternCharsTag[]="localPatternChars";
+
+static UMTX LOCK;
+
+/**
+ * Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly.
+ * Work around this.
+ */
+static inline UnicodeString* newUnicodeStringArray(size_t count) {
+ return new UnicodeString[count ? count : 1];
+}
+
+//------------------------------------------------------
+
+DateFormatSymbols::DateFormatSymbols(const Locale& locale,
+ UErrorCode& status)
+ : UObject()
+{
+ initializeData(locale, NULL, status);
+}
+
+DateFormatSymbols::DateFormatSymbols(UErrorCode& status)
+ : UObject()
+{
+ initializeData(Locale::getDefault(), NULL, status, TRUE);
+}
+
+
+DateFormatSymbols::DateFormatSymbols(const Locale& locale,
+ const char *type,
+ UErrorCode& status)
+ : UObject()
+{
+ initializeData(locale, type, status);
+}
+
+DateFormatSymbols::DateFormatSymbols(const char *type, UErrorCode& status)
+ : UObject()
+{
+ initializeData(Locale::getDefault(), type, status, TRUE);
+}
+
+DateFormatSymbols::DateFormatSymbols(const DateFormatSymbols& other)
+ : UObject(other)
+{
+ copyData(other);
+}
+
+void
+DateFormatSymbols::assignArray(UnicodeString*& dstArray,
+ int32_t& dstCount,
+ const UnicodeString* srcArray,
+ int32_t srcCount)
+{
+ // assignArray() is only called by copyData(), which in turn implements the
+ // copy constructor and the assignment operator.
+ // All strings in a DateFormatSymbols object are created in one of the following
+ // three ways that all allow to safely use UnicodeString::fastCopyFrom():
+ // - readonly-aliases from resource bundles
+ // - readonly-aliases or allocated strings from constants
+ // - safely cloned strings (with owned buffers) from setXYZ() functions
+ //
+ // Note that this is true for as long as DateFormatSymbols can be constructed
+ // only from a locale bundle or set via the cloning API,
+ // *and* for as long as all the strings are in *private* fields, preventing
+ // a subclass from creating these strings in an "unsafe" way (with respect to fastCopyFrom()).
+ dstCount = srcCount;
+ dstArray = newUnicodeStringArray(srcCount);
+ if(dstArray != NULL) {
+ int32_t i;
+ for(i=0; i<srcCount; ++i) {
+ dstArray[i].fastCopyFrom(srcArray[i]);
+ }
+ }
+}
+
+/**
+ * Create a copy, in fZoneStrings, of the given zone strings array. The
+ * member variables fZoneStringsRowCount and fZoneStringsColCount should
+ * be set already by the caller.
+ */
+void
+DateFormatSymbols::createZoneStrings(const UnicodeString *const * otherStrings)
+{
+ int32_t row, col;
+
+ fZoneStrings = (UnicodeString **)uprv_malloc(fZoneStringsRowCount * sizeof(UnicodeString *));
+ for (row=0; row<fZoneStringsRowCount; ++row)
+ {
+ fZoneStrings[row] = newUnicodeStringArray(fZoneStringsColCount);
+ for (col=0; col<fZoneStringsColCount; ++col) {
+ // fastCopyFrom() - see assignArray comments
+ fZoneStrings[row][col].fastCopyFrom(otherStrings[row][col]);
+ }
+ }
+}
+
+/**
+ * Copy all of the other's data to this.
+ */
+void
+DateFormatSymbols::copyData(const DateFormatSymbols& other) {
+ assignArray(fEras, fErasCount, other.fEras, other.fErasCount);
+ assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount);
+ assignArray(fMonths, fMonthsCount, other.fMonths, other.fMonthsCount);
+ assignArray(fShortMonths, fShortMonthsCount, other.fShortMonths, other.fShortMonthsCount);
+ assignArray(fNarrowMonths, fNarrowMonthsCount, other.fNarrowMonths, other.fNarrowMonthsCount);
+ assignArray(fStandaloneMonths, fStandaloneMonthsCount, other.fStandaloneMonths, other.fStandaloneMonthsCount);
+ assignArray(fStandaloneShortMonths, fStandaloneShortMonthsCount, other.fStandaloneShortMonths, other.fStandaloneShortMonthsCount);
+ assignArray(fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, other.fStandaloneNarrowMonths, other.fStandaloneNarrowMonthsCount);
+ assignArray(fWeekdays, fWeekdaysCount, other.fWeekdays, other.fWeekdaysCount);
+ assignArray(fShortWeekdays, fShortWeekdaysCount, other.fShortWeekdays, other.fShortWeekdaysCount);
+ assignArray(fNarrowWeekdays, fNarrowWeekdaysCount, other.fNarrowWeekdays, other.fNarrowWeekdaysCount);
+ assignArray(fStandaloneWeekdays, fStandaloneWeekdaysCount, other.fStandaloneWeekdays, other.fStandaloneWeekdaysCount);
+ assignArray(fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, other.fStandaloneShortWeekdays, other.fStandaloneShortWeekdaysCount);
+ assignArray(fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, other.fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdaysCount);
+ assignArray(fAmPms, fAmPmsCount, other.fAmPms, other.fAmPmsCount);
+ assignArray(fQuarters, fQuartersCount, other.fQuarters, other.fQuartersCount);
+ assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount);
+ assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount);
+ assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount);
+ fGmtFormat = other.fGmtFormat;
+ assignArray(fGmtHourFormats, fGmtHourFormatsCount, other.fGmtHourFormats, other.fGmtHourFormatsCount);
+
+ if (other.fZoneStrings != NULL) {
+ fZoneStringsColCount = other.fZoneStringsColCount;
+ fZoneStringsRowCount = other.fZoneStringsRowCount;
+ createZoneStrings((const UnicodeString**)other.fZoneStrings);
+
+ } else {
+ fZoneStrings = NULL;
+ fZoneStringsColCount = 0;
+ fZoneStringsRowCount = 0;
+ }
+ fZSFLocale = other.fZSFLocale;
+ // Other zone strings data is created on demand
+ fZoneStringFormat = NULL;
+ fLocaleZoneStrings = NULL;
+ fZSFCachePtr = NULL;
+ fZSFLocal = NULL;
+
+ // fastCopyFrom() - see assignArray comments
+ fLocalPatternChars.fastCopyFrom(other.fLocalPatternChars);
+}
+
+/**
+ * Assignment operator.
+ */
+DateFormatSymbols& DateFormatSymbols::operator=(const DateFormatSymbols& other)
+{
+ dispose();
+ copyData(other);
+
+ return *this;
+}
+
+DateFormatSymbols::~DateFormatSymbols()
+{
+ dispose();
+}
+
+void DateFormatSymbols::dispose()
+{
+ if (fEras) delete[] fEras;
+ if (fEraNames) delete[] fEraNames;
+ if (fMonths) delete[] fMonths;
+ if (fShortMonths) delete[] fShortMonths;
+ if (fNarrowMonths) delete[] fNarrowMonths;
+ if (fStandaloneMonths) delete[] fStandaloneMonths;
+ if (fStandaloneShortMonths) delete[] fStandaloneShortMonths;
+ if (fStandaloneNarrowMonths) delete[] fStandaloneNarrowMonths;
+ if (fWeekdays) delete[] fWeekdays;
+ if (fShortWeekdays) delete[] fShortWeekdays;
+ if (fNarrowWeekdays) delete[] fNarrowWeekdays;
+ if (fStandaloneWeekdays) delete[] fStandaloneWeekdays;
+ if (fStandaloneShortWeekdays) delete[] fStandaloneShortWeekdays;
+ if (fStandaloneNarrowWeekdays) delete[] fStandaloneNarrowWeekdays;
+ if (fAmPms) delete[] fAmPms;
+ if (fQuarters) delete[] fQuarters;
+ if (fShortQuarters) delete[] fShortQuarters;
+ if (fStandaloneQuarters) delete[] fStandaloneQuarters;
+ if (fStandaloneShortQuarters) delete[] fStandaloneShortQuarters;
+ if (fGmtHourFormats) delete[] fGmtHourFormats;
+
+ disposeZoneStrings();
+}
+
+void DateFormatSymbols::disposeZoneStrings()
+{
+ if (fZoneStrings) {
+ for (int32_t row = 0; row < fZoneStringsRowCount; ++row) {
+ delete[] fZoneStrings[row];
+ }
+ uprv_free(fZoneStrings);
+ }
+ if (fLocaleZoneStrings) {
+ for (int32_t row = 0; row < fZoneStringsRowCount; ++row) {
+ delete[] fLocaleZoneStrings[row];
+ }
+ uprv_free(fLocaleZoneStrings);
+ }
+ if (fZSFLocal) {
+ delete fZSFLocal;
+ }
+ if (fZSFCachePtr) {
+ delete fZSFCachePtr;
+ }
+
+ fZoneStrings = NULL;
+ fLocaleZoneStrings = NULL;
+ fZoneStringsRowCount = 0;
+ fZoneStringsColCount = 0;
+
+ fZoneStringFormat = NULL;
+ fZSFLocal = NULL;
+ fZSFCachePtr = NULL;
+}
+
+UBool
+DateFormatSymbols::arrayCompare(const UnicodeString* array1,
+ const UnicodeString* array2,
+ int32_t count)
+{
+ if (array1 == array2) return TRUE;
+ while (count>0)
+ {
+ --count;
+ if (array1[count] != array2[count]) return FALSE;
+ }
+ return TRUE;
+}
+
+UBool
+DateFormatSymbols::operator==(const DateFormatSymbols& other) const
+{
+ // First do cheap comparisons
+ if (this == &other) {
+ return TRUE;
+ }
+ if (fErasCount == other.fErasCount &&
+ fEraNamesCount == other.fEraNamesCount &&
+ fMonthsCount == other.fMonthsCount &&
+ fShortMonthsCount == other.fShortMonthsCount &&
+ fNarrowMonthsCount == other.fNarrowMonthsCount &&
+ fStandaloneMonthsCount == other.fStandaloneMonthsCount &&
+ fStandaloneShortMonthsCount == other.fStandaloneShortMonthsCount &&
+ fStandaloneNarrowMonthsCount == other.fStandaloneNarrowMonthsCount &&
+ fWeekdaysCount == other.fWeekdaysCount &&
+ fShortWeekdaysCount == other.fShortWeekdaysCount &&
+ fNarrowWeekdaysCount == other.fNarrowWeekdaysCount &&
+ fStandaloneWeekdaysCount == other.fStandaloneWeekdaysCount &&
+ fStandaloneShortWeekdaysCount == other.fStandaloneShortWeekdaysCount &&
+ fStandaloneNarrowWeekdaysCount == other.fStandaloneNarrowWeekdaysCount &&
+ fAmPmsCount == other.fAmPmsCount &&
+ fQuartersCount == other.fQuartersCount &&
+ fShortQuartersCount == other.fShortQuartersCount &&
+ fStandaloneQuartersCount == other.fStandaloneQuartersCount &&
+ fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount &&
+ fGmtHourFormatsCount == other.fGmtHourFormatsCount &&
+ fGmtFormat == other.fGmtFormat)
+ {
+ // Now compare the arrays themselves
+ if (arrayCompare(fEras, other.fEras, fErasCount) &&
+ arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) &&
+ arrayCompare(fMonths, other.fMonths, fMonthsCount) &&
+ arrayCompare(fShortMonths, other.fShortMonths, fShortMonthsCount) &&
+ arrayCompare(fNarrowMonths, other.fNarrowMonths, fNarrowMonthsCount) &&
+ arrayCompare(fStandaloneMonths, other.fStandaloneMonths, fStandaloneMonthsCount) &&
+ arrayCompare(fStandaloneShortMonths, other.fStandaloneShortMonths, fStandaloneShortMonthsCount) &&
+ arrayCompare(fStandaloneNarrowMonths, other.fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount) &&
+ arrayCompare(fWeekdays, other.fWeekdays, fWeekdaysCount) &&
+ arrayCompare(fShortWeekdays, other.fShortWeekdays, fShortWeekdaysCount) &&
+ arrayCompare(fNarrowWeekdays, other.fNarrowWeekdays, fNarrowWeekdaysCount) &&
+ arrayCompare(fStandaloneWeekdays, other.fStandaloneWeekdays, fStandaloneWeekdaysCount) &&
+ arrayCompare(fStandaloneShortWeekdays, other.fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount) &&
+ arrayCompare(fStandaloneNarrowWeekdays, other.fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount) &&
+ arrayCompare(fAmPms, other.fAmPms, fAmPmsCount) &&
+ arrayCompare(fQuarters, other.fQuarters, fQuartersCount) &&
+ arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) &&
+ arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) &&
+ arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount) &&
+ arrayCompare(fGmtHourFormats, other.fGmtHourFormats, fGmtHourFormatsCount))
+ {
+ // Compare the contents of fZoneStrings
+ if (fZoneStrings == NULL && other.fZoneStrings == NULL) {
+ if (fZSFLocale == other.fZSFLocale) {
+ return TRUE;
+ }
+ } else if (fZoneStrings != NULL && other.fZoneStrings != NULL) {
+ if (fZoneStringsRowCount == other.fZoneStringsRowCount
+ && fZoneStringsColCount == other.fZoneStringsColCount) {
+ UBool cmpres = TRUE;
+ for (int32_t i = 0; (i < fZoneStringsRowCount) && cmpres; i++) {
+ cmpres = arrayCompare(fZoneStrings[i], other.fZoneStrings[i], fZoneStringsColCount);
+ }
+ return cmpres;
+ }
+ }
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+//------------------------------------------------------
+
+const UnicodeString*
+DateFormatSymbols::getEras(int32_t &count) const
+{
+ count = fErasCount;
+ return fEras;
+}
+
+const UnicodeString*
+DateFormatSymbols::getEraNames(int32_t &count) const
+{
+ count = fEraNamesCount;
+ return fEraNames;
+}
+
+const UnicodeString*
+DateFormatSymbols::getMonths(int32_t &count) const
+{
+ count = fMonthsCount;
+ return fMonths;
+}
+
+const UnicodeString*
+DateFormatSymbols::getShortMonths(int32_t &count) const
+{
+ count = fShortMonthsCount;
+ return fShortMonths;
+}
+
+const UnicodeString*
+DateFormatSymbols::getMonths(int32_t &count, DtContextType context, DtWidthType width ) const
+{
+ UnicodeString *returnValue = NULL;
+
+ switch (context) {
+ case FORMAT :
+ switch(width) {
+ case WIDE :
+ count = fMonthsCount;
+ returnValue = fMonths;
+ break;
+ case ABBREVIATED :
+ count = fShortMonthsCount;
+ returnValue = fShortMonths;
+ break;
+ case NARROW :
+ count = fNarrowMonthsCount;
+ returnValue = fNarrowMonths;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case STANDALONE :
+ switch(width) {
+ case WIDE :
+ count = fStandaloneMonthsCount;
+ returnValue = fStandaloneMonths;
+ break;
+ case ABBREVIATED :
+ count = fStandaloneShortMonthsCount;
+ returnValue = fStandaloneShortMonths;
+ break;
+ case NARROW :
+ count = fStandaloneNarrowMonthsCount;
+ returnValue = fStandaloneNarrowMonths;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case DT_CONTEXT_COUNT :
+ break;
+ }
+ return returnValue;
+}
+
+const UnicodeString*
+DateFormatSymbols::getWeekdays(int32_t &count) const
+{
+ count = fWeekdaysCount;
+ return fWeekdays;
+}
+
+const UnicodeString*
+DateFormatSymbols::getShortWeekdays(int32_t &count) const
+{
+ count = fShortWeekdaysCount;
+ return fShortWeekdays;
+}
+
+const UnicodeString*
+DateFormatSymbols::getWeekdays(int32_t &count, DtContextType context, DtWidthType width) const
+{
+ UnicodeString *returnValue = NULL;
+ switch (context) {
+ case FORMAT :
+ switch(width) {
+ case WIDE :
+ count = fWeekdaysCount;
+ returnValue = fWeekdays;
+ break;
+ case ABBREVIATED :
+ count = fShortWeekdaysCount;
+ returnValue = fShortWeekdays;
+ break;
+ case NARROW :
+ count = fNarrowWeekdaysCount;
+ returnValue = fNarrowWeekdays;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case STANDALONE :
+ switch(width) {
+ case WIDE :
+ count = fStandaloneWeekdaysCount;
+ returnValue = fStandaloneWeekdays;
+ break;
+ case ABBREVIATED :
+ count = fStandaloneShortWeekdaysCount;
+ returnValue = fStandaloneShortWeekdays;
+ break;
+ case NARROW :
+ count = fStandaloneNarrowWeekdaysCount;
+ returnValue = fStandaloneNarrowWeekdays;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case DT_CONTEXT_COUNT :
+ break;
+ }
+ return returnValue;
+}
+
+const UnicodeString*
+DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthType width ) const
+{
+ UnicodeString *returnValue = NULL;
+
+ switch (context) {
+ case FORMAT :
+ switch(width) {
+ case WIDE :
+ count = fQuartersCount;
+ returnValue = fQuarters;
+ break;
+ case ABBREVIATED :
+ count = fShortQuartersCount;
+ returnValue = fShortQuarters;
+ break;
+ case NARROW :
+ count = 0;
+ returnValue = NULL;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case STANDALONE :
+ switch(width) {
+ case WIDE :
+ count = fStandaloneQuartersCount;
+ returnValue = fStandaloneQuarters;
+ break;
+ case ABBREVIATED :
+ count = fStandaloneShortQuartersCount;
+ returnValue = fStandaloneShortQuarters;
+ break;
+ case NARROW :
+ count = 0;
+ returnValue = NULL;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case DT_CONTEXT_COUNT :
+ break;
+ }
+ return returnValue;
+}
+
+const UnicodeString*
+DateFormatSymbols::getAmPmStrings(int32_t &count) const
+{
+ count = fAmPmsCount;
+ return fAmPms;
+}
+
+//------------------------------------------------------
+
+void
+DateFormatSymbols::setEras(const UnicodeString* erasArray, int32_t count)
+{
+ // delete the old list if we own it
+ if (fEras)
+ delete[] fEras;
+
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+ fEras = newUnicodeStringArray(count);
+ uprv_arrayCopy(erasArray,fEras, count);
+ fErasCount = count;
+}
+
+void
+DateFormatSymbols::setEraNames(const UnicodeString* eraNamesArray, int32_t count)
+{
+ // delete the old list if we own it
+ if (fEraNames)
+ delete[] fEraNames;
+
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+ fEraNames = newUnicodeStringArray(count);
+ uprv_arrayCopy(eraNamesArray,fEraNames, count);
+ fEraNamesCount = count;
+}
+
+void
+DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count)
+{
+ // delete the old list if we own it
+ if (fMonths)
+ delete[] fMonths;
+
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+ fMonths = newUnicodeStringArray(count);
+ uprv_arrayCopy( monthsArray,fMonths,count);
+ fMonthsCount = count;
+}
+
+void
+DateFormatSymbols::setShortMonths(const UnicodeString* shortMonthsArray, int32_t count)
+{
+ // delete the old list if we own it
+ if (fShortMonths)
+ delete[] fShortMonths;
+
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+ fShortMonths = newUnicodeStringArray(count);
+ uprv_arrayCopy(shortMonthsArray,fShortMonths, count);
+ fShortMonthsCount = count;
+}
+
+void
+DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count, DtContextType context, DtWidthType width)
+{
+ // delete the old list if we own it
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+
+ switch (context) {
+ case FORMAT :
+ switch (width) {
+ case WIDE :
+ if (fMonths)
+ delete[] fMonths;
+ fMonths = newUnicodeStringArray(count);
+ uprv_arrayCopy( monthsArray,fMonths,count);
+ fMonthsCount = count;
+ break;
+ case ABBREVIATED :
+ if (fShortMonths)
+ delete[] fShortMonths;
+ fShortMonths = newUnicodeStringArray(count);
+ uprv_arrayCopy( monthsArray,fShortMonths,count);
+ fShortMonthsCount = count;
+ break;
+ case NARROW :
+ if (fNarrowMonths)
+ delete[] fNarrowMonths;
+ fNarrowMonths = newUnicodeStringArray(count);
+ uprv_arrayCopy( monthsArray,fNarrowMonths,count);
+ fNarrowMonthsCount = count;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case STANDALONE :
+ switch (width) {
+ case WIDE :
+ if (fStandaloneMonths)
+ delete[] fStandaloneMonths;
+ fStandaloneMonths = newUnicodeStringArray(count);
+ uprv_arrayCopy( monthsArray,fStandaloneMonths,count);
+ fStandaloneMonthsCount = count;
+ break;
+ case ABBREVIATED :
+ if (fStandaloneShortMonths)
+ delete[] fStandaloneShortMonths;
+ fStandaloneShortMonths = newUnicodeStringArray(count);
+ uprv_arrayCopy( monthsArray,fStandaloneShortMonths,count);
+ fStandaloneShortMonthsCount = count;
+ break;
+ case NARROW :
+ if (fStandaloneNarrowMonths)
+ delete[] fStandaloneNarrowMonths;
+ fStandaloneNarrowMonths = newUnicodeStringArray(count);
+ uprv_arrayCopy( monthsArray,fStandaloneNarrowMonths,count);
+ fStandaloneNarrowMonthsCount = count;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case DT_CONTEXT_COUNT :
+ break;
+ }
+}
+
+void DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count)
+{
+ // delete the old list if we own it
+ if (fWeekdays)
+ delete[] fWeekdays;
+
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+ fWeekdays = newUnicodeStringArray(count);
+ uprv_arrayCopy(weekdaysArray,fWeekdays,count);
+ fWeekdaysCount = count;
+}
+
+void
+DateFormatSymbols::setShortWeekdays(const UnicodeString* shortWeekdaysArray, int32_t count)
+{
+ // delete the old list if we own it
+ if (fShortWeekdays)
+ delete[] fShortWeekdays;
+
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+ fShortWeekdays = newUnicodeStringArray(count);
+ uprv_arrayCopy(shortWeekdaysArray, fShortWeekdays, count);
+ fShortWeekdaysCount = count;
+}
+
+void
+DateFormatSymbols::setWeekdays(const UnicodeString* weekdaysArray, int32_t count, DtContextType context, DtWidthType width)
+{
+ // delete the old list if we own it
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+
+ switch (context) {
+ case FORMAT :
+ switch (width) {
+ case WIDE :
+ if (fWeekdays)
+ delete[] fWeekdays;
+ fWeekdays = newUnicodeStringArray(count);
+ uprv_arrayCopy(weekdaysArray, fWeekdays, count);
+ fWeekdaysCount = count;
+ break;
+ case ABBREVIATED :
+ if (fShortWeekdays)
+ delete[] fShortWeekdays;
+ fShortWeekdays = newUnicodeStringArray(count);
+ uprv_arrayCopy(weekdaysArray, fShortWeekdays, count);
+ fShortWeekdaysCount = count;
+ break;
+ case NARROW :
+ if (fNarrowWeekdays)
+ delete[] fNarrowWeekdays;
+ fNarrowWeekdays = newUnicodeStringArray(count);
+ uprv_arrayCopy(weekdaysArray, fNarrowWeekdays, count);
+ fNarrowWeekdaysCount = count;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case STANDALONE :
+ switch (width) {
+ case WIDE :
+ if (fStandaloneWeekdays)
+ delete[] fStandaloneWeekdays;
+ fStandaloneWeekdays = newUnicodeStringArray(count);
+ uprv_arrayCopy(weekdaysArray, fStandaloneWeekdays, count);
+ fStandaloneWeekdaysCount = count;
+ break;
+ case ABBREVIATED :
+ if (fStandaloneShortWeekdays)
+ delete[] fStandaloneShortWeekdays;
+ fStandaloneShortWeekdays = newUnicodeStringArray(count);
+ uprv_arrayCopy(weekdaysArray, fStandaloneShortWeekdays, count);
+ fStandaloneShortWeekdaysCount = count;
+ break;
+ case NARROW :
+ if (fStandaloneNarrowWeekdays)
+ delete[] fStandaloneNarrowWeekdays;
+ fStandaloneNarrowWeekdays = newUnicodeStringArray(count);
+ uprv_arrayCopy(weekdaysArray, fStandaloneNarrowWeekdays, count);
+ fStandaloneNarrowWeekdaysCount = count;
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case DT_CONTEXT_COUNT :
+ break;
+ }
+}
+
+void
+DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count, DtContextType context, DtWidthType width)
+{
+ // delete the old list if we own it
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+
+ switch (context) {
+ case FORMAT :
+ switch (width) {
+ case WIDE :
+ if (fQuarters)
+ delete[] fQuarters;
+ fQuarters = newUnicodeStringArray(count);
+ uprv_arrayCopy( quartersArray,fQuarters,count);
+ fQuartersCount = count;
+ break;
+ case ABBREVIATED :
+ if (fShortQuarters)
+ delete[] fShortQuarters;
+ fShortQuarters = newUnicodeStringArray(count);
+ uprv_arrayCopy( quartersArray,fShortQuarters,count);
+ fShortQuartersCount = count;
+ break;
+ case NARROW :
+ /*
+ if (fNarrowQuarters)
+ delete[] fNarrowQuarters;
+ fNarrowQuarters = newUnicodeStringArray(count);
+ uprv_arrayCopy( quartersArray,fNarrowQuarters,count);
+ fNarrowQuartersCount = count;
+ */
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case STANDALONE :
+ switch (width) {
+ case WIDE :
+ if (fStandaloneQuarters)
+ delete[] fStandaloneQuarters;
+ fStandaloneQuarters = newUnicodeStringArray(count);
+ uprv_arrayCopy( quartersArray,fStandaloneQuarters,count);
+ fStandaloneQuartersCount = count;
+ break;
+ case ABBREVIATED :
+ if (fStandaloneShortQuarters)
+ delete[] fStandaloneShortQuarters;
+ fStandaloneShortQuarters = newUnicodeStringArray(count);
+ uprv_arrayCopy( quartersArray,fStandaloneShortQuarters,count);
+ fStandaloneShortQuartersCount = count;
+ break;
+ case NARROW :
+ /*
+ if (fStandaloneNarrowQuarters)
+ delete[] fStandaloneNarrowQuarters;
+ fStandaloneNarrowQuarters = newUnicodeStringArray(count);
+ uprv_arrayCopy( quartersArray,fStandaloneNarrowQuarters,count);
+ fStandaloneNarrowQuartersCount = count;
+ */
+ break;
+ case DT_WIDTH_COUNT :
+ break;
+ }
+ break;
+ case DT_CONTEXT_COUNT :
+ break;
+ }
+}
+
+void
+DateFormatSymbols::setAmPmStrings(const UnicodeString* amPmsArray, int32_t count)
+{
+ // delete the old list if we own it
+ if (fAmPms) delete[] fAmPms;
+
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+ fAmPms = newUnicodeStringArray(count);
+ uprv_arrayCopy(amPmsArray,fAmPms,count);
+ fAmPmsCount = count;
+}
+
+//------------------------------------------------------
+const ZoneStringFormat*
+DateFormatSymbols::getZoneStringFormat(void) const {
+ umtx_lock(&LOCK);
+ if (fZoneStringFormat == NULL) {
+ ((DateFormatSymbols*)this)->initZoneStringFormat();
+ }
+ umtx_unlock(&LOCK);
+ return fZoneStringFormat;
+}
+
+void
+DateFormatSymbols::initZoneStringFormat(void) {
+ if (fZoneStringFormat == NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ if (fZoneStrings) {
+ // Create an istance of ZoneStringFormat by the custom zone strings array
+ fZSFLocal = new ZoneStringFormat(fZoneStrings, fZoneStringsRowCount,
+ fZoneStringsColCount, status);
+ if (U_FAILURE(status)) {
+ delete fZSFLocal;
+ } else {
+ fZoneStringFormat = (const ZoneStringFormat*)fZSFLocal;
+ }
+ } else {
+ fZSFCachePtr = ZoneStringFormat::getZoneStringFormat(fZSFLocale, status);
+ if (U_FAILURE(status)) {
+ delete fZSFCachePtr;
+ } else {
+ fZoneStringFormat = fZSFCachePtr->get();
+ }
+ }
+ }
+}
+
+const UnicodeString**
+DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
+{
+ const UnicodeString **result = NULL;
+
+ umtx_lock(&LOCK);
+ if (fZoneStrings == NULL) {
+ if (fLocaleZoneStrings == NULL) {
+ ((DateFormatSymbols*)this)->initZoneStringsArray();
+ }
+ result = (const UnicodeString**)fLocaleZoneStrings;
+ } else {
+ result = (const UnicodeString**)fZoneStrings;
+ }
+ rowCount = fZoneStringsRowCount;
+ columnCount = fZoneStringsColCount;
+ umtx_unlock(&LOCK);
+
+ return result;
+}
+
+void
+DateFormatSymbols::initZoneStringsArray(void) {
+ if (fZoneStrings == NULL && fLocaleZoneStrings == NULL) {
+ if (fZoneStringFormat == NULL) {
+ initZoneStringFormat();
+ }
+ if (fZoneStringFormat) {
+ UErrorCode status = U_ZERO_ERROR;
+ fLocaleZoneStrings = fZoneStringFormat->createZoneStringsArray(uprv_getUTCtime() /* use current time */,
+ fZoneStringsRowCount, fZoneStringsColCount, status);
+ }
+ }
+}
+
+void
+DateFormatSymbols::setZoneStrings(const UnicodeString* const *strings, int32_t rowCount, int32_t columnCount)
+{
+ // since deleting a 2-d array is a pain in the butt, we offload that task to
+ // a separate function
+ disposeZoneStrings();
+ UErrorCode status = U_ZERO_ERROR;
+ // we always own the new list, which we create here (we duplicate rather
+ // than adopting the list passed in)
+ fZoneStringsRowCount = rowCount;
+ fZoneStringsColCount = columnCount;
+ createZoneStrings((const UnicodeString**)strings);
+}
+
+//------------------------------------------------------
+
+const UChar * U_EXPORT2
+DateFormatSymbols::getPatternUChars(void)
+{
+ return gPatternChars;
+}
+
+//------------------------------------------------------
+
+UnicodeString&
+DateFormatSymbols::getLocalPatternChars(UnicodeString& result) const
+{
+ // fastCopyFrom() - see assignArray comments
+ return result.fastCopyFrom(fLocalPatternChars);
+}
+
+//------------------------------------------------------
+
+void
+DateFormatSymbols::setLocalPatternChars(const UnicodeString& newLocalPatternChars)
+{
+ fLocalPatternChars = newLocalPatternChars;
+}
+
+//------------------------------------------------------
+
+static void
+initField(UnicodeString **field, int32_t& length, const UResourceBundle *data, UErrorCode &status) {
+ if (U_SUCCESS(status)) {
+ int32_t strLen = 0;
+ length = ures_getSize(data);
+ *field = newUnicodeStringArray(length);
+ if (*field) {
+ for(int32_t i = 0; i<length; i++) {
+ const UChar *resStr = ures_getStringByIndex(data, i, &strLen, &status);
+ // setTo() - see assignArray comments
+ (*(field)+i)->setTo(TRUE, resStr, strLen);
+ }
+ }
+ else {
+ length = 0;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+}
+
+static void
+initField(UnicodeString **field, int32_t& length, const UChar *data, LastResortSize numStr, LastResortSize strLen, UErrorCode &status) {
+ if (U_SUCCESS(status)) {
+ length = numStr;
+ *field = newUnicodeStringArray((size_t)numStr);
+ if (*field) {
+ for(int32_t i = 0; i<length; i++) {
+ // readonly aliases - all "data" strings are constant
+ // -1 as length for variable-length strings (gLastResortDayNames[0] is empty)
+ (*(field)+i)->setTo(TRUE, data+(i*((int32_t)strLen)), -1);
+ }
+ }
+ else {
+ length = 0;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+}
+
+void
+DateFormatSymbols::initializeData(const Locale& locale, const char *type, UErrorCode& status, UBool useLastResortData)
+{
+ int32_t i;
+ int32_t len = 0;
+ const UChar *resStr;
+ /* In case something goes wrong, initialize all of the data to NULL. */
+ fEras = NULL;
+ fErasCount = 0;
+ fEraNames = NULL;
+ fEraNamesCount = 0;
+ fMonths = NULL;
+ fMonthsCount=0;
+ fShortMonths = NULL;
+ fShortMonthsCount=0;
+ fNarrowMonths = NULL;
+ fNarrowMonthsCount=0;
+ fStandaloneMonths = NULL;
+ fStandaloneMonthsCount=0;
+ fStandaloneShortMonths = NULL;
+ fStandaloneShortMonthsCount=0;
+ fStandaloneNarrowMonths = NULL;
+ fStandaloneNarrowMonthsCount=0;
+ fWeekdays = NULL;
+ fWeekdaysCount=0;
+ fShortWeekdays = NULL;
+ fShortWeekdaysCount=0;
+ fNarrowWeekdays = NULL;
+ fNarrowWeekdaysCount=0;
+ fStandaloneWeekdays = NULL;
+ fStandaloneWeekdaysCount=0;
+ fStandaloneShortWeekdays = NULL;
+ fStandaloneShortWeekdaysCount=0;
+ fStandaloneNarrowWeekdays = NULL;
+ fStandaloneNarrowWeekdaysCount=0;
+ fAmPms = NULL;
+ fAmPmsCount=0;
+ fQuarters = NULL;
+ fQuartersCount = 0;
+ fShortQuarters = NULL;
+ fShortQuartersCount = 0;
+ fStandaloneQuarters = NULL;
+ fStandaloneQuartersCount = 0;
+ fStandaloneShortQuarters = NULL;
+ fStandaloneShortQuartersCount = 0;
+ fGmtHourFormats = NULL;
+ fGmtHourFormatsCount = 0;
+ fZoneStringsRowCount = 0;
+ fZoneStringsColCount = 0;
+ fZoneStrings = NULL;
+ fLocaleZoneStrings = NULL;
+
+ fZoneStringFormat = NULL;
+ fZSFLocal = NULL;
+ fZSFCachePtr = NULL;
+
+ // We need to preserve the requested locale for
+ // lazy ZoneStringFormat instantiation. ZoneStringFormat
+ // is region sensitive, thus, bundle locale bundle's locale
+ // is not sufficient.
+ fZSFLocale = locale;
+
+ if (U_FAILURE(status)) return;
+
+ /**
+ * Retrieve the string arrays we need from the resource bundle file.
+ * We cast away const here, but that's okay; we won't delete any of
+ * these.
+ */
+ CalendarData calData(locale, type, status);
+
+ /**
+ * Use the localeBundle for getting zone GMT formatting patterns
+ */
+ UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status);
+ UResourceBundle *zoneStringsArray = ures_getByKeyWithFallback(localeBundle, gZoneStringsTag, NULL, &status);
+
+ // load the first data item
+ UResourceBundle *erasMain = calData.getByKey(gErasTag, status);
+ UResourceBundle *eras = ures_getByKeyWithFallback(erasMain, gAbbreviatedTag, NULL, &status);
+ UErrorCode oldStatus = status;
+ UResourceBundle *eraNames = ures_getByKeyWithFallback(erasMain, gNamesWideTag, NULL, &status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) { // Workaround because eras/wide was omitted from CLDR 1.3
+ status = oldStatus;
+ eraNames = ures_getByKeyWithFallback(erasMain, gAbbreviatedTag, NULL, &status);
+ }
+
+ UResourceBundle *lsweekdaysData = NULL; // Data closed by calData
+ UResourceBundle *weekdaysData = NULL; // Data closed by calData
+ UResourceBundle *narrowWeekdaysData = NULL; // Data closed by calData
+ UResourceBundle *standaloneWeekdaysData = NULL; // Data closed by calData
+ UResourceBundle *standaloneShortWeekdaysData = NULL; // Data closed by calData
+ UResourceBundle *standaloneNarrowWeekdaysData = NULL; // Data closed by calData
+
+ U_LOCALE_BASED(locBased, *this);
+ if (U_FAILURE(status))
+ {
+ if (useLastResortData)
+ {
+ // Handle the case in which there is no resource data present.
+ // We don't have to generate usable patterns in this situation;
+ // we just need to produce something that will be semi-intelligible
+ // in most locales.
+
+ status = U_USING_FALLBACK_WARNING;
+
+ initField(&fEras, fErasCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status);
+ initField(&fEraNames, fEraNamesCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status);
+ initField(&fMonths, fMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
+ initField(&fShortMonths, fShortMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
+ initField(&fNarrowMonths, fNarrowMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
+ initField(&fStandaloneMonths, fStandaloneMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
+ initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
+ initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status);
+ initField(&fWeekdays, fWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
+ initField(&fShortWeekdays, fShortWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
+ initField(&fNarrowWeekdays, fNarrowWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
+ initField(&fStandaloneWeekdays, fStandaloneWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
+ initField(&fStandaloneShortWeekdays, fStandaloneShortWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
+ initField(&fStandaloneNarrowWeekdays, fStandaloneNarrowWeekdaysCount, (const UChar *)gLastResortDayNames, kDayNum, kDayLen, status);
+ initField(&fAmPms, fAmPmsCount, (const UChar *)gLastResortAmPmMarkers, kAmPmNum, kAmPmLen, status);
+ initField(&fQuarters, fQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
+ initField(&fShortQuarters, fShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
+ initField(&fStandaloneQuarters, fStandaloneQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
+ initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
+ initField(&fGmtHourFormats, fGmtHourFormatsCount, (const UChar *)gLastResortGmtHourFormats, kGmtHourNum, kGmtHourLen, status);
+ fGmtFormat.setTo(TRUE, gLastResortGmtFormat, -1);
+ fLocalPatternChars.setTo(TRUE, gPatternChars, PATTERN_CHARS_LEN);
+ }
+ goto cleanup;
+ }
+
+ // if we make it to here, the resource data is cool, and we can get everything out
+ // of it that we need except for the time-zone and localized-pattern data, which
+ // are stored in a separate file
+ locBased.setLocaleIDs(ures_getLocaleByType(eras, ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(eras, ULOC_ACTUAL_LOCALE, &status));
+
+ initField(&fEras, fErasCount, eras, status);
+ initField(&fEraNames, fEraNamesCount, eraNames, status);
+
+ initField(&fMonths, fMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesWideTag, status), status);
+ initField(&fShortMonths, fShortMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
+
+ initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesNarrowTag, status), status);
+ if(status == U_MISSING_RESOURCE_ERROR) {
+ status = U_ZERO_ERROR;
+ initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
+ }
+ if ( status == U_MISSING_RESOURCE_ERROR ) { /* If format/narrow not available, use format/abbreviated */
+ status = U_ZERO_ERROR;
+ initField(&fNarrowMonths, fNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
+ }
+
+ initField(&fStandaloneMonths, fStandaloneMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesWideTag, status), status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) { /* If standalone/wide not available, use format/wide */
+ status = U_ZERO_ERROR;
+ initField(&fStandaloneMonths, fStandaloneMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesWideTag, status), status);
+ }
+ initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) { /* If standalone/abbreviated not available, use format/abbreviated */
+ status = U_ZERO_ERROR;
+ initField(&fStandaloneShortMonths, fStandaloneShortMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
+ }
+ initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey3(gMonthNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) { /* if standalone/narrow not availabe, try format/narrow */
+ status = U_ZERO_ERROR;
+ initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesNarrowTag, status), status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) { /* if still not there, use format/abbreviated */
+ status = U_ZERO_ERROR;
+ initField(&fStandaloneNarrowMonths, fStandaloneNarrowMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status);
+ }
+ }
+ initField(&fAmPms, fAmPmsCount, calData.getByKey(gAmPmMarkersTag, status), status);
+
+ initField(&fQuarters, fQuartersCount, calData.getByKey2(gQuartersTag, gNamesWideTag, status), status);
+ initField(&fShortQuarters, fShortQuartersCount, calData.getByKey2(gQuartersTag, gNamesAbbrTag, status), status);
+
+ initField(&fStandaloneQuarters, fStandaloneQuartersCount, calData.getByKey3(gQuartersTag, gNamesStandaloneTag, gNamesWideTag, status), status);
+ if(status == U_MISSING_RESOURCE_ERROR) {
+ status = U_ZERO_ERROR;
+ initField(&fStandaloneQuarters, fStandaloneQuartersCount, calData.getByKey2(gQuartersTag, gNamesWideTag, status), status);
+ }
+
+ initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calData.getByKey3(gQuartersTag, gNamesStandaloneTag, gNamesAbbrTag, status), status);
+ if(status == U_MISSING_RESOURCE_ERROR) {
+ status = U_ZERO_ERROR;
+ initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, calData.getByKey2(gQuartersTag, gNamesAbbrTag, status), status);
+ }
+
+ // GMT format patterns
+ resStr = ures_getStringByKeyWithFallback(zoneStringsArray, gGmtFormatTag, &len, &status);
+ if (len > 0) {
+ fGmtFormat.setTo(TRUE, resStr, len);
+ }
+
+ resStr = ures_getStringByKeyWithFallback(zoneStringsArray, gHourFormatTag, &len, &status);
+ if (len > 0) {
+ UChar *sep = u_strchr(resStr, (UChar)0x003B /* ';' */);
+ if (sep != NULL) {
+ fGmtHourFormats = newUnicodeStringArray(GMT_HOUR_COUNT);
+ if (fGmtHourFormats == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ fGmtHourFormatsCount = GMT_HOUR_COUNT;
+ fGmtHourFormats[GMT_NEGATIVE_HM].setTo(TRUE, sep + 1, -1);
+ fGmtHourFormats[GMT_POSITIVE_HM].setTo(FALSE, resStr, sep - resStr);
+
+ // CLDR 1.5 does not have GMT offset pattern including second field.
+ // For now, append "ss" to the end.
+ if (fGmtHourFormats[GMT_NEGATIVE_HM].indexOf((UChar)0x003A /* ':' */) != -1) {
+ fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + ":ss";
+ } else {
+ fGmtHourFormats[GMT_NEGATIVE_HMS] = fGmtHourFormats[GMT_NEGATIVE_HM] + "ss";
+ }
+ if (fGmtHourFormats[GMT_POSITIVE_HM].indexOf((UChar)0x003A /* ':' */) != -1) {
+ fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + ":ss";
+ } else {
+ fGmtHourFormats[GMT_POSITIVE_HMS] = fGmtHourFormats[GMT_POSITIVE_HM] + "ss";
+ }
+ }
+ }
+ }
+
+ // ICU 3.8 or later version no longer uses localized date-time pattern characters by default (ticket#5597)
+ /*
+ // fastCopyFrom()/setTo() - see assignArray comments
+ resStr = ures_getStringByKey(fResourceBundle, gLocalPatternCharsTag, &len, &status);
+ fLocalPatternChars.setTo(TRUE, resStr, len);
+ // If the locale data does not include new pattern chars, use the defaults
+ // TODO: Consider making this an error, since this may add conflicting characters.
+ if (len < PATTERN_CHARS_LEN) {
+ fLocalPatternChars.append(UnicodeString(TRUE, &gPatternChars[len], PATTERN_CHARS_LEN-len));
+ }
+ */
+ fLocalPatternChars.setTo(TRUE, gPatternChars, PATTERN_CHARS_LEN);
+
+ // {sfb} fixed to handle 1-based weekdays
+ weekdaysData = calData.getByKey2(gDayNamesTag, gNamesWideTag, status);
+ fWeekdaysCount = ures_getSize(weekdaysData);
+ fWeekdays = new UnicodeString[fWeekdaysCount+1];
+ /* pin the blame on system. If we cannot get a chunk of memory .. the system is dying!*/
+ if (fWeekdays == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ // leave fWeekdays[0] empty
+ for(i = 0; i<fWeekdaysCount; i++) {
+ resStr = ures_getStringByIndex(weekdaysData, i, &len, &status);
+ // setTo() - see assignArray comments
+ fWeekdays[i+1].setTo(TRUE, resStr, len);
+ }
+ fWeekdaysCount++;
+
+ lsweekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
+ fShortWeekdaysCount = ures_getSize(lsweekdaysData);
+ fShortWeekdays = new UnicodeString[fShortWeekdaysCount+1];
+ /* test for NULL */
+ if (fShortWeekdays == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ // leave fShortWeekdays[0] empty
+ for(i = 0; i<fShortWeekdaysCount; i++) {
+ resStr = ures_getStringByIndex(lsweekdaysData, i, &len, &status);
+ // setTo() - see assignArray comments
+ fShortWeekdays[i+1].setTo(TRUE, resStr, len);
+ }
+ fShortWeekdaysCount++;
+
+ narrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesNarrowTag, status);
+ if(status == U_MISSING_RESOURCE_ERROR) {
+ status = U_ZERO_ERROR;
+ narrowWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status);
+ }
+ if ( status == U_MISSING_RESOURCE_ERROR ) {
+ status = U_ZERO_ERROR;
+ narrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
+ }
+ fNarrowWeekdaysCount = ures_getSize(narrowWeekdaysData);
+ fNarrowWeekdays = new UnicodeString[fNarrowWeekdaysCount+1];
+ /* test for NULL */
+ if (fNarrowWeekdays == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ // leave fNarrowWeekdays[0] empty
+ for(i = 0; i<fNarrowWeekdaysCount; i++) {
+ resStr = ures_getStringByIndex(narrowWeekdaysData, i, &len, &status);
+ // setTo() - see assignArray comments
+ fNarrowWeekdays[i+1].setTo(TRUE, resStr, len);
+ }
+ fNarrowWeekdaysCount++;
+
+ standaloneWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesWideTag, status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) {
+ status = U_ZERO_ERROR;
+ standaloneWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesWideTag, status);
+ }
+ fStandaloneWeekdaysCount = ures_getSize(standaloneWeekdaysData);
+ fStandaloneWeekdays = new UnicodeString[fStandaloneWeekdaysCount+1];
+ /* test for NULL */
+ if (fStandaloneWeekdays == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ // leave fStandaloneWeekdays[0] empty
+ for(i = 0; i<fStandaloneWeekdaysCount; i++) {
+ resStr = ures_getStringByIndex(standaloneWeekdaysData, i, &len, &status);
+ // setTo() - see assignArray comments
+ fStandaloneWeekdays[i+1].setTo(TRUE, resStr, len);
+ }
+ fStandaloneWeekdaysCount++;
+
+ standaloneShortWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesAbbrTag, status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) {
+ status = U_ZERO_ERROR;
+ standaloneShortWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
+ }
+ fStandaloneShortWeekdaysCount = ures_getSize(standaloneShortWeekdaysData);
+ fStandaloneShortWeekdays = new UnicodeString[fStandaloneShortWeekdaysCount+1];
+ /* test for NULL */
+ if (fStandaloneShortWeekdays == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ // leave fStandaloneShortWeekdays[0] empty
+ for(i = 0; i<fStandaloneShortWeekdaysCount; i++) {
+ resStr = ures_getStringByIndex(standaloneShortWeekdaysData, i, &len, &status);
+ // setTo() - see assignArray comments
+ fStandaloneShortWeekdays[i+1].setTo(TRUE, resStr, len);
+ }
+ fStandaloneShortWeekdaysCount++;
+
+ standaloneNarrowWeekdaysData = calData.getByKey3(gDayNamesTag, gNamesStandaloneTag, gNamesNarrowTag, status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) {
+ status = U_ZERO_ERROR;
+ standaloneNarrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesNarrowTag, status);
+ if ( status == U_MISSING_RESOURCE_ERROR ) {
+ status = U_ZERO_ERROR;
+ standaloneNarrowWeekdaysData = calData.getByKey2(gDayNamesTag, gNamesAbbrTag, status);
+ }
+ }
+ fStandaloneNarrowWeekdaysCount = ures_getSize(standaloneNarrowWeekdaysData);
+ fStandaloneNarrowWeekdays = new UnicodeString[fStandaloneNarrowWeekdaysCount+1];
+ /* test for NULL */
+ if (fStandaloneNarrowWeekdays == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ // leave fStandaloneNarrowWeekdays[0] empty
+ for(i = 0; i<fStandaloneNarrowWeekdaysCount; i++) {
+ resStr = ures_getStringByIndex(standaloneNarrowWeekdaysData, i, &len, &status);
+ // setTo() - see assignArray comments
+ fStandaloneNarrowWeekdays[i+1].setTo(TRUE, resStr, len);
+ }
+ fStandaloneNarrowWeekdaysCount++;
+
+cleanup:
+ ures_close(eras);
+ ures_close(eraNames);
+ ures_close(zoneStringsArray);
+ ures_close(localeBundle);
+}
+
+Locale
+DateFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
+ U_LOCALE_BASED(locBased, *this);
+ return locBased.getLocale(type, status);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/dtptngen.cpp b/Build/source/libs/icu/icu-xetex/i18n/dtptngen.cpp
new file mode 100644
index 00000000000..3cd632923f5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/dtptngen.cpp
@@ -0,0 +1,1849 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTPTNGEN.CPP
+*
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/datefmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/dtptngen.h"
+#include "unicode/msgfmt.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/udat.h"
+#include "unicode/udatpg.h"
+#include "unicode/uniset.h"
+#include "unicode/ures.h"
+#include "unicode/rep.h"
+#include "cpputils.h"
+#include "ucln_in.h"
+#include "mutex.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "locbased.h"
+#include "gregoimp.h"
+#include "hash.h"
+#include "uresimp.h"
+#include "dtptngen_impl.h"
+
+
+#if defined U_DEBUG_DTPTN
+#include <stdio.h>
+#endif
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+U_NAMESPACE_BEGIN
+
+// *****************************************************************************
+// class DateTimePatternGenerator
+// *****************************************************************************
+static const UChar Canonical_Items[] = {
+ // GyQMwWedDFHmsSv
+ CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, LOW_E, LOW_D, CAP_D, CAP_F,
+ CAP_H, LOW_M, LOW_S, CAP_S, LOW_V, 0
+};
+
+static const dtTypeElem dtTypes[] = {
+ // patternChar, field, type, minLen, weight
+ {CAP_G, UDATPG_ERA_FIELD, DT_SHORT, 1, 3,},
+ {CAP_G, UDATPG_ERA_FIELD, DT_LONG, 4, 0},
+ {LOW_Y, UDATPG_YEAR_FIELD, DT_NUMERIC, 1, 20},
+ {CAP_Y, UDATPG_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 20},
+ {LOW_U, UDATPG_YEAR_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 20},
+ {CAP_Q, UDATPG_QUARTER_FIELD, DT_NUMERIC, 1, 2},
+ {CAP_Q, UDATPG_QUARTER_FIELD, DT_SHORT, 3, 0},
+ {CAP_Q, UDATPG_QUARTER_FIELD, DT_LONG, 4, 0},
+ {CAP_M, UDATPG_MONTH_FIELD, DT_NUMERIC, 1, 2},
+ {CAP_M, UDATPG_MONTH_FIELD, DT_SHORT, 3, 0},
+ {CAP_M, UDATPG_MONTH_FIELD, DT_LONG, 4, 0},
+ {CAP_M, UDATPG_MONTH_FIELD, DT_NARROW, 5, 0},
+ {CAP_L, UDATPG_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
+ {CAP_L, UDATPG_MONTH_FIELD, DT_SHORT - DT_DELTA, 3, 0},
+ {CAP_L, UDATPG_MONTH_FIELD, DT_LONG - DT_DELTA, 4, 0},
+ {CAP_L, UDATPG_MONTH_FIELD, DT_NARROW - DT_DELTA, 5, 0},
+ {LOW_W, UDATPG_WEEK_OF_YEAR_FIELD, DT_NUMERIC, 1, 2},
+ {CAP_W, UDATPG_WEEK_OF_MONTH_FIELD, DT_NUMERIC + DT_DELTA, 1, 0},
+ {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
+ {LOW_E, UDATPG_WEEKDAY_FIELD, DT_SHORT - DT_DELTA, 3, 0},
+ {LOW_E, UDATPG_WEEKDAY_FIELD, DT_LONG - DT_DELTA, 4, 0},
+ {LOW_E, UDATPG_WEEKDAY_FIELD, DT_NARROW - DT_DELTA, 5, 0},
+ {CAP_E, UDATPG_WEEKDAY_FIELD, DT_SHORT, 1, 3},
+ {CAP_E, UDATPG_WEEKDAY_FIELD, DT_LONG, 4, 0},
+ {CAP_E, UDATPG_WEEKDAY_FIELD, DT_NARROW, 5, 0},
+ {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 2},
+ {LOW_C, UDATPG_WEEKDAY_FIELD, DT_SHORT - 2*DT_DELTA, 3, 0},
+ {LOW_C, UDATPG_WEEKDAY_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
+ {LOW_C, UDATPG_WEEKDAY_FIELD, DT_NARROW - 2*DT_DELTA, 5, 0},
+ {LOW_D, UDATPG_DAY_FIELD, DT_NUMERIC, 1, 2},
+ {CAP_D, UDATPG_DAY_OF_YEAR_FIELD, DT_NUMERIC + DT_DELTA, 1, 3},
+ {CAP_F, UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 0},
+ {LOW_G, UDATPG_DAY_FIELD, DT_NUMERIC + 3*DT_DELTA, 1, 20}, // really internal use, so we d'ont care
+ {LOW_A, UDATPG_DAYPERIOD_FIELD, DT_SHORT, 1, 0},
+ {CAP_H, UDATPG_HOUR_FIELD, DT_NUMERIC + 10*DT_DELTA, 1, 2}, // 24 hour
+ {LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + 11*DT_DELTA, 1, 2},
+ {LOW_H, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12 hour
+ {LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + DT_DELTA, 1, 2},
+ {LOW_M, UDATPG_MINUTE_FIELD, DT_NUMERIC, 1, 2},
+ {LOW_S, UDATPG_SECOND_FIELD, DT_NUMERIC, 1, 2},
+ {CAP_S, UDATPG_FRACTIONAL_SECOND_FIELD, DT_NUMERIC + DT_DELTA, 1, 1000},
+ {CAP_A, UDATPG_SECOND_FIELD, DT_NUMERIC + 2*DT_DELTA, 1, 1000},
+ {LOW_V, UDATPG_ZONE_FIELD, DT_SHORT - 2*DT_DELTA, 1, 0},
+ {LOW_V, UDATPG_ZONE_FIELD, DT_LONG - 2*DT_DELTA, 4, 0},
+ {LOW_Z, UDATPG_ZONE_FIELD, DT_SHORT, 1, 3},
+ {LOW_Z, UDATPG_ZONE_FIELD, DT_LONG, 4, 0},
+ {CAP_Z, UDATPG_ZONE_FIELD, DT_SHORT - DT_DELTA, 1, 3},
+ {CAP_Z, UDATPG_ZONE_FIELD, DT_LONG - DT_DELTA, 4, 0},
+ {0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[]
+ };
+
+static const char* CLDR_FIELD_APPEND[] = {
+ "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "Day", "*", "*", "*",
+ "Hour", "Minute", "Second", "*", "Timezone"
+};
+
+static const char* CLDR_FIELD_NAME[] = {
+ "era", "year", "quarter", "month", "week", "*", "weekday", "day", "*", "*", "dayperiod",
+ "hour", "minute", "second", "*", "zone"
+};
+
+static const char* Resource_Fields[] = {
+ "day", "dayperiod", "era", "hour", "minute", "month", "second", "week",
+ "weekday", "year", "zone", "quarter" };
+
+// For appendItems
+static const UChar UDATPG_ItemFormat[]= {0x7B, 0x30, 0x7D, 0x20, 0x251C, 0x7B, 0x32, 0x7D, 0x3A,
+ 0x20, 0x7B, 0x31, 0x7D, 0x2524, 0}; // {0} \u251C{2}: {1}\u2524
+
+static const UChar repeatedPatterns[6]={CAP_G, CAP_E, LOW_Z, LOW_V, CAP_Q, 0}; // "GEzvQ"
+
+static const char DT_DateTimePatternsTag[]="DateTimePatterns";
+static const char DT_DateTimeCalendarTag[]="calendar";
+static const char DT_DateTimeGregorianTag[]="gregorian";
+static const char DT_DateTimeAppendItemsTag[]="appendItems";
+static const char DT_DateTimeFieldsTag[]="fields";
+static const char DT_DateTimeAvailableFormatsTag[]="availableFormats";
+static const UnicodeString repeatedPattern=UnicodeString(repeatedPatterns);
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimePatternGenerator)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTSkeletonEnumeration)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DTRedundantEnumeration)
+
+DateTimePatternGenerator* U_EXPORT2
+DateTimePatternGenerator::createInstance(UErrorCode& status) {
+ return createInstance(Locale::getDefault(), status);
+}
+
+DateTimePatternGenerator* U_EXPORT2
+DateTimePatternGenerator::createInstance(const Locale& locale, UErrorCode& status) {
+ return new DateTimePatternGenerator(locale, status);
+}
+
+DateTimePatternGenerator* U_EXPORT2
+DateTimePatternGenerator::createEmptyInstance(UErrorCode& status) {
+ return new DateTimePatternGenerator(status);
+}
+
+DateTimePatternGenerator::DateTimePatternGenerator(UErrorCode &status) : UObject()
+{
+ fStatus = U_ZERO_ERROR;
+ skipMatcher = NULL;
+ fAvailableFormatKeyHash=NULL;
+ fp = new FormatParser();
+ dtMatcher = new DateTimeMatcher();
+ distanceInfo = new DistanceInfo();
+ patternMap = new PatternMap();
+ if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+}
+
+DateTimePatternGenerator::DateTimePatternGenerator(const Locale& locale, UErrorCode &status) : UObject()
+{
+ fp = new FormatParser();
+ dtMatcher = new DateTimeMatcher();
+ distanceInfo = new DistanceInfo();
+ patternMap = new PatternMap();
+ if (fp == NULL || dtMatcher == NULL || distanceInfo == NULL || patternMap == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ else {
+ initData(locale);
+ status = getStatus();
+ }
+}
+
+DateTimePatternGenerator::DateTimePatternGenerator(const DateTimePatternGenerator& other) : UObject() {
+ fStatus = U_ZERO_ERROR;
+ skipMatcher = NULL;
+ fAvailableFormatKeyHash=NULL;
+ fp = new FormatParser();
+ dtMatcher = new DateTimeMatcher();
+ distanceInfo = new DistanceInfo();
+ patternMap = new PatternMap();
+ *this=other;
+}
+
+DateTimePatternGenerator&
+DateTimePatternGenerator::operator=(const DateTimePatternGenerator& other) {
+ fStatus = U_ZERO_ERROR;
+ pLocale = other.pLocale;
+ *fp = *(other.fp);
+ dtMatcher->copyFrom(other.dtMatcher->skeleton);
+ *distanceInfo = *(other.distanceInfo);
+ dateTimeFormat = other.dateTimeFormat;
+ decimal = other.decimal;
+ // NUL-terminate for the C API.
+ dateTimeFormat.getTerminatedBuffer();
+ decimal.getTerminatedBuffer();
+ delete skipMatcher;
+ if ( other.skipMatcher == NULL ) {
+ skipMatcher = NULL;
+ }
+ else {
+ skipMatcher = new DateTimeMatcher(*other.skipMatcher);
+ }
+ for (int32_t i=0; i< UDATPG_FIELD_COUNT; ++i ) {
+ appendItemFormats[i] = other.appendItemFormats[i];
+ appendItemNames[i] = other.appendItemNames[i];
+ // NUL-terminate for the C API.
+ appendItemFormats[i].getTerminatedBuffer();
+ appendItemNames[i].getTerminatedBuffer();
+ }
+ patternMap->copyFrom(*other.patternMap, fStatus);
+ copyHashtable(other.fAvailableFormatKeyHash);
+ return *this;
+}
+
+
+UBool
+DateTimePatternGenerator::operator==(const DateTimePatternGenerator& other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ if ((pLocale==other.pLocale) && (patternMap->equals(*other.patternMap)) &&
+ (dateTimeFormat==other.dateTimeFormat) && (decimal==other.decimal)) {
+ for ( int32_t i=0 ; i<UDATPG_FIELD_COUNT; ++i ) {
+ if ((appendItemFormats[i] != other.appendItemFormats[i]) ||
+ (appendItemNames[i] != other.appendItemNames[i]) ) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+UBool
+DateTimePatternGenerator::operator!=(const DateTimePatternGenerator& other) const {
+ return !operator==(other);
+}
+
+DateTimePatternGenerator::~DateTimePatternGenerator() {
+ if (fAvailableFormatKeyHash!=NULL) {
+ delete fAvailableFormatKeyHash;
+ fAvailableFormatKeyHash=NULL;
+ }
+
+ if (fp != NULL) delete fp;
+ if (dtMatcher != NULL) delete dtMatcher;
+ if (distanceInfo != NULL) delete distanceInfo;
+ if (patternMap != NULL) delete patternMap;
+ if (skipMatcher != NULL) delete skipMatcher;
+}
+
+void
+DateTimePatternGenerator::initData(const Locale& locale) {
+ fStatus = U_ZERO_ERROR;
+ skipMatcher = NULL;
+ fAvailableFormatKeyHash=NULL;
+
+ addCanonicalItems();
+ addICUPatterns(locale, fStatus);
+ if (U_FAILURE(fStatus)) {
+ return;
+ }
+ addCLDRData(locale);
+ setDateTimeFromCalendar(locale, fStatus);
+ setDecimalSymbols(locale, fStatus);
+} // DateTimePatternGenerator::initData
+
+UnicodeString
+DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode& status) {
+ dtMatcher->set(pattern, fp);
+ return dtMatcher->getSkeletonPtr()->getSkeleton();
+}
+
+UnicodeString
+DateTimePatternGenerator::getBaseSkeleton(const UnicodeString& pattern, UErrorCode& status) {
+ dtMatcher->set(pattern, fp);
+ return dtMatcher->getSkeletonPtr()->getBaseSkeleton();
+}
+
+void
+DateTimePatternGenerator::addICUPatterns(const Locale& locale, UErrorCode& status) {
+ UnicodeString dfPattern;
+ UnicodeString conflictingString;
+ UDateTimePatternConflict conflictingStatus;
+ SimpleDateFormat* df;
+
+ // Load with ICU patterns
+ for (int32_t i=DateFormat::kFull; i<=DateFormat::kShort; i++) {
+ if ((df = (SimpleDateFormat*)DateFormat::createDateInstance((DateFormat::EStyle)i, locale))!= NULL) {
+ conflictingStatus = addPattern(df->toPattern(dfPattern), FALSE, conflictingString, status);
+ delete df;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+
+ if ((df = (SimpleDateFormat*)DateFormat::createTimeInstance((DateFormat::EStyle)i, locale)) != NULL) {
+ conflictingStatus = addPattern(df->toPattern(dfPattern), FALSE, conflictingString, status);
+ delete df;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // HACK for hh:ss
+ if ( i==DateFormat::kMedium ) {
+ hackPattern = dfPattern;
+ }
+ }
+ }
+}
+
+void
+DateTimePatternGenerator::hackTimes(const UnicodeString& hackPattern, UErrorCode& status) {
+ UDateTimePatternConflict conflictingStatus;
+ UnicodeString conflictingString;
+
+ fp->set(hackPattern);
+ UnicodeString mmss;
+ UBool gotMm=FALSE;
+ for (int32_t i=0; i<fp->itemNumber; ++i) {
+ UnicodeString field = fp->items[i];
+ if ( fp->isQuoteLiteral(field) ) {
+ if ( gotMm ) {
+ UnicodeString quoteLiteral;
+ fp->getQuoteLiteral(quoteLiteral, &i);
+ mmss += quoteLiteral;
+ }
+ }
+ else {
+ if (fp->isPatternSeparator(field) && gotMm) {
+ mmss+=field;
+ }
+ else {
+ UChar ch=field.charAt(0);
+ if (ch==LOW_M) {
+ gotMm=TRUE;
+ mmss+=field;
+ }
+ else {
+ if (ch==LOW_S) {
+ if (!gotMm) {
+ break;
+ }
+ mmss+= field;
+ conflictingStatus = addPattern(mmss, FALSE, conflictingString, status);
+ break;
+ }
+ else {
+ if (gotMm || ch==LOW_Z || ch==CAP_Z || ch==LOW_V || ch==CAP_V) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+DateTimePatternGenerator::addCLDRData(const Locale& locale) {
+ UErrorCode err = U_ZERO_ERROR;
+ UResourceBundle *rb, *gregorianBundle, *calBundle;
+ UResourceBundle *patBundle, *fieldBundle, *fBundle;
+ UnicodeString rbPattern, value, field;
+ UnicodeString conflictingPattern;
+ UDateTimePatternConflict conflictingStatus;
+ const char *key=NULL;
+ int32_t i;
+
+ UnicodeString defaultItemFormat(TRUE, UDATPG_ItemFormat, LENGTHOF(UDATPG_ItemFormat)-1); // Read-only alias.
+
+ for (i=0; i<UDATPG_FIELD_COUNT; ++i ) {
+ appendItemNames[i]=CAP_F;
+ if (i<10) {
+ appendItemNames[i]+=(UChar)(i+0x30);
+ }
+ else {
+ appendItemNames[i]+=(UChar)0x31;
+ appendItemNames[i]+=(UChar)(i-10 + 0x30);
+ }
+ // NUL-terminate for the C API.
+ appendItemNames[i].getTerminatedBuffer();
+ }
+
+ rb = ures_open(NULL, locale.getName(), &err);
+ calBundle = ures_getByKey(rb, DT_DateTimeCalendarTag, NULL, &err);
+ gregorianBundle = ures_getByKey(calBundle, DT_DateTimeGregorianTag, NULL, &err);
+
+ key=NULL;
+ int32_t dtCount=0;
+ patBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimePatternsTag, NULL, &err);
+ while (U_SUCCESS(err)) {
+ rbPattern = ures_getNextUnicodeString(patBundle, &key, &err);
+ dtCount++;
+ if (rbPattern.length()==0 ) {
+ break; // no more pattern
+ }
+ else {
+ if (dtCount==9) {
+ setDateTimeFormat(rbPattern);
+ }
+ }
+ };
+ ures_close(patBundle);
+
+ err = U_ZERO_ERROR;
+ patBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimeAppendItemsTag, NULL, &err);
+ key=NULL;
+ UnicodeString itemKey;
+ while (U_SUCCESS(err)) {
+ rbPattern = ures_getNextUnicodeString(patBundle, &key, &err);
+ if (rbPattern.length()==0 ) {
+ break; // no more pattern
+ }
+ else {
+ setAppendItemFormat(getAppendFormatNumber(key), rbPattern);
+ }
+ }
+ ures_close(patBundle);
+
+ key=NULL;
+ err = U_ZERO_ERROR;
+ fBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimeFieldsTag, NULL, &err);
+ for (i=0; i<MAX_RESOURCE_FIELD; ++i) {
+ err = U_ZERO_ERROR;
+ patBundle = ures_getByKeyWithFallback(fBundle, Resource_Fields[i], NULL, &err);
+ fieldBundle = ures_getByKeyWithFallback(patBundle, "dn", NULL, &err);
+ rbPattern = ures_getNextUnicodeString(fieldBundle, &key, &err);
+ ures_close(fieldBundle);
+ ures_close(patBundle);
+ if (rbPattern.length()==0 ) {
+ continue;
+ }
+ else {
+ setAppendItemName(getAppendNameNumber(Resource_Fields[i]), rbPattern);
+ }
+ }
+ ures_close(fBundle);
+
+ // add available formats
+ err = U_ZERO_ERROR;
+ initHashtable(err);
+ patBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimeAvailableFormatsTag, NULL, &err);
+ if (U_SUCCESS(err)) {
+ int32_t numberKeys = ures_getSize(patBundle);
+ int32_t len;
+ const UChar *retPattern;
+ key=NULL;
+ for(i=0; i<numberKeys; ++i) {
+ retPattern=ures_getNextString(patBundle, &len, &key, &err);
+ UnicodeString format=UnicodeString(retPattern);
+ UnicodeString retKey=UnicodeString(key, -1, US_INV);
+ setAvailableFormat(retKey, err);
+ conflictingStatus = addPattern(format, FALSE, conflictingPattern, err);
+ }
+ }
+ ures_close(patBundle);
+ ures_close(gregorianBundle);
+ ures_close(calBundle);
+ ures_close(rb);
+
+ err = U_ZERO_ERROR;
+ char parentLocale[50];
+ const char *curLocaleName=locale.getName();
+ int32_t localeNameLen=0;
+ uprv_strcpy(parentLocale, curLocaleName);
+ while((localeNameLen=uloc_getParent(parentLocale, parentLocale, 50, &err))>=0 ) {
+ rb = ures_open(NULL, parentLocale, &err);
+ calBundle = ures_getByKey(rb, DT_DateTimeCalendarTag, NULL, &err);
+ gregorianBundle = ures_getByKey(calBundle, DT_DateTimeGregorianTag, NULL, &err);
+ patBundle = ures_getByKeyWithFallback(gregorianBundle, DT_DateTimeAvailableFormatsTag, NULL, &err);
+ if (U_SUCCESS(err)) {
+ int32_t numberKeys = ures_getSize(patBundle);
+ int32_t len;
+ const UChar *retPattern;
+ key=NULL;
+
+ for(i=0; i<numberKeys; ++i) {
+ retPattern=ures_getNextString(patBundle, &len, &key, &err);
+ UnicodeString format=UnicodeString(retPattern);
+ UnicodeString retKey=UnicodeString(key, -1, US_INV);
+ if ( !isAvailableFormatSet(retKey) ) {
+ setAvailableFormat(retKey, err);
+ conflictingStatus = addPattern(format, FALSE, conflictingPattern, err);
+ }
+ }
+ }
+ ures_close(patBundle);
+ ures_close(gregorianBundle);
+ ures_close(calBundle);
+ ures_close(rb);
+ if (localeNameLen==0) {
+ break;
+ }
+ }
+
+ if (hackPattern.length()>0) {
+ hackTimes(hackPattern, err);
+ }
+}
+
+void
+DateTimePatternGenerator::initHashtable(UErrorCode& err) {
+ if (fAvailableFormatKeyHash!=NULL) {
+ return;
+ }
+ if ((fAvailableFormatKeyHash = new Hashtable(FALSE, err))==NULL) {
+ err=U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+}
+
+
+void
+DateTimePatternGenerator::setAppendItemFormat(UDateTimePatternField field, const UnicodeString& value) {
+ appendItemFormats[field] = value;
+ // NUL-terminate for the C API.
+ appendItemFormats[field].getTerminatedBuffer();
+}
+
+const UnicodeString&
+DateTimePatternGenerator::getAppendItemFormat(UDateTimePatternField field) const {
+ return appendItemFormats[field];
+}
+
+void
+DateTimePatternGenerator::setAppendItemName(UDateTimePatternField field, const UnicodeString& value) {
+ appendItemNames[field] = value;
+ // NUL-terminate for the C API.
+ appendItemNames[field].getTerminatedBuffer();
+}
+
+const UnicodeString&
+DateTimePatternGenerator:: getAppendItemName(UDateTimePatternField field) const {
+ return appendItemNames[field];
+}
+
+void
+DateTimePatternGenerator::getAppendName(UDateTimePatternField field, UnicodeString& value) {
+ value = SINGLE_QUOTE;
+ value += appendItemNames[field];
+ value += SINGLE_QUOTE;
+}
+
+UnicodeString
+DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UErrorCode& status) {
+ const UnicodeString *bestPattern=NULL;
+ UnicodeString dtFormat;
+ UnicodeString resultPattern;
+
+ int32_t dateMask=(1<<UDATPG_DAYPERIOD_FIELD) - 1;
+ int32_t timeMask=(1<<UDATPG_FIELD_COUNT) - 1 - dateMask;
+
+ resultPattern.remove();
+ dtMatcher->set(patternForm, fp);
+ bestPattern=getBestRaw(*dtMatcher, -1, distanceInfo);
+ if ( distanceInfo->missingFieldMask==0 && distanceInfo->extraFieldMask==0 ) {
+ resultPattern = adjustFieldTypes(*bestPattern, FALSE);
+
+ return resultPattern;
+ }
+ int32_t neededFields = dtMatcher->getFieldMask();
+ UnicodeString datePattern=getBestAppending(neededFields & dateMask);
+ UnicodeString timePattern=getBestAppending(neededFields & timeMask);
+ if (datePattern.length()==0) {
+ if (timePattern.length()==0) {
+ resultPattern.remove();
+ }
+ else {
+ return timePattern;
+ }
+ }
+ if (timePattern.length()==0) {
+ return datePattern;
+ }
+ resultPattern.remove();
+ status = U_ZERO_ERROR;
+ dtFormat=getDateTimeFormat();
+ Formattable dateTimeObject[] = { datePattern, timePattern };
+ resultPattern = MessageFormat::format(dtFormat, dateTimeObject, 2, resultPattern, status );
+ return resultPattern;
+}
+
+UnicodeString
+DateTimePatternGenerator::replaceFieldTypes(const UnicodeString& pattern,
+ const UnicodeString& skeleton,
+ UErrorCode& status) {
+ dtMatcher->set(skeleton, fp);
+ UnicodeString result = adjustFieldTypes(pattern, FALSE);
+ return result;
+}
+
+void
+DateTimePatternGenerator::setDecimal(const UnicodeString& newDecimal) {
+ this->decimal = newDecimal;
+ // NUL-terminate for the C API.
+ this->decimal.getTerminatedBuffer();
+}
+
+const UnicodeString&
+DateTimePatternGenerator::getDecimal() const {
+ return decimal;
+}
+
+void
+DateTimePatternGenerator::addCanonicalItems() {
+ UnicodeString conflictingPattern;
+ UDateTimePatternConflict conflictingStatus;
+ UErrorCode status = U_ZERO_ERROR;
+
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; i++) {
+ conflictingStatus = addPattern(UnicodeString(Canonical_Items[i]), FALSE, conflictingPattern, status);
+ }
+}
+
+void
+DateTimePatternGenerator::setDateTimeFormat(const UnicodeString& dtFormat) {
+ dateTimeFormat = dtFormat;
+ // NUL-terminate for the C API.
+ dateTimeFormat.getTerminatedBuffer();
+}
+
+const UnicodeString&
+DateTimePatternGenerator::getDateTimeFormat() const {
+ return dateTimeFormat;
+}
+
+void
+DateTimePatternGenerator::setDateTimeFromCalendar(const Locale& locale, UErrorCode& status) {
+ const UChar *resStr;
+ int32_t resStrLen = 0;
+
+ Calendar* fCalendar = Calendar::createInstance(locale, status);
+ CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
+ UResourceBundle *dateTimePatterns = calData.getByKey(DT_DateTimePatternsTag, status);
+ if (U_FAILURE(status)) return;
+
+ if (ures_getSize(dateTimePatterns) <= DateFormat::kDateTime)
+ {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)DateFormat::kDateTime, &resStrLen, &status);
+ setDateTimeFormat(UnicodeString(TRUE, resStr, resStrLen));
+
+ delete fCalendar;
+}
+
+void
+DateTimePatternGenerator::setDecimalSymbols(const Locale& locale, UErrorCode& status) {
+ DecimalFormatSymbols dfs = DecimalFormatSymbols(locale, status);
+ if(U_SUCCESS(status)) {
+ decimal = dfs.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ // NUL-terminate for the C API.
+ decimal.getTerminatedBuffer();
+ }
+}
+
+UDateTimePatternConflict
+DateTimePatternGenerator::addPattern(
+ const UnicodeString& pattern,
+ UBool override,
+ UnicodeString &conflictingPattern,
+ UErrorCode& status)
+{
+
+ UnicodeString basePattern;
+ PtnSkeleton skeleton;
+ UDateTimePatternConflict conflictingStatus = UDATPG_NO_CONFLICT;
+
+ DateTimeMatcher matcher;
+ matcher.set(pattern, fp, skeleton);
+ matcher.getBasePattern(basePattern);
+ const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern);
+ if (duplicatePattern != NULL ) {
+ conflictingStatus = UDATPG_BASE_CONFLICT;
+ conflictingPattern = *duplicatePattern;
+ if (!override) {
+ return conflictingStatus;
+ }
+ }
+ duplicatePattern = patternMap->getPatternFromSkeleton(skeleton);
+ if (duplicatePattern != NULL ) {
+ conflictingStatus = UDATPG_CONFLICT;
+ conflictingPattern = *duplicatePattern;
+ if (!override) {
+ return conflictingStatus;
+ }
+ }
+ patternMap->add(basePattern, skeleton, pattern, status);
+ if(U_FAILURE(status)) {
+ return conflictingStatus;
+ }
+
+ return UDATPG_NO_CONFLICT;
+}
+
+
+UDateTimePatternField
+DateTimePatternGenerator::getAppendFormatNumber(const char* field) const {
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
+ if (uprv_strcmp(CLDR_FIELD_APPEND[i], field)==0) {
+ return (UDateTimePatternField)i;
+ }
+ }
+ return UDATPG_FIELD_COUNT;
+}
+
+UDateTimePatternField
+DateTimePatternGenerator::getAppendNameNumber(const char* field) const {
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
+ if (uprv_strcmp(CLDR_FIELD_NAME[i],field)==0) {
+ return (UDateTimePatternField)i;
+ }
+ }
+ return UDATPG_FIELD_COUNT;
+}
+
+const UnicodeString*
+DateTimePatternGenerator::getBestRaw(DateTimeMatcher& source,
+ int32_t includeMask,
+ DistanceInfo* missingFields) {
+ int32_t bestDistance = 0x7fffffff;
+ DistanceInfo tempInfo;
+ const UnicodeString *bestPattern=NULL;
+
+ PatternMapIterator it;
+ for (it.set(*patternMap); it.hasNext(); ) {
+ DateTimeMatcher trial = it.next();
+ if (trial.equals(skipMatcher)) {
+ continue;
+ }
+ int32_t distance=source.getDistance(trial, includeMask, tempInfo);
+ if (distance<bestDistance) {
+ bestDistance=distance;
+ bestPattern=patternMap->getPatternFromSkeleton(*trial.getSkeletonPtr());
+ missingFields->setTo(tempInfo);
+ if (distance==0) {
+ break;
+ }
+ }
+ }
+
+ return bestPattern;
+}
+
+UnicodeString
+DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern,
+ UBool fixFractionalSeconds) {
+ UnicodeString newPattern;
+ fp->set(pattern);
+ for (int32_t i=0; i < fp->itemNumber; i++) {
+ UnicodeString field = fp->items[i];
+ if ( fp->isQuoteLiteral(field) ) {
+
+ UnicodeString quoteLiteral;
+ fp->getQuoteLiteral(quoteLiteral, &i);
+ newPattern += quoteLiteral;
+ }
+ else {
+ if (fp->isPatternSeparator(field)) {
+ newPattern+=field;
+ continue;
+ }
+ int32_t canonicalIndex = fp->getCanonicalIndex(field);
+ if (canonicalIndex < 0) {
+ newPattern+=field;
+ continue; // don't adjust
+ }
+ const dtTypeElem *row = &dtTypes[canonicalIndex];
+ int32_t typeValue = row->field;
+ if (fixFractionalSeconds && typeValue == UDATPG_SECOND_FIELD) {
+ UnicodeString newField=dtMatcher->skeleton.original[UDATPG_FRACTIONAL_SECOND_FIELD];
+ field = field + decimal + newField;
+ }
+ else {
+ if (dtMatcher->skeleton.type[typeValue]!=0) {
+ UnicodeString newField=dtMatcher->skeleton.original[typeValue];
+ if (typeValue!= UDATPG_HOUR_FIELD) {
+ field=newField;
+ }
+ else {
+ if (field.length()!=newField.length()) {
+ UChar c=field.charAt(0);
+ field.remove();
+ for (int32_t i=newField.length(); i>0; --i) {
+ field+=c;
+ }
+ }
+ }
+ }
+ newPattern+=field;
+ }
+ }
+ }
+ return newPattern;
+}
+
+UnicodeString
+DateTimePatternGenerator::getBestAppending(int32_t missingFields) {
+ UnicodeString resultPattern, tempPattern, formattedPattern;
+ UErrorCode err=U_ZERO_ERROR;
+ int32_t lastMissingFieldMask=0;
+ if (missingFields!=0) {
+ resultPattern=UnicodeString();
+ tempPattern = *getBestRaw(*dtMatcher, missingFields, distanceInfo);
+ resultPattern = adjustFieldTypes(tempPattern, FALSE);
+ if ( distanceInfo->missingFieldMask==0 ) {
+ return resultPattern;
+ }
+ while (distanceInfo->missingFieldMask!=0) { // precondition: EVERY single field must work!
+ if ( lastMissingFieldMask == distanceInfo->missingFieldMask ) {
+ break; // cannot find the proper missing field
+ }
+ if (((distanceInfo->missingFieldMask & UDATPG_SECOND_AND_FRACTIONAL_MASK)==UDATPG_FRACTIONAL_MASK) &&
+ ((missingFields & UDATPG_SECOND_AND_FRACTIONAL_MASK) == UDATPG_SECOND_AND_FRACTIONAL_MASK)) {
+ resultPattern = adjustFieldTypes(resultPattern, FALSE);
+ //resultPattern = tempPattern;
+ distanceInfo->missingFieldMask &= ~UDATPG_FRACTIONAL_MASK;
+ continue;
+ }
+ int32_t startingMask = distanceInfo->missingFieldMask;
+ tempPattern = *getBestRaw(*dtMatcher, distanceInfo->missingFieldMask, distanceInfo);
+ tempPattern = adjustFieldTypes(tempPattern, FALSE);
+ int32_t foundMask=startingMask& ~distanceInfo->missingFieldMask;
+ int32_t topField=getTopBitNumber(foundMask);
+ UnicodeString appendName;
+ getAppendName((UDateTimePatternField)topField, appendName);
+ const Formattable formatPattern[] = {
+ resultPattern,
+ tempPattern,
+ appendName
+ };
+ formattedPattern = MessageFormat::format(appendItemFormats[topField], formatPattern, 3, resultPattern, err);
+ lastMissingFieldMask = distanceInfo->missingFieldMask;
+ }
+ }
+ return formattedPattern;
+}
+
+int32_t
+DateTimePatternGenerator::getTopBitNumber(int32_t foundMask) {
+ if ( foundMask==0 ) {
+ return 0;
+ }
+ int32_t i=0;
+ while (foundMask!=0) {
+ foundMask >>=1;
+ ++i;
+ }
+ if (i-1 >UDATPG_ZONE_FIELD) {
+ return UDATPG_ZONE_FIELD;
+ }
+ else
+ return i-1;
+}
+
+void
+DateTimePatternGenerator::setAvailableFormat(const UnicodeString &key, UErrorCode& err)
+{
+ fAvailableFormatKeyHash->puti(key, 1, err);
+}
+
+UBool
+DateTimePatternGenerator::isAvailableFormatSet(const UnicodeString &key) const {
+ return (UBool)(fAvailableFormatKeyHash->geti(key) == 1);
+}
+
+void
+DateTimePatternGenerator::copyHashtable(Hashtable *other) {
+
+ if (fAvailableFormatKeyHash !=NULL) {
+ delete fAvailableFormatKeyHash;
+ }
+ if (other == NULL) {
+ fAvailableFormatKeyHash = NULL;
+ return;
+ }
+ initHashtable(fStatus);
+ if(U_FAILURE(fStatus)){
+ return;
+ }
+ int32_t pos = -1;
+ const UHashElement* elem = NULL;
+ // walk through the hash table and create a deep clone
+ while((elem = other->nextElement(pos))!= NULL){
+ const UHashTok otherKeyTok = elem->key;
+ UnicodeString* otherKey = (UnicodeString*)otherKeyTok.pointer;
+ fAvailableFormatKeyHash->puti(*otherKey, 1, fStatus);
+ if(U_FAILURE(fStatus)){
+ return;
+ }
+ }
+}
+
+StringEnumeration*
+DateTimePatternGenerator::getSkeletons(UErrorCode& status) const {
+ StringEnumeration* skeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_SKELETON, status);
+ return skeletonEnumerator;
+}
+
+const UnicodeString&
+DateTimePatternGenerator::getPatternForSkeleton(const UnicodeString& skeleton) const {
+ PtnElem *curElem;
+
+ if (skeleton.length() ==0) {
+ return emptyString;
+ }
+ curElem = patternMap->getHeader(skeleton.charAt(0));
+ while ( curElem != NULL ) {
+ if ( curElem->skeleton->getSkeleton()==skeleton ) {
+ return curElem->pattern;
+ }
+ curElem=curElem->next;
+ }
+ return emptyString;
+}
+
+StringEnumeration*
+DateTimePatternGenerator::getBaseSkeletons(UErrorCode& status) const {
+ StringEnumeration* baseSkeletonEnumerator = new DTSkeletonEnumeration(*patternMap, DT_BASESKELETON, status);
+ return baseSkeletonEnumerator;
+}
+
+StringEnumeration*
+DateTimePatternGenerator::getRedundants(UErrorCode& status) {
+ StringEnumeration* output = new DTRedundantEnumeration();
+ const UnicodeString *pattern;
+ PatternMapIterator it;
+ for (it.set(*patternMap); it.hasNext(); ) {
+ DateTimeMatcher current = it.next();
+ pattern = patternMap->getPatternFromSkeleton(*(it.getSkeleton()));
+ if ( isCanonicalItem(*pattern) ) {
+ continue;
+ }
+ if ( skipMatcher == NULL ) {
+ skipMatcher = new DateTimeMatcher(current);
+ }
+ else {
+ *skipMatcher = current;
+ }
+ UnicodeString trial = getBestPattern(current.getPattern(), status);
+ if (trial == *pattern) {
+ ((DTRedundantEnumeration *)output)->add(*pattern, status);
+ }
+ if (current.equals(skipMatcher)) {
+ continue;
+ }
+ }
+ return output;
+}
+
+UBool
+DateTimePatternGenerator::isCanonicalItem(const UnicodeString& item) const {
+ if ( item.length() != 1 ) {
+ return FALSE;
+ }
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (item.charAt(0)==Canonical_Items[i]) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+DateTimePatternGenerator*
+DateTimePatternGenerator::clone() const {
+ return new DateTimePatternGenerator(*this);
+}
+
+PatternMap::PatternMap() {
+ for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
+ boot[i]=NULL;
+ }
+ isDupAllowed = TRUE;
+}
+
+void
+PatternMap::copyFrom(const PatternMap& other, UErrorCode& status) {
+ this->isDupAllowed = other.isDupAllowed;
+ for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
+ PtnElem *curElem, *otherElem, *prevElem=NULL;
+ otherElem = other.boot[bootIndex];
+ while (otherElem!=NULL) {
+ if ((curElem = new PtnElem(otherElem->basePattern, otherElem->pattern))==NULL) {
+ // out of memory
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if ( this->boot[bootIndex]== NULL ) {
+ this->boot[bootIndex] = curElem;
+ }
+ if ((curElem->skeleton=new PtnSkeleton(*(otherElem->skeleton))) == NULL ) {
+ // out of memory
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ if (prevElem!=NULL) {
+ prevElem->next=curElem;
+ }
+ curElem->next=NULL;
+ prevElem = curElem;
+ otherElem = otherElem->next;
+ }
+
+ }
+}
+
+PtnElem*
+PatternMap::getHeader(UChar baseChar) {
+ PtnElem* curElem;
+
+ if ( (baseChar >= CAP_A) && (baseChar <= CAP_Z) ) {
+ curElem = boot[baseChar-CAP_A];
+ }
+ else {
+ if ( (baseChar >=LOW_A) && (baseChar <= LOW_Z) ) {
+ curElem = boot[26+baseChar-LOW_A];
+ }
+ else {
+ return NULL;
+ }
+ }
+ return curElem;
+}
+
+PatternMap::~PatternMap() {
+ for (int32_t i=0; i < MAX_PATTERN_ENTRIES; ++i ) {
+ if (boot[i]!=NULL ) {
+ delete boot[i];
+ boot[i]=NULL;
+ }
+ }
+} // PatternMap destructor
+
+void
+PatternMap::add(const UnicodeString& basePattern,
+ const PtnSkeleton& skeleton,
+ const UnicodeString& value,// mapped pattern value
+ UErrorCode &status) {
+ UChar baseChar = basePattern.charAt(0);
+ PtnElem *curElem, *baseElem;
+ status = U_ZERO_ERROR;
+
+ // the baseChar must be A-Z or a-z
+ if ((baseChar >= CAP_A) && (baseChar <= CAP_Z)) {
+ baseElem = boot[baseChar-CAP_A];
+ }
+ else {
+ if ((baseChar >=LOW_A) && (baseChar <= LOW_Z)) {
+ baseElem = boot[26+baseChar-LOW_A];
+ }
+ else {
+ status = U_ILLEGAL_CHARACTER;
+ return;
+ }
+ }
+
+ if (baseElem == NULL) {
+ if ((curElem = new PtnElem(basePattern, value)) == NULL ) {
+ // out of memory
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (baseChar >= LOW_A) {
+ boot[26 + (baseChar-LOW_A)] = curElem;
+ }
+ else {
+ boot[baseChar-CAP_A] = curElem;
+ }
+ curElem->skeleton = new PtnSkeleton(skeleton);
+ }
+ if ( baseElem != NULL ) {
+ curElem = getDuplicateElem(basePattern, skeleton, baseElem);
+
+ if (curElem == NULL) {
+ // add new element to the list.
+ curElem = baseElem;
+ while( curElem -> next != NULL )
+ {
+ curElem = curElem->next;
+ }
+ if ((curElem->next = new PtnElem(basePattern, value)) == NULL ) {
+ // out of memory
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ curElem=curElem->next;
+ curElem->skeleton = new PtnSkeleton(skeleton);
+ }
+ else {
+ // Pattern exists in the list already.
+ if ( !isDupAllowed ) {
+ return;
+ }
+ // Overwrite the value.
+ curElem->pattern = value;
+ }
+ }
+} // PatternMap::add
+
+// Find the pattern from the given basePattern string.
+const UnicodeString *
+PatternMap::getPatternFromBasePattern(UnicodeString& basePattern) { // key to search for
+ PtnElem *curElem;
+
+ if ((curElem=getHeader(basePattern.charAt(0)))==NULL) {
+ return NULL; // no match
+ }
+
+ do {
+ if ( basePattern.compare(curElem->basePattern)==0 ) {
+ return &(curElem->pattern);
+ }
+ curElem=curElem->next;
+ }while (curElem != NULL);
+
+ return NULL;
+} // PatternMap::getFromBasePattern
+
+
+// Find the pattern from the given skeleton.
+const UnicodeString *
+PatternMap::getPatternFromSkeleton(PtnSkeleton& skeleton) { // key to search for
+ PtnElem *curElem;
+
+ // find boot entry
+ UChar baseChar='\0';
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (skeleton.baseOriginal[i].length() !=0 ) {
+ baseChar = skeleton.baseOriginal[i].charAt(0);
+ break;
+ }
+ }
+
+ if ((curElem=getHeader(baseChar))==NULL) {
+ return NULL; // no match
+ }
+
+ do {
+ int32_t i=0;
+ for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (curElem->skeleton->baseOriginal[i].compare(skeleton.baseOriginal[i]) != 0 )
+ {
+ break;
+ }
+ }
+ if (i == UDATPG_FIELD_COUNT) {
+ return &(curElem->pattern);
+ }
+ curElem=curElem->next;
+ }while (curElem != NULL);
+
+ return NULL;
+}
+
+UBool
+PatternMap::equals(const PatternMap& other) {
+ if ( this==&other ) {
+ return TRUE;
+ }
+ for (int32_t bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
+ if ( boot[bootIndex]==other.boot[bootIndex] ) {
+ continue;
+ }
+ if ( (boot[bootIndex]==NULL)||(other.boot[bootIndex]==NULL) ) {
+ return FALSE;
+ }
+ PtnElem *otherElem = other.boot[bootIndex];
+ PtnElem *myElem = boot[bootIndex];
+ while ((otherElem!=NULL) || (myElem!=NULL)) {
+ if ( myElem == otherElem ) {
+ break;
+ }
+ if ((otherElem==NULL) || (myElem==NULL)) {
+ return FALSE;
+ }
+ if ( (myElem->basePattern != otherElem->basePattern) ||
+ (myElem->pattern != otherElem->pattern) ) {
+ return FALSE;
+ }
+ if ((myElem->skeleton!=otherElem->skeleton)&&
+ !myElem->skeleton->equals(*(otherElem->skeleton))) {
+ return FALSE;
+ }
+ myElem = myElem->next;
+ otherElem=otherElem->next;
+ }
+ }
+ return TRUE;
+}
+
+// find any key existing in the mapping table already.
+// return TRUE if there is an existing key, otherwise return FALSE.
+PtnElem*
+PatternMap::getDuplicateElem(
+ const UnicodeString &basePattern,
+ const PtnSkeleton &skeleton,
+ PtnElem *baseElem) {
+ PtnElem *curElem;
+
+ if ( baseElem == (PtnElem *)NULL ) {
+ return (PtnElem*)NULL;
+ }
+ else {
+ curElem = baseElem;
+ }
+ do {
+ if ( basePattern.compare(curElem->basePattern)==0 ) {
+ UBool isEqual=TRUE;
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (curElem->skeleton->type[i] != skeleton.type[i] ) {
+ isEqual=FALSE;
+ break;
+ }
+ }
+ if (isEqual) {
+ return curElem;
+ }
+ }
+ curElem = curElem->next;
+ } while( curElem != (PtnElem *)NULL );
+
+ // end of the list
+ return (PtnElem*)NULL;
+
+} // PatternMap::getDuplicateElem
+
+DateTimeMatcher::DateTimeMatcher(void) {
+}
+
+DateTimeMatcher::DateTimeMatcher(const DateTimeMatcher& other) {
+ copyFrom(other.skeleton);
+}
+
+
+void
+DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp) {
+ PtnSkeleton localSkeleton;
+ return set(pattern, fp, localSkeleton);
+}
+
+void
+DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton& skeletonResult) {
+ int32_t i;
+ for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ skeletonResult.type[i]=NONE;
+ }
+ fp->set(pattern);
+ for (i=0; i < fp->itemNumber; i++) {
+ UnicodeString field = fp->items[i];
+ if ( field.charAt(0) == LOW_A ) {
+ continue; // skip 'a'
+ }
+
+ if ( fp->isQuoteLiteral(field) ) {
+ UnicodeString quoteLiteral;
+ fp->getQuoteLiteral(quoteLiteral, &i);
+ continue;
+ }
+ int32_t canonicalIndex = fp->getCanonicalIndex(field);
+ if (canonicalIndex < 0 ) {
+ continue;
+ }
+ const dtTypeElem *row = &dtTypes[canonicalIndex];
+ int32_t typeValue = row->field;
+ skeletonResult.original[typeValue]=field;
+ UChar repeatChar = row->patternChar;
+ int32_t repeatCount = row->minLen > 3 ? 3: row->minLen;
+ while (repeatCount-- > 0) {
+ skeletonResult.baseOriginal[typeValue] += repeatChar;
+ }
+ int16_t subTypeValue = row->type;
+ if ( row->type > 0) {
+ subTypeValue += field.length();
+ }
+ skeletonResult.type[typeValue] = (int8_t)subTypeValue;
+ }
+ copyFrom(skeletonResult);
+}
+
+void
+DateTimeMatcher::getBasePattern(UnicodeString &result ) {
+ result.remove(); // Reset the result first.
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
+ if (skeleton.baseOriginal[i].length()!=0) {
+ result += skeleton.baseOriginal[i];
+ }
+ }
+}
+
+UnicodeString
+DateTimeMatcher::getPattern() {
+ UnicodeString result;
+
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
+ if (skeleton.original[i].length()!=0) {
+ result += skeleton.original[i];
+ }
+ }
+ return result;
+}
+
+int32_t
+DateTimeMatcher::getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo) {
+ int32_t result=0;
+ distanceInfo.clear();
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i ) {
+ int32_t myType = (includeMask&(1<<i))==0 ? 0 : skeleton.type[i];
+ int32_t otherType = other.skeleton.type[i];
+ if (myType==otherType) {
+ continue;
+ }
+ if (myType==0) {// and other is not
+ result += EXTRA_FIELD;
+ distanceInfo.addExtra(i);
+ }
+ else {
+ if (otherType==0) {
+ result += MISSING_FIELD;
+ distanceInfo.addMissing(i);
+ }
+ else {
+ result += abs(myType - otherType);
+ }
+ }
+
+ }
+ return result;
+}
+
+void
+DateTimeMatcher::copyFrom(const PtnSkeleton& newSkeleton) {
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ this->skeleton.type[i]=newSkeleton.type[i];
+ this->skeleton.original[i]=newSkeleton.original[i];
+ this->skeleton.baseOriginal[i]=newSkeleton.baseOriginal[i];
+ }
+}
+
+void
+DateTimeMatcher::copyFrom() {
+ // same as clear
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ this->skeleton.type[i]=0;
+ this->skeleton.original[i].remove();
+ this->skeleton.baseOriginal[i].remove();
+ }
+}
+
+UBool
+DateTimeMatcher::equals(const DateTimeMatcher* other) const {
+ if (other==NULL) {
+ return FALSE;
+ }
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (this->skeleton.original[i]!=other->skeleton.original[i] ) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+int32_t
+DateTimeMatcher::getFieldMask() {
+ int32_t result=0;
+
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (skeleton.type[i]!=0) {
+ result |= (1<<i);
+ }
+ }
+ return result;
+}
+
+PtnSkeleton*
+DateTimeMatcher::getSkeletonPtr() {
+ return &skeleton;
+}
+
+FormatParser::FormatParser () {
+ status = START;
+ itemNumber=0;
+}
+
+
+FormatParser::~FormatParser () {
+}
+
+
+// Find the next token with the starting position and length
+// Note: the startPos may
+FormatParser::TokenStatus
+FormatParser::setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len) {
+ int32_t curLoc = startPos;
+ if ( curLoc >= pattern.length()) {
+ return DONE;
+ }
+ // check the current char is between A-Z or a-z
+ do {
+ UChar c=pattern.charAt(curLoc);
+ if ( (c>=CAP_A && c<=CAP_Z) || (c>=LOW_A && c<=LOW_Z) ) {
+ curLoc++;
+ }
+ else {
+ startPos = curLoc;
+ *len=1;
+ return ADD_TOKEN;
+ }
+
+ if ( pattern.charAt(curLoc)!= pattern.charAt(startPos) ) {
+ break; // not the same token
+ }
+ } while(curLoc <= pattern.length());
+ *len = curLoc-startPos;
+ return ADD_TOKEN;
+}
+
+void
+FormatParser::set(const UnicodeString& pattern) {
+ int32_t startPos=0;
+ TokenStatus result=START;
+ int32_t len=0;
+ itemNumber =0;
+
+ do {
+ result = setTokens( pattern, startPos, &len );
+ if ( result == ADD_TOKEN )
+ {
+ items[itemNumber++] = UnicodeString(pattern, startPos, len );
+ startPos += len;
+ }
+ else {
+ break;
+ }
+ } while (result==ADD_TOKEN && itemNumber < MAX_DT_TOKEN);
+}
+
+int32_t
+FormatParser::getCanonicalIndex(const UnicodeString& s) {
+ int32_t len = s.length();
+ UChar ch = s.charAt(0);
+ int32_t i=0;
+
+ while (dtTypes[i].patternChar!='\0') {
+ if ( dtTypes[i].patternChar!=ch ) {
+ ++i;
+ continue;
+ }
+ if (dtTypes[i].patternChar!=dtTypes[i+1].patternChar) {
+ return i;
+ }
+ if (dtTypes[i+1].minLen <= len) {
+ ++i;
+ continue;
+ }
+ return i;
+ }
+ return -1;
+}
+
+UBool
+FormatParser::isQuoteLiteral(const UnicodeString& s) const {
+ return (UBool)(s.charAt(0)==SINGLE_QUOTE);
+}
+
+// This function aussumes the current itemIndex points to the quote literal.
+// Please call isQuoteLiteral prior to this function.
+void
+FormatParser::getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex) {
+ int32_t i=*itemIndex;
+
+ quote.remove();
+ if (items[i].charAt(0)==SINGLE_QUOTE) {
+ quote += items[i];
+ ++i;
+ }
+ while ( i < itemNumber ) {
+ if ( items[i].charAt(0)==SINGLE_QUOTE ) {
+ if ( (i+1<itemNumber) && (items[i+1].charAt(0)==SINGLE_QUOTE)) {
+ // two single quotes e.g. 'o''clock'
+ quote += items[i++];
+ quote += items[i++];
+ continue;
+ }
+ else {
+ quote += items[i];
+ break;
+ }
+ }
+ else {
+ quote += items[i];
+ }
+ ++i;
+ }
+ *itemIndex=i;
+}
+
+UBool
+FormatParser::isPatternSeparator(UnicodeString& field) {
+ for (int32_t i=0; i<field.length(); ++i ) {
+ UChar c= field.charAt(i);
+ if ( (c==SINGLE_QUOTE) || (c==BACKSLASH) || (c==SPACE) || (c==COLON) ||
+ (c==QUOTATION_MARK) || (c==COMMA) || (c==HYPHEN) ||(items[i].charAt(0)==DOT) ) {
+ continue;
+ }
+ else {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+void
+DistanceInfo::setTo(DistanceInfo &other) {
+ missingFieldMask = other.missingFieldMask;
+ extraFieldMask= other.extraFieldMask;
+}
+
+PatternMapIterator::PatternMapIterator() {
+ bootIndex = 0;
+ nodePtr = NULL;
+ patternMap=NULL;
+ matcher= new DateTimeMatcher();
+}
+
+
+PatternMapIterator::~PatternMapIterator() {
+ delete matcher;
+}
+
+void
+PatternMapIterator::set(PatternMap& newPatternMap) {
+ this->patternMap=&newPatternMap;
+}
+
+PtnSkeleton*
+PatternMapIterator::getSkeleton() {
+ if ( nodePtr == NULL ) {
+ return NULL;
+ }
+ else {
+ return nodePtr->skeleton;
+ }
+}
+
+UBool
+PatternMapIterator::hasNext() {
+ int32_t headIndex=bootIndex;
+ PtnElem *curPtr=nodePtr;
+
+ if (patternMap==NULL) {
+ return FALSE;
+ }
+ while ( headIndex < MAX_PATTERN_ENTRIES ) {
+ if ( curPtr != NULL ) {
+ if ( curPtr->next != NULL ) {
+ return TRUE;
+ }
+ else {
+ headIndex++;
+ curPtr=NULL;
+ continue;
+ }
+ }
+ else {
+ if ( patternMap->boot[headIndex] != NULL ) {
+ return TRUE;
+ }
+ else {
+ headIndex++;
+ continue;
+ }
+ }
+
+ }
+ return FALSE;
+}
+
+DateTimeMatcher&
+PatternMapIterator::next() {
+ while ( bootIndex < MAX_PATTERN_ENTRIES ) {
+ if ( nodePtr != NULL ) {
+ if ( nodePtr->next != NULL ) {
+ nodePtr = nodePtr->next;
+ break;
+ }
+ else {
+ bootIndex++;
+ nodePtr=NULL;
+ continue;
+ }
+ }
+ else {
+ if ( patternMap->boot[bootIndex] != NULL ) {
+ nodePtr = patternMap->boot[bootIndex];
+ break;
+ }
+ else {
+ bootIndex++;
+ continue;
+ }
+ }
+ }
+ if (nodePtr!=NULL) {
+ matcher->copyFrom(*nodePtr->skeleton);
+ }
+ else {
+ matcher->copyFrom();
+ }
+ return *matcher;
+}
+
+PtnSkeleton::PtnSkeleton() {
+}
+
+
+PtnSkeleton::PtnSkeleton(const PtnSkeleton& other) {
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ this->type[i]=other.type[i];
+ this->original[i]=other.original[i];
+ this->baseOriginal[i]=other.baseOriginal[i];
+ }
+}
+
+UBool
+PtnSkeleton::equals(const PtnSkeleton& other) {
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if ( (type[i]!= other.type[i]) ||
+ (original[i]!=other.original[i]) ||
+ (baseOriginal[i]!=other.baseOriginal[i]) ) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+UnicodeString
+PtnSkeleton::getSkeleton() {
+ UnicodeString result;
+
+ for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) {
+ if (original[i].length()!=0) {
+ result += original[i];
+ }
+ }
+ return result;
+}
+
+UnicodeString
+PtnSkeleton::getBaseSkeleton() {
+ UnicodeString result;
+
+ for(int32_t i=0; i< UDATPG_FIELD_COUNT; ++i) {
+ if (baseOriginal[i].length()!=0) {
+ result += baseOriginal[i];
+ }
+ }
+ return result;
+}
+
+PtnSkeleton::~PtnSkeleton() {
+}
+
+PtnElem::PtnElem(const UnicodeString &basePat, const UnicodeString &pat) :
+basePattern(basePat),
+skeleton(NULL),
+pattern(pat),
+next(NULL)
+{
+}
+
+PtnElem::~PtnElem() {
+
+ if (next!=NULL) {
+ delete next;
+ }
+ delete skeleton;
+}
+
+DTSkeletonEnumeration::DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status) {
+ PtnElem *curElem;
+ PtnSkeleton *curSkeleton;
+ UnicodeString s;
+ int32_t bootIndex;
+
+ pos=0;
+ fSkeletons = new UVector(status);
+ if (U_FAILURE(status)) {
+ delete fSkeletons;
+ return;
+ }
+ for (bootIndex=0; bootIndex<MAX_PATTERN_ENTRIES; ++bootIndex ) {
+ curElem = patternMap.boot[bootIndex];
+ while (curElem!=NULL) {
+ switch(type) {
+ case DT_BASESKELETON:
+ s=curElem->basePattern;
+ break;
+ case DT_PATTERN:
+ s=curElem->pattern;
+ break;
+ case DT_SKELETON:
+ curSkeleton=curElem->skeleton;
+ s=curSkeleton->getSkeleton();
+ break;
+ }
+ if ( !isCanonicalItem(s) ) {
+ fSkeletons->addElement(new UnicodeString(s), status);
+ if (U_FAILURE(status)) {
+ delete fSkeletons;
+ fSkeletons = NULL;
+ return;
+ }
+ }
+ curElem = curElem->next;
+ }
+ }
+ if ((bootIndex==MAX_PATTERN_ENTRIES) && (curElem!=NULL) ) {
+ status = U_BUFFER_OVERFLOW_ERROR;
+ }
+}
+
+const UnicodeString*
+DTSkeletonEnumeration::snext(UErrorCode& status) {
+ if (U_SUCCESS(status) && pos < fSkeletons->size()) {
+ return (const UnicodeString*)fSkeletons->elementAt(pos++);
+ }
+ return NULL;
+}
+
+void
+DTSkeletonEnumeration::reset(UErrorCode& /*status*/) {
+ pos=0;
+}
+
+int32_t
+DTSkeletonEnumeration::count(UErrorCode& /*status*/) const {
+ return (fSkeletons==NULL) ? 0 : fSkeletons->size();
+}
+
+UBool
+DTSkeletonEnumeration::isCanonicalItem(const UnicodeString& item) {
+ if ( item.length() != 1 ) {
+ return FALSE;
+ }
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (item.charAt(0)==Canonical_Items[i]) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+DTSkeletonEnumeration::~DTSkeletonEnumeration() {
+ UnicodeString *s;
+ for (int32_t i=0; i<fSkeletons->size(); ++i) {
+ if ((s=(UnicodeString *)fSkeletons->elementAt(i))!=NULL) {
+ delete s;
+ }
+ }
+ delete fSkeletons;
+}
+
+DTRedundantEnumeration::DTRedundantEnumeration() {
+ pos=0;
+ fPatterns = NULL;
+}
+
+void
+DTRedundantEnumeration::add(const UnicodeString& pattern, UErrorCode& status) {
+ if (U_FAILURE(status)) return;
+ if (fPatterns == NULL) {
+ fPatterns = new UVector(status);
+ if (U_FAILURE(status)) {
+ delete fPatterns;
+ fPatterns = NULL;
+ return;
+ }
+ }
+ fPatterns->addElement(new UnicodeString(pattern), status);
+ if (U_FAILURE(status)) {
+ delete fPatterns;
+ fPatterns = NULL;
+ return;
+ }
+}
+
+const UnicodeString*
+DTRedundantEnumeration::snext(UErrorCode& status) {
+ if (U_SUCCESS(status) && pos < fPatterns->size()) {
+ return (const UnicodeString*)fPatterns->elementAt(pos++);
+ }
+ return NULL;
+}
+
+void
+DTRedundantEnumeration::reset(UErrorCode& /*status*/) {
+ pos=0;
+}
+
+int32_t
+DTRedundantEnumeration::count(UErrorCode& /*status*/) const {
+ return (fPatterns==NULL) ? 0 : fPatterns->size();
+}
+
+UBool
+DTRedundantEnumeration::isCanonicalItem(const UnicodeString& item) {
+ if ( item.length() != 1 ) {
+ return FALSE;
+ }
+ for (int32_t i=0; i<UDATPG_FIELD_COUNT; ++i) {
+ if (item.charAt(0)==Canonical_Items[i]) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+DTRedundantEnumeration::~DTRedundantEnumeration() {
+ UnicodeString *s;
+ for (int32_t i=0; i<fPatterns->size(); ++i) {
+ if ((s=(UnicodeString *)fPatterns->elementAt(i))!=NULL) {
+ delete s;
+ }
+ }
+ delete fPatterns;
+}
+
+U_NAMESPACE_END
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/dtptngen_impl.h b/Build/source/libs/icu/icu-xetex/i18n/dtptngen_impl.h
new file mode 100644
index 00000000000..73956ec6b4e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/dtptngen_impl.h
@@ -0,0 +1,256 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File DTPTNGEN.H
+*
+*******************************************************************************
+*/
+
+#include "uvector.h"
+
+#ifndef __DTPTNGEN_IMPL_H__
+#define __DTPTNGEN_IMPL_H__
+
+// TODO(claireho): Split off Builder class.
+// TODO(claireho): If splitting off Builder class: As subclass or independent?
+
+#define MAX_PATTERN_ENTRIES 52
+#define MAX_CLDR_FIELD_LEN 60
+#define MAX_DT_TOKEN 50
+#define MAX_RESOURCE_FIELD 12
+#define MAX_AVAILABLE_FORMATS 12
+#define NONE 0
+#define EXTRA_FIELD 0x10000
+#define MISSING_FIELD 0x1000
+#define MAX_STRING_ENUMERATION 200
+#define SINGLE_QUOTE ((UChar)0x0027)
+#define FORWARDSLASH ((UChar)0x002F)
+#define BACKSLASH ((UChar)0x005C)
+#define SPACE ((UChar)0x0020)
+#define QUOTATION_MARK ((UChar)0x0022)
+#define ASTERISK ((UChar)0x002A)
+#define PLUSSITN ((UChar)0x002B)
+#define COMMA ((UChar)0x002C)
+#define HYPHEN ((UChar)0x002D)
+#define DOT ((UChar)0x002E)
+#define COLON ((UChar)0x003A)
+#define CAP_A ((UChar)0x0041)
+#define CAP_C ((UChar)0x0043)
+#define CAP_D ((UChar)0x0044)
+#define CAP_E ((UChar)0x0045)
+#define CAP_F ((UChar)0x0046)
+#define CAP_G ((UChar)0x0047)
+#define CAP_H ((UChar)0x0048)
+#define CAP_L ((UChar)0x004C)
+#define CAP_M ((UChar)0x004D)
+#define CAP_O ((UChar)0x004F)
+#define CAP_Q ((UChar)0x0051)
+#define CAP_S ((UChar)0x0053)
+#define CAP_T ((UChar)0x0054)
+#define CAP_V ((UChar)0x0056)
+#define CAP_W ((UChar)0x0057)
+#define CAP_Y ((UChar)0x0059)
+#define CAP_Z ((UChar)0x005A)
+#define LOWLINE ((UChar)0x005F)
+#define LOW_A ((UChar)0x0061)
+#define LOW_C ((UChar)0x0063)
+#define LOW_D ((UChar)0x0064)
+#define LOW_E ((UChar)0x0065)
+#define LOW_F ((UChar)0x0066)
+#define LOW_G ((UChar)0x0067)
+#define LOW_H ((UChar)0x0068)
+#define LOW_I ((UChar)0x0069)
+#define LOW_K ((UChar)0x006B)
+#define LOW_L ((UChar)0x006C)
+#define LOW_M ((UChar)0x006D)
+#define LOW_N ((UChar)0x006E)
+#define LOW_O ((UChar)0x006F)
+#define LOW_P ((UChar)0x0070)
+#define LOW_Q ((UChar)0x0071)
+#define LOW_R ((UChar)0x0072)
+#define LOW_S ((UChar)0x0073)
+#define LOW_T ((UChar)0x0074)
+#define LOW_U ((UChar)0x0075)
+#define LOW_V ((UChar)0x0076)
+#define LOW_W ((UChar)0x0077)
+#define LOW_Y ((UChar)0x0079)
+#define LOW_Z ((UChar)0x007A)
+#define DT_SHORT -0x101
+#define DT_LONG -0x102
+#define DT_NUMERIC 0x100
+#define DT_NARROW -0x100
+#define DT_DELTA 0x10
+
+U_NAMESPACE_BEGIN
+
+const int32_t UDATPG_FRACTIONAL_MASK = 1<<UDATPG_FRACTIONAL_SECOND_FIELD;
+const int32_t UDATPG_SECOND_AND_FRACTIONAL_MASK = (1<<UDATPG_SECOND_FIELD) | (1<<UDATPG_FRACTIONAL_SECOND_FIELD);
+
+typedef enum dtStrEnum {
+ DT_BASESKELETON,
+ DT_SKELETON,
+ DT_PATTERN
+}dtStrEnum;
+
+typedef struct dtTypeElem {
+ UChar patternChar;
+ UDateTimePatternField field;
+ int32_t type;
+ int32_t minLen;
+ int32_t weight;
+}dtTypeElem;
+
+class PtnSkeleton : public UMemory {
+public:
+ int32_t type[UDATPG_FIELD_COUNT];
+ UnicodeString original[UDATPG_FIELD_COUNT];
+ UnicodeString baseOriginal[UDATPG_FIELD_COUNT];
+
+ PtnSkeleton();
+ PtnSkeleton(const PtnSkeleton& other);
+ UBool equals(const PtnSkeleton& other);
+ UnicodeString getSkeleton();
+ UnicodeString getBaseSkeleton();
+ virtual ~PtnSkeleton();
+};
+
+
+class PtnElem : public UMemory {
+public:
+ UnicodeString basePattern;
+ PtnSkeleton *skeleton;
+ UnicodeString pattern;
+ PtnElem *next;
+
+ PtnElem(const UnicodeString &basePattern, const UnicodeString &pattern);
+ virtual ~PtnElem();
+
+};
+
+class FormatParser : public UMemory {
+public:
+ UnicodeString items[MAX_DT_TOKEN];
+ int32_t itemNumber;
+
+ FormatParser();
+ virtual ~FormatParser();
+ void set(const UnicodeString& patternString);
+ UBool isQuoteLiteral(const UnicodeString& s) const;
+ void getQuoteLiteral(UnicodeString& quote, int32_t *itemIndex);
+ int32_t getCanonicalIndex(const UnicodeString& s);
+ UBool isPatternSeparator(UnicodeString& field);
+ void setFilter(UErrorCode &status);
+
+private:
+ typedef enum TokenStatus {
+ START,
+ ADD_TOKEN,
+ SYNTAX_ERROR,
+ DONE
+ } ToeknStatus;
+
+ TokenStatus status;
+ virtual TokenStatus setTokens(const UnicodeString& pattern, int32_t startPos, int32_t *len);
+};
+
+class DistanceInfo : public UMemory {
+public:
+ int32_t missingFieldMask;
+ int32_t extraFieldMask;
+
+ DistanceInfo() {};
+ virtual ~DistanceInfo() {};
+ void clear() { missingFieldMask = extraFieldMask = 0; };
+ void setTo(DistanceInfo& other);
+ void addMissing(int32_t field) { missingFieldMask |= (1<<field); };
+ void addExtra(int32_t field) { extraFieldMask |= (1<<field); };
+};
+
+class DateTimeMatcher: public UMemory {
+public:
+ PtnSkeleton skeleton;
+
+ void getBasePattern(UnicodeString &basePattern);
+ UnicodeString getPattern();
+ void set(const UnicodeString& pattern, FormatParser* fp);
+ void set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton& skeleton);
+ void copyFrom(const PtnSkeleton& skeleton);
+ void copyFrom();
+ PtnSkeleton* getSkeletonPtr();
+ UBool equals(const DateTimeMatcher* other) const;
+ int32_t getDistance(const DateTimeMatcher& other, int32_t includeMask, DistanceInfo& distanceInfo);
+ DateTimeMatcher();
+ DateTimeMatcher(const DateTimeMatcher& other);
+ virtual ~DateTimeMatcher() {};
+ int32_t getFieldMask();
+};
+
+class PatternMap : public UMemory {
+public:
+ PtnElem *boot[MAX_PATTERN_ENTRIES];
+ PatternMap();
+ virtual ~PatternMap();
+ void add(const UnicodeString& basePattern, const PtnSkeleton& skeleton, const UnicodeString& value, UErrorCode& status);
+ UErrorCode status;
+ const UnicodeString* getPatternFromBasePattern(UnicodeString& basePattern);
+ const UnicodeString* getPatternFromSkeleton(PtnSkeleton& skeleton);
+ void copyFrom(const PatternMap& other, UErrorCode& status);
+ PtnElem* getHeader(UChar baseChar);
+ UBool equals(const PatternMap& other);
+private:
+ UBool isDupAllowed;
+ PtnElem* getDuplicateElem(const UnicodeString &basePattern, const PtnSkeleton& skeleton, PtnElem *baseElem);
+}; // end PatternMap
+
+class PatternMapIterator : public UMemory {
+public:
+ PatternMapIterator();
+ virtual ~PatternMapIterator();
+ void set(PatternMap& patternMap);
+ PtnSkeleton* getSkeleton();
+ UBool hasNext();
+ DateTimeMatcher& next();
+private:
+ int32_t bootIndex;
+ PtnElem *nodePtr;
+ DateTimeMatcher *matcher;
+ PatternMap *patternMap;
+};
+
+class U_I18N_API DTSkeletonEnumeration : public StringEnumeration {
+public:
+ DTSkeletonEnumeration(PatternMap &patternMap, dtStrEnum type, UErrorCode& status);
+ virtual ~DTSkeletonEnumeration();
+ static UClassID U_EXPORT2 getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+ virtual const UnicodeString* snext(UErrorCode& status);
+ virtual void reset(UErrorCode& status);
+ virtual int32_t count(UErrorCode& status) const;
+private:
+ int32_t pos;
+ UBool isCanonicalItem(const UnicodeString& item);
+ UVector *fSkeletons;
+};
+
+class U_I18N_API DTRedundantEnumeration : public StringEnumeration {
+public:
+ DTRedundantEnumeration();
+ virtual ~DTRedundantEnumeration();
+ static UClassID U_EXPORT2 getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+ virtual const UnicodeString* snext(UErrorCode& status);
+ virtual void reset(UErrorCode& status);
+ virtual int32_t count(UErrorCode& status) const;
+ void add(const UnicodeString &pattern, UErrorCode& status);
+private:
+ int32_t pos;
+ UBool isCanonicalItem(const UnicodeString& item);
+ UVector *fPatterns;
+};
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/dtrule.cpp b/Build/source/libs/icu/icu-xetex/i18n/dtrule.cpp
new file mode 100644
index 00000000000..42140249648
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/dtrule.cpp
@@ -0,0 +1,137 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/dtrule.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateTimeRule)
+
+DateTimeRule::DateTimeRule(int32_t month,
+ int32_t dayOfMonth,
+ int32_t millisInDay,
+ TimeRuleType timeType)
+: fMonth(month), fDayOfMonth(dayOfMonth), fDayOfWeek(0), fWeekInMonth(0), fMillisInDay(millisInDay),
+ fDateRuleType(DateTimeRule::DOM), fTimeRuleType(timeType) {
+}
+
+DateTimeRule::DateTimeRule(int32_t month,
+ int32_t weekInMonth,
+ int32_t dayOfWeek,
+ int32_t millisInDay,
+ TimeRuleType timeType)
+: fMonth(month), fDayOfMonth(0), fDayOfWeek(dayOfWeek), fWeekInMonth(weekInMonth), fMillisInDay(millisInDay),
+ fDateRuleType(DateTimeRule::DOW), fTimeRuleType(timeType) {
+}
+
+DateTimeRule::DateTimeRule(int32_t month,
+ int32_t dayOfMonth,
+ int32_t dayOfWeek,
+ UBool after,
+ int32_t millisInDay,
+ TimeRuleType timeType)
+: UObject(),
+ fMonth(month), fDayOfMonth(dayOfMonth), fDayOfWeek(dayOfWeek), fWeekInMonth(0), fMillisInDay(millisInDay),
+ fTimeRuleType(timeType) {
+ if (after) {
+ fDateRuleType = DateTimeRule::DOW_GEQ_DOM;
+ } else {
+ fDateRuleType = DateTimeRule::DOW_LEQ_DOM;
+ }
+}
+
+DateTimeRule::DateTimeRule(const DateTimeRule& source)
+: UObject(source),
+ fMonth(source.fMonth), fDayOfMonth(source.fDayOfMonth), fDayOfWeek(source.fDayOfWeek),
+ fWeekInMonth(source.fWeekInMonth), fMillisInDay(source.fMillisInDay),
+ fDateRuleType(source.fDateRuleType), fTimeRuleType(source.fTimeRuleType) {
+}
+
+DateTimeRule::~DateTimeRule() {
+}
+
+DateTimeRule*
+DateTimeRule::clone() const {
+ return new DateTimeRule(*this);
+}
+
+DateTimeRule&
+DateTimeRule::operator=(const DateTimeRule& right) {
+ if (this != &right) {
+ fMonth = right.fMonth;
+ fDayOfMonth = right.fDayOfMonth;
+ fDayOfWeek = right.fDayOfWeek;
+ fWeekInMonth = right.fWeekInMonth;
+ fMillisInDay = right.fMillisInDay;
+ fDateRuleType = right.fDateRuleType;
+ fTimeRuleType = right.fTimeRuleType;
+ }
+ return *this;
+}
+
+UBool
+DateTimeRule::operator==(const DateTimeRule& that) const {
+ return ((this == &that) ||
+ (getDynamicClassID() == that.getDynamicClassID() &&
+ fMonth == that.fMonth &&
+ fDayOfMonth == that.fDayOfMonth &&
+ fDayOfWeek == that.fDayOfWeek &&
+ fWeekInMonth == that.fWeekInMonth &&
+ fMillisInDay == that.fMillisInDay &&
+ fDateRuleType == that.fDateRuleType &&
+ fTimeRuleType == that.fTimeRuleType));
+}
+
+UBool
+DateTimeRule::operator!=(const DateTimeRule& that) const {
+ return !operator==(that);
+}
+
+DateTimeRule::DateRuleType
+DateTimeRule::getDateRuleType(void) const {
+ return fDateRuleType;
+}
+
+DateTimeRule::TimeRuleType
+DateTimeRule::getTimeRuleType(void) const {
+ return fTimeRuleType;
+}
+
+int32_t
+DateTimeRule::getRuleMonth(void) const {
+ return fMonth;
+}
+
+int32_t
+DateTimeRule::getRuleDayOfMonth(void) const {
+ return fDayOfMonth;
+}
+
+int32_t
+DateTimeRule::getRuleDayOfWeek(void) const {
+ return fDayOfWeek;
+}
+
+int32_t
+DateTimeRule::getRuleWeekInMonth(void) const {
+ return fWeekInMonth;
+}
+
+int32_t
+DateTimeRule::getRuleMillisInDay(void) const {
+ return fMillisInDay;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/esctrn.cpp b/Build/source/libs/icu/icu-xetex/i18n/esctrn.cpp
new file mode 100644
index 00000000000..93f13f5816c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/esctrn.cpp
@@ -0,0 +1,179 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/19/2001 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "esctrn.h"
+#include "util.h"
+
+U_NAMESPACE_BEGIN
+
+static const UChar UNIPRE[] = {85,43,0}; // "U+"
+static const UChar BS_u[] = {92,117,0}; // "\\u"
+static const UChar BS_U[] = {92,85,0}; // "\\U"
+static const UChar XMLPRE[] = {38,35,120,0}; // "&#x"
+static const UChar XML10PRE[] = {38,35,0}; // "&#"
+static const UChar PERLPRE[] = {92,120,123,0}; // "\\x{"
+static const UChar SEMI[] = {59,0}; // ";"
+static const UChar RBRACE[] = {125,0}; // "}"
+static const UChar EMPTY[] = {0}; // ""
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EscapeTransliterator)
+
+/**
+ * Factory methods
+ */
+static Transliterator* _createEscUnicode(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ // Unicode: "U+10FFFF" hex, min=4, max=6
+ return new EscapeTransliterator(ID, UNIPRE, EMPTY, 16, 4, TRUE, NULL);
+}
+static Transliterator* _createEscJava(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ // Java: "\\uFFFF" hex, min=4, max=4
+ return new EscapeTransliterator(ID, BS_u, EMPTY, 16, 4, FALSE, NULL);
+}
+static Transliterator* _createEscC(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ // C: "\\uFFFF" hex, min=4, max=4; \\U0010FFFF hex, min=8, max=8
+ return new EscapeTransliterator(ID, BS_u, EMPTY, 16, 4, TRUE,
+ new EscapeTransliterator(EMPTY, BS_U, EMPTY, 16, 8, TRUE, NULL));
+}
+static Transliterator* _createEscXML(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ // XML: "&#x10FFFF;" hex, min=1, max=6
+ return new EscapeTransliterator(ID, XMLPRE, SEMI, 16, 1, TRUE, NULL);
+}
+static Transliterator* _createEscXML10(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ // XML10: "&1114111;" dec, min=1, max=7 (not really "Any-Hex")
+ return new EscapeTransliterator(ID, XML10PRE, SEMI, 10, 1, TRUE, NULL);
+}
+static Transliterator* _createEscPerl(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ // Perl: "\\x{263A}" hex, min=1, max=6
+ return new EscapeTransliterator(ID, PERLPRE, RBRACE, 16, 1, TRUE, NULL);
+}
+
+/**
+ * Registers standard variants with the system. Called by
+ * Transliterator during initialization.
+ */
+void EscapeTransliterator::registerIDs() {
+ Token t = integerToken(0);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-Hex/Unicode"), _createEscUnicode, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-Hex/Java"), _createEscJava, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-Hex/C"), _createEscC, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-Hex/XML"), _createEscXML, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-Hex/XML10"), _createEscXML10, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-Hex/Perl"), _createEscPerl, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-Hex"), _createEscJava, t);
+}
+
+/**
+ * Constructs an escape transliterator with the given ID and
+ * parameters. See the class member documentation for details.
+ */
+EscapeTransliterator::EscapeTransliterator(const UnicodeString& newID,
+ const UnicodeString& _prefix, const UnicodeString& _suffix,
+ int32_t _radix, int32_t _minDigits,
+ UBool _grokSupplementals,
+ EscapeTransliterator* adoptedSupplementalHandler) :
+ Transliterator(newID, NULL)
+{
+ this->prefix = _prefix;
+ this->suffix = _suffix;
+ this->radix = _radix;
+ this->minDigits = _minDigits;
+ this->grokSupplementals = _grokSupplementals;
+ this->supplementalHandler = adoptedSupplementalHandler;
+}
+
+/**
+ * Copy constructor.
+ */
+EscapeTransliterator::EscapeTransliterator(const EscapeTransliterator& o) :
+ Transliterator(o),
+ prefix(o.prefix),
+ suffix(o.suffix),
+ radix(o.radix),
+ minDigits(o.minDigits),
+ grokSupplementals(o.grokSupplementals) {
+ supplementalHandler = (o.supplementalHandler != 0) ?
+ new EscapeTransliterator(*o.supplementalHandler) : NULL;
+}
+
+EscapeTransliterator::~EscapeTransliterator() {
+ delete supplementalHandler;
+}
+
+/**
+ * Transliterator API.
+ */
+Transliterator* EscapeTransliterator::clone() const {
+ return new EscapeTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void EscapeTransliterator::handleTransliterate(Replaceable& text,
+ UTransPosition& pos,
+ UBool /*isIncremental*/) const
+{
+ /* TODO: Verify that isIncremental can be ignored */
+ int32_t start = pos.start;
+ int32_t limit = pos.limit;
+
+ UnicodeString buf(prefix);
+ int32_t prefixLen = prefix.length();
+ UBool redoPrefix = FALSE;
+
+ while (start < limit) {
+ int32_t c = grokSupplementals ? text.char32At(start) : text.charAt(start);
+ int32_t charLen = grokSupplementals ? UTF_CHAR_LENGTH(c) : 1;
+
+ if ((c & 0xFFFF0000) != 0 && supplementalHandler != NULL) {
+ buf.truncate(0);
+ buf.append(supplementalHandler->prefix);
+ ICU_Utility::appendNumber(buf, c, supplementalHandler->radix,
+ supplementalHandler->minDigits);
+ buf.append(supplementalHandler->suffix);
+ redoPrefix = TRUE;
+ } else {
+ if (redoPrefix) {
+ buf.truncate(0);
+ buf.append(prefix);
+ redoPrefix = FALSE;
+ } else {
+ buf.truncate(prefixLen);
+ }
+ ICU_Utility::appendNumber(buf, c, radix, minDigits);
+ buf.append(suffix);
+ }
+
+ text.handleReplaceBetween(start, start + charLen, buf);
+ start += buf.length();
+ limit += buf.length() - charLen;
+ }
+
+ pos.contextLimit += limit - pos.limit;
+ pos.limit = limit;
+ pos.start = start;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/esctrn.h b/Build/source/libs/icu/icu-xetex/i18n/esctrn.h
new file mode 100644
index 00000000000..96872b91684
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/esctrn.h
@@ -0,0 +1,142 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/20/2001 aliu Creation.
+**********************************************************************
+*/
+#ifndef ESCTRN_H
+#define ESCTRN_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that converts Unicode characters to an escape
+ * form. Examples of escape forms are "U+4E01" and "&#x10FFFF;".
+ * Escape forms have a prefix and suffix, either of which may be
+ * empty, a radix, typically 16 or 10, a minimum digit count,
+ * typically 1, 4, or 8, and a boolean that specifies whether
+ * supplemental characters are handled as 32-bit code points or as two
+ * 16-bit code units. Most escape forms handle 32-bit code points,
+ * but some, such as the Java form, intentionally break them into two
+ * surrogate pairs, for backward compatibility.
+ *
+ * <p>Some escape forms actually have two different patterns, one for
+ * BMP characters (0..FFFF) and one for supplements (>FFFF). To
+ * handle this, a second EscapeTransliterator may be defined that
+ * specifies the pattern to be produced for supplementals. An example
+ * of a form that requires this is the C form, which uses "\\uFFFF"
+ * for BMP characters and "\\U0010FFFF" for supplementals.
+ *
+ * <p>This class is package private. It registers several standard
+ * variants with the system which are then accessed via their IDs.
+ *
+ * @author Alan Liu
+ */
+class EscapeTransliterator : public Transliterator {
+
+ private:
+
+ /**
+ * The prefix of the escape form; may be empty, but usually isn't.
+ */
+ UnicodeString prefix;
+
+ /**
+ * The prefix of the escape form; often empty.
+ */
+ UnicodeString suffix;
+
+ /**
+ * The radix to display the number in. Typically 16 or 10. Must
+ * be in the range 2 to 36.
+ */
+ int32_t radix;
+
+ /**
+ * The minimum number of digits. Typically 1, 4, or 8. Values
+ * less than 1 are equivalent to 1.
+ */
+ int32_t minDigits;
+
+ /**
+ * If true, supplementals are handled as 32-bit code points. If
+ * false, they are handled as two 16-bit code units.
+ */
+ UBool grokSupplementals;
+
+ /**
+ * The form to be used for supplementals. If this is null then
+ * the same form is used for BMP characters and supplementals. If
+ * this is not null and if grokSupplementals is true then the
+ * prefix, suffix, radix, and minDigits of this object are used
+ * for supplementals. This pointer is owned.
+ */
+ EscapeTransliterator* supplementalHandler;
+
+ public:
+
+ /**
+ * Registers standard variants with the system. Called by
+ * Transliterator during initialization.
+ */
+ static void registerIDs();
+
+ /**
+ * Constructs an escape transliterator with the given ID and
+ * parameters. See the class member documentation for details.
+ */
+ EscapeTransliterator(const UnicodeString& ID,
+ const UnicodeString& prefix, const UnicodeString& suffix,
+ int32_t radix, int32_t minDigits,
+ UBool grokSupplementals,
+ EscapeTransliterator* adoptedSupplementalHandler);
+
+ /**
+ * Copy constructor.
+ */
+ EscapeTransliterator(const EscapeTransliterator&);
+
+ /**
+ * Destructor.
+ */
+ virtual ~EscapeTransliterator();
+
+ /**
+ * Transliterator API.
+ */
+ virtual Transliterator* clone() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+ protected:
+
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& offset,
+ UBool isIncremental) const;
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/fmtable.cpp b/Build/source/libs/icu/icu-xetex/i18n/fmtable.cpp
new file mode 100644
index 00000000000..b767b332166
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/fmtable.cpp
@@ -0,0 +1,679 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File FMTABLE.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 03/25/97 clhuang Initial Implementation.
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/fmtable.h"
+#include "unicode/ustring.h"
+#include "unicode/measure.h"
+#include "unicode/curramt.h"
+#include "cmemory.h"
+
+// *****************************************************************************
+// class Formattable
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable)
+
+//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
+
+// NOTE: As of 3.0, there are limitations to the UObject API. It does
+// not (yet) support cloning, operator=, nor operator==. RTTI is also
+// restricted in that subtype testing is not (yet) implemented. To
+// work around this, I implement some simple inlines here. Later
+// these can be modified or removed. [alan]
+
+// NOTE: These inlines assume that all fObjects are in fact instances
+// of the Measure class, which is true as of 3.0. [alan]
+
+// Return TRUE if *a == *b.
+static inline UBool objectEquals(const UObject* a, const UObject* b) {
+ // LATER: return *a == *b;
+ return *((const Measure*) a) == *((const Measure*) b);
+}
+
+// Return a clone of *a.
+static inline UObject* objectClone(const UObject* a) {
+ // LATER: return a->clone();
+ return ((const Measure*) a)->clone();
+}
+
+// Return TRUE if *a is an instance of Measure.
+static inline UBool instanceOfMeasure(const UObject* a) {
+ // LATER: return a->instanceof(Measure::getStaticClassID());
+ return a->getDynamicClassID() ==
+ CurrencyAmount::getStaticClassID();
+}
+
+/**
+ * Creates a new Formattable array and copies the values from the specified
+ * original.
+ * @param array the original array
+ * @param count the original array count
+ * @return the new Formattable array.
+ */
+static inline Formattable* createArrayCopy(const Formattable* array, int32_t count) {
+ Formattable *result = new Formattable[count];
+ for (int32_t i=0; i<count; ++i) result[i] = array[i]; // Don't memcpy!
+ return result;
+}
+
+//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.
+
+/**
+ * Set 'ec' to 'err' only if 'ec' is not already set to a failing UErrorCode.
+ */
+static inline void setError(UErrorCode& ec, UErrorCode err) {
+ if (U_SUCCESS(ec)) {
+ ec = err;
+ }
+}
+
+// -------------------------------------
+// default constructor.
+// Creates a formattable object with a long value 0.
+
+Formattable::Formattable()
+ : UObject(), fType(kLong)
+{
+ fBogus.setToBogus();
+ fValue.fInt64 = 0;
+}
+
+// -------------------------------------
+// Creates a formattable object with a Date instance.
+
+Formattable::Formattable(UDate date, ISDATE /*isDate*/)
+ : UObject(), fType(kDate)
+{
+ fBogus.setToBogus();
+ fValue.fDate = date;
+}
+
+// -------------------------------------
+// Creates a formattable object with a double value.
+
+Formattable::Formattable(double value)
+ : UObject(), fType(kDouble)
+{
+ fBogus.setToBogus();
+ fValue.fDouble = value;
+}
+
+// -------------------------------------
+// Creates a formattable object with a long value.
+
+Formattable::Formattable(int32_t value)
+ : UObject(), fType(kLong)
+{
+ fBogus.setToBogus();
+ fValue.fInt64 = value;
+}
+
+// -------------------------------------
+// Creates a formattable object with a long value.
+
+Formattable::Formattable(int64_t value)
+ : UObject(), fType(kInt64)
+{
+ fBogus.setToBogus();
+ fValue.fInt64 = value;
+}
+
+// -------------------------------------
+// Creates a formattable object with a UnicodeString instance.
+
+Formattable::Formattable(const UnicodeString& stringToCopy)
+ : UObject(), fType(kString)
+{
+ fBogus.setToBogus();
+ fValue.fString = new UnicodeString(stringToCopy);
+}
+
+// -------------------------------------
+// Creates a formattable object with a UnicodeString* value.
+// (adopting symantics)
+
+Formattable::Formattable(UnicodeString* stringToAdopt)
+ : UObject(), fType(kString)
+{
+ fBogus.setToBogus();
+ fValue.fString = stringToAdopt;
+}
+
+Formattable::Formattable(UObject* objectToAdopt)
+ : UObject(), fType(kObject)
+{
+ fBogus.setToBogus();
+ fValue.fObject = objectToAdopt;
+}
+
+// -------------------------------------
+
+Formattable::Formattable(const Formattable* arrayToCopy, int32_t count)
+ : UObject(), fType(kArray)
+{
+ fBogus.setToBogus();
+ fValue.fArrayAndCount.fArray = createArrayCopy(arrayToCopy, count);
+ fValue.fArrayAndCount.fCount = count;
+}
+
+// -------------------------------------
+// copy constructor
+
+Formattable::Formattable(const Formattable &source)
+ : UObject(source), fType(kLong)
+{
+ fBogus.setToBogus();
+ *this = source;
+}
+
+// -------------------------------------
+// assignment operator
+
+Formattable&
+Formattable::operator=(const Formattable& source)
+{
+ if (this != &source)
+ {
+ // Disposes the current formattable value/setting.
+ dispose();
+
+ // Sets the correct data type for this value.
+ fType = source.fType;
+ switch (fType)
+ {
+ case kArray:
+ // Sets each element in the array one by one and records the array count.
+ fValue.fArrayAndCount.fCount = source.fValue.fArrayAndCount.fCount;
+ fValue.fArrayAndCount.fArray = createArrayCopy(source.fValue.fArrayAndCount.fArray,
+ source.fValue.fArrayAndCount.fCount);
+ break;
+ case kString:
+ // Sets the string value.
+ fValue.fString = new UnicodeString(*source.fValue.fString);
+ break;
+ case kDouble:
+ // Sets the double value.
+ fValue.fDouble = source.fValue.fDouble;
+ break;
+ case kLong:
+ case kInt64:
+ // Sets the long value.
+ fValue.fInt64 = source.fValue.fInt64;
+ break;
+ case kDate:
+ // Sets the Date value.
+ fValue.fDate = source.fValue.fDate;
+ break;
+ case kObject:
+ fValue.fObject = objectClone(source.fValue.fObject);
+ break;
+ }
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+UBool
+Formattable::operator==(const Formattable& that) const
+{
+ int32_t i;
+
+ if (this == &that) return TRUE;
+
+ // Returns FALSE if the data types are different.
+ if (fType != that.fType) return FALSE;
+
+ // Compares the actual data values.
+ UBool equal = TRUE;
+ switch (fType) {
+ case kDate:
+ equal = (fValue.fDate == that.fValue.fDate);
+ break;
+ case kDouble:
+ equal = (fValue.fDouble == that.fValue.fDouble);
+ break;
+ case kLong:
+ case kInt64:
+ equal = (fValue.fInt64 == that.fValue.fInt64);
+ break;
+ case kString:
+ equal = (*(fValue.fString) == *(that.fValue.fString));
+ break;
+ case kArray:
+ if (fValue.fArrayAndCount.fCount != that.fValue.fArrayAndCount.fCount) {
+ equal = FALSE;
+ break;
+ }
+ // Checks each element for equality.
+ for (i=0; i<fValue.fArrayAndCount.fCount; ++i) {
+ if (fValue.fArrayAndCount.fArray[i] != that.fValue.fArrayAndCount.fArray[i]) {
+ equal = FALSE;
+ break;
+ }
+ }
+ break;
+ case kObject:
+ equal = objectEquals(fValue.fObject, that.fValue.fObject);
+ break;
+ }
+
+ return equal;
+}
+
+// -------------------------------------
+
+Formattable::~Formattable()
+{
+ dispose();
+}
+
+// -------------------------------------
+
+void Formattable::dispose()
+{
+ // Deletes the data value if necessary.
+ switch (fType) {
+ case kString:
+ delete fValue.fString;
+ break;
+ case kArray:
+ delete[] fValue.fArrayAndCount.fArray;
+ break;
+ case kObject:
+ delete fValue.fObject;
+ break;
+ default:
+ break;
+ }
+}
+
+Formattable *
+Formattable::clone() const {
+ return new Formattable(*this);
+}
+
+// -------------------------------------
+// Gets the data type of this Formattable object.
+Formattable::Type
+Formattable::getType() const
+{
+ return fType;
+}
+
+UBool
+Formattable::isNumeric() const {
+ switch (fType) {
+ case kDouble:
+ case kLong:
+ case kInt64:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+// -------------------------------------
+int32_t
+//Formattable::getLong(UErrorCode* status) const
+Formattable::getLong(UErrorCode& status) const
+{
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ switch (fType) {
+ case Formattable::kLong:
+ return (int32_t)fValue.fInt64;
+ case Formattable::kInt64:
+ if (fValue.fInt64 > INT32_MAX) {
+ status = U_INVALID_FORMAT_ERROR;
+ return INT32_MAX;
+ } else if (fValue.fInt64 < INT32_MIN) {
+ status = U_INVALID_FORMAT_ERROR;
+ return INT32_MIN;
+ } else {
+ return (int32_t)fValue.fInt64;
+ }
+ case Formattable::kDouble:
+ if (fValue.fDouble > INT32_MAX) {
+ status = U_INVALID_FORMAT_ERROR;
+ return INT32_MAX;
+ } else if (fValue.fDouble < INT32_MIN) {
+ status = U_INVALID_FORMAT_ERROR;
+ return INT32_MIN;
+ } else {
+ return (int32_t)fValue.fDouble; // loses fraction
+ }
+ case Formattable::kObject:
+ // TODO Later replace this with instanceof call
+ if (instanceOfMeasure(fValue.fObject)) {
+ return ((const Measure*) fValue.fObject)->
+ getNumber().getLong(status);
+ }
+ default:
+ status = U_INVALID_FORMAT_ERROR;
+ return 0;
+ }
+}
+
+// -------------------------------------
+int64_t
+Formattable::getInt64(UErrorCode& status) const
+{
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ switch (fType) {
+ case Formattable::kLong:
+ case Formattable::kInt64:
+ return fValue.fInt64;
+ case Formattable::kDouble:
+ if (fValue.fDouble > U_INT64_MAX) {
+ status = U_INVALID_FORMAT_ERROR;
+ return U_INT64_MAX;
+ } else if (fValue.fDouble < U_INT64_MIN) {
+ status = U_INVALID_FORMAT_ERROR;
+ return U_INT64_MIN;
+ } else {
+ return (int64_t)fValue.fDouble;
+ }
+ case Formattable::kObject:
+ // TODO Later replace this with instanceof call
+ if (instanceOfMeasure(fValue.fObject)) {
+ return ((const Measure*) fValue.fObject)->
+ getNumber().getInt64(status);
+ }
+ default:
+ status = U_INVALID_FORMAT_ERROR;
+ return 0;
+ }
+}
+
+// -------------------------------------
+double
+Formattable::getDouble(UErrorCode& status) const
+{
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ switch (fType) {
+ case Formattable::kLong:
+ case Formattable::kInt64: // loses precision
+ return (double)fValue.fInt64;
+ case Formattable::kDouble:
+ return fValue.fDouble;
+ case Formattable::kObject:
+ // TODO Later replace this with instanceof call
+ if (instanceOfMeasure(fValue.fObject)) {
+ return ((const Measure*) fValue.fObject)->
+ getNumber().getDouble(status);
+ }
+ default:
+ status = U_INVALID_FORMAT_ERROR;
+ return 0;
+ }
+}
+
+const UObject*
+Formattable::getObject() const {
+ return (fType == kObject) ? fValue.fObject : NULL;
+}
+
+// -------------------------------------
+// Sets the value to a double value d.
+
+void
+Formattable::setDouble(double d)
+{
+ dispose();
+ fType = kDouble;
+ fValue.fDouble = d;
+}
+
+// -------------------------------------
+// Sets the value to a long value l.
+
+void
+Formattable::setLong(int32_t l)
+{
+ dispose();
+ fType = kLong;
+ fValue.fInt64 = l;
+}
+
+// -------------------------------------
+// Sets the value to an int64 value ll.
+
+void
+Formattable::setInt64(int64_t ll)
+{
+ dispose();
+ fType = kInt64;
+ fValue.fInt64 = ll;
+}
+
+// -------------------------------------
+// Sets the value to a Date instance d.
+
+void
+Formattable::setDate(UDate d)
+{
+ dispose();
+ fType = kDate;
+ fValue.fDate = d;
+}
+
+// -------------------------------------
+// Sets the value to a string value stringToCopy.
+
+void
+Formattable::setString(const UnicodeString& stringToCopy)
+{
+ dispose();
+ fType = kString;
+ fValue.fString = new UnicodeString(stringToCopy);
+}
+
+// -------------------------------------
+// Sets the value to an array of Formattable objects.
+
+void
+Formattable::setArray(const Formattable* array, int32_t count)
+{
+ dispose();
+ fType = kArray;
+ fValue.fArrayAndCount.fArray = createArrayCopy(array, count);
+ fValue.fArrayAndCount.fCount = count;
+}
+
+// -------------------------------------
+// Adopts the stringToAdopt value.
+
+void
+Formattable::adoptString(UnicodeString* stringToAdopt)
+{
+ dispose();
+ fType = kString;
+ fValue.fString = stringToAdopt;
+}
+
+// -------------------------------------
+// Adopts the array value and its count.
+
+void
+Formattable::adoptArray(Formattable* array, int32_t count)
+{
+ dispose();
+ fType = kArray;
+ fValue.fArrayAndCount.fArray = array;
+ fValue.fArrayAndCount.fCount = count;
+}
+
+void
+Formattable::adoptObject(UObject* objectToAdopt) {
+ dispose();
+ fType = kObject;
+ fValue.fObject = objectToAdopt;
+}
+
+// -------------------------------------
+UnicodeString&
+Formattable::getString(UnicodeString& result, UErrorCode& status) const
+{
+ if (fType != kString) {
+ setError(status, U_INVALID_FORMAT_ERROR);
+ result.setToBogus();
+ } else {
+ result = *fValue.fString;
+ }
+ return result;
+}
+
+// -------------------------------------
+const UnicodeString&
+Formattable::getString(UErrorCode& status) const
+{
+ if (fType != kString) {
+ setError(status, U_INVALID_FORMAT_ERROR);
+ return *getBogus();
+ }
+ return *fValue.fString;
+}
+
+// -------------------------------------
+UnicodeString&
+Formattable::getString(UErrorCode& status)
+{
+ if (fType != kString) {
+ setError(status, U_INVALID_FORMAT_ERROR);
+ return *getBogus();
+ }
+ return *fValue.fString;
+}
+
+// -------------------------------------
+const Formattable*
+Formattable::getArray(int32_t& count, UErrorCode& status) const
+{
+ if (fType != kArray) {
+ setError(status, U_INVALID_FORMAT_ERROR);
+ count = 0;
+ return NULL;
+ }
+ count = fValue.fArrayAndCount.fCount;
+ return fValue.fArrayAndCount.fArray;
+}
+
+// -------------------------------------
+// Gets the bogus string, ensures mondo bogosity.
+
+UnicodeString*
+Formattable::getBogus() const
+{
+ return (UnicodeString*)&fBogus; /* cast away const :-( */
+}
+
+#if 0
+//----------------------------------------------------
+// console I/O
+//----------------------------------------------------
+#ifdef _DEBUG
+
+#if U_IOSTREAM_SOURCE >= 199711
+#include <iostream>
+using namespace std;
+#elif U_IOSTREAM_SOURCE >= 198506
+#include <iostream.h>
+#endif
+
+#include "unicode/datefmt.h"
+#include "unistrm.h"
+
+class FormattableStreamer /* not : public UObject because all methods are static */ {
+public:
+ static void streamOut(ostream& stream, const Formattable& obj);
+
+private:
+ FormattableStreamer() {} // private - forbid instantiation
+};
+
+// This is for debugging purposes only. This will send a displayable
+// form of the Formattable object to the output stream.
+
+void
+FormattableStreamer::streamOut(ostream& stream, const Formattable& obj)
+{
+ static DateFormat *defDateFormat = 0;
+
+ UnicodeString buffer;
+ switch(obj.getType()) {
+ case Formattable::kDate :
+ // Creates a DateFormat instance for formatting the
+ // Date instance.
+ if (defDateFormat == 0) {
+ defDateFormat = DateFormat::createInstance();
+ }
+ defDateFormat->format(obj.getDate(), buffer);
+ stream << buffer;
+ break;
+ case Formattable::kDouble :
+ // Output the double as is.
+ stream << obj.getDouble() << 'D';
+ break;
+ case Formattable::kLong :
+ // Output the double as is.
+ stream << obj.getLong() << 'L';
+ break;
+ case Formattable::kString:
+ // Output the double as is. Please see UnicodeString console
+ // I/O routine for more details.
+ stream << '"' << obj.getString(buffer) << '"';
+ break;
+ case Formattable::kArray:
+ int32_t i, count;
+ const Formattable* array;
+ array = obj.getArray(count);
+ stream << '[';
+ // Recursively calling the console I/O routine for each element in the array.
+ for (i=0; i<count; ++i) {
+ FormattableStreamer::streamOut(stream, array[i]);
+ stream << ( (i==(count-1)) ? "" : ", " );
+ }
+ stream << ']';
+ break;
+ default:
+ // Not a recognizable Formattable object.
+ stream << "INVALID_Formattable";
+ }
+ stream.flush();
+}
+#endif
+
+#endif
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/fmtable_cnv.cpp b/Build/source/libs/icu/icu-xetex/i18n/fmtable_cnv.cpp
new file mode 100644
index 00000000000..9a270997f5a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/fmtable_cnv.cpp
@@ -0,0 +1,44 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2005, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File FMTABLE.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 03/25/97 clhuang Initial Implementation.
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_CONVERSION
+
+#include "unicode/fmtable.h"
+
+// *****************************************************************************
+// class Formattable
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+// -------------------------------------
+// Creates a formattable object with a char* string.
+// This API is useless. The API that takes a UnicodeString is actually just as good.
+// This is just a grandfathered API.
+
+Formattable::Formattable(const char* stringToCopy)
+ : UObject(), fType(kString)
+{
+ fBogus.setToBogus();
+ fValue.fString = new UnicodeString(stringToCopy);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING || !UCONFIG_NO_CONVERSION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/format.cpp b/Build/source/libs/icu/icu-xetex/i18n/format.cpp
new file mode 100644
index 00000000000..883a41d575e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/format.cpp
@@ -0,0 +1,193 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File FORMAT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/17/97 clhuang Implemented with new APIs.
+* 03/27/97 helena Updated to pass the simple test after code review.
+* 07/20/98 stephen Added explicit init values for Field/ParsePosition
+********************************************************************************
+*/
+// *****************************************************************************
+// This file was generated from the java source file Format.java
+// *****************************************************************************
+
+#include "unicode/utypes.h"
+
+/*
+ * Dummy code:
+ * If all modules in the I18N library are switched off, then there are no
+ * library exports and MSVC 6 writes a .dll but not a .lib file.
+ * Unless we export _something_ in that case...
+ */
+#if UCONFIG_NO_COLLATION && UCONFIG_NO_FORMATTING && UCONFIG_NO_TRANSLITERATION
+U_CAPI int32_t U_EXPORT2
+uprv_icuin_lib_dummy(int32_t i) {
+ return -i;
+}
+#endif
+
+/* Format class implementation ---------------------------------------------- */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+#include "unicode/ures.h"
+#include "cstring.h"
+#include "locbased.h"
+
+// *****************************************************************************
+// class Format
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FieldPosition)
+
+FieldPosition::~FieldPosition() {}
+
+FieldPosition *
+FieldPosition::clone() const {
+ return new FieldPosition(*this);
+}
+
+// -------------------------------------
+// default constructor
+
+Format::Format()
+ : UObject()
+{
+ *validLocale = *actualLocale = 0;
+}
+
+// -------------------------------------
+
+Format::~Format()
+{
+}
+
+// -------------------------------------
+// copy constructor
+
+Format::Format(const Format &that)
+ : UObject(that)
+{
+ *this = that;
+}
+
+// -------------------------------------
+// assignment operator
+
+Format&
+Format::operator=(const Format& that)
+{
+ uprv_strcpy(validLocale, that.validLocale);
+ uprv_strcpy(actualLocale, that.actualLocale);
+ return *this;
+}
+
+// -------------------------------------
+// Formats the obj and append the result in the buffer, toAppendTo.
+// This calls the actual implementation in the concrete subclasses.
+
+UnicodeString&
+Format::format(const Formattable& obj,
+ UnicodeString& toAppendTo,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return toAppendTo;
+
+ FieldPosition pos(FieldPosition::DONT_CARE);
+
+ return format(obj, toAppendTo, pos, status);
+}
+
+// -------------------------------------
+// Parses the source string and create the corresponding
+// result object. Checks the parse position for errors.
+
+void
+Format::parseObject(const UnicodeString& source,
+ Formattable& result,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return;
+
+ ParsePosition parsePosition(0);
+ parseObject(source, result, parsePosition);
+ if (parsePosition.getIndex() == 0) {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+}
+
+// -------------------------------------
+
+UBool
+Format::operator==(const Format& that) const
+{
+ // Subclasses: Call this method and then add more specific checks.
+ return getDynamicClassID() == that.getDynamicClassID();
+}
+//---------------------------------------
+
+/**
+ * Simple function for initializing a UParseError from a UnicodeString.
+ *
+ * @param pattern The pattern to copy into the parseError
+ * @param pos The position in pattern where the error occured
+ * @param parseError The UParseError object to fill in
+ * @draft ICU 2.4
+ */
+void Format::syntaxError(const UnicodeString& pattern,
+ int32_t pos,
+ UParseError& parseError) {
+ parseError.offset = pos;
+ parseError.line=0; // we are not using line number
+
+ // for pre-context
+ int32_t start = (pos < U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1
+ /* subtract 1 so that we have room for null*/));
+ int32_t stop = pos;
+ pattern.extract(start,stop-start,parseError.preContext,0);
+ //null terminate the buffer
+ parseError.preContext[stop-start] = 0;
+
+ //for post-context
+ start = pos+1;
+ stop = ((pos+U_PARSE_CONTEXT_LEN)<=pattern.length()) ? (pos+(U_PARSE_CONTEXT_LEN-1)) :
+ pattern.length();
+ pattern.extract(start,stop-start,parseError.postContext,0);
+ //null terminate the buffer
+ parseError.postContext[stop-start]= 0;
+}
+
+Locale
+Format::getLocale(ULocDataLocaleType type, UErrorCode& status) const {
+ U_LOCALE_BASED(locBased, *this);
+ return locBased.getLocale(type, status);
+}
+
+const char *
+Format::getLocaleID(ULocDataLocaleType type, UErrorCode& status) const {
+ U_LOCALE_BASED(locBased, *this);
+ return locBased.getLocaleID(type, status);
+}
+
+void
+Format::setLocaleIDs(const char* valid, const char* actual) {
+ U_LOCALE_BASED(locBased, *this);
+ locBased.setLocaleIDs(valid, actual);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/funcrepl.cpp b/Build/source/libs/icu/icu-xetex/i18n/funcrepl.cpp
new file mode 100644
index 00000000000..61198a26592
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/funcrepl.cpp
@@ -0,0 +1,124 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2003, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 02/04/2002 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "unicode/uniset.h"
+#include "funcrepl.h"
+
+static const UChar AMPERSAND = 38; // '&'
+static const UChar OPEN[] = {40,32,0}; // "( "
+static const UChar CLOSE[] = {32,41,0}; // " )"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FunctionReplacer)
+
+/**
+ * Construct a replacer that takes the output of the given
+ * replacer, passes it through the given transliterator, and emits
+ * the result as output.
+ */
+FunctionReplacer::FunctionReplacer(Transliterator* adoptedTranslit,
+ UnicodeFunctor* adoptedReplacer) {
+ translit = adoptedTranslit;
+ replacer = adoptedReplacer;
+}
+
+/**
+ * Copy constructor.
+ */
+FunctionReplacer::FunctionReplacer(const FunctionReplacer& other) :
+ UnicodeFunctor(other),
+ UnicodeReplacer(other)
+{
+ translit = other.translit->clone();
+ replacer = other.replacer->clone();
+}
+
+/**
+ * Destructor
+ */
+FunctionReplacer::~FunctionReplacer() {
+ delete translit;
+ delete replacer;
+}
+
+/**
+ * Implement UnicodeFunctor
+ */
+UnicodeFunctor* FunctionReplacer::clone() const {
+ return new FunctionReplacer(*this);
+}
+
+/**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
+ * and return the pointer.
+ */
+UnicodeReplacer* FunctionReplacer::toReplacer() const {
+ return (UnicodeReplacer*) this;
+}
+
+/**
+ * UnicodeReplacer API
+ */
+int32_t FunctionReplacer::replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& cursor) {
+
+ // First delegate to subordinate replacer
+ int32_t len = replacer->toReplacer()->replace(text, start, limit, cursor);
+ limit = start + len;
+
+ // Now transliterate
+ limit = translit->transliterate(text, start, limit);
+
+ return limit - start;
+}
+
+/**
+ * UnicodeReplacer API
+ */
+UnicodeString& FunctionReplacer::toReplacerPattern(UnicodeString& rule,
+ UBool escapeUnprintable) const {
+ UnicodeString str;
+ rule.truncate(0);
+ rule.append(AMPERSAND);
+ rule.append(translit->getID());
+ rule.append(OPEN);
+ rule.append(replacer->toReplacer()->toReplacerPattern(str, escapeUnprintable));
+ rule.append(CLOSE);
+ return rule;
+}
+
+/**
+ * Implement UnicodeReplacer
+ */
+void FunctionReplacer::addReplacementSetTo(UnicodeSet& toUnionTo) const {
+ UnicodeSet set;
+ toUnionTo.addAll(translit->getTargetSet(set));
+}
+
+/**
+ * UnicodeFunctor API
+ */
+void FunctionReplacer::setData(const TransliterationRuleData* d) {
+ replacer->setData(d);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/funcrepl.h b/Build/source/libs/icu/icu-xetex/i18n/funcrepl.h
new file mode 100644
index 00000000000..f58d613bb5a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/funcrepl.h
@@ -0,0 +1,123 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2007, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 02/04/2002 aliu Creation.
+**********************************************************************
+*/
+
+#ifndef FUNCREPL_H
+#define FUNCREPL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifunct.h"
+#include "unicode/unirepl.h"
+
+U_NAMESPACE_BEGIN
+
+class Transliterator;
+
+/**
+ * A replacer that calls a transliterator to generate its output text.
+ * The input text to the transliterator is the output of another
+ * UnicodeReplacer object. That is, this replacer wraps another
+ * replacer with a transliterator.
+ *
+ * @author Alan Liu
+ */
+class FunctionReplacer : public UnicodeFunctor, public UnicodeReplacer {
+
+ private:
+
+ /**
+ * The transliterator. Must not be null. OWNED.
+ */
+ Transliterator* translit;
+
+ /**
+ * The replacer object. This generates text that is then
+ * processed by 'translit'. Must not be null. OWNED.
+ */
+ UnicodeFunctor* replacer;
+
+ public:
+
+ /**
+ * Construct a replacer that takes the output of the given
+ * replacer, passes it through the given transliterator, and emits
+ * the result as output.
+ */
+ FunctionReplacer(Transliterator* adoptedTranslit,
+ UnicodeFunctor* adoptedReplacer);
+
+ /**
+ * Copy constructor.
+ */
+ FunctionReplacer(const FunctionReplacer& other);
+
+ /**
+ * Destructor
+ */
+ virtual ~FunctionReplacer();
+
+ /**
+ * Implement UnicodeFunctor
+ */
+ virtual UnicodeFunctor* clone() const;
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
+ * and return the pointer.
+ */
+ virtual UnicodeReplacer* toReplacer() const;
+
+ /**
+ * UnicodeReplacer API
+ */
+ virtual int32_t replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& cursor);
+
+ /**
+ * UnicodeReplacer API
+ */
+ virtual UnicodeString& toReplacerPattern(UnicodeString& rule,
+ UBool escapeUnprintable) const;
+
+ /**
+ * Implement UnicodeReplacer
+ */
+ virtual void addReplacementSetTo(UnicodeSet& toUnionTo) const;
+
+ /**
+ * UnicodeFunctor API
+ */
+ virtual void setData(const TransliterationRuleData*);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+#endif
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/gregocal.cpp b/Build/source/libs/icu/icu-xetex/i18n/gregocal.cpp
new file mode 100644
index 00000000000..ba342505d5b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/gregocal.cpp
@@ -0,0 +1,1345 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File GREGOCAL.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/05/97 clhuang Creation.
+* 03/28/97 aliu Made highly questionable fix to computeFields to
+* handle DST correctly.
+* 04/22/97 aliu Cleaned up code drastically. Added monthLength().
+* Finished unimplemented parts of computeTime() for
+* week-based date determination. Removed quetionable
+* fix and wrote correct fix for computeFields() and
+* daylight time handling. Rewrote inDaylightTime()
+* and computeFields() to handle sensitive Daylight to
+* Standard time transitions correctly.
+* 05/08/97 aliu Added code review changes. Fixed isLeapYear() to
+* not cutover.
+* 08/12/97 aliu Added equivalentTo. Misc other fixes. Updated
+* add() from Java source.
+* 07/28/98 stephen Sync up with JDK 1.2
+* 09/14/98 stephen Changed type of kOneDay, kOneWeek to double.
+* Fixed bug in roll()
+* 10/15/99 aliu Fixed j31, incorrect WEEK_OF_YEAR computation.
+* 10/15/99 aliu Fixed j32, cannot set date to Feb 29 2000 AD.
+* {JDK bug 4210209 4209272}
+* 11/15/99 weiv Added YEAR_WOY and DOW_LOCAL computation
+* to timeToFields method, updated kMinValues, kMaxValues & kLeastMaxValues
+* 12/09/99 aliu Fixed j81, calculation errors and roll bugs
+* in year of cutover.
+* 01/24/2000 aliu Revised computeJulianDay for YEAR YEAR_WOY WOY.
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include <float.h>
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/gregocal.h"
+#include "gregoimp.h"
+#include "umutex.h"
+#include "uassert.h"
+
+// *****************************************************************************
+// class GregorianCalendar
+// *****************************************************************************
+
+/**
+* Note that the Julian date used here is not a true Julian date, since
+* it is measured from midnight, not noon. This value is the Julian
+* day number of January 1, 1970 (Gregorian calendar) at noon UTC. [LIU]
+*/
+
+static const int32_t kNumDays[]
+= {0,31,59,90,120,151,181,212,243,273,304,334}; // 0-based, for day-in-year
+static const int32_t kLeapNumDays[]
+= {0,31,60,91,121,152,182,213,244,274,305,335}; // 0-based, for day-in-year
+static const int32_t kMonthLength[]
+= {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
+static const int32_t kLeapMonthLength[]
+= {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
+
+// setTimeInMillis() limits the Julian day range to +/-7F000000.
+// This would seem to limit the year range to:
+// ms=+183882168921600000 jd=7f000000 December 20, 5828963 AD
+// ms=-184303902528000000 jd=81000000 September 20, 5838270 BC
+// HOWEVER, CalendarRegressionTest/Test4167060 shows that the actual
+// range limit on the year field is smaller (~ +/-140000). [alan 3.0]
+
+static const int32_t kGregorianCalendarLimits[UCAL_FIELD_COUNT][4] = {
+ // Minimum Greatest Least Maximum
+ // Minimum Maximum
+ { 0, 0, 1, 1 }, // ERA
+ { 1, 1, 140742, 144683 }, // YEAR
+ { 0, 0, 11, 11 }, // MONTH
+ { 1, 1, 52, 53 }, // WEEK_OF_YEAR
+ { 0, 0, 4, 6 }, // WEEK_OF_MONTH
+ { 1, 1, 28, 31 }, // DAY_OF_MONTH
+ { 1, 1, 365, 366 }, // DAY_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// DAY_OF_WEEK
+ { -1, -1, 4, 5 }, // DAY_OF_WEEK_IN_MONTH
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// AM_PM
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// HOUR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// HOUR_OF_DAY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// MINUTE
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// SECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// MILLISECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// ZONE_OFFSET
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// DST_OFFSET
+ { -140742, -140742, 140742, 144683 }, // YEAR_WOY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// DOW_LOCAL
+ { -140742, -140742, 140742, 144683 }, // EXTENDED_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1},// JULIAN_DAY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1} // MILLISECONDS_IN_DAY
+};
+
+/*
+* <pre>
+* Greatest Least
+* Field name Minimum Minimum Maximum Maximum
+* ---------- ------- ------- ------- -------
+* ERA 0 0 1 1
+* YEAR 1 1 140742 144683
+* MONTH 0 0 11 11
+* WEEK_OF_YEAR 1 1 52 53
+* WEEK_OF_MONTH 0 0 4 6
+* DAY_OF_MONTH 1 1 28 31
+* DAY_OF_YEAR 1 1 365 366
+* DAY_OF_WEEK 1 1 7 7
+* DAY_OF_WEEK_IN_MONTH -1 -1 4 5
+* AM_PM 0 0 1 1
+* HOUR 0 0 11 11
+* HOUR_OF_DAY 0 0 23 23
+* MINUTE 0 0 59 59
+* SECOND 0 0 59 59
+* MILLISECOND 0 0 999 999
+* ZONE_OFFSET -12* -12* 12* 12*
+* DST_OFFSET 0 0 1* 1*
+* YEAR_WOY 1 1 140742 144683
+* DOW_LOCAL 1 1 7 7
+* </pre>
+* (*) In units of one-hour
+*/
+
+#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
+#include <stdio.h>
+#endif
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(GregorianCalendar)
+
+// 00:00:00 UTC, October 15, 1582, expressed in ms from the epoch.
+// Note that only Italy and other Catholic countries actually
+// observed this cutover. Most other countries followed in
+// the next few centuries, some as late as 1928. [LIU]
+// in Java, -12219292800000L
+//const UDate GregorianCalendar::kPapalCutover = -12219292800000L;
+static const uint32_t kCutoverJulianDay = 2299161;
+static const UDate kPapalCutover = (2299161.0 - kEpochStartAsJulianDay) * U_MILLIS_PER_DAY;
+//static const UDate kPapalCutoverJulian = (2299161.0 - kEpochStartAsJulianDay);
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(UErrorCode& status)
+: Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
+fGregorianCutover(kPapalCutover),
+fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
+fIsGregorian(TRUE), fInvertGregorian(FALSE)
+{
+ setTimeInMillis(getNow(), status);
+}
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(TimeZone* zone, UErrorCode& status)
+: Calendar(zone, Locale::getDefault(), status),
+fGregorianCutover(kPapalCutover),
+fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
+fIsGregorian(TRUE), fInvertGregorian(FALSE)
+{
+ setTimeInMillis(getNow(), status);
+}
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(const TimeZone& zone, UErrorCode& status)
+: Calendar(zone, Locale::getDefault(), status),
+fGregorianCutover(kPapalCutover),
+fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
+fIsGregorian(TRUE), fInvertGregorian(FALSE)
+{
+ setTimeInMillis(getNow(), status);
+}
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(const Locale& aLocale, UErrorCode& status)
+: Calendar(TimeZone::createDefault(), aLocale, status),
+fGregorianCutover(kPapalCutover),
+fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
+fIsGregorian(TRUE), fInvertGregorian(FALSE)
+{
+ setTimeInMillis(getNow(), status);
+}
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(TimeZone* zone, const Locale& aLocale,
+ UErrorCode& status)
+ : Calendar(zone, aLocale, status),
+ fGregorianCutover(kPapalCutover),
+ fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
+ fIsGregorian(TRUE), fInvertGregorian(FALSE)
+{
+ setTimeInMillis(getNow(), status);
+}
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(const TimeZone& zone, const Locale& aLocale,
+ UErrorCode& status)
+ : Calendar(zone, aLocale, status),
+ fGregorianCutover(kPapalCutover),
+ fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
+ fIsGregorian(TRUE), fInvertGregorian(FALSE)
+{
+ setTimeInMillis(getNow(), status);
+}
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
+ UErrorCode& status)
+ : Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
+ fGregorianCutover(kPapalCutover),
+ fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
+ fIsGregorian(TRUE), fInvertGregorian(FALSE)
+{
+ set(UCAL_ERA, AD);
+ set(UCAL_YEAR, year);
+ set(UCAL_MONTH, month);
+ set(UCAL_DATE, date);
+}
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
+ int32_t hour, int32_t minute, UErrorCode& status)
+ : Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
+ fGregorianCutover(kPapalCutover),
+ fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
+ fIsGregorian(TRUE), fInvertGregorian(FALSE)
+{
+ set(UCAL_ERA, AD);
+ set(UCAL_YEAR, year);
+ set(UCAL_MONTH, month);
+ set(UCAL_DATE, date);
+ set(UCAL_HOUR_OF_DAY, hour);
+ set(UCAL_MINUTE, minute);
+}
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(int32_t year, int32_t month, int32_t date,
+ int32_t hour, int32_t minute, int32_t second,
+ UErrorCode& status)
+ : Calendar(TimeZone::createDefault(), Locale::getDefault(), status),
+ fGregorianCutover(kPapalCutover),
+ fCutoverJulianDay(kCutoverJulianDay), fNormalizedGregorianCutover(fGregorianCutover), fGregorianCutoverYear(1582),
+ fIsGregorian(TRUE), fInvertGregorian(FALSE)
+{
+ set(UCAL_ERA, AD);
+ set(UCAL_YEAR, year);
+ set(UCAL_MONTH, month);
+ set(UCAL_DATE, date);
+ set(UCAL_HOUR_OF_DAY, hour);
+ set(UCAL_MINUTE, minute);
+ set(UCAL_SECOND, second);
+}
+
+// -------------------------------------
+
+GregorianCalendar::~GregorianCalendar()
+{
+}
+
+// -------------------------------------
+
+GregorianCalendar::GregorianCalendar(const GregorianCalendar &source)
+: Calendar(source),
+fGregorianCutover(source.fGregorianCutover),
+fCutoverJulianDay(source.fCutoverJulianDay), fNormalizedGregorianCutover(source.fNormalizedGregorianCutover), fGregorianCutoverYear(source.fGregorianCutoverYear),
+fIsGregorian(source.fIsGregorian), fInvertGregorian(source.fInvertGregorian)
+{
+}
+
+// -------------------------------------
+
+Calendar* GregorianCalendar::clone() const
+{
+ return new GregorianCalendar(*this);
+}
+
+// -------------------------------------
+
+GregorianCalendar &
+GregorianCalendar::operator=(const GregorianCalendar &right)
+{
+ if (this != &right)
+ {
+ Calendar::operator=(right);
+ fGregorianCutover = right.fGregorianCutover;
+ fNormalizedGregorianCutover = right.fNormalizedGregorianCutover;
+ fGregorianCutoverYear = right.fGregorianCutoverYear;
+ fCutoverJulianDay = right.fCutoverJulianDay;
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+UBool GregorianCalendar::isEquivalentTo(const Calendar& other) const
+{
+ // Calendar override.
+ return Calendar::isEquivalentTo(other) &&
+ fGregorianCutover == ((GregorianCalendar*)&other)->fGregorianCutover;
+}
+
+// -------------------------------------
+
+void
+GregorianCalendar::setGregorianChange(UDate date, UErrorCode& status)
+{
+ if (U_FAILURE(status))
+ return;
+
+ fGregorianCutover = date;
+
+ // Precompute two internal variables which we use to do the actual
+ // cutover computations. These are the normalized cutover, which is the
+ // midnight at or before the cutover, and the cutover year. The
+ // normalized cutover is in pure date milliseconds; it contains no time
+ // of day or timezone component, and it used to compare against other
+ // pure date values.
+ int32_t cutoverDay = (int32_t)Math::floorDivide(fGregorianCutover, (double)kOneDay);
+ fNormalizedGregorianCutover = cutoverDay * kOneDay;
+
+ // Handle the rare case of numeric overflow. If the user specifies a
+ // change of UDate(Long.MIN_VALUE), in order to get a pure Gregorian
+ // calendar, then the epoch day is -106751991168, which when multiplied
+ // by ONE_DAY gives 9223372036794351616 -- the negative value is too
+ // large for 64 bits, and overflows into a positive value. We correct
+ // this by using the next day, which for all intents is semantically
+ // equivalent.
+ if (cutoverDay < 0 && fNormalizedGregorianCutover > 0) {
+ fNormalizedGregorianCutover = (cutoverDay + 1) * kOneDay;
+ }
+
+ // Normalize the year so BC values are represented as 0 and negative
+ // values.
+ GregorianCalendar *cal = new GregorianCalendar(getTimeZone(), status);
+ /* test for NULL */
+ if (cal == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if(U_FAILURE(status))
+ return;
+ cal->setTime(date, status);
+ fGregorianCutoverYear = cal->get(UCAL_YEAR, status);
+ if (cal->get(UCAL_ERA, status) == BC)
+ fGregorianCutoverYear = 1 - fGregorianCutoverYear;
+ fCutoverJulianDay = cutoverDay;
+ delete cal;
+}
+
+
+void GregorianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) {
+ int32_t eyear, month, dayOfMonth, dayOfYear;
+
+
+ if(U_FAILURE(status)) {
+ return;
+ }
+
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: jd%d- (greg's %d)- [cut=%d]\n",
+ __FILE__, __LINE__, julianDay, getGregorianDayOfYear(), fCutoverJulianDay);
+#endif
+
+
+ if (julianDay >= fCutoverJulianDay) {
+ month = getGregorianMonth();
+ dayOfMonth = getGregorianDayOfMonth();
+ dayOfYear = getGregorianDayOfYear();
+ eyear = getGregorianYear();
+ } else {
+ // The Julian epoch day (not the same as Julian Day)
+ // is zero on Saturday December 30, 0 (Gregorian).
+ int32_t julianEpochDay = julianDay - (kJan1_1JulianDay - 2);
+ eyear = (int32_t) Math::floorDivide(4*julianEpochDay + 1464, 1461);
+
+ // Compute the Julian calendar day number for January 1, eyear
+ int32_t january1 = 365*(eyear-1) + Math::floorDivide(eyear-1, (int32_t)4);
+ dayOfYear = (julianEpochDay - january1); // 0-based
+
+ // Julian leap years occurred historically every 4 years starting
+ // with 8 AD. Before 8 AD the spacing is irregular; every 3 years
+ // from 45 BC to 9 BC, and then none until 8 AD. However, we don't
+ // implement this historical detail; instead, we implement the
+ // computatinally cleaner proleptic calendar, which assumes
+ // consistent 4-year cycles throughout time.
+ UBool isLeap = ((eyear&0x3) == 0); // equiv. to (eyear%4 == 0)
+
+ // Common Julian/Gregorian calculation
+ int32_t correction = 0;
+ int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
+ if (dayOfYear >= march1) {
+ correction = isLeap ? 1 : 2;
+ }
+ month = (12 * (dayOfYear + correction) + 6) / 367; // zero-based month
+ dayOfMonth = dayOfYear - (isLeap?kLeapNumDays[month]:kNumDays[month]) + 1; // one-based DOM
+ ++dayOfYear;
+#if defined (U_DEBUG_CAL)
+ // fprintf(stderr, "%d - %d[%d] + 1\n", dayOfYear, isLeap?kLeapNumDays[month]:kNumDays[month], month );
+ // fprintf(stderr, "%s:%d: greg's HCF %d -> %d/%d/%d not %d/%d/%d\n",
+ // __FILE__, __LINE__,julianDay,
+ // eyear,month,dayOfMonth,
+ // getGregorianYear(), getGregorianMonth(), getGregorianDayOfMonth() );
+ fprintf(stderr, "%s:%d: doy %d (greg's %d)- [cut=%d]\n",
+ __FILE__, __LINE__, dayOfYear, getGregorianDayOfYear(), fCutoverJulianDay);
+#endif
+
+ }
+
+ // [j81] if we are after the cutover in its year, shift the day of the year
+ if((eyear == fGregorianCutoverYear) && (julianDay >= fCutoverJulianDay)) {
+ //from handleComputeMonthStart
+ int32_t gregShift = Grego::gregorianShift(eyear);
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: gregorian shift %d ::: doy%d => %d [cut=%d]\n",
+ __FILE__, __LINE__,gregShift, dayOfYear, dayOfYear+gregShift, fCutoverJulianDay);
+#endif
+ dayOfYear += gregShift;
+ }
+
+ internalSet(UCAL_MONTH, month);
+ internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
+ internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
+ internalSet(UCAL_EXTENDED_YEAR, eyear);
+ int32_t era = AD;
+ if (eyear < 1) {
+ era = BC;
+ eyear = 1 - eyear;
+ }
+ internalSet(UCAL_ERA, era);
+ internalSet(UCAL_YEAR, eyear);
+}
+
+
+// -------------------------------------
+
+UDate
+GregorianCalendar::getGregorianChange() const
+{
+ return fGregorianCutover;
+}
+
+// -------------------------------------
+
+UBool
+GregorianCalendar::isLeapYear(int32_t year) const
+{
+ // MSVC complains bitterly if we try to use Grego::isLeapYear here
+ // NOTE: year&0x3 == year%4
+ return (year >= fGregorianCutoverYear ?
+ (((year&0x3) == 0) && ((year%100 != 0) || (year%400 == 0))) : // Gregorian
+ ((year&0x3) == 0)); // Julian
+}
+
+// -------------------------------------
+
+int32_t GregorianCalendar::handleComputeJulianDay(UCalendarDateFields bestField)
+{
+ fInvertGregorian = FALSE;
+
+ int32_t jd = Calendar::handleComputeJulianDay(bestField);
+
+ if((bestField == UCAL_WEEK_OF_YEAR) && // if we are doing WOY calculations, we are counting relative to Jan 1 *julian*
+ (internalGet(UCAL_EXTENDED_YEAR)==fGregorianCutoverYear) &&
+ jd >= fCutoverJulianDay) {
+ fInvertGregorian = TRUE; // So that the Julian Jan 1 will be used in handleComputeMonthStart
+ return Calendar::handleComputeJulianDay(bestField);
+ }
+
+
+ // The following check handles portions of the cutover year BEFORE the
+ // cutover itself happens.
+ //if ((fIsGregorian==TRUE) != (jd >= fCutoverJulianDay)) { /* cutoverJulianDay)) { */
+ if ((fIsGregorian==TRUE) != (jd >= fCutoverJulianDay)) { /* cutoverJulianDay)) { */
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: jd [invert] %d\n",
+ __FILE__, __LINE__, jd);
+#endif
+ fInvertGregorian = TRUE;
+ jd = Calendar::handleComputeJulianDay(bestField);
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: fIsGregorian %s, fInvertGregorian %s - ",
+ __FILE__, __LINE__,fIsGregorian?"T":"F", fInvertGregorian?"T":"F");
+ fprintf(stderr, " jd NOW %d\n",
+ jd);
+#endif
+ } else {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: jd [==] %d - %sfIsGregorian %sfInvertGregorian, %d\n",
+ __FILE__, __LINE__, jd, fIsGregorian?"T":"F", fInvertGregorian?"T":"F", bestField);
+#endif
+ }
+
+ if(fIsGregorian && (internalGet(UCAL_EXTENDED_YEAR) == fGregorianCutoverYear)) {
+ int32_t gregShift = Grego::gregorianShift(internalGet(UCAL_EXTENDED_YEAR));
+ if (bestField == UCAL_DAY_OF_YEAR) {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: [DOY%d] gregorian shift of JD %d += %d\n",
+ __FILE__, __LINE__, fFields[bestField],jd, gregShift);
+#endif
+ jd -= gregShift;
+ } else if ( bestField == UCAL_WEEK_OF_MONTH ) {
+ int32_t weekShift = 14;
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: [WOY/WOM] gregorian week shift of %d += %d\n",
+ __FILE__, __LINE__, jd, weekShift);
+#endif
+ jd += weekShift; // shift by weeks for week based fields.
+ }
+ }
+
+ return jd;
+}
+
+int32_t GregorianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month,
+
+ UBool /* useMonth */) const
+{
+ GregorianCalendar *nonConstThis = (GregorianCalendar*)this; // cast away const
+
+ // If the month is out of range, adjust it into range, and
+ // modify the extended year value accordingly.
+ if (month < 0 || month > 11) {
+ eyear += Math::floorDivide(month, 12, month);
+ }
+
+ UBool isLeap = eyear%4 == 0;
+ int32_t y = eyear-1;
+ int32_t julianDay = 365*y + Math::floorDivide(y, 4) + (kJan1_1JulianDay - 3);
+
+ nonConstThis->fIsGregorian = (eyear >= fGregorianCutoverYear);
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: (hcms%d/%d) fIsGregorian %s, fInvertGregorian %s\n",
+ __FILE__, __LINE__, eyear,month, fIsGregorian?"T":"F", fInvertGregorian?"T":"F");
+#endif
+ if (fInvertGregorian) {
+ nonConstThis->fIsGregorian = !fIsGregorian;
+ }
+ if (fIsGregorian) {
+ isLeap = isLeap && ((eyear%100 != 0) || (eyear%400 == 0));
+ // Add 2 because Gregorian calendar starts 2 days after
+ // Julian calendar
+ int32_t gregShift = Grego::gregorianShift(eyear);
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: (hcms%d/%d) gregorian shift of %d += %d\n",
+ __FILE__, __LINE__, eyear, month, julianDay, gregShift);
+#endif
+ julianDay += gregShift;
+ }
+
+ // At this point julianDay indicates the day BEFORE the first
+ // day of January 1, <eyear> of either the Julian or Gregorian
+ // calendar.
+
+ if (month != 0) {
+ julianDay += isLeap?kLeapNumDays[month]:kNumDays[month];
+ }
+
+ return julianDay;
+}
+
+int32_t GregorianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const
+{
+ // If the month is out of range, adjust it into range, and
+ // modify the extended year value accordingly.
+ if (month < 0 || month > 11) {
+ extendedYear += Math::floorDivide(month, 12, month);
+ }
+
+ return isLeapYear(extendedYear) ? kLeapMonthLength[month] : kMonthLength[month];
+}
+
+int32_t GregorianCalendar::handleGetYearLength(int32_t eyear) const {
+ return isLeapYear(eyear) ? 366 : 365;
+}
+
+
+int32_t
+GregorianCalendar::monthLength(int32_t month) const
+{
+ int32_t year = internalGet(UCAL_EXTENDED_YEAR);
+ return handleGetMonthLength(year, month);
+}
+
+// -------------------------------------
+
+int32_t
+GregorianCalendar::monthLength(int32_t month, int32_t year) const
+{
+ return isLeapYear(year) ? kLeapMonthLength[month] : kMonthLength[month];
+}
+
+// -------------------------------------
+
+int32_t
+GregorianCalendar::yearLength(int32_t year) const
+{
+ return isLeapYear(year) ? 366 : 365;
+}
+
+// -------------------------------------
+
+int32_t
+GregorianCalendar::yearLength() const
+{
+ return isLeapYear(internalGet(UCAL_YEAR)) ? 366 : 365;
+}
+
+// -------------------------------------
+
+/**
+* After adjustments such as add(MONTH), add(YEAR), we don't want the
+* month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar
+* 3, we want it to go to Feb 28. Adjustments which might run into this
+* problem call this method to retain the proper month.
+*/
+void
+GregorianCalendar::pinDayOfMonth()
+{
+ int32_t monthLen = monthLength(internalGet(UCAL_MONTH));
+ int32_t dom = internalGet(UCAL_DATE);
+ if(dom > monthLen)
+ set(UCAL_DATE, monthLen);
+}
+
+// -------------------------------------
+
+
+UBool
+GregorianCalendar::validateFields() const
+{
+ for (int32_t field = 0; field < UCAL_FIELD_COUNT; field++) {
+ // Ignore DATE and DAY_OF_YEAR which are handled below
+ if (field != UCAL_DATE &&
+ field != UCAL_DAY_OF_YEAR &&
+ isSet((UCalendarDateFields)field) &&
+ ! boundsCheck(internalGet((UCalendarDateFields)field), (UCalendarDateFields)field))
+ return FALSE;
+ }
+
+ // Values differ in Least-Maximum and Maximum should be handled
+ // specially.
+ if (isSet(UCAL_DATE)) {
+ int32_t date = internalGet(UCAL_DATE);
+ if (date < getMinimum(UCAL_DATE) ||
+ date > monthLength(internalGet(UCAL_MONTH))) {
+ return FALSE;
+ }
+ }
+
+ if (isSet(UCAL_DAY_OF_YEAR)) {
+ int32_t days = internalGet(UCAL_DAY_OF_YEAR);
+ if (days < 1 || days > yearLength()) {
+ return FALSE;
+ }
+ }
+
+ // Handle DAY_OF_WEEK_IN_MONTH, which must not have the value zero.
+ // We've checked against minimum and maximum above already.
+ if (isSet(UCAL_DAY_OF_WEEK_IN_MONTH) &&
+ 0 == internalGet(UCAL_DAY_OF_WEEK_IN_MONTH)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -------------------------------------
+
+UBool
+GregorianCalendar::boundsCheck(int32_t value, UCalendarDateFields field) const
+{
+ return value >= getMinimum(field) && value <= getMaximum(field);
+}
+
+// -------------------------------------
+
+UDate
+GregorianCalendar::getEpochDay(UErrorCode& status)
+{
+ complete(status);
+ // Divide by 1000 (convert to seconds) in order to prevent overflow when
+ // dealing with UDate(Long.MIN_VALUE) and UDate(Long.MAX_VALUE).
+ double wallSec = internalGetTime()/1000 + (internalGet(UCAL_ZONE_OFFSET) + internalGet(UCAL_DST_OFFSET))/1000;
+
+ return Math::floorDivide(wallSec, kOneDay/1000.0);
+}
+
+// -------------------------------------
+
+
+// -------------------------------------
+
+/**
+* Compute the julian day number of the day BEFORE the first day of
+* January 1, year 1 of the given calendar. If julianDay == 0, it
+* specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
+* or Gregorian).
+*/
+double GregorianCalendar::computeJulianDayOfYear(UBool isGregorian,
+ int32_t year, UBool& isLeap)
+{
+ isLeap = year%4 == 0;
+ int32_t y = year - 1;
+ double julianDay = 365.0*y + Math::floorDivide(y, 4) + (kJan1_1JulianDay - 3);
+
+ if (isGregorian) {
+ isLeap = isLeap && ((year%100 != 0) || (year%400 == 0));
+ // Add 2 because Gregorian calendar starts 2 days after Julian calendar
+ julianDay += Grego::gregorianShift(year);
+ }
+
+ return julianDay;
+}
+
+// /**
+// * Compute the day of week, relative to the first day of week, from
+// * 0..6, of the current DOW_LOCAL or DAY_OF_WEEK fields. This is
+// * equivalent to get(DOW_LOCAL) - 1.
+// */
+// int32_t GregorianCalendar::computeRelativeDOW() const {
+// int32_t relDow = 0;
+// if (fStamp[UCAL_DOW_LOCAL] > fStamp[UCAL_DAY_OF_WEEK]) {
+// relDow = internalGet(UCAL_DOW_LOCAL) - 1; // 1-based
+// } else if (fStamp[UCAL_DAY_OF_WEEK] != kUnset) {
+// relDow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
+// if (relDow < 0) relDow += 7;
+// }
+// return relDow;
+// }
+
+// /**
+// * Compute the day of week, relative to the first day of week,
+// * from 0..6 of the given julian day.
+// */
+// int32_t GregorianCalendar::computeRelativeDOW(double julianDay) const {
+// int32_t relDow = julianDayToDayOfWeek(julianDay) - getFirstDayOfWeek();
+// if (relDow < 0) {
+// relDow += 7;
+// }
+// return relDow;
+// }
+
+// /**
+// * Compute the DOY using the WEEK_OF_YEAR field and the julian day
+// * of the day BEFORE January 1 of a year (a return value from
+// * computeJulianDayOfYear).
+// */
+// int32_t GregorianCalendar::computeDOYfromWOY(double julianDayOfYear) const {
+// // Compute DOY from day of week plus week of year
+
+// // Find the day of the week for the first of this year. This
+// // is zero-based, with 0 being the locale-specific first day of
+// // the week. Add 1 to get first day of year.
+// int32_t fdy = computeRelativeDOW(julianDayOfYear + 1);
+
+// return
+// // Compute doy of first (relative) DOW of WOY 1
+// (((7 - fdy) < getMinimalDaysInFirstWeek())
+// ? (8 - fdy) : (1 - fdy))
+
+// // Adjust for the week number.
+// + (7 * (internalGet(UCAL_WEEK_OF_YEAR) - 1))
+
+// // Adjust for the DOW
+// + computeRelativeDOW();
+// }
+
+// -------------------------------------
+
+double
+GregorianCalendar::millisToJulianDay(UDate millis)
+{
+ return (double)kEpochStartAsJulianDay + Math::floorDivide(millis, (double)kOneDay);
+}
+
+// -------------------------------------
+
+UDate
+GregorianCalendar::julianDayToMillis(double julian)
+{
+ return (UDate) ((julian - kEpochStartAsJulianDay) * (double) kOneDay);
+}
+
+// -------------------------------------
+
+int32_t
+GregorianCalendar::aggregateStamp(int32_t stamp_a, int32_t stamp_b)
+{
+ return (((stamp_a != kUnset && stamp_b != kUnset)
+ ? uprv_max(stamp_a, stamp_b)
+ : (int32_t)kUnset));
+}
+
+// -------------------------------------
+
+/**
+* Roll a field by a signed amount.
+* Note: This will be made public later. [LIU]
+*/
+
+void
+GregorianCalendar::roll(EDateFields field, int32_t amount, UErrorCode& status) {
+ roll((UCalendarDateFields) field, amount, status);
+}
+
+void
+GregorianCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
+{
+ if((amount == 0) || U_FAILURE(status)) {
+ return;
+ }
+
+ // J81 processing. (gregorian cutover)
+ UBool inCutoverMonth = FALSE;
+ int32_t cMonthLen=0; // 'c' for cutover; in days
+ int32_t cDayOfMonth=0; // no discontinuity: [0, cMonthLen)
+ double cMonthStart=0.0; // in ms
+
+ // Common code - see if we're in the cutover month of the cutover year
+ if(get(UCAL_EXTENDED_YEAR, status) == fGregorianCutoverYear) {
+ switch (field) {
+ case UCAL_DAY_OF_MONTH:
+ case UCAL_WEEK_OF_MONTH:
+ {
+ int32_t max = monthLength(internalGet(UCAL_MONTH));
+ UDate t = internalGetTime();
+ // We subtract 1 from the DAY_OF_MONTH to make it zero-based, and an
+ // additional 10 if we are after the cutover. Thus the monthStart
+ // value will be correct iff we actually are in the cutover month.
+ cDayOfMonth = internalGet(UCAL_DAY_OF_MONTH) - ((t >= fGregorianCutover) ? 10 : 0);
+ cMonthStart = t - ((cDayOfMonth - 1) * kOneDay);
+ // A month containing the cutover is 10 days shorter.
+ if ((cMonthStart < fGregorianCutover) &&
+ (cMonthStart + (cMonthLen=(max-10))*kOneDay >= fGregorianCutover)) {
+ inCutoverMonth = TRUE;
+ }
+ }
+ default:
+ ;
+ }
+ }
+
+ switch (field) {
+ case UCAL_WEEK_OF_YEAR: {
+ // Unlike WEEK_OF_MONTH, WEEK_OF_YEAR never shifts the day of the
+ // week. Also, rolling the week of the year can have seemingly
+ // strange effects simply because the year of the week of year
+ // may be different from the calendar year. For example, the
+ // date Dec 28, 1997 is the first day of week 1 of 1998 (if
+ // weeks start on Sunday and the minimal days in first week is
+ // <= 3).
+ int32_t woy = get(UCAL_WEEK_OF_YEAR, status);
+ // Get the ISO year, which matches the week of year. This
+ // may be one year before or after the calendar year.
+ int32_t isoYear = get(UCAL_YEAR_WOY, status);
+ int32_t isoDoy = internalGet(UCAL_DAY_OF_YEAR);
+ if (internalGet(UCAL_MONTH) == UCAL_JANUARY) {
+ if (woy >= 52) {
+ isoDoy += handleGetYearLength(isoYear);
+ }
+ } else {
+ if (woy == 1) {
+ isoDoy -= handleGetYearLength(isoYear - 1);
+ }
+ }
+ woy += amount;
+ // Do fast checks to avoid unnecessary computation:
+ if (woy < 1 || woy > 52) {
+ // Determine the last week of the ISO year.
+ // We do this using the standard formula we use
+ // everywhere in this file. If we can see that the
+ // days at the end of the year are going to fall into
+ // week 1 of the next year, we drop the last week by
+ // subtracting 7 from the last day of the year.
+ int32_t lastDoy = handleGetYearLength(isoYear);
+ int32_t lastRelDow = (lastDoy - isoDoy + internalGet(UCAL_DAY_OF_WEEK) -
+ getFirstDayOfWeek()) % 7;
+ if (lastRelDow < 0) lastRelDow += 7;
+ if ((6 - lastRelDow) >= getMinimalDaysInFirstWeek()) lastDoy -= 7;
+ int32_t lastWoy = weekNumber(lastDoy, lastRelDow + 1);
+ woy = ((woy + lastWoy - 1) % lastWoy) + 1;
+ }
+ set(UCAL_WEEK_OF_YEAR, woy);
+ set(UCAL_YEAR_WOY,isoYear);
+ return;
+ }
+
+ case UCAL_DAY_OF_MONTH:
+ if( !inCutoverMonth ) {
+ Calendar::roll(field, amount, status);
+ return;
+ } else {
+ // [j81] 1582 special case for DOM
+ // The default computation works except when the current month
+ // contains the Gregorian cutover. We handle this special case
+ // here. [j81 - aliu]
+ double monthLen = cMonthLen * kOneDay;
+ double msIntoMonth = uprv_fmod(internalGetTime() - cMonthStart +
+ amount * kOneDay, monthLen);
+ if (msIntoMonth < 0) {
+ msIntoMonth += monthLen;
+ }
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: roll DOM %d -> %.0lf ms \n",
+ __FILE__, __LINE__,amount, cMonthLen, cMonthStart+msIntoMonth);
+#endif
+ setTimeInMillis(cMonthStart + msIntoMonth, status);
+ return;
+ }
+
+ case UCAL_WEEK_OF_MONTH:
+ if( !inCutoverMonth ) {
+ Calendar::roll(field, amount, status);
+ return;
+ } else {
+#if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: roll WOM %d ??????????????????? \n",
+ __FILE__, __LINE__,amount);
+#endif
+ // NOTE: following copied from the old
+ // GregorianCalendar::roll( WEEK_OF_MONTH ) code
+
+ // This is tricky, because during the roll we may have to shift
+ // to a different day of the week. For example:
+
+ // s m t w r f s
+ // 1 2 3 4 5
+ // 6 7 8 9 10 11 12
+
+ // When rolling from the 6th or 7th back one week, we go to the
+ // 1st (assuming that the first partial week counts). The same
+ // thing happens at the end of the month.
+
+ // The other tricky thing is that we have to figure out whether
+ // the first partial week actually counts or not, based on the
+ // minimal first days in the week. And we have to use the
+ // correct first day of the week to delineate the week
+ // boundaries.
+
+ // Here's our algorithm. First, we find the real boundaries of
+ // the month. Then we discard the first partial week if it
+ // doesn't count in this locale. Then we fill in the ends with
+ // phantom days, so that the first partial week and the last
+ // partial week are full weeks. We then have a nice square
+ // block of weeks. We do the usual rolling within this block,
+ // as is done elsewhere in this method. If we wind up on one of
+ // the phantom days that we added, we recognize this and pin to
+ // the first or the last day of the month. Easy, eh?
+
+ // Another wrinkle: To fix jitterbug 81, we have to make all this
+ // work in the oddball month containing the Gregorian cutover.
+ // This month is 10 days shorter than usual, and also contains
+ // a discontinuity in the days; e.g., the default cutover month
+ // is Oct 1582, and goes from day of month 4 to day of month 15.
+
+ // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
+ // in this locale. We have dow in 0..6.
+ int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
+ if (dow < 0)
+ dow += 7;
+
+ // Find the day of month, compensating for cutover discontinuity.
+ int32_t dom = cDayOfMonth;
+
+ // Find the day of the week (normalized for locale) for the first
+ // of the month.
+ int32_t fdm = (dow - dom + 1) % 7;
+ if (fdm < 0)
+ fdm += 7;
+
+ // Get the first day of the first full week of the month,
+ // including phantom days, if any. Figure out if the first week
+ // counts or not; if it counts, then fill in phantom days. If
+ // not, advance to the first real full week (skip the partial week).
+ int32_t start;
+ if ((7 - fdm) < getMinimalDaysInFirstWeek())
+ start = 8 - fdm; // Skip the first partial week
+ else
+ start = 1 - fdm; // This may be zero or negative
+
+ // Get the day of the week (normalized for locale) for the last
+ // day of the month.
+ int32_t monthLen = cMonthLen;
+ int32_t ldm = (monthLen - dom + dow) % 7;
+ // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.
+
+ // Get the limit day for the blocked-off rectangular month; that
+ // is, the day which is one past the last day of the month,
+ // after the month has already been filled in with phantom days
+ // to fill out the last week. This day has a normalized DOW of 0.
+ int32_t limit = monthLen + 7 - ldm;
+
+ // Now roll between start and (limit - 1).
+ int32_t gap = limit - start;
+ int32_t newDom = (dom + amount*7 - start) % gap;
+ if (newDom < 0)
+ newDom += gap;
+ newDom += start;
+
+ // Finally, pin to the real start and end of the month.
+ if (newDom < 1)
+ newDom = 1;
+ if (newDom > monthLen)
+ newDom = monthLen;
+
+ // Set the DAY_OF_MONTH. We rely on the fact that this field
+ // takes precedence over everything else (since all other fields
+ // are also set at this point). If this fact changes (if the
+ // disambiguation algorithm changes) then we will have to unset
+ // the appropriate fields here so that DAY_OF_MONTH is attended
+ // to.
+
+ // If we are in the cutover month, manipulate ms directly. Don't do
+ // this in general because it doesn't work across DST boundaries
+ // (details, details). This takes care of the discontinuity.
+ setTimeInMillis(cMonthStart + (newDom-1)*kOneDay, status);
+ return;
+ }
+
+ default:
+ Calendar::roll(field, amount, status);
+ return;
+ }
+}
+
+// -------------------------------------
+
+
+/**
+* Return the minimum value that this field could have, given the current date.
+* For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
+* @param field the time field.
+* @return the minimum value that this field could have, given the current date.
+* @deprecated ICU 2.6. Use getActualMinimum(UCalendarDateFields field) instead.
+*/
+int32_t GregorianCalendar::getActualMinimum(EDateFields field) const
+{
+ return getMinimum((UCalendarDateFields)field);
+}
+
+int32_t GregorianCalendar::getActualMinimum(EDateFields field, UErrorCode& /* status */) const
+{
+ return getMinimum((UCalendarDateFields)field);
+}
+
+/**
+* Return the minimum value that this field could have, given the current date.
+* For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
+* @param field the time field.
+* @return the minimum value that this field could have, given the current date.
+* @draft ICU 2.6.
+*/
+int32_t GregorianCalendar::getActualMinimum(UCalendarDateFields field, UErrorCode& /* status */) const
+{
+ return getMinimum(field);
+}
+
+
+// ------------------------------------
+
+/**
+* Old year limits were least max 292269054, max 292278994.
+*/
+
+/**
+* @stable ICU 2.0
+*/
+int32_t GregorianCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
+ return kGregorianCalendarLimits[field][limitType];
+}
+
+/**
+* Return the maximum value that this field could have, given the current date.
+* For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field, the actual
+* maximum would be 28; for "Feb 3, 1996" it s 29. Similarly for a Hebrew calendar,
+* for some years the actual maximum for MONTH is 12, and for others 13.
+* @stable ICU 2.0
+*/
+int32_t GregorianCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const
+{
+ /* It is a known limitation that the code here (and in getActualMinimum)
+ * won't behave properly at the extreme limits of GregorianCalendar's
+ * representable range (except for the code that handles the YEAR
+ * field). That's because the ends of the representable range are at
+ * odd spots in the year. For calendars with the default Gregorian
+ * cutover, these limits are Sun Dec 02 16:47:04 GMT 292269055 BC to Sun
+ * Aug 17 07:12:55 GMT 292278994 AD, somewhat different for non-GMT
+ * zones. As a result, if the calendar is set to Aug 1 292278994 AD,
+ * the actual maximum of DAY_OF_MONTH is 17, not 30. If the date is Mar
+ * 31 in that year, the actual maximum month might be Jul, whereas is
+ * the date is Mar 15, the actual maximum might be Aug -- depending on
+ * the precise semantics that are desired. Similar considerations
+ * affect all fields. Nonetheless, this effect is sufficiently arcane
+ * that we permit it, rather than complicating the code to handle such
+ * intricacies. - liu 8/20/98
+
+ * UPDATE: No longer true, since we have pulled in the limit values on
+ * the year. - Liu 11/6/00 */
+
+ switch (field) {
+
+ case UCAL_YEAR:
+ /* The year computation is no different, in principle, from the
+ * others, however, the range of possible maxima is large. In
+ * addition, the way we know we've exceeded the range is different.
+ * For these reasons, we use the special case code below to handle
+ * this field.
+ *
+ * The actual maxima for YEAR depend on the type of calendar:
+ *
+ * Gregorian = May 17, 292275056 BC - Aug 17, 292278994 AD
+ * Julian = Dec 2, 292269055 BC - Jan 3, 292272993 AD
+ * Hybrid = Dec 2, 292269055 BC - Aug 17, 292278994 AD
+ *
+ * We know we've exceeded the maximum when either the month, date,
+ * time, or era changes in response to setting the year. We don't
+ * check for month, date, and time here because the year and era are
+ * sufficient to detect an invalid year setting. NOTE: If code is
+ * added to check the month and date in the future for some reason,
+ * Feb 29 must be allowed to shift to Mar 1 when setting the year.
+ */
+ {
+ if(U_FAILURE(status)) return 0;
+ Calendar *cal = clone();
+ if(!cal) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ cal->setLenient(TRUE);
+
+ int32_t era = cal->get(UCAL_ERA, status);
+ UDate d = cal->getTime(status);
+
+ /* Perform a binary search, with the invariant that lowGood is a
+ * valid year, and highBad is an out of range year.
+ */
+ int32_t lowGood = kGregorianCalendarLimits[UCAL_YEAR][1];
+ int32_t highBad = kGregorianCalendarLimits[UCAL_YEAR][2]+1;
+ while ((lowGood + 1) < highBad) {
+ int32_t y = (lowGood + highBad) / 2;
+ cal->set(UCAL_YEAR, y);
+ if (cal->get(UCAL_YEAR, status) == y && cal->get(UCAL_ERA, status) == era) {
+ lowGood = y;
+ } else {
+ highBad = y;
+ cal->setTime(d, status); // Restore original fields
+ }
+ }
+
+ delete cal;
+ return lowGood;
+ }
+
+ default:
+ return Calendar::getActualMaximum(field,status);
+ }
+}
+
+
+int32_t GregorianCalendar::handleGetExtendedYear() {
+ int32_t year = kEpochYear;
+ switch(resolveFields(kYearPrecedence)) {
+ case UCAL_EXTENDED_YEAR:
+ year = internalGet(UCAL_EXTENDED_YEAR, kEpochYear);
+ break;
+
+ case UCAL_YEAR:
+ {
+ // The year defaults to the epoch start, the era to AD
+ int32_t era = internalGet(UCAL_ERA, AD);
+ if (era == BC) {
+ year = 1 - internalGet(UCAL_YEAR, 1); // Convert to extended year
+ } else {
+ year = internalGet(UCAL_YEAR, kEpochYear);
+ }
+ }
+ break;
+
+ case UCAL_YEAR_WOY:
+ year = handleGetExtendedYearFromWeekFields(internalGet(UCAL_YEAR_WOY), internalGet(UCAL_WEEK_OF_YEAR));
+#if defined (U_DEBUG_CAL)
+ // if(internalGet(UCAL_YEAR_WOY) != year) {
+ fprintf(stderr, "%s:%d: hGEYFWF[%d,%d] -> %d\n",
+ __FILE__, __LINE__,internalGet(UCAL_YEAR_WOY),internalGet(UCAL_WEEK_OF_YEAR),year);
+ //}
+#endif
+ break;
+
+ default:
+ year = kEpochYear;
+ }
+ return year;
+}
+
+int32_t GregorianCalendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy)
+{
+ // convert year to extended form
+ int32_t era = internalGet(UCAL_ERA, AD);
+ if(era == BC) {
+ yearWoy = 1 - yearWoy;
+ }
+ return Calendar::handleGetExtendedYearFromWeekFields(yearWoy, woy);
+}
+
+
+// -------------------------------------
+
+UBool
+GregorianCalendar::inDaylightTime(UErrorCode& status) const
+{
+ if (U_FAILURE(status) || !getTimeZone().useDaylightTime())
+ return FALSE;
+
+ // Force an update of the state of the Calendar.
+ ((GregorianCalendar*)this)->complete(status); // cast away const
+
+ return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
+}
+
+// -------------------------------------
+
+/**
+* Return the ERA. We need a special method for this because the
+* default ERA is AD, but a zero (unset) ERA is BC.
+*/
+int32_t
+GregorianCalendar::internalGetEra() const {
+ return isSet(UCAL_ERA) ? internalGet(UCAL_ERA) : (int32_t)AD;
+}
+
+const char *
+GregorianCalendar::getType() const {
+ //static const char kGregorianType = "gregorian";
+
+ return "gregorian";
+}
+
+const UDate GregorianCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t GregorianCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate GregorianCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t GregorianCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+
+UBool GregorianCalendar::haveDefaultCentury() const
+{
+ return TRUE;
+}
+
+UDate GregorianCalendar::defaultCenturyStart() const
+{
+ return internalGetDefaultCenturyStart();
+}
+
+int32_t GregorianCalendar::defaultCenturyStartYear() const
+{
+ return internalGetDefaultCenturyStartYear();
+}
+
+UDate
+GregorianCalendar::internalGetDefaultCenturyStart() const
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStart
+
+ return fgSystemDefaultCenturyStart;
+}
+
+int32_t
+GregorianCalendar::internalGetDefaultCenturyStartYear() const
+{
+ // lazy-evaluate systemDefaultCenturyStartYear
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStartYear
+
+ return fgSystemDefaultCenturyStartYear;
+}
+
+void
+GregorianCalendar::initializeSystemDefaultCentury()
+{
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ // No point in locking as it should be idempotent.
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *calendar = new GregorianCalendar(status);
+ if (calendar != NULL && U_SUCCESS(status))
+ {
+ calendar->setTime(Calendar::getNow(), status);
+ calendar->add(UCAL_YEAR, -80, status);
+
+ UDate newStart = calendar->getTime(status);
+ int32_t newYear = calendar->get(UCAL_YEAR, status);
+ {
+ umtx_lock(NULL);
+ fgSystemDefaultCenturyStart = newStart;
+ fgSystemDefaultCenturyStartYear = newYear;
+ umtx_unlock(NULL);
+ }
+ delete calendar;
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/gregoimp.cpp b/Build/source/libs/icu/icu-xetex/i18n/gregoimp.cpp
new file mode 100644
index 00000000000..22c22ca0139
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/gregoimp.cpp
@@ -0,0 +1,328 @@
+/*
+ **********************************************************************
+ * Copyright (c) 2003-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * Author: Alan Liu
+ * Created: September 2 2003
+ * Since: ICU 2.8
+ **********************************************************************
+ */
+
+#include "gregoimp.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ucal.h"
+#include "uresimp.h"
+#include "cstring.h"
+#include "uassert.h"
+
+#if defined(U_DEBUG_CALDATA)
+#include <stdio.h>
+#endif
+
+U_NAMESPACE_BEGIN
+
+int32_t Math::floorDivide(int32_t numerator, int32_t denominator) {
+ return (numerator >= 0) ?
+ numerator / denominator : ((numerator + 1) / denominator) - 1;
+}
+
+int32_t Math::floorDivide(double numerator, int32_t denominator,
+ int32_t& remainder) {
+ double quotient;
+ quotient = uprv_floor(numerator / denominator);
+ remainder = (int32_t) (numerator - (quotient * denominator));
+ return (int32_t) quotient;
+}
+
+double Math::floorDivide(double dividend, double divisor,
+ double& remainder) {
+ // Only designed to work for positive divisors
+ U_ASSERT(divisor > 0);
+ double quotient = floorDivide(dividend, divisor);
+ remainder = dividend - (quotient * divisor);
+ // N.B. For certain large dividends, on certain platforms, there
+ // is a bug such that the quotient is off by one. If you doubt
+ // this to be true, set a breakpoint below and run cintltst.
+ if (remainder < 0 || remainder >= divisor) {
+ // E.g. 6.7317038241449352e+022 / 86400000.0 is wrong on my
+ // machine (too high by one). 4.1792057231752762e+024 /
+ // 86400000.0 is wrong the other way (too low).
+ double q = quotient;
+ quotient += (remainder < 0) ? -1 : +1;
+ if (q == quotient) {
+ // For quotients > ~2^53, we won't be able to add or
+ // subtract one, since the LSB of the mantissa will be >
+ // 2^0; that is, the exponent (base 2) will be larger than
+ // the length, in bits, of the mantissa. In that case, we
+ // can't give a correct answer, so we set the remainder to
+ // zero. This has the desired effect of making extreme
+ // values give back an approximate answer rather than
+ // crashing. For example, UDate values above a ~10^25
+ // might all have a time of midnight.
+ remainder = 0;
+ } else {
+ remainder = dividend - (quotient * divisor);
+ }
+ }
+ U_ASSERT(0 <= remainder && remainder < divisor);
+ return quotient;
+}
+
+const int32_t JULIAN_1_CE = 1721426; // January 1, 1 CE Gregorian
+const int32_t JULIAN_1970_CE = 2440588; // January 1, 1970 CE Gregorian
+
+const int16_t Grego::DAYS_BEFORE[24] =
+ {0,31,59,90,120,151,181,212,243,273,304,334,
+ 0,31,60,91,121,152,182,213,244,274,305,335};
+
+const int8_t Grego::MONTH_LENGTH[24] =
+ {31,28,31,30,31,30,31,31,30,31,30,31,
+ 31,29,31,30,31,30,31,31,30,31,30,31};
+
+double Grego::fieldsToDay(int32_t year, int32_t month, int32_t dom) {
+
+ int32_t y = year - 1;
+
+ double julian = 365 * y + Math::floorDivide(y, 4) + (JULIAN_1_CE - 3) + // Julian cal
+ Math::floorDivide(y, 400) - Math::floorDivide(y, 100) + 2 + // => Gregorian cal
+ DAYS_BEFORE[month + (isLeapYear(year) ? 12 : 0)] + dom; // => month/dom
+
+ return julian - JULIAN_1970_CE; // JD => epoch day
+}
+
+void Grego::dayToFields(double day, int32_t& year, int32_t& month,
+ int32_t& dom, int32_t& dow, int32_t& doy) {
+
+ // Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
+ day += JULIAN_1970_CE - JULIAN_1_CE;
+
+ // Convert from the day number to the multiple radix
+ // representation. We use 400-year, 100-year, and 4-year cycles.
+ // For example, the 4-year cycle has 4 years + 1 leap day; giving
+ // 1461 == 365*4 + 1 days.
+ int32_t n400 = Math::floorDivide(day, 146097, doy); // 400-year cycle length
+ int32_t n100 = Math::floorDivide(doy, 36524, doy); // 100-year cycle length
+ int32_t n4 = Math::floorDivide(doy, 1461, doy); // 4-year cycle length
+ int32_t n1 = Math::floorDivide(doy, 365, doy);
+ year = 400*n400 + 100*n100 + 4*n4 + n1;
+ if (n100 == 4 || n1 == 4) {
+ doy = 365; // Dec 31 at end of 4- or 400-year cycle
+ } else {
+ ++year;
+ }
+
+ UBool isLeap = isLeapYear(year);
+
+ // Gregorian day zero is a Monday.
+ dow = (int32_t) uprv_fmod(day + 1, 7);
+ dow += (dow < 0) ? (UCAL_SUNDAY + 7) : UCAL_SUNDAY;
+
+ // Common Julian/Gregorian calculation
+ int32_t correction = 0;
+ int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
+ if (doy >= march1) {
+ correction = isLeap ? 1 : 2;
+ }
+ month = (12 * (doy + correction) + 6) / 367; // zero-based month
+ dom = doy - DAYS_BEFORE[month + (isLeap ? 12 : 0)] + 1; // one-based DOM
+ doy++; // one-based doy
+}
+
+void Grego::timeToFields(UDate time, int32_t& year, int32_t& month,
+ int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid) {
+ double millisInDay;
+ double day = Math::floorDivide((double)time, (double)U_MILLIS_PER_DAY, millisInDay);
+ mid = (int32_t)millisInDay;
+ dayToFields(day, year, month, dom, dow, doy);
+}
+
+int32_t Grego::dayOfWeek(double day) {
+ int32_t dow;
+ Math::floorDivide(day + UCAL_THURSDAY, 7, dow);
+ return (dow == 0) ? UCAL_SATURDAY : dow;
+}
+
+int32_t Grego::dayOfWeekInMonth(int32_t year, int32_t month, int32_t dom) {
+ int32_t weekInMonth = (dom + 6)/7;
+ if (weekInMonth == 4) {
+ if (dom + 7 > monthLength(year, month)) {
+ weekInMonth = -1;
+ }
+ } else if (weekInMonth == 5) {
+ weekInMonth = -1;
+ }
+ return weekInMonth;
+}
+
+/* ---- CalendarData ------ */
+
+#define U_CALENDAR_KEY "calendar"
+#define U_GREGORIAN_KEY "gregorian"
+#define U_FORMAT_KEY "format"
+#define U_DEFAULT_KEY "default"
+#define U_CALENDAR_DATA ((char*)0)
+
+
+// CalendarData::CalendarData(const Locale& loc, UErrorCode& status)
+// : fFillin(NULL), fBundle(NULL), fFallback(NULL) {
+// initData(loc.getBaseName(), (char*) "???", status);
+// }
+
+CalendarData::CalendarData(const Locale& loc, const char *type, UErrorCode& status)
+ : fFillin(NULL), fOtherFillin(NULL), fBundle(NULL), fFallback(NULL) {
+ initData(loc.getBaseName(), type, status);
+}
+
+void CalendarData::initData(const char *locale, const char *type, UErrorCode& status) {
+ fOtherFillin = ures_open(U_CALENDAR_DATA, locale, &status);
+ fFillin = ures_getByKey(fOtherFillin, U_CALENDAR_KEY, fFillin, &status);
+
+ if((type != NULL) &&
+ (*type != '\0') &&
+ (uprv_strcmp(type, U_GREGORIAN_KEY)))
+ {
+ fBundle = ures_getByKeyWithFallback(fFillin, type, NULL, &status);
+ fFallback = ures_getByKeyWithFallback(fFillin, U_GREGORIAN_KEY, NULL, &status);
+
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback(%p, %s)=%s\n",
+ this, locale, type, u_errorName(status), fBundle, type, fBundle?ures_getLocale(fBundle, &status):"",
+ fFallback, U_GREGORIAN_KEY, fFallback?ures_getLocale(fFallback, &status):"");
+#endif
+
+ } else {
+ fBundle = ures_getByKeyWithFallback(fFillin, U_GREGORIAN_KEY, NULL, &status);
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: CalendarData(%s, %s, %s) -> main(%p, %s)=%s, fallback = NULL\n",
+ this, locale, type, u_errorName(status), fBundle, U_GREGORIAN_KEY, fBundle?ures_getLocale(fBundle, &status):"" );
+#endif
+ }
+}
+
+CalendarData::~CalendarData() {
+ ures_close(fFillin);
+ ures_close(fBundle);
+ ures_close(fFallback);
+ ures_close(fOtherFillin);
+}
+
+UResourceBundle*
+CalendarData::getByKey(const char *key, UErrorCode& status) {
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ if(fBundle) {
+ fFillin = ures_getByKeyWithFallback(fBundle, key, fFillin, &status);
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: get %s -> %s - from MAIN %s\n",this, key, u_errorName(status), ures_getLocale(fFillin, &status));
+#endif
+ }
+ if(fFallback && (status == U_MISSING_RESOURCE_ERROR)) {
+ status = U_ZERO_ERROR; // retry with fallback (gregorian)
+ fFillin = ures_getByKeyWithFallback(fFallback, key, fFillin, &status);
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: get %s -> %s - from FALLBACK %s\n",this, key, u_errorName(status), ures_getLocale(fFillin, &status));
+#endif
+ }
+ return fFillin;
+}
+
+UResourceBundle* CalendarData::getByKey2(const char *key, const char *subKey, UErrorCode& status) {
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ if(fBundle) {
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: //\n");
+#endif
+ fFillin = ures_getByKeyWithFallback(fBundle, key, fFillin, &status);
+ fOtherFillin = ures_getByKeyWithFallback(fFillin, U_FORMAT_KEY, fOtherFillin, &status);
+ fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status);
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: get %s/format/%s -> %s - from MAIN %s\n", this, key, subKey, u_errorName(status), ures_getLocale(fFillin, &status));
+#endif
+ }
+ if(fFallback && (status == U_MISSING_RESOURCE_ERROR)) {
+ status = U_ZERO_ERROR; // retry with fallback (gregorian)
+ fFillin = ures_getByKeyWithFallback(fFallback, key, fFillin, &status);
+ fOtherFillin = ures_getByKeyWithFallback(fFillin, U_FORMAT_KEY, fOtherFillin, &status);
+ fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status);
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: get %s/format/%s -> %s - from FALLBACK %s\n",this, key, subKey, u_errorName(status), ures_getLocale(fFillin,&status));
+#endif
+ }
+
+//// handling of 'default' keyword on failure: Commented out for 3.0.
+// if((status == U_MISSING_RESOURCE_ERROR) &&
+// uprv_strcmp(subKey,U_DEFAULT_KEY)) { // avoid recursion
+// #if defined (U_DEBUG_CALDATA)
+// fprintf(stderr, "%p: - attempting fallback -\n", this);
+// fflush(stderr);
+// #endif
+// UErrorCode subStatus = U_ZERO_ERROR;
+// int32_t len;
+// char kwBuf[128] = "";
+// const UChar *kw;
+// /* fFillin = */ getByKey2(key, U_DEFAULT_KEY, subStatus);
+// kw = ures_getString(fFillin, &len, &subStatus);
+// if(len>126) { // too big
+// len = 0;
+// }
+// if(U_SUCCESS(subStatus) && (len>0)) {
+// u_UCharsToChars(kw, kwBuf, len+1);
+// if(*kwBuf && uprv_strcmp(kwBuf,subKey)) {
+// #if defined (U_DEBUG_CALDATA)
+// fprintf(stderr, "%p: trying %s/format/default -> \"%s\"\n",this, key, kwBuf);
+// #endif
+// // now try again with the default
+// status = U_ZERO_ERROR;
+// /* fFillin = */ getByKey2(key, kwBuf, status);
+// }
+// #if defined (U_DEBUG_CALDATA)
+// } else {
+// fprintf(stderr, "%p: could not load %s/format/default - fail out (%s)\n",this, key, kwBuf, u_errorName(status));
+// #endif
+// }
+// }
+
+ return fFillin;
+}
+
+UResourceBundle* CalendarData::getByKey3(const char *key, const char *contextKey, const char *subKey, UErrorCode& status) {
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ if(fBundle) {
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: //\n");
+#endif
+ fFillin = ures_getByKeyWithFallback(fBundle, key, fFillin, &status);
+ fOtherFillin = ures_getByKeyWithFallback(fFillin, contextKey, fOtherFillin, &status);
+ fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status);
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: get %s/%s/%s -> %s - from MAIN %s\n", this, key, contextKey, subKey, u_errorName(status), ures_getLocale(fFillin, &status));
+#endif
+ }
+ if(fFallback && (status == U_MISSING_RESOURCE_ERROR)) {
+ status = U_ZERO_ERROR; // retry with fallback (gregorian)
+ fFillin = ures_getByKeyWithFallback(fFallback, key, fFillin, &status);
+ fOtherFillin = ures_getByKeyWithFallback(fFillin, contextKey, fOtherFillin, &status);
+ fFillin = ures_getByKeyWithFallback(fOtherFillin, subKey, fFillin, &status);
+#if defined (U_DEBUG_CALDATA)
+ fprintf(stderr, "%p: get %s/%s/%s -> %s - from FALLBACK %s\n",this, key, contextKey, subKey, u_errorName(status), ures_getLocale(fFillin,&status));
+#endif
+ }
+
+ return fFillin;
+}
+
+U_NAMESPACE_END
+
+#endif
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/gregoimp.h b/Build/source/libs/icu/icu-xetex/i18n/gregoimp.h
new file mode 100644
index 00000000000..d8ab8de48b0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/gregoimp.h
@@ -0,0 +1,363 @@
+/*
+ **********************************************************************
+ * Copyright (c) 2003-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * Author: Alan Liu
+ * Created: September 2 2003
+ * Since: ICU 2.8
+ **********************************************************************
+ */
+
+#ifndef GREGOIMP_H
+#define GREGOIMP_H
+#include "unicode/utypes.h"
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ures.h"
+#include "unicode/locid.h"
+#include "putilimp.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A utility class providing mathematical functions used by time zone
+ * and calendar code. Do not instantiate.
+ */
+class Math {
+ public:
+ /**
+ * Divide two integers, returning the floor of the quotient.
+ * Unlike the built-in division, this is mathematically
+ * well-behaved. E.g., <code>-1/4</code> => 0 but
+ * <code>floorDivide(-1,4)</code> => -1.
+ * @param numerator the numerator
+ * @param denominator a divisor which must be != 0
+ * @return the floor of the quotient
+ */
+ static int32_t floorDivide(int32_t numerator, int32_t denominator);
+
+ /**
+ * Divide two numbers, returning the floor of the quotient.
+ * Unlike the built-in division, this is mathematically
+ * well-behaved. E.g., <code>-1/4</code> => 0 but
+ * <code>floorDivide(-1,4)</code> => -1.
+ * @param numerator the numerator
+ * @param denominator a divisor which must be != 0
+ * @return the floor of the quotient
+ */
+ static inline double floorDivide(double numerator, double denominator);
+
+ /**
+ * Divide two numbers, returning the floor of the quotient and
+ * the modulus remainder. Unlike the built-in division, this is
+ * mathematically well-behaved. E.g., <code>-1/4</code> => 0 and
+ * <code>-1%4</code> => -1, but <code>floorDivide(-1,4)</code> =>
+ * -1 with <code>remainder</code> => 3. NOTE: If numerator is
+ * too large, the returned quotient may overflow.
+ * @param numerator the numerator
+ * @param denominator a divisor which must be != 0
+ * @param remainder output parameter to receive the
+ * remainder. Unlike <code>numerator % denominator</code>, this
+ * will always be non-negative, in the half-open range <code>[0,
+ * |denominator|)</code>.
+ * @return the floor of the quotient
+ */
+ static int32_t floorDivide(double numerator, int32_t denominator,
+ int32_t& remainder);
+
+ /**
+ * For a positive divisor, return the quotient and remainder
+ * such that dividend = quotient*divisor + remainder and
+ * 0 <= remainder < divisor.
+ *
+ * Works around edge-case bugs. Handles pathological input
+ * (divident >> divisor) reasonably.
+ *
+ * Calling with a divisor <= 0 is disallowed.
+ */
+ static double floorDivide(double dividend, double divisor,
+ double& remainder);
+};
+
+// Useful millisecond constants
+#define kOneDay (1.0 * U_MILLIS_PER_DAY) // 86,400,000
+#define kOneHour (60*60*1000)
+#define kOneMinute 60000
+#define kOneSecond 1000
+#define kOneMillisecond 1
+#define kOneWeek (7.0 * kOneDay) // 604,800,000
+
+// Epoch constants
+#define kJan1_1JulianDay 1721426 // January 1, year 1 (Gregorian)
+
+#define kEpochStartAsJulianDay 2440588 // January 1, 1970 (Gregorian)
+
+#define kEpochYear 1970
+
+
+#define kEarliestViableMillis -185331720384000000.0 // minimum representable by julian day -1e17
+
+#define kLatestViableMillis 185753453990400000.0 // max representable by julian day +1e17
+
+/**
+ * The minimum supported Julian day. This value is equivalent to
+ * MIN_MILLIS.
+ */
+#define MIN_JULIAN (-0x7F000000)
+
+/**
+ * The minimum supported epoch milliseconds. This value is equivalent
+ * to MIN_JULIAN.
+ */
+#define MIN_MILLIS ((MIN_JULIAN - kEpochStartAsJulianDay) * kOneDay)
+
+/**
+ * The maximum supported Julian day. This value is equivalent to
+ * MAX_MILLIS.
+ */
+#define MAX_JULIAN (+0x7F000000)
+
+/**
+ * The maximum supported epoch milliseconds. This value is equivalent
+ * to MAX_JULIAN.
+ */
+#define MAX_MILLIS ((MAX_JULIAN - kEpochStartAsJulianDay) * kOneDay)
+
+/**
+ * A utility class providing proleptic Gregorian calendar functions
+ * used by time zone and calendar code. Do not instantiate.
+ *
+ * Note: Unlike GregorianCalendar, all computations performed by this
+ * class occur in the pure proleptic GregorianCalendar.
+ */
+class Grego {
+ public:
+ /**
+ * Return TRUE if the given year is a leap year.
+ * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
+ * @return TRUE if the year is a leap year
+ */
+ static inline UBool isLeapYear(int32_t year);
+
+ /**
+ * Return the number of days in the given month.
+ * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
+ * @param month 0-based month, with 0==Jan
+ * @return the number of days in the given month
+ */
+ static inline int8_t monthLength(int32_t year, int32_t month);
+
+ /**
+ * Return the length of a previous month of the Gregorian calendar.
+ * @param y the extended year
+ * @param m the 0-based month number
+ * @return the number of days in the month previous to the given month
+ */
+ static inline int8_t previousMonthLength(int y, int m);
+
+ /**
+ * Convert a year, month, and day-of-month, given in the proleptic
+ * Gregorian calendar, to 1970 epoch days.
+ * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
+ * @param month 0-based month, with 0==Jan
+ * @param dom 1-based day of month
+ * @return the day number, with day 0 == Jan 1 1970
+ */
+ static double fieldsToDay(int32_t year, int32_t month, int32_t dom);
+
+ /**
+ * Convert a 1970-epoch day number to proleptic Gregorian year,
+ * month, day-of-month, and day-of-week.
+ * @param day 1970-epoch day (integral value)
+ * @param year output parameter to receive year
+ * @param month output parameter to receive month (0-based, 0==Jan)
+ * @param dom output parameter to receive day-of-month (1-based)
+ * @param dow output parameter to receive day-of-week (1-based, 1==Sun)
+ * @param doy output parameter to receive day-of-year (1-based)
+ */
+ static void dayToFields(double day, int32_t& year, int32_t& month,
+ int32_t& dom, int32_t& dow, int32_t& doy);
+
+ /**
+ * Convert a 1970-epoch day number to proleptic Gregorian year,
+ * month, day-of-month, and day-of-week.
+ * @param day 1970-epoch day (integral value)
+ * @param year output parameter to receive year
+ * @param month output parameter to receive month (0-based, 0==Jan)
+ * @param dom output parameter to receive day-of-month (1-based)
+ * @param dow output parameter to receive day-of-week (1-based, 1==Sun)
+ */
+ static inline void dayToFields(double day, int32_t& year, int32_t& month,
+ int32_t& dom, int32_t& dow);
+
+ /**
+ * Convert a 1970-epoch milliseconds to proleptic Gregorian year,
+ * month, day-of-month, and day-of-week, day of year and millis-in-day.
+ * @param time 1970-epoch milliseconds
+ * @param year output parameter to receive year
+ * @param month output parameter to receive month (0-based, 0==Jan)
+ * @param dom output parameter to receive day-of-month (1-based)
+ * @param dow output parameter to receive day-of-week (1-based, 1==Sun)
+ * @param doy output parameter to receive day-of-year (1-based)
+ * @param mid output parameter to recieve millis-in-day
+ */
+ static void timeToFields(UDate time, int32_t& year, int32_t& month,
+ int32_t& dom, int32_t& dow, int32_t& doy, int32_t& mid);
+
+ /**
+ * Return the day of week on the 1970-epoch day
+ * @param day the 1970-epoch day (integral value)
+ * @return the day of week
+ */
+ static int32_t dayOfWeek(double day);
+
+ /**
+ * Returns the ordinal number for the specified day of week within the month.
+ * The valid return value is 1, 2, 3, 4 or -1.
+ * @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
+ * @param month 0-based month, with 0==Jan
+ * @param dom 1-based day of month
+ * @return The ordinal number for the specified day of week within the month
+ */
+ static int32_t dayOfWeekInMonth(int32_t year, int32_t month, int32_t dom);
+
+ /**
+ * Converts Julian day to time as milliseconds.
+ * @param julian the given Julian day number.
+ * @return time as milliseconds.
+ * @internal
+ */
+ static inline double julianDayToMillis(int32_t julian);
+
+ /**
+ * Converts time as milliseconds to Julian day.
+ * @param millis the given milliseconds.
+ * @return the Julian day number.
+ * @internal
+ */
+ static inline int32_t millisToJulianDay(double millis);
+
+ /**
+ * Calculates the Gregorian day shift value for an extended year.
+ * @param eyear Extended year
+ * @returns number of days to ADD to Julian in order to convert from J->G
+ */
+ static inline int32_t gregorianShift(int32_t eyear);
+
+ private:
+ static const int16_t DAYS_BEFORE[24];
+ static const int8_t MONTH_LENGTH[24];
+};
+
+inline double Math::floorDivide(double numerator, double denominator) {
+ return uprv_floor(numerator / denominator);
+}
+
+inline UBool Grego::isLeapYear(int32_t year) {
+ // year&0x3 == year%4
+ return ((year&0x3) == 0) && ((year%100 != 0) || (year%400 == 0));
+}
+
+inline int8_t
+Grego::monthLength(int32_t year, int32_t month) {
+ return MONTH_LENGTH[month + (isLeapYear(year) ? 12 : 0)];
+}
+
+inline int8_t
+Grego::previousMonthLength(int y, int m) {
+ return (m > 0) ? monthLength(y, m-1) : 31;
+}
+
+inline void Grego::dayToFields(double day, int32_t& year, int32_t& month,
+ int32_t& dom, int32_t& dow) {
+ int32_t doy_unused;
+ dayToFields(day,year,month,dom,dow,doy_unused);
+}
+
+inline double Grego::julianDayToMillis(int32_t julian)
+{
+ return (julian - kEpochStartAsJulianDay) * kOneDay;
+}
+
+inline int32_t Grego::millisToJulianDay(double millis) {
+ return (int32_t) (kEpochStartAsJulianDay + Math::floorDivide(millis, (double)kOneDay));
+}
+
+inline int32_t Grego::gregorianShift(int32_t eyear) {
+ int32_t y = eyear-1;
+ int32_t gregShift = Math::floorDivide(y, 400) - Math::floorDivide(y, 100) + 2;
+ return gregShift;
+}
+
+/**
+ * This utility class provides convenient access to the data needed for a calendar.
+ * @internal ICU 3.0
+ */
+class CalendarData : public UMemory {
+public:
+ /**
+ * Construct a CalendarData from the given locale.
+ * @param loc locale to use. The 'calendar' keyword will be ignored.
+ * @param type calendar type. NULL indicates the gregorian calendar.
+ * No default lookup is done.
+ * @param status error code
+ */
+ CalendarData(const Locale& loc, const char *type, UErrorCode& status);
+
+ /**
+ * Load data for calendar. Note, this object owns the resources, do NOT call ures_close()!
+ * The ResourceBundle C++ API should NOT be used because it is too slow for a low level API.
+ *
+ * @param key Resource key to data
+ * @param status Error Status
+ * @internal
+ */
+ UResourceBundle* getByKey(const char *key, UErrorCode& status);
+
+ /**
+ * Load data for calendar. Note, this object owns the resources, do NOT call ures_close()!
+ * There is an implicit key of 'format'
+ * data is located in: "calendar/key/format/subKey"
+ * for example, calendar/dayNames/format/abbreviated
+ * The ResourceBundle C++ API should NOT be used because it is too slow for a low level API.
+ *
+ * @param key Resource key to data
+ * @param subKey Resource key to data
+ * @param status Error Status
+ * @internal
+ */
+ UResourceBundle* getByKey2(const char *key, const char *subKey, UErrorCode& status);
+
+ /**
+ * Load data for calendar. Note, this object owns the resources, do NOT call ures_close()!
+ * data is located in: "calendar/key/contextKey/subKey"
+ * for example, calendar/dayNames/standalone/narrow
+ * The ResourceBundle C++ API should NOT be used because it is too slow for a low level API.
+ *
+ * @param key Resource key to data
+ * @param contextKey Resource key to data
+ * @param subKey Resource key to data
+ * @param status Error Status
+ * @internal
+ */
+ UResourceBundle* getByKey3(const char *key, const char *contextKey, const char *subKey, UErrorCode& status);
+
+ ~CalendarData();
+
+private:
+ void initData(const char *locale, const char *type, UErrorCode& status);
+
+ UResourceBundle *fFillin;
+ UResourceBundle *fOtherFillin;
+ UResourceBundle *fBundle;
+ UResourceBundle *fFallback;
+ CalendarData(); // Not implemented.
+};
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
+#endif // GREGOIMP_H
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/hebrwcal.cpp b/Build/source/libs/icu/icu-xetex/i18n/hebrwcal.cpp
new file mode 100644
index 00000000000..b3ac7bc7fe7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/hebrwcal.cpp
@@ -0,0 +1,747 @@
+/*
+******************************************************************************
+* Copyright (C) 2003-2007, International Business Machines Corporation
+* and others. All Rights Reserved.
+******************************************************************************
+*
+* File HEBRWCAL.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 12/03/2003 srl ported from java HebrewCalendar
+*****************************************************************************
+*/
+
+#include "hebrwcal.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "umutex.h"
+#include <float.h>
+#include "gregoimp.h" // Math
+#include "astro.h" // CalendarAstronomer
+#include "uhash.h"
+#include "ucln_in.h"
+
+// Hebrew Calendar implementation
+
+/**
+* The absolute date, in milliseconds since 1/1/1970 AD, Gregorian,
+* of the start of the Hebrew calendar. In order to keep this calendar's
+* time of day in sync with that of the Gregorian calendar, we use
+* midnight, rather than sunset the day before.
+*/
+//static const double EPOCH_MILLIS = -180799862400000.; // 1/1/1 HY
+
+static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
+ // Minimum Greatest Least Maximum
+ // Minimum Maximum
+ { 0, 0, 0, 0 }, // ERA
+ { 1, 1, 5000000, 5000000 }, // YEAR
+ { 0, 0, 12, 12 }, // MONTH
+ { 1, 1, 51, 56 }, // WEEK_OF_YEAR
+ { 0, 0, 4, 6 }, // WEEK_OF_MONTH
+ { 1, 1, 29, 30 }, // DAY_OF_MONTH
+ { 1, 1, 353, 385 }, // DAY_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
+ { -1, -1, 5, 5 }, // DAY_OF_WEEK_IN_MONTH
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1/* */}, // AM_PM
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
+ { -5000001, -5000001, 5000001, 5000001 }, // YEAR_WOY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
+ { -5000000, -5000000, 5000000, 5000000 }, // EXTENDED_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
+};
+
+/**
+* The lengths of the Hebrew months. This is complicated, because there
+* are three different types of years, or six if you count leap years.
+* Due to the rules for postponing the start of the year to avoid having
+* certain holidays fall on the sabbath, the year can end up being three
+* different lengths, called "deficient", "normal", and "complete".
+*/
+static const int32_t MONTH_LENGTH[][3] = {
+ // Deficient Normal Complete
+ { 30, 30, 30 }, //Tishri
+ { 29, 29, 30 }, //Heshvan
+ { 29, 30, 30 }, //Kislev
+ { 29, 29, 29 }, //Tevet
+ { 30, 30, 30 }, //Shevat
+ { 30, 30, 30 }, //Adar I (leap years only)
+ { 29, 29, 29 }, //Adar
+ { 30, 30, 30 }, //Nisan
+ { 29, 29, 29 }, //Iyar
+ { 30, 30, 30 }, //Sivan
+ { 29, 29, 29 }, //Tammuz
+ { 30, 30, 30 }, //Av
+ { 29, 29, 29 }, //Elul
+};
+
+/**
+* The cumulative # of days to the end of each month in a non-leap year
+* Although this can be calculated from the MONTH_LENGTH table,
+* keeping it around separately makes some calculations a lot faster
+*/
+
+static const int32_t MONTH_START[][3] = {
+ // Deficient Normal Complete
+ { 0, 0, 0 }, // (placeholder)
+ { 30, 30, 30 }, // Tishri
+ { 59, 59, 60 }, // Heshvan
+ { 88, 89, 90 }, // Kislev
+ { 117, 118, 119 }, // Tevet
+ { 147, 148, 149 }, // Shevat
+ { 147, 148, 149 }, // (Adar I placeholder)
+ { 176, 177, 178 }, // Adar
+ { 206, 207, 208 }, // Nisan
+ { 235, 236, 237 }, // Iyar
+ { 265, 266, 267 }, // Sivan
+ { 294, 295, 296 }, // Tammuz
+ { 324, 325, 326 }, // Av
+ { 353, 354, 355 }, // Elul
+};
+
+/**
+* The cumulative # of days to the end of each month in a leap year
+*/
+static const int32_t LEAP_MONTH_START[][3] = {
+ // Deficient Normal Complete
+ { 0, 0, 0 }, // (placeholder)
+ { 30, 30, 30 }, // Tishri
+ { 59, 59, 60 }, // Heshvan
+ { 88, 89, 90 }, // Kislev
+ { 117, 118, 119 }, // Tevet
+ { 147, 148, 149 }, // Shevat
+ { 177, 178, 179 }, // Adar I
+ { 206, 207, 208 }, // Adar II
+ { 236, 237, 238 }, // Nisan
+ { 265, 266, 267 }, // Iyar
+ { 295, 296, 297 }, // Sivan
+ { 324, 325, 326 }, // Tammuz
+ { 354, 355, 356 }, // Av
+ { 383, 384, 385 }, // Elul
+};
+
+static U_NAMESPACE_QUALIFIER CalendarCache *gCache = NULL;
+
+U_CDECL_BEGIN
+static UBool calendar_hebrew_cleanup(void) {
+ delete gCache;
+ gCache = NULL;
+ return TRUE;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+//-------------------------------------------------------------------------
+// Constructors...
+//-------------------------------------------------------------------------
+
+/**
+* Constructs a default <code>HebrewCalendar</code> using the current time
+* in the default time zone with the default locale.
+* @internal
+*/
+HebrewCalendar::HebrewCalendar(const Locale& aLocale, UErrorCode& success)
+: Calendar(TimeZone::createDefault(), aLocale, success)
+
+{
+ setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
+}
+
+
+HebrewCalendar::~HebrewCalendar() {
+}
+
+const char *HebrewCalendar::getType() const {
+ return "hebrew";
+}
+
+Calendar* HebrewCalendar::clone() const {
+ return new HebrewCalendar(*this);
+}
+
+HebrewCalendar::HebrewCalendar(const HebrewCalendar& other) : Calendar(other) {
+}
+
+
+//-------------------------------------------------------------------------
+// Rolling and adding functions overridden from Calendar
+//
+// These methods call through to the default implementation in IBMCalendar
+// for most of the fields and only handle the unusual ones themselves.
+//-------------------------------------------------------------------------
+
+/**
+* Add a signed amount to a specified field, using this calendar's rules.
+* For example, to add three days to the current date, you can call
+* <code>add(Calendar.DATE, 3)</code>.
+* <p>
+* When adding to certain fields, the values of other fields may conflict and
+* need to be changed. For example, when adding one to the {@link #MONTH MONTH} field
+* for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
+* must be adjusted so that the result is "29 Elul 5758" rather than the invalid
+* "30 Elul 5758".
+* <p>
+* This method is able to add to
+* all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
+* and {@link #ZONE_OFFSET ZONE_OFFSET}.
+* <p>
+* <b>Note:</b> You should always use {@link #roll roll} and add rather
+* than attempting to perform arithmetic operations directly on the fields
+* of a <tt>HebrewCalendar</tt>. Since the {@link #MONTH MONTH} field behaves
+* discontinuously in non-leap years, simple arithmetic can give invalid results.
+* <p>
+* @param field the time field.
+* @param amount the amount to add to the field.
+*
+* @exception IllegalArgumentException if the field is invalid or refers
+* to a field that cannot be handled by this method.
+* @internal
+*/
+void HebrewCalendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status)
+{
+ if(U_FAILURE(status)) {
+ return;
+ }
+ switch (field) {
+ case UCAL_MONTH:
+ {
+ // We can't just do a set(MONTH, get(MONTH) + amount). The
+ // reason is ADAR_1. Suppose amount is +2 and we land in
+ // ADAR_1 -- then we have to bump to ADAR_2 aka ADAR. But
+ // if amount is -2 and we land in ADAR_1, then we have to
+ // bump the other way -- down to SHEVAT. - Alan 11/00
+ int32_t month = get(UCAL_MONTH, status);
+ int32_t year = get(UCAL_YEAR, status);
+ UBool acrossAdar1;
+ if (amount > 0) {
+ acrossAdar1 = (month < ADAR_1); // started before ADAR_1?
+ month += amount;
+ for (;;) {
+ if (acrossAdar1 && month>=ADAR_1 && !isLeapYear(year)) {
+ ++month;
+ }
+ if (month <= ELUL) {
+ break;
+ }
+ month -= ELUL+1;
+ ++year;
+ acrossAdar1 = TRUE;
+ }
+ } else {
+ acrossAdar1 = (month > ADAR_1); // started after ADAR_1?
+ month += amount;
+ for (;;) {
+ if (acrossAdar1 && month<=ADAR_1 && !isLeapYear(year)) {
+ --month;
+ }
+ if (month >= 0) {
+ break;
+ }
+ month += ELUL+1;
+ --year;
+ acrossAdar1 = TRUE;
+ }
+ }
+ set(UCAL_MONTH, month);
+ set(UCAL_YEAR, year);
+ pinField(UCAL_DAY_OF_MONTH, status);
+ break;
+ }
+
+ default:
+ Calendar::add(field, amount, status);
+ break;
+ }
+}
+
+/**
+* @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
+*/
+void HebrewCalendar::add(EDateFields field, int32_t amount, UErrorCode& status)
+{
+ add((UCalendarDateFields)field, amount, status);
+}
+
+/**
+* Rolls (up/down) a specified amount time on the given field. For
+* example, to roll the current date up by three days, you can call
+* <code>roll(Calendar.DATE, 3)</code>. If the
+* field is rolled past its maximum allowable value, it will "wrap" back
+* to its minimum and continue rolling.
+* For example, calling <code>roll(Calendar.DATE, 10)</code>
+* on a Hebrew calendar set to "25 Av 5758" will result in the date "5 Av 5758".
+* <p>
+* When rolling certain fields, the values of other fields may conflict and
+* need to be changed. For example, when rolling the {@link #MONTH MONTH} field
+* upward by one for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
+* must be adjusted so that the result is "29 Elul 5758" rather than the invalid
+* "30 Elul".
+* <p>
+* This method is able to roll
+* all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
+* and {@link #ZONE_OFFSET ZONE_OFFSET}. Subclasses may, of course, add support for
+* additional fields in their overrides of <code>roll</code>.
+* <p>
+* <b>Note:</b> You should always use roll and {@link #add add} rather
+* than attempting to perform arithmetic operations directly on the fields
+* of a <tt>HebrewCalendar</tt>. Since the {@link #MONTH MONTH} field behaves
+* discontinuously in non-leap years, simple arithmetic can give invalid results.
+* <p>
+* @param field the time field.
+* @param amount the amount by which the field should be rolled.
+*
+* @exception IllegalArgumentException if the field is invalid or refers
+* to a field that cannot be handled by this method.
+* @internal
+*/
+void HebrewCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
+{
+ if(U_FAILURE(status)) {
+ return;
+ }
+ switch (field) {
+ case UCAL_MONTH:
+ {
+ int32_t month = get(UCAL_MONTH, status);
+ int32_t year = get(UCAL_YEAR, status);
+
+ UBool leapYear = isLeapYear(year);
+ int32_t yearLength = monthsInYear(year);
+ int32_t newMonth = month + (amount % yearLength);
+ //
+ // If it's not a leap year and we're rolling past the missing month
+ // of ADAR_1, we need to roll an extra month to make up for it.
+ //
+ if (!leapYear) {
+ if (amount > 0 && month < ADAR_1 && newMonth >= ADAR_1) {
+ newMonth++;
+ } else if (amount < 0 && month > ADAR_1 && newMonth <= ADAR_1) {
+ newMonth--;
+ }
+ }
+ set(UCAL_MONTH, (newMonth + 13) % 13);
+ pinField(UCAL_DAY_OF_MONTH, status);
+ return;
+ }
+ default:
+ Calendar::roll(field, amount, status);
+ }
+}
+
+void HebrewCalendar::roll(EDateFields field, int32_t amount, UErrorCode& status) {
+ roll((UCalendarDateFields)field, amount, status);
+}
+
+//-------------------------------------------------------------------------
+// Support methods
+//-------------------------------------------------------------------------
+
+// Hebrew date calculations are performed in terms of days, hours, and
+// "parts" (or halakim), which are 1/1080 of an hour, or 3 1/3 seconds.
+static const int32_t HOUR_PARTS = 1080;
+static const int32_t DAY_PARTS = 24*HOUR_PARTS;
+
+// An approximate value for the length of a lunar month.
+// It is used to calculate the approximate year and month of a given
+// absolute date.
+static const int32_t MONTH_DAYS = 29;
+static const int32_t MONTH_FRACT = 12*HOUR_PARTS + 793;
+static const int32_t MONTH_PARTS = MONTH_DAYS*DAY_PARTS + MONTH_FRACT;
+
+// The time of the new moon (in parts) on 1 Tishri, year 1 (the epoch)
+// counting from noon on the day before. BAHARAD is an abbreviation of
+// Bet (Monday), Hey (5 hours from sunset), Resh-Daled (204).
+static const int32_t BAHARAD = 11*HOUR_PARTS + 204;
+
+/**
+* Finds the day # of the first day in the given Hebrew year.
+* To do this, we want to calculate the time of the Tishri 1 new moon
+* in that year.
+* <p>
+* The algorithm here is similar to ones described in a number of
+* references, including:
+* <ul>
+* <li>"Calendrical Calculations", by Nachum Dershowitz & Edward Reingold,
+* Cambridge University Press, 1997, pages 85-91.
+*
+* <li>Hebrew Calendar Science and Myths,
+* <a href="http://www.geocities.com/Athens/1584/">
+* http://www.geocities.com/Athens/1584/</a>
+*
+* <li>The Calendar FAQ,
+* <a href="http://www.faqs.org/faqs/calendars/faq/">
+* http://www.faqs.org/faqs/calendars/faq/</a>
+* </ul>
+*/
+int32_t HebrewCalendar::startOfYear(int32_t year, UErrorCode &status)
+{
+ ucln_i18n_registerCleanup(UCLN_I18N_HEBREW_CALENDAR, calendar_hebrew_cleanup);
+ int32_t day = CalendarCache::get(&gCache, year, status);
+
+ if (day == 0) {
+ int32_t months = (235 * year - 234) / 19; // # of months before year
+
+ int32_t frac = months * MONTH_FRACT + BAHARAD; // Fractional part of day #
+ day = months * 29 + (frac / DAY_PARTS); // Whole # part of calculation
+ frac = frac % DAY_PARTS; // Time of day
+
+ int32_t wd = (day % 7); // Day of week (0 == Monday)
+
+ if (wd == 2 || wd == 4 || wd == 6) {
+ // If the 1st is on Sun, Wed, or Fri, postpone to the next day
+ day += 1;
+ wd = (day % 7);
+ }
+ if (wd == 1 && frac > 15*HOUR_PARTS+204 && !isLeapYear(year) ) {
+ // If the new moon falls after 3:11:20am (15h204p from the previous noon)
+ // on a Tuesday and it is not a leap year, postpone by 2 days.
+ // This prevents 356-day years.
+ day += 2;
+ }
+ else if (wd == 0 && frac > 21*HOUR_PARTS+589 && isLeapYear(year-1) ) {
+ // If the new moon falls after 9:32:43 1/3am (21h589p from yesterday noon)
+ // on a Monday and *last* year was a leap year, postpone by 1 day.
+ // Prevents 382-day years.
+ day += 1;
+ }
+ CalendarCache::put(&gCache, year, day, status);
+ }
+ return day;
+}
+
+/**
+* Find the day of the week for a given day
+*
+* @param day The # of days since the start of the Hebrew calendar,
+* 1-based (i.e. 1/1/1 AM is day 1).
+*/
+int32_t HebrewCalendar::absoluteDayToDayOfWeek(int32_t day)
+{
+ // We know that 1/1/1 AM is a Monday, which makes the math easy...
+ return (day % 7) + 1;
+}
+
+/**
+* Returns the the type of a given year.
+* 0 "Deficient" year with 353 or 383 days
+* 1 "Normal" year with 354 or 384 days
+* 2 "Complete" year with 355 or 385 days
+*/
+int32_t HebrewCalendar::yearType(int32_t year) const
+{
+ int32_t yearLength = handleGetYearLength(year);
+
+ if (yearLength > 380) {
+ yearLength -= 30; // Subtract length of leap month.
+ }
+
+ int type = 0;
+
+ switch (yearLength) {
+ case 353:
+ type = 0; break;
+ case 354:
+ type = 1; break;
+ case 355:
+ type = 2; break;
+ default:
+ //throw new RuntimeException("Illegal year length " + yearLength + " in year " + year);
+ type = 1;
+ }
+ return type;
+}
+
+/**
+* Determine whether a given Hebrew year is a leap year
+*
+* The rule here is that if (year % 19) == 0, 3, 6, 8, 11, 14, or 17.
+* The formula below performs the same test, believe it or not.
+*/
+UBool HebrewCalendar::isLeapYear(int32_t year) {
+ //return (year * 12 + 17) % 19 >= 12;
+ int32_t x = (year*12 + 17) % 19;
+ return x >= ((x < 0) ? -7 : 12);
+}
+
+int32_t HebrewCalendar::monthsInYear(int32_t year) {
+ return isLeapYear(year) ? 13 : 12;
+}
+
+//-------------------------------------------------------------------------
+// Calendar framework
+//-------------------------------------------------------------------------
+
+/**
+* @internal
+*/
+int32_t HebrewCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
+ return LIMITS[field][limitType];
+}
+
+/**
+* Returns the length of the given month in the given year
+* @internal
+*/
+int32_t HebrewCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
+ // Resolve out-of-range months. This is necessary in order to
+ // obtain the correct year. We correct to
+ // a 12- or 13-month year (add/subtract 12 or 13, depending
+ // on the year) but since we _always_ number from 0..12, and
+ // the leap year determines whether or not month 5 (Adar 1)
+ // is present, we allow 0..12 in any given year.
+ while (month < 0) {
+ month += monthsInYear(--extendedYear);
+ }
+ // Careful: allow 0..12 in all years
+ while (month > 12) {
+ month -= monthsInYear(extendedYear++);
+ }
+
+ switch (month) {
+ case HESHVAN:
+ case KISLEV:
+ // These two month lengths can vary
+ return MONTH_LENGTH[month][yearType(extendedYear)];
+
+ default:
+ // The rest are a fixed length
+ return MONTH_LENGTH[month][0];
+ }
+}
+
+/**
+* Returns the number of days in the given Hebrew year
+* @internal
+*/
+int32_t HebrewCalendar::handleGetYearLength(int32_t eyear) const {
+ UErrorCode status = U_ZERO_ERROR;
+ return startOfYear(eyear+1, status) - startOfYear(eyear, status);
+}
+
+//-------------------------------------------------------------------------
+// Functions for converting from milliseconds to field values
+//-------------------------------------------------------------------------
+
+/**
+* Subclasses may override this method to compute several fields
+* specific to each calendar system. These are:
+*
+* <ul><li>ERA
+* <li>YEAR
+* <li>MONTH
+* <li>DAY_OF_MONTH
+* <li>DAY_OF_YEAR
+* <li>EXTENDED_YEAR</ul>
+*
+* Subclasses can refer to the DAY_OF_WEEK and DOW_LOCAL fields,
+* which will be set when this method is called. Subclasses can
+* also call the getGregorianXxx() methods to obtain Gregorian
+* calendar equivalents for the given Julian day.
+*
+* <p>In addition, subclasses should compute any subclass-specific
+* fields, that is, fields from BASE_FIELD_COUNT to
+* getFieldCount() - 1.
+* @internal
+*/
+void HebrewCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
+ int32_t d = julianDay - 347997;
+ double m = ((d * (double)DAY_PARTS)/ (double) MONTH_PARTS); // Months (approx)
+ int32_t year = (int32_t)( ((19. * m + 234.) / 235.) + 1.); // Years (approx)
+ int32_t ys = startOfYear(year, status); // 1st day of year
+ int32_t dayOfYear = (d - ys);
+
+ // Because of the postponement rules, it's possible to guess wrong. Fix it.
+ while (dayOfYear < 1) {
+ year--;
+ ys = startOfYear(year, status);
+ dayOfYear = (d - ys);
+ }
+
+ // Now figure out which month we're in, and the date within that month
+ int32_t type = yearType(year);
+ UBool isLeap = isLeapYear(year);
+
+ int32_t month = 0;
+ while (dayOfYear > ( isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type] ) ) {
+ month++;
+ }
+ month--;
+ int dayOfMonth = dayOfYear - (isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type]);
+
+ internalSet(UCAL_ERA, 0);
+ internalSet(UCAL_YEAR, year);
+ internalSet(UCAL_EXTENDED_YEAR, year);
+ internalSet(UCAL_MONTH, month);
+ internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
+ internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
+}
+
+//-------------------------------------------------------------------------
+// Functions for converting from field values to milliseconds
+//-------------------------------------------------------------------------
+
+/**
+* @internal
+*/
+int32_t HebrewCalendar::handleGetExtendedYear() {
+ int32_t year;
+ if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
+ year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
+ } else {
+ year = internalGet(UCAL_YEAR, 1); // Default to year 1
+ }
+ return year;
+}
+
+/**
+* Return JD of start of given month/year.
+* @internal
+*/
+int32_t HebrewCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /*useMonth*/) const {
+ UErrorCode status = U_ZERO_ERROR;
+ // Resolve out-of-range months. This is necessary in order to
+ // obtain the correct year. We correct to
+ // a 12- or 13-month year (add/subtract 12 or 13, depending
+ // on the year) but since we _always_ number from 0..12, and
+ // the leap year determines whether or not month 5 (Adar 1)
+ // is present, we allow 0..12 in any given year.
+ while (month < 0) {
+ month += monthsInYear(--eyear);
+ }
+ // Careful: allow 0..12 in all years
+ while (month > 12) {
+ month -= monthsInYear(eyear++);
+ }
+
+ int32_t day = startOfYear(eyear, status);
+
+ if(U_FAILURE(status)) {
+ return 0;
+ }
+
+ if (month != 0) {
+ if (isLeapYear(eyear)) {
+ day += LEAP_MONTH_START[month][yearType(eyear)];
+ } else {
+ day += MONTH_START[month][yearType(eyear)];
+ }
+ }
+
+ return (int) (day + 347997);
+}
+
+UBool
+HebrewCalendar::inDaylightTime(UErrorCode& status) const
+{
+ // copied from GregorianCalendar
+ if (U_FAILURE(status) || !getTimeZone().useDaylightTime())
+ return FALSE;
+
+ // Force an update of the state of the Calendar.
+ ((HebrewCalendar*)this)->complete(status); // cast away const
+
+ return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
+}
+
+// default century
+const UDate HebrewCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t HebrewCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate HebrewCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t HebrewCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+
+UBool HebrewCalendar::haveDefaultCentury() const
+{
+ return TRUE;
+}
+
+UDate HebrewCalendar::defaultCenturyStart() const
+{
+ return internalGetDefaultCenturyStart();
+}
+
+int32_t HebrewCalendar::defaultCenturyStartYear() const
+{
+ return internalGetDefaultCenturyStartYear();
+}
+
+UDate
+HebrewCalendar::internalGetDefaultCenturyStart() const
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStart
+
+ return fgSystemDefaultCenturyStart;
+}
+
+int32_t
+HebrewCalendar::internalGetDefaultCenturyStartYear() const
+{
+ // lazy-evaluate systemDefaultCenturyStartYear
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStartYear
+
+ return fgSystemDefaultCenturyStartYear;
+}
+
+void
+HebrewCalendar::initializeSystemDefaultCentury()
+{
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ // No point in locking as it should be idempotent.
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ HebrewCalendar calendar(Locale("@calendar=hebrew"),status);
+ if (U_SUCCESS(status))
+ {
+ calendar.setTime(Calendar::getNow(), status);
+ calendar.add(UCAL_YEAR, -80, status);
+ UDate newStart = calendar.getTime(status);
+ int32_t newYear = calendar.get(UCAL_YEAR, status);
+ {
+ umtx_lock(NULL);
+ fgSystemDefaultCenturyStart = newStart;
+ fgSystemDefaultCenturyStartYear = newYear;
+ umtx_unlock(NULL);
+ }
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+ }
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(HebrewCalendar)
+
+U_NAMESPACE_END
+
+#endif // UCONFIG_NO_FORMATTING
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/hebrwcal.h b/Build/source/libs/icu/icu-xetex/i18n/hebrwcal.h
new file mode 100644
index 00000000000..ead8bfae0b5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/hebrwcal.h
@@ -0,0 +1,486 @@
+/*
+******************************************************************************
+* Copyright (C) 2003-2007, International Business Machines Corporation
+* and others. All Rights Reserved.
+******************************************************************************
+*
+* File HEBRWCAL.H
+*
+* Modification History:
+*
+* Date Name Description
+* 05/13/2003 srl copied from gregocal.h
+* 11/26/2003 srl copied from buddhcal.h
+******************************************************************************
+*/
+
+#ifndef HEBRWCAL_H
+#define HEBRWCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * <code>HebrewCalendar</code> is a subclass of <code>Calendar</code>
+ * that that implements the traditional Hebrew calendar.
+ * This is the civil calendar in Israel and the liturgical calendar
+ * of the Jewish faith worldwide.
+ * <p>
+ * The Hebrew calendar is lunisolar and thus has a number of interesting
+ * properties that distinguish it from the Gregorian. Months start
+ * on the day of (an arithmetic approximation of) each new moon. Since the
+ * solar year (approximately 365.24 days) is not an even multiple of
+ * the lunar month (approximately 29.53 days) an extra "leap month" is
+ * inserted in 7 out of every 19 years. To make matters even more
+ * interesting, the start of a year can be delayed by up to three days
+ * in order to prevent certain holidays from falling on the Sabbath and
+ * to prevent certain illegal year lengths. Finally, the lengths of certain
+ * months can vary depending on the number of days in the year.
+ * <p>
+ * The leap month is known as "Adar 1" and is inserted between the
+ * months of Shevat and Adar in leap years. Since the leap month does
+ * not come at the end of the year, calculations involving
+ * month numbers are particularly complex. Users of this class should
+ * make sure to use the {@link #roll roll} and {@link #add add} methods
+ * rather than attempting to perform date arithmetic by manipulating
+ * the fields directly.
+ * <p>
+ * <b>Note:</b> In the traditional Hebrew calendar, days start at sunset.
+ * However, in order to keep the time fields in this class
+ * synchronized with those of the other calendars and with local clock time,
+ * we treat days and months as beginning at midnight,
+ * roughly 6 hours after the corresponding sunset.
+ * <p>
+ * If you are interested in more information on the rules behind the Hebrew
+ * calendar, see one of the following references:
+ * <ul>
+ * <li>"<a href="http://www.amazon.com/exec/obidos/ASIN/0521564743">Calendrical Calculations</a>",
+ * by Nachum Dershowitz & Edward Reingold, Cambridge University Press, 1997, pages 85-91.
+ *
+ * <li>Hebrew Calendar Science and Myths,
+ * <a href="http://www.geocities.com/Athens/1584/">
+ * http://www.geocities.com/Athens/1584/</a>
+ *
+ * <li>The Calendar FAQ,
+ * <a href="http://www.faqs.org/faqs/calendars/faq/">
+ * http://www.faqs.org/faqs/calendars/faq/</a>
+ * </ul>
+ * <p>
+ * @see com.ibm.icu.util.GregorianCalendar
+ *
+ * @author Laura Werner
+ * @author Alan Liu
+ * @author Steven R. Loomis
+ * <p>
+ * @internal
+ */
+class HebrewCalendar : public Calendar {
+public:
+ /**
+ * Useful constants for HebrewCalendar.
+ * @internal
+ */
+ enum EEras {
+ /**
+ * Constant for Tishri, the 1st month of the Hebrew year.
+ */
+ TISHRI,
+ /**
+ * Constant for Heshvan, the 2nd month of the Hebrew year.
+ */
+ HESHVAN,
+ /**
+ * Constant for Kislev, the 3rd month of the Hebrew year.
+ */
+ KISLEV,
+
+ /**
+ * Constant for Tevet, the 4th month of the Hebrew year.
+ */
+ TEVET,
+
+ /**
+ * Constant for Shevat, the 5th month of the Hebrew year.
+ */
+ SHEVAT,
+
+ /**
+ * Constant for Adar I, the 6th month of the Hebrew year
+ * (present in leap years only). In non-leap years, the calendar
+ * jumps from Shevat (5th month) to Adar (7th month).
+ */
+ ADAR_1,
+
+ /**
+ * Constant for the Adar, the 7th month of the Hebrew year.
+ */
+ ADAR,
+
+ /**
+ * Constant for Nisan, the 8th month of the Hebrew year.
+ */
+ NISAN,
+
+ /**
+ * Constant for Iyar, the 9th month of the Hebrew year.
+ */
+ IYAR,
+
+ /**
+ * Constant for Sivan, the 10th month of the Hebrew year.
+ */
+ SIVAN,
+
+ /**
+ * Constant for Tammuz, the 11th month of the Hebrew year.
+ */
+ TAMUZ,
+
+ /**
+ * Constant for Av, the 12th month of the Hebrew year.
+ */
+ AV,
+
+ /**
+ * Constant for Elul, the 13th month of the Hebrew year.
+ */
+ ELUL
+ };
+
+ /**
+ * Constructs a HebrewCalendar based on the current time in the default time zone
+ * with the given locale.
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the status of HebrewCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @internal
+ */
+ HebrewCalendar(const Locale& aLocale, UErrorCode& success);
+
+
+ /**
+ * Destructor
+ * @internal
+ */
+ virtual ~HebrewCalendar();
+
+ /**
+ * Copy constructor
+ * @param source the object to be copied.
+ * @internal
+ */
+ HebrewCalendar(const HebrewCalendar& source);
+
+ /**
+ * Default assignment operator
+ * @param right the object to be copied.
+ * @internal
+ */
+ HebrewCalendar& operator=(const HebrewCalendar& right);
+
+ /**
+ * Create and return a polymorphic copy of this calendar.
+ * @return return a polymorphic copy of this calendar.
+ * @internal
+ */
+ virtual Calendar* clone(void) const;
+
+public:
+ /**
+ * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
+ * override. This method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
+ * this method.
+ *
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @internal
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to a return
+ * value from getDynamicClassID(). For example:
+ *
+ * Base* polymorphic_pointer = createPolymorphicObject();
+ * if (polymorphic_pointer->getDynamicClassID() ==
+ * Derived::getStaticClassID()) ...
+ *
+ * @return The class ID for all objects of this class.
+ * @internal
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * return the calendar type, "hebrew".
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+
+ // Calendar API
+ public:
+ /**
+ * (Overrides Calendar) UDate Arithmetic function. Adds the specified (signed) amount
+ * of time to the given time field, based on the calendar's rules. For more
+ * information, see the documentation for Calendar::add().
+ *
+ * @param field The time field.
+ * @param amount The amount of date or time to be added to the field.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ */
+ virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode& status);
+ /**
+ * @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
+ */
+ virtual void add(EDateFields field, int32_t amount, UErrorCode& status);
+
+
+ /**
+ * (Overrides Calendar) Rolls up or down by the given amount in the specified field.
+ * For more information, see the documentation for Calendar::roll().
+ *
+ * @param field The time field.
+ * @param amount Indicates amount to roll.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ * @internal
+ */
+ virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode& status);
+
+ /**
+ * (Overrides Calendar) Rolls up or down by the given amount in the specified field.
+ * For more information, see the documentation for Calendar::roll().
+ *
+ * @param field The time field.
+ * @param amount Indicates amount to roll.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ * @deprecated ICU 2.6. Use roll(UCalendarDateFields field, int32_t amount, UErrorCode& status) instead.
+` */
+ virtual void roll(EDateFields field, int32_t amount, UErrorCode& status);
+
+
+ protected:
+
+ /**
+ * Subclass API for defining limits of different types.
+ * Subclasses must implement this method to return limits for the
+ * following fields:
+ *
+ * <pre>UCAL_ERA
+ * UCAL_YEAR
+ * UCAL_MONTH
+ * UCAL_WEEK_OF_YEAR
+ * UCAL_WEEK_OF_MONTH
+ * UCAL_DATE (DAY_OF_MONTH on Java)
+ * UCAL_DAY_OF_YEAR
+ * UCAL_DAY_OF_WEEK_IN_MONTH
+ * UCAL_YEAR_WOY
+ * UCAL_EXTENDED_YEAR</pre>
+ *
+ * @param field one of the above field numbers
+ * @param limitType one of <code>MINIMUM</code>, <code>GREATEST_MINIMUM</code>,
+ * <code>LEAST_MAXIMUM</code>, or <code>MAXIMUM</code>
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+
+ /**
+ * Return the number of days in the given month of the given extended
+ * year of this calendar system. Subclasses should override this
+ * method if they can provide a more correct or more efficient
+ * implementation than the default implementation in Calendar.
+ * @internal
+ */
+ virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const;
+
+ /**
+ * Return the number of days in the given extended year of this
+ * calendar system. Subclasses should override this method if they can
+ * provide a more correct or more efficient implementation than the
+ * default implementation in Calendar.
+ * @stable ICU 2.0
+ */
+ virtual int32_t handleGetYearLength(int32_t eyear) const;
+ /**
+ * Subclasses may override this method to compute several fields
+ * specific to each calendar system. These are:
+ *
+ * <ul><li>ERA
+ * <li>YEAR
+ * <li>MONTH
+ * <li>DAY_OF_MONTH
+ * <li>DAY_OF_YEAR
+ * <li>EXTENDED_YEAR</ul>
+ *
+ * <p>The GregorianCalendar implementation implements
+ * a calendar with the specified Julian/Gregorian cutover date.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
+ /**
+ * Return the extended year defined by the current fields. This will
+ * use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
+ * as UCAL_ERA) specific to the calendar system, depending on which set of
+ * fields is newer.
+ * @return the extended year
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+ /**
+ * Return the Julian day number of day before the first day of the
+ * given month in the given extended year. Subclasses should override
+ * this method to implement their calendar system.
+ * @param eyear the extended year
+ * @param month the zero-based month, or 0 if useMonth is false
+ * @param useMonth if false, compute the day before the first day of
+ * the given year, otherwise, compute the day before the first day of
+ * the given month
+ * @param return the Julian day number of the day before the first
+ * day of the given month and year
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month,
+ UBool useMonth) const;
+
+
+
+ protected:
+
+ /**
+ * (Overrides Calendar) Return true if the current date for this Calendar is in
+ * Daylight Savings Time. Recognizes DST_OFFSET, if it is set.
+ *
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return True if the current date for this Calendar is in Daylight Savings Time,
+ * false, otherwise.
+ * @internal
+ */
+ virtual UBool inDaylightTime(UErrorCode& status) const;
+
+ /**
+ * Returns TRUE because the Hebrew Calendar does have a default century
+ * @internal
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * Returns the date of the start of the default century
+ * @return start of century - in milliseconds since epoch, 1970
+ * @internal
+ */
+ virtual UDate defaultCenturyStart() const;
+
+ /**
+ * Returns the year in which the default century begins
+ * @internal
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+ private: // default century stuff.
+ /**
+ * The system maintains a static default century start date. This is initialized
+ * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
+ * indicate an uninitialized state. Once the system default century date and year
+ * are set, they do not change.
+ */
+ static UDate fgSystemDefaultCenturyStart;
+
+ /**
+ * See documentation for systemDefaultCenturyStart.
+ */
+ static int32_t fgSystemDefaultCenturyStartYear;
+
+ /**
+ * Default value that indicates the defaultCenturyStartYear is unitialized
+ */
+ static const int32_t fgSystemDefaultCenturyYear;
+
+ /**
+ * start of default century, as a date
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * Returns the beginning date of the 100-year window that dates
+ * with 2-digit years are considered to fall within.
+ */
+ UDate internalGetDefaultCenturyStart(void) const;
+
+ /**
+ * Returns the first year of the 100-year window that dates with
+ * 2-digit years are considered to fall within.
+ */
+ int32_t internalGetDefaultCenturyStartYear(void) const;
+
+ /**
+ * Initializes the 100-year window that dates with 2-digit years
+ * are considered to fall within so that its start date is 80 years
+ * before the current time.
+ */
+ static void initializeSystemDefaultCentury(void);
+
+ private: // Calendar-specific implementation
+ /**
+ * Finds the day # of the first day in the given Hebrew year.
+ * To do this, we want to calculate the time of the Tishri 1 new moon
+ * in that year.
+ * <p>
+ * The algorithm here is similar to ones described in a number of
+ * references, including:
+ * <ul>
+ * <li>"Calendrical Calculations", by Nachum Dershowitz & Edward Reingold,
+ * Cambridge University Press, 1997, pages 85-91.
+ *
+ * <li>Hebrew Calendar Science and Myths,
+ * <a href="http://www.geocities.com/Athens/1584/">
+ * http://www.geocities.com/Athens/1584/</a>
+ *
+ * <li>The Calendar FAQ,
+ * <a href="http://www.faqs.org/faqs/calendars/faq/">
+ * http://www.faqs.org/faqs/calendars/faq/</a>
+ * </ul>
+ * @param year extended year
+ * @return day number (JD)
+ * @internal
+ */
+ static int32_t startOfYear(int32_t year, UErrorCode& status);
+
+ static int32_t absoluteDayToDayOfWeek(int32_t day) ;
+
+ /**
+ * @internal
+ */
+ int32_t yearType(int32_t year) const;
+
+ /**
+ * @internal
+ */
+ static UBool isLeapYear(int32_t year) ;
+ /**
+ * @internal
+ */
+ static int32_t monthsInYear(int32_t year) ;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/i18n.rc b/Build/source/libs/icu/icu-xetex/i18n/i18n.rc
new file mode 100644
index 00000000000..668ce3c3c9f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/i18n.rc
@@ -0,0 +1,108 @@
+// Do not edit with Microsoft Developer Studio Resource Editor.
+// It will permanently substitute version numbers that are intended to be
+// picked up by the pre-processor during each build.
+// Copyright (c) 2001-2005 International Business Machines
+// Corporation and others. All Rights Reserved.
+//
+#include "../common/msvcres.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <winresrc.h>
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+//
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "../common/msvcres.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <winresrc.h>\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#define STR(s) #s
+#define CommaVersionString(a, b, c, d) STR(a) ", " STR(b) ", " STR(c) ", " STR(d) "\0"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION U_ICU_VERSION_MAJOR_NUM, U_ICU_VERSION_MINOR_NUM, U_ICU_VERSION_PATCHLEVEL_NUM, 0
+ PRODUCTVERSION U_ICU_VERSION_MAJOR_NUM, U_ICU_VERSION_MINOR_NUM, U_ICU_VERSION_PATCHLEVEL_NUM, 0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "00000000"
+ BEGIN
+ VALUE "Comments", ICU_WEBSITE "\0"
+ VALUE "CompanyName", "IBM Corporation and others\0"
+ VALUE "FileDescription", "IBM ICU I18N DLL\0"
+ VALUE "FileVersion", CommaVersionString(U_ICU_VERSION_MAJOR_NUM, U_ICU_VERSION_MINOR_NUM, U_ICU_VERSION_PATCHLEVEL_NUM, 0)
+ VALUE "LegalCopyright", U_COPYRIGHT_STRING "\0"
+#ifdef _DEBUG
+ VALUE "OriginalFilename", "icuin" U_ICU_VERSION_SHORT "d.dll\0")
+#else
+ VALUE "OriginalFilename", "icuin" U_ICU_VERSION_SHORT ".dll\0")
+#endif
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "International Components for Unicode\0"
+ VALUE "ProductVersion", CommaVersionString(U_ICU_VERSION_MAJOR_NUM, U_ICU_VERSION_MINOR_NUM, U_ICU_VERSION_PATCHLEVEL_NUM, 0)
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x000, 0000
+ END
+END
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/i18n.vcproj b/Build/source/libs/icu/icu-xetex/i18n/i18n.vcproj
new file mode 100644
index 00000000000..288a45cd379
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/i18n.vcproj
@@ -0,0 +1,2137 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="i18n"
+ ProjectGUID="{0178B127-6269-407D-B112-93877BB62776}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\..\..\lib"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\..\..\lib\icuin.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\include;..\common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;U_I18N_IMPLEMENTATION"
+ StringPooling="true"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="true"
+ TreatWChar_tAsBuiltInType="true"
+ PrecompiledHeaderFile=".\Release/i18n.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories="../common"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\bin\icuin38.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ ProgramDatabaseFile=".\..\..\lib\icuin38.pdb"
+ EnableCOMDATFolding="2"
+ BaseAddress="0x4a900000"
+ ImportLibrary="..\..\lib\icuin.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\..\..\lib"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\..\..\lib\icuind.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include;..\common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;U_I18N_IMPLEMENTATION"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="true"
+ DisableLanguageExtensions="true"
+ TreatWChar_tAsBuiltInType="true"
+ PrecompiledHeaderFile=".\Debug/i18n.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ AdditionalIncludeDirectories="../common"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\bin\icuin38d.dll"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\..\..\lib\icuin38d.pdb"
+ BaseAddress="0x4a900000"
+ ImportLibrary="..\..\lib\icuind.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ UseFAT32Workaround="true"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="collation"
+ >
+ <File
+ RelativePath=".\bocsu.c"
+ >
+ </File>
+ <File
+ RelativePath=".\bocsu.h"
+ >
+ </File>
+ <File
+ RelativePath=".\coleitr.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\coleitr.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\coll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\coll.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\search.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\search.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\sortkey.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\sortkey.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\stsearch.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\stsearch.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\tblcoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\tblcoll.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\ucol.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\ucol.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\ucol_bld.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_bld.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_cnt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_cnt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_elm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_elm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_imp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_res.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_sit.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_tok.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_tok.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_wgt.c"
+ >
+ </File>
+ <File
+ RelativePath=".\ucol_wgt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ucoleitr.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\ucoleitr.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\usearch.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\usearch.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\usrchimp.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="formatting"
+ >
+ <File
+ RelativePath=".\astro.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\astro.h"
+ >
+ </File>
+ <File
+ RelativePath=".\basictz.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\basictz.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\buddhcal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\buddhcal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\calendar.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\calendar.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\choicfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\choicfmt.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\curramt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\curramt.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\currfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\currfmt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\currunit.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\currunit.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\datefmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\datefmt.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\dcfmtsym.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\dcfmtsym.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\decimfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\decimfmt.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\digitlst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\digitlst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dtfmtsym.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\dtfmtsym.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\dtptngen.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\dtptngen.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\dtptngen_impl.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dtrule.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\dtrule.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\unicode\fieldpos.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\fmtable.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\fmtable.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\fmtable_cnv.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\format.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\format.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\gregocal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\gregocal.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\gregoimp.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\gregoimp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\hebrwcal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\hebrwcal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\indiancal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\indiancal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\islamcal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\islamcal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\japancal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\japancal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\measfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\measfmt.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\unicode\measunit.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\measure.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\measure.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\msgfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\msgfmt.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\nfrlist.h"
+ >
+ </File>
+ <File
+ RelativePath=".\nfrs.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\nfrs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\nfrule.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\nfrule.h"
+ >
+ </File>
+ <File
+ RelativePath=".\nfsubs.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\nfsubs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\numfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\numfmt.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\olsontz.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\olsontz.h"
+ >
+ </File>
+ <File
+ RelativePath=".\persncal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\persncal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rbnf.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\rbnf.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\rbtz.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\rbtz.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\reldtfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\reldtfmt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\simpletz.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\simpletz.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\smpdtfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\smpdtfmt.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\taiwncal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\taiwncal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\timezone.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\timezone.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\tzrule.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\tzrule.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\tztrans.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\tztrans.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\ucal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\ucal.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\ucurr.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\ucurr.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\ucurrimp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\udat.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\udat.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\udatpg.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\udatpg.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\ulocdata.c"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\ulocdata.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\umsg.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\umsg.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\umsg_imp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\unum.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\unum.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\utmscale.c"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\utmscale.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\vtzone.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\vtzone.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\windtfmt.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\windtfmt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\winnmfmt.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\winnmfmt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\zonemeta.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\zonemeta.h"
+ >
+ </File>
+ <File
+ RelativePath=".\zstrfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\zstrfmt.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="misc"
+ >
+ <File
+ RelativePath=".\i18n.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\ucln_in.c"
+ >
+ </File>
+ <File
+ RelativePath=".\ucln_in.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="regex"
+ >
+ <File
+ RelativePath=".\unicode\regex.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\regexcmp.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\regexcmp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\regexcst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\regeximp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\regexst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\regexst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rematch.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\repattrn.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\uregex.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\uregex.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\uregexc.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="transforms"
+ >
+ <File
+ RelativePath=".\anytrans.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\anytrans.h"
+ >
+ </File>
+ <File
+ RelativePath=".\casetrn.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\casetrn.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cpdtrans.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\cpdtrans.h"
+ >
+ </File>
+ <File
+ RelativePath=".\esctrn.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\esctrn.h"
+ >
+ </File>
+ <File
+ RelativePath=".\funcrepl.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\funcrepl.h"
+ >
+ </File>
+ <File
+ RelativePath=".\name2uni.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\name2uni.h"
+ >
+ </File>
+ <File
+ RelativePath=".\nortrans.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\nortrans.h"
+ >
+ </File>
+ <File
+ RelativePath=".\nultrans.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\nultrans.h"
+ >
+ </File>
+ <File
+ RelativePath=".\quant.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\quant.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt_data.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt_data.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt_pars.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt_pars.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt_rule.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt_rule.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt_set.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\rbt_set.h"
+ >
+ </File>
+ <File
+ RelativePath=".\remtrans.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\remtrans.h"
+ >
+ </File>
+ <File
+ RelativePath=".\strmatch.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\strmatch.h"
+ >
+ </File>
+ <File
+ RelativePath=".\strrepl.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\strrepl.h"
+ >
+ </File>
+ <File
+ RelativePath=".\titletrn.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\titletrn.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tolowtrn.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tolowtrn.h"
+ >
+ </File>
+ <File
+ RelativePath=".\toupptrn.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\toupptrn.h"
+ >
+ </File>
+ <File
+ RelativePath=".\translit.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\translit.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\transreg.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\transreg.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tridpars.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tridpars.h"
+ >
+ </File>
+ <File
+ RelativePath=".\unesctrn.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unesctrn.h"
+ >
+ </File>
+ <File
+ RelativePath=".\uni2name.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\uni2name.h"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\unirepl.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\utrans.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\utrans.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="charset detect"
+ >
+ <File
+ RelativePath=".\csdetect.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\csdetect.h"
+ >
+ </File>
+ <File
+ RelativePath=".\csmatch.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\csmatch.h"
+ >
+ </File>
+ <File
+ RelativePath=".\csr2022.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\csr2022.h"
+ >
+ </File>
+ <File
+ RelativePath=".\csrecog.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\csrecog.h"
+ >
+ </File>
+ <File
+ RelativePath=".\csrmbcs.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\csrmbcs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\csrsbcs.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\csrsbcs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\csrucode.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\csrucode.h"
+ >
+ </File>
+ <File
+ RelativePath=".\csrutf8.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\csrutf8.h"
+ >
+ </File>
+ <File
+ RelativePath=".\inputext.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\inputext.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ucsdet.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\unicode\ucsdet.h"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode&#x0D;&#x0A;"
+ Outputs="..\..\include\unicode\$(InputFileName)"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Build/source/libs/icu/icu-xetex/i18n/indiancal.cpp b/Build/source/libs/icu/icu-xetex/i18n/indiancal.cpp
new file mode 100644
index 00000000000..0d948cb520e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/indiancal.cpp
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ******************************************************************************
+ *
+ * File INDIANCAL.CPP
+ *****************************************************************************
+ */
+
+#include "indiancal.h"
+#include <stdlib.h>
+#if !UCONFIG_NO_FORMATTING
+
+#include "mutex.h"
+#include <float.h>
+#include "gregoimp.h" // Math
+#include "astro.h" // CalendarAstronomer
+#include "uhash.h"
+#include "ucln_in.h"
+
+// Debugging
+#ifdef U_DEBUG_INDIANCAL
+#include <stdio.h>
+#include <stdarg.h>
+
+#endif
+
+U_NAMESPACE_BEGIN
+
+// Implementation of the IndianCalendar class
+
+//-------------------------------------------------------------------------
+// Constructors...
+//-------------------------------------------------------------------------
+
+
+Calendar* IndianCalendar::clone() const {
+ return new IndianCalendar(*this);
+}
+
+IndianCalendar::IndianCalendar(const Locale& aLocale, UErrorCode& success)
+ : Calendar(TimeZone::createDefault(), aLocale, success)
+{
+ setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
+}
+
+IndianCalendar::IndianCalendar(const IndianCalendar& other) : Calendar(other) {
+}
+
+IndianCalendar::~IndianCalendar()
+{
+}
+const char *IndianCalendar::getType() const {
+ return "indian";
+}
+
+static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
+ // Minimum Greatest Least Maximum
+ // Minimum Maximum
+ { 0, 0, 0, 0 }, // ERA
+ { 1, 1, 5000000, 5000000 }, // YEAR
+ { 0, 0, 11, 11 }, // MONTH
+ { 1, 1, 52, 53 }, // WEEK_OF_YEAR
+ { 0, 0, 4, 6 }, // WEEK_OF_MONTH
+ { 1, 1, 30, 31 }, // DAY_OF_MONTH
+ { 1, 1, 365, 366 }, // DAY_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
+ { -1, -1, 5, 5 }, // DAY_OF_WEEK_IN_MONTH
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
+ { 1, 1, 5000001, 5000001}, // YEAR_WOY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
+ { 1, 1, 5000000, 5000000}, // EXTENDED_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1} // MILLISECONDS_IN_DAY
+};
+
+static const double JULIAN_EPOCH = 1721425.5;
+static const int32_t INDIAN_ERA_START = 78;
+static const int32_t INDIAN_YEAR_START = 80;
+
+int32_t IndianCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
+ return LIMITS[field][limitType];
+}
+
+/*
+ * Determine whether the given gregorian year is a Leap year
+ */
+static UBool isGregorianLeap(int32_t year)
+{
+ return ((year % 4) == 0) && (!(((year % 100) == 0) && ((year % 400) != 0)));
+}
+
+//----------------------------------------------------------------------
+// Calendar framework
+//----------------------------------------------------------------------
+
+/*
+ * Return the length (in days) of the given month.
+ *
+ * @param eyear The year in Saka Era
+ * @param month The month(0-based) in Indian calendar
+ */
+int32_t IndianCalendar::handleGetMonthLength(int32_t eyear, int32_t month) const {
+ if (month < 0 || month > 11) {
+ eyear += Math::floorDivide(month, 12, month);
+ }
+
+ if (isGregorianLeap(eyear + INDIAN_ERA_START) && month == 0) {
+ return 31;
+ }
+
+ if (month >= 1 && month <= 5) {
+ return 31;
+ }
+
+ return 30;
+}
+
+/*
+ * Return the number of days in the given Indian year
+ *
+ * @param eyear The year in Saka Era.
+ */
+int32_t IndianCalendar::handleGetYearLength(int32_t eyear) const {
+ return isGregorianLeap(eyear + INDIAN_ERA_START) ? 366 : 365;
+}
+/*
+ * Returns the Julian Day corresponding to gregorian date
+ *
+ * @param year The Gregorian year
+ * @param month The month in Gregorian Year
+ * @param date The date in Gregorian day in month
+ */
+static double gregorianToJD(int32_t year, int32_t month, int32_t date) {
+ double julianDay = (JULIAN_EPOCH - 1) +
+ (365 * (year - 1)) +
+ uprv_floor((year - 1) / 4) +
+ (-uprv_floor((year - 1) / 100)) +
+ uprv_floor((year - 1) / 400) +
+ uprv_floor((((367 * month) - 362) / 12) +
+ ((month <= 2) ? 0 :
+ (isGregorianLeap(year) ? -1 : -2)
+ ) +
+ date);
+
+ return julianDay;
+}
+
+/*
+ * Returns the Gregorian Date corresponding to a given Julian Day
+ * @param jd The Julian Day
+ */
+static int32_t* jdToGregorian(double jd, int32_t gregorianDate[3]) {
+ double wjd, depoch, quadricent, dqc, cent, dcent, quad, dquad, yindex, yearday, leapadj;
+ int32_t year, month, day;
+ wjd = uprv_floor(jd - 0.5) + 0.5;
+ depoch = wjd - JULIAN_EPOCH;
+ quadricent = uprv_floor(depoch / 146097);
+ dqc = (int32_t)uprv_floor(depoch) % 146097;
+ cent = uprv_floor(dqc / 36524);
+ dcent = (int32_t)uprv_floor(dqc) % 36524;
+ quad = uprv_floor(dcent / 1461);
+ dquad = (int32_t)uprv_floor(dcent) % 1461;
+ yindex = uprv_floor(dquad / 365);
+ year = (int32_t)((quadricent * 400) + (cent * 100) + (quad * 4) + yindex);
+ if (!((cent == 4) || (yindex == 4))) {
+ year++;
+ }
+ yearday = wjd - gregorianToJD(year, 1, 1);
+ leapadj = ((wjd < gregorianToJD(year, 3, 1)) ? 0
+ :
+ (isGregorianLeap(year) ? 1 : 2)
+ );
+ month = (int32_t)uprv_floor((((yearday + leapadj) * 12) + 373) / 367);
+ day = (int32_t)(wjd - gregorianToJD(year, month, 1)) + 1;
+
+ gregorianDate[0] = year;
+ gregorianDate[1] = month;
+ gregorianDate[2] = day;
+
+ return gregorianDate;
+}
+
+
+//-------------------------------------------------------------------------
+// Functions for converting from field values to milliseconds....
+//-------------------------------------------------------------------------
+static double IndianToJD(int32_t year, int32_t month, int32_t date) {
+ int32_t leapMonth, gyear, m;
+ double start, jd;
+
+ gyear = year + INDIAN_ERA_START;
+
+
+ if(isGregorianLeap(gyear)) {
+ leapMonth = 31;
+ start = gregorianToJD(gyear, 3, 21);
+ }
+ else {
+ leapMonth = 30;
+ start = gregorianToJD(gyear, 3, 22);
+ }
+
+ if (month == 1) {
+ jd = start + (date - 1);
+ } else {
+ jd = start + leapMonth;
+ m = month - 2;
+
+ //m = Math.min(m, 5);
+ if (m > 5) {
+ m = 5;
+ }
+
+ jd += m * 31;
+
+ if (month >= 8) {
+ m = month - 7;
+ jd += m * 30;
+ }
+ jd += date - 1;
+ }
+
+ return jd;
+}
+
+/*
+ * Return JD of start of given month/year of Indian Calendar
+ * @param eyear The year in Indian Calendar measured from Saka Era (78 AD).
+ * @param month The month in Indian calendar
+ */
+int32_t IndianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const {
+
+ //month is 0 based; converting it to 1-based
+ int32_t imonth;
+
+ // If the month is out of range, adjust it into range, and adjust the extended eyar accordingly
+ if (month < 0 || month > 11) {
+ eyear += (int32_t)Math::floorDivide(month, 12, month);
+ }
+
+ if(month == 12){
+ imonth = 1;
+ } else {
+ imonth = month + 1;
+ }
+
+ double jd = IndianToJD(eyear ,imonth, 1);
+
+ return (int32_t)jd;
+}
+
+//-------------------------------------------------------------------------
+// Functions for converting from milliseconds to field values
+//-------------------------------------------------------------------------
+
+int32_t IndianCalendar::handleGetExtendedYear() {
+ int32_t year;
+
+ if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
+ year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
+ } else {
+ year = internalGet(UCAL_YEAR, 1); // Default to year 1
+ }
+
+ return year;
+}
+
+/*
+ * Override Calendar to compute several fields specific to the Indian
+ * calendar system. These are:
+ *
+ * <ul><li>ERA
+ * <li>YEAR
+ * <li>MONTH
+ * <li>DAY_OF_MONTH
+ * <li>EXTENDED_YEAR</ul>
+ *
+ * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+ * method is called. The getGregorianXxx() methods return Gregorian
+ * calendar equivalents for the given Julian day.
+ */
+void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) {
+ double jdAtStartOfGregYear;
+ int32_t leapMonth, IndianYear, yday, IndianMonth, IndianDayOfMonth, mday;
+ int32_t gregorianYear; // Stores gregorian date corresponding to Julian day;
+ int32_t gd[3];
+
+ gregorianYear = jdToGregorian(julianDay, gd)[0]; // Gregorian date for Julian day
+ IndianYear = gregorianYear - INDIAN_ERA_START; // Year in Saka era
+ jdAtStartOfGregYear = gregorianToJD(gregorianYear, 1, 1); // JD at start of Gregorian year
+ yday = (int32_t)(julianDay - jdAtStartOfGregYear); // Day number in Gregorian year (starting from 0)
+ leapMonth = isGregorianLeap(gregorianYear) ? 31 : 30; // Days in leapMonth this year
+
+ if (yday < INDIAN_YEAR_START) {
+ // Day is at the end of the preceding Saka year
+ IndianYear -= 1;
+ yday += leapMonth + (31 * 5) + (30 * 3) + 10 + INDIAN_YEAR_START;
+ }
+
+ yday -= INDIAN_YEAR_START;
+ if (yday < leapMonth) {
+ IndianMonth = 0;
+ IndianDayOfMonth = yday + 1;
+ } else {
+ mday = yday - leapMonth;
+ if (mday < (31 * 5)) {
+ IndianMonth = (int32_t)uprv_floor(mday / 31) + 1;
+ IndianDayOfMonth = (mday % 31) + 1;
+ } else {
+ mday -= 31 * 5;
+ IndianMonth = (int32_t)uprv_floor(mday / 30) + 6;
+ IndianDayOfMonth = (mday % 30) + 1;
+ }
+ }
+
+ internalSet(UCAL_ERA, 0);
+ internalSet(UCAL_EXTENDED_YEAR, IndianYear);
+ internalSet(UCAL_YEAR, IndianYear);
+ internalSet(UCAL_MONTH, IndianMonth);
+ internalSet(UCAL_DAY_OF_MONTH, IndianDayOfMonth );
+}
+
+UBool
+IndianCalendar::inDaylightTime(UErrorCode& status) const
+{
+ // copied from GregorianCalendar
+ if (U_FAILURE(status) || !getTimeZone().useDaylightTime()) {
+ return FALSE;
+ }
+
+ // Force an update of the state of the Calendar.
+ ((IndianCalendar*)this)->complete(status); // cast away const
+
+ return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
+}
+
+// default century
+const UDate IndianCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t IndianCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate IndianCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t IndianCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+
+UBool IndianCalendar::haveDefaultCentury() const
+{
+ return TRUE;
+}
+
+UDate IndianCalendar::defaultCenturyStart() const
+{
+ return internalGetDefaultCenturyStart();
+}
+
+int32_t IndianCalendar::defaultCenturyStartYear() const
+{
+ return internalGetDefaultCenturyStartYear();
+}
+
+UDate
+IndianCalendar::internalGetDefaultCenturyStart() const
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ UBool needsUpdate;
+ {
+ Mutex m;
+ needsUpdate = (fgSystemDefaultCenturyStart == fgSystemDefaultCentury);
+ }
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStart
+
+ return fgSystemDefaultCenturyStart;
+}
+
+int32_t
+IndianCalendar::internalGetDefaultCenturyStartYear() const
+{
+ // lazy-evaluate systemDefaultCenturyStartYear
+ UBool needsUpdate;
+ {
+ Mutex m;
+
+ needsUpdate = (fgSystemDefaultCenturyStart == fgSystemDefaultCentury);
+ }
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStartYear
+
+ return fgSystemDefaultCenturyStartYear;
+}
+
+void
+IndianCalendar::initializeSystemDefaultCentury()
+{
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ // No point in locking as it should be idempotent.
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ IndianCalendar calendar(Locale("@calendar=Indian"),status);
+ if (U_SUCCESS(status)) {
+ calendar.setTime(Calendar::getNow(), status);
+ calendar.add(UCAL_YEAR, -80, status);
+
+ UDate newStart = calendar.getTime(status);
+ int32_t newYear = calendar.get(UCAL_YEAR, status);
+
+ {
+ Mutex m;
+
+ fgSystemDefaultCenturyStart = newStart;
+ fgSystemDefaultCenturyStartYear = newYear;
+ }
+ }
+
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+ }
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndianCalendar)
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/indiancal.h b/Build/source/libs/icu/icu-xetex/i18n/indiancal.h
new file mode 100644
index 00000000000..94a6e9cf006
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/indiancal.h
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ******************************************************************************
+ *
+ * File INDIANCAL.H
+ *****************************************************************************
+ */
+
+#ifndef INDIANCAL_H
+#define INDIANCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Concrete class which provides the Indian calendar.
+ * <P>
+ * <code>IndianCalendar</code> is a subclass of <code>Calendar</code>
+ * that numbers years since the begining of SAKA ERA. This is the civil calendar
+ * which is accepted by government of India as Indian National Calendar.
+ * The two calendars most widely used in India today are the Vikrama calendar
+ * followed in North India and the Shalivahana or Saka calendar which is followed
+ * in South India and Maharashtra.
+
+ * A variant of the Shalivahana Calendar was reformed and standardized as the
+ * Indian National calendar in 1957.
+ * <p>
+ * Some details of Indian National Calendar (to be implemented) :
+ * The Months
+ * Month Length Start date (Gregorian)
+ * =================================================
+ * 1 Chaitra 30/31 March 22*
+ * 2 Vaisakha 31 April 21
+ * 3 Jyaistha 31 May 22
+ * 4 Asadha 31 June 22
+ * 5 Sravana 31 July 23
+ * 6 Bhadra 31 August 23
+ * 7 Asvina 30 September 23
+ * 8 Kartika 30 October 23
+ * 9 Agrahayana 30 November 22
+ * 10 Pausa 30 December 22
+ * 11 Magha 30 January 21
+ * 12 Phalguna 30 February 20
+
+ * In leap years, Chaitra has 31 days and starts on March 21 instead.
+ * The leap years of Gregorian calendar and Indian National Calendar are in synchornization.
+ * So When its a leap year in Gregorian calendar then Chaitra has 31 days.
+ *
+ * The Years
+ * Years are counted in the Saka Era, which starts its year 0 in 78AD (by gregorian calendar).
+ * So for eg. 9th June 2006 by Gregorian Calendar, is same as 19th of Jyaistha in 1928 of Saka
+ * era by Indian National Calendar.
+ * <p>
+ * The Indian Calendar has only one allowable era: <code>Saka Era</code>. If the
+ * calendar is not in lenient mode (see <code>setLenient</code>), dates before
+ * 1/1/1 Saka Era are rejected with an <code>IllegalArgumentException</code>.
+ * <p>
+ * @internal
+ */
+
+
+class U_I18N_API IndianCalendar : public Calendar {
+ public:
+ /**
+ * Useful constants for IndianCalendar.
+ * @internal
+ */
+ enum EEras {
+ /**
+ * Constant for Chaitra, the 1st month of the Indian year.
+ */
+ CHAITRA,
+
+ /**
+ * Constant for Vaisakha, the 2nd month of the Indian year.
+ */
+ VAISAKHA,
+
+ /**
+ * Constant for Jyaistha, the 3rd month of the Indian year.
+ */
+ JYAISTHA,
+
+ /**
+ * Constant for Asadha, the 4th month of the Indian year.
+ */
+ ASADHA,
+
+ /**
+ * Constant for Sravana, the 5th month of the Indian year.
+ */
+ SRAVANA,
+
+ /**
+ * Constant for Bhadra the 6th month of the Indian year
+ */
+ BHADRA,
+
+ /**
+ * Constant for the Asvina, the 7th month of the Indian year.
+ */
+ ASVINA,
+
+ /**
+ * Constant for Kartika, the 8th month of the Indian year.
+ */
+ KARTIKA,
+
+ /**
+ * Constant for Agrahayana, the 9th month of the Indian year.
+ */
+ AGRAHAYANA,
+
+ /**
+ * Constant for Pausa, the 10th month of the Indian year.
+ */
+ PAUSA,
+
+ /**
+ * Constant for Magha, the 11th month of the Indian year.
+ */
+ MAGHA,
+
+ /**
+ * Constant for Phalguna, the 12th month of the Indian year.
+ */
+ PHALGUNA
+ };
+
+ //-------------------------------------------------------------------------
+ // Constructors...
+ //-------------------------------------------------------------------------
+
+ /**
+ * Constructs an IndianCalendar based on the current time in the default time zone
+ * with the given locale.
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the status of IndianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @param beCivil Whether the calendar should be civil (default-TRUE) or religious (FALSE)
+ * @internal
+ */
+ IndianCalendar(const Locale& aLocale, UErrorCode &success);
+
+ /**
+ * Copy Constructor
+ * @internal
+ */
+ IndianCalendar(const IndianCalendar& other);
+
+ /**
+ * Destructor.
+ * @internal
+ */
+ virtual ~IndianCalendar();
+
+ /**
+ * Determines whether this object uses the fixed-cycle Indian civil calendar
+ * or an approximation of the religious, astronomical calendar.
+ *
+ * @param beCivil <code>CIVIL</code> to use the civil calendar,
+ * <code>ASTRONOMICAL</code> to use the astronomical calendar.
+ * @internal
+ */
+ //void setCivil(ECivil beCivil, UErrorCode &status);
+
+ /**
+ * Returns <code>true</code> if this object is using the fixed-cycle civil
+ * calendar, or <code>false</code> if using the religious, astronomical
+ * calendar.
+ * @internal
+ */
+ //UBool isCivil();
+
+
+ // TODO: copy c'tor, etc
+
+ // clone
+ virtual Calendar* clone() const;
+
+ private:
+ /**
+ * Determine whether a year is the gregorian year a leap year
+ */
+ //static UBool isGregorianLeap(int32_t year);
+ //----------------------------------------------------------------------
+ // Calendar framework
+ //----------------------------------------------------------------------
+ protected:
+ /**
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+
+ /**
+ * Return the length (in days) of the given month.
+ *
+ * @param year The year in Saka era
+ * @param year The month(0-based) in Indian year
+ * @internal
+ */
+ virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const;
+
+ /**
+ * Return the number of days in the given Indian year
+ * @internal
+ */
+ virtual int32_t handleGetYearLength(int32_t extendedYear) const;
+
+ //-------------------------------------------------------------------------
+ // Functions for converting from field values to milliseconds....
+ //-------------------------------------------------------------------------
+
+ // Return JD of start of given month/year
+ /**
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const;
+
+ //-------------------------------------------------------------------------
+ // Functions for converting from milliseconds to field values
+ //-------------------------------------------------------------------------
+
+ /**
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+
+ /**
+ * Override Calendar to compute several fields specific to the Indian
+ * calendar system. These are:
+ *
+ * <ul><li>ERA
+ * <li>YEAR
+ * <li>MONTH
+ * <li>DAY_OF_MONTH
+ * <li>DAY_OF_YEAR
+ * <li>EXTENDED_YEAR</ul>
+ *
+ * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+ * method is called. The getGregorianXxx() methods return Gregorian
+ * calendar equivalents for the given Julian day.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
+
+ // UObject stuff
+ public:
+ /**
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @internal
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to a return
+ * value from getDynamicClassID(). For example:
+ *
+ * Base* polymorphic_pointer = createPolymorphicObject();
+ * if (polymorphic_pointer->getDynamicClassID() ==
+ * Derived::getStaticClassID()) ...
+ *
+ * @return The class ID for all objects of this class.
+ * @internal
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * return the calendar type, "buddhist".
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+ private:
+ IndianCalendar(); // default constructor not implemented
+
+ // Default century.
+ protected:
+
+ /**
+ * (Overrides Calendar) Return true if the current date for this Calendar is in
+ * Daylight Savings Time. Recognizes DST_OFFSET, if it is set.
+ *
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return True if the current date for this Calendar is in Daylight Savings Time,
+ * false, otherwise.
+ * @internal
+ */
+ virtual UBool inDaylightTime(UErrorCode& status) const;
+
+
+ /**
+ * Returns TRUE because the Indian Calendar does have a default century
+ * @internal
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * Returns the date of the start of the default century
+ * @return start of century - in milliseconds since epoch, 1970
+ * @internal
+ */
+ virtual UDate defaultCenturyStart() const;
+
+ /**
+ * Returns the year in which the default century begins
+ * @internal
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+ private: // default century stuff.
+ /**
+ * The system maintains a static default century start date. This is initialized
+ * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
+ * indicate an uninitialized state. Once the system default century date and year
+ * are set, they do not change.
+ */
+ static UDate fgSystemDefaultCenturyStart;
+
+ /**
+ * See documentation for systemDefaultCenturyStart.
+ */
+ static int32_t fgSystemDefaultCenturyStartYear;
+
+ /**
+ * Default value that indicates the defaultCenturyStartYear is unitialized
+ */
+ static const int32_t fgSystemDefaultCenturyYear;
+
+ /**
+ * start of default century, as a date
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * Returns the beginning date of the 100-year window that dates
+ * with 2-digit years are considered to fall within.
+ */
+ UDate internalGetDefaultCenturyStart(void) const;
+
+ /**
+ * Returns the first year of the 100-year window that dates with
+ * 2-digit years are considered to fall within.
+ */
+ int32_t internalGetDefaultCenturyStartYear(void) const;
+
+ /**
+ * Initializes the 100-year window that dates with 2-digit years
+ * are considered to fall within so that its start date is 80 years
+ * before the current time.
+ */
+ static void initializeSystemDefaultCentury(void);
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif
+
+
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/inputext.cpp b/Build/source/libs/icu/icu-xetex/i18n/inputext.cpp
new file mode 100644
index 00000000000..a36a931ab55
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/inputext.cpp
@@ -0,0 +1,162 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+#include "inputext.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+
+#include <string.h>
+
+U_NAMESPACE_BEGIN
+
+#define BUFFER_SIZE 8192
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
+#define DELETE_ARRAY(array) uprv_free((void *) (array))
+
+InputText::InputText()
+ : fInputBytes(NEW_ARRAY(uint8_t, BUFFER_SIZE)), // The text to be checked. Markup will have been
+ // removed if appropriate.
+ fByteStats(NEW_ARRAY(int16_t, 256)), // byte frequency statistics for the input text.
+ // Value is percent, not absolute.
+ fDeclaredEncoding(0),
+ fRawInput(0),
+ fRawLength(0)
+{
+
+}
+
+InputText::~InputText()
+{
+ DELETE_ARRAY(fDeclaredEncoding);
+ DELETE_ARRAY(fByteStats);
+ DELETE_ARRAY(fInputBytes);
+}
+
+void InputText::setText(const char *in, int32_t len)
+{
+ fInputLen = 0;
+ fC1Bytes = FALSE;
+ fRawInput = (const uint8_t *) in;
+ fRawLength = len == -1? uprv_strlen(in) : len;
+}
+
+void InputText::setDeclaredEncoding(const char* encoding, int32_t len)
+{
+ if(encoding) {
+ if (len == -1) {
+ len = uprv_strlen(encoding);
+ }
+
+ len += 1; // to make place for the \0 at the end.
+ uprv_free(fDeclaredEncoding);
+ fDeclaredEncoding = NEW_ARRAY(char, len);
+ uprv_strncpy(fDeclaredEncoding, encoding, len);
+ }
+}
+
+UBool InputText::isSet() const
+{
+ return fRawInput != NULL;
+}
+
+/**
+* MungeInput - after getting a set of raw input data to be analyzed, preprocess
+* it by removing what appears to be html markup.
+*
+* @internal
+*/
+void InputText::MungeInput(UBool fStripTags) {
+ int srci = 0;
+ int dsti = 0;
+ uint8_t b;
+ bool inMarkup = FALSE;
+ int32_t openTags = 0;
+ int32_t badTags = 0;
+
+ //
+ // html / xml markup stripping.
+ // quick and dirty, not 100% accurate, but hopefully good enough, statistically.
+ // discard everything within < brackets >
+ // Count how many total '<' and illegal (nested) '<' occur, so we can make some
+ // guess as to whether the input was actually marked up at all.
+ // TODO: Think about how this interacts with EBCDIC charsets that are detected.
+ if (fStripTags) {
+ for (srci = 0; srci < fRawLength && dsti < BUFFER_SIZE; srci += 1) {
+ b = fRawInput[srci];
+
+ if (b == (uint8_t)0x3C) { /* Check for the ASCII '<' */
+ if (inMarkup) {
+ badTags += 1;
+ }
+
+ inMarkup = TRUE;
+ openTags += 1;
+ }
+
+ if (! inMarkup) {
+ fInputBytes[dsti++] = b;
+ }
+
+ if (b == (uint8_t)0x3E) { /* Check for the ASCII '>' */
+ inMarkup = FALSE;
+ }
+ }
+
+ fInputLen = dsti;
+ }
+
+ //
+ // If it looks like this input wasn't marked up, or if it looks like it's
+ // essentially nothing but markup abandon the markup stripping.
+ // Detection will have to work on the unstripped input.
+ //
+ if (openTags<5 || openTags/5 < badTags ||
+ (fInputLen < 100 && fRawLength>600))
+ {
+ int32_t limit = fRawLength;
+
+ if (limit > BUFFER_SIZE) {
+ limit = BUFFER_SIZE;
+ }
+
+ for (srci=0; srci<limit; srci++) {
+ fInputBytes[srci] = fRawInput[srci];
+ }
+
+ fInputLen = srci;
+ }
+
+ //
+ // Tally up the byte occurence statistics.
+ // These are available for use by the various detectors.
+ //
+
+ uprv_memset(fByteStats, 0, (sizeof fByteStats[0]) * 256);
+
+ for (srci = 0; srci < fInputLen; srci += 1) {
+ fByteStats[fInputBytes[srci]] += 1;
+ }
+
+ for (int32_t i = 0x80; i <= 0x9F; i += 1) {
+ if (fByteStats[i] != 0) {
+ fC1Bytes = TRUE;
+ break;
+ }
+ }
+}
+
+U_NAMESPACE_END
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/inputext.h b/Build/source/libs/icu/icu-xetex/i18n/inputext.h
new file mode 100644
index 00000000000..1528f48e63f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/inputext.h
@@ -0,0 +1,59 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __INPUTEXT_H
+#define __INPUTEXT_H
+
+/**
+ * \file
+ * \internal
+ *
+ * This is an internal header for the Character Set Detection code. The
+ * name is probably too generic...
+ */
+
+
+#include "unicode/uobject.h"
+
+#if !UCONFIG_NO_CONVERSION
+
+U_NAMESPACE_BEGIN
+
+class InputText : public UMemory
+{
+public:
+ InputText();
+ ~InputText();
+
+ void setText(const char *in, int32_t len);
+ void setDeclaredEncoding(const char *encoding, int32_t len);
+ UBool isSet() const;
+ void MungeInput(UBool fStripTags);
+
+ // The text to be checked. Markup will have been
+ // removed if appropriate.
+ uint8_t *fInputBytes;
+ int32_t fInputLen; // Length of the byte data in fInputBytes.
+ // byte frequency statistics for the input text.
+ // Value is percent, not absolute.
+ // Value is rounded up, so zero really means zero occurences.
+ int16_t *fByteStats;
+ UBool fC1Bytes; // True if any bytes in the range 0x80 - 0x9F are in the input;false by default
+ char *fDeclaredEncoding;
+
+ const uint8_t *fRawInput; // Original, untouched input bytes.
+ // If user gave us a byte array, this is it.
+ // If user gave us a stream, it's read to a
+ // buffer here.
+ int32_t fRawLength; // Length of data in fRawInput array.
+
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif /* __INPUTEXT_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/islamcal.cpp b/Build/source/libs/icu/icu-xetex/i18n/islamcal.cpp
new file mode 100644
index 00000000000..a6d093a94eb
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/islamcal.cpp
@@ -0,0 +1,524 @@
+/*
+******************************************************************************
+* Copyright (C) 2003-2006, International Business Machines Corporation
+* and others. All Rights Reserved.
+******************************************************************************
+*
+* File ISLAMCAL.H
+*
+* Modification History:
+*
+* Date Name Description
+* 10/14/2003 srl ported from java IslamicCalendar
+*****************************************************************************
+*/
+
+#include "islamcal.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "umutex.h"
+#include <float.h>
+#include "gregoimp.h" // Math
+#include "astro.h" // CalendarAstronomer
+#include "uhash.h"
+#include "ucln_in.h"
+
+static const UDate HIJRA_MILLIS = -42521587200000.0; // 7/16/622 AD 00:00
+
+// Debugging
+#ifdef U_DEBUG_ISLAMCAL
+# include <stdio.h>
+# include <stdarg.h>
+static void debug_islamcal_loc(const char *f, int32_t l)
+{
+ fprintf(stderr, "%s:%d: ", f, l);
+}
+
+static void debug_islamcal_msg(const char *pat, ...)
+{
+ va_list ap;
+ va_start(ap, pat);
+ vfprintf(stderr, pat, ap);
+ fflush(stderr);
+}
+// must use double parens, i.e.: U_DEBUG_ISLAMCAL_MSG(("four is: %d",4));
+#define U_DEBUG_ISLAMCAL_MSG(x) {debug_islamcal_loc(__FILE__,__LINE__);debug_islamcal_msg x;}
+#else
+#define U_DEBUG_ISLAMCAL_MSG(x)
+#endif
+
+
+// --- The cache --
+// cache of months
+static UMTX astroLock = 0; // pod bay door lock
+static U_NAMESPACE_QUALIFIER CalendarCache *gMonthCache = NULL;
+static U_NAMESPACE_QUALIFIER CalendarAstronomer *gIslamicCalendarAstro = NULL;
+
+U_CDECL_BEGIN
+static UBool calendar_islamic_cleanup(void) {
+ if (gMonthCache) {
+ delete gMonthCache;
+ gMonthCache = NULL;
+ }
+ if (gIslamicCalendarAstro) {
+ delete gIslamicCalendarAstro;
+ gIslamicCalendarAstro = NULL;
+ }
+ umtx_destroy(&astroLock);
+ return TRUE;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+// Implementation of the IslamicCalendar class
+
+//-------------------------------------------------------------------------
+// Constructors...
+//-------------------------------------------------------------------------
+
+const char *IslamicCalendar::getType() const {
+ if(civil==CIVIL) {
+ return "islamic-civil";
+ } else {
+ return "islamic";
+ }
+}
+
+Calendar* IslamicCalendar::clone() const {
+ return new IslamicCalendar(*this);
+}
+
+IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success, ECivil beCivil)
+: Calendar(TimeZone::createDefault(), aLocale, success),
+civil(beCivil)
+{
+ setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
+}
+
+IslamicCalendar::IslamicCalendar(const IslamicCalendar& other) : Calendar(other), civil(other.civil) {
+}
+
+IslamicCalendar::~IslamicCalendar()
+{
+}
+
+/**
+* Determines whether this object uses the fixed-cycle Islamic civil calendar
+* or an approximation of the religious, astronomical calendar.
+*
+* @param beCivil <code>true</code> to use the civil calendar,
+* <code>false</code> to use the astronomical calendar.
+* @draft ICU 2.4
+*/
+void IslamicCalendar::setCivil(ECivil beCivil, UErrorCode &status)
+{
+ if (civil != beCivil) {
+ // The fields of the calendar will become invalid, because the calendar
+ // rules are different
+ UDate m = getTimeInMillis(status);
+ civil = beCivil;
+ clear();
+ setTimeInMillis(m, status);
+ }
+}
+
+/**
+* Returns <code>true</code> if this object is using the fixed-cycle civil
+* calendar, or <code>false</code> if using the religious, astronomical
+* calendar.
+* @draft ICU 2.4
+*/
+UBool IslamicCalendar::isCivil() {
+ return (civil == CIVIL);
+}
+
+//-------------------------------------------------------------------------
+// Minimum / Maximum access functions
+//-------------------------------------------------------------------------
+
+static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
+ // Minimum Greatest Least Maximum
+ // Minimum Maximum
+ { 0, 0, 0, 0 }, // ERA
+ { 1, 1, 5000000, 5000000 }, // YEAR
+ { 0, 0, 11, 11 }, // MONTH
+ { 1, 1, 50, 51 }, // WEEK_OF_YEAR
+ { 0, 0, 4, 6 }, // WEEK_OF_MONTH
+ { 1, 1, 29, 30 }, // DAY_OF_MONTH
+ { 1, 1, 354, 355 }, // DAY_OF_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
+ { -1, -1, 5, 5 }, // DAY_OF_WEEK_IN_MONTH
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
+ { 1, 1, 5000001, 5000001 }, // YEAR_WOY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
+ { 1, 1, 5000000, 5000000 }, // EXTENDED_YEAR
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
+ {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1} // MILLISECONDS_IN_DAY
+};
+
+/**
+* @draft ICU 2.4
+*/
+int32_t IslamicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
+ return LIMITS[field][limitType];
+}
+
+//-------------------------------------------------------------------------
+// Assorted calculation utilities
+//
+
+/**
+* Determine whether a year is a leap year in the Islamic civil calendar
+*/
+UBool IslamicCalendar::civilLeapYear(int32_t year)
+{
+ return (14 + 11 * year) % 30 < 11;
+}
+
+/**
+* Return the day # on which the given year starts. Days are counted
+* from the Hijri epoch, origin 0.
+*/
+int32_t IslamicCalendar::yearStart(int32_t year) {
+ if (civil == CIVIL) {
+ return (year-1)*354 + Math::floorDivide((3+11*year),30);
+ } else {
+ return trueMonthStart(12*(year-1));
+ }
+}
+
+/**
+* Return the day # on which the given month starts. Days are counted
+* from the Hijri epoch, origin 0.
+*
+* @param year The hijri year
+* @param year The hijri month, 0-based
+*/
+int32_t IslamicCalendar::monthStart(int32_t year, int32_t month) const {
+ if (civil == CIVIL) {
+ return (int32_t)uprv_ceil(29.5*month)
+ + (year-1)*354 + (int32_t)Math::floorDivide((3+11*year),30);
+ } else {
+ return trueMonthStart(12*(year-1) + month);
+ }
+}
+
+/**
+* Find the day number on which a particular month of the true/lunar
+* Islamic calendar starts.
+*
+* @param month The month in question, origin 0 from the Hijri epoch
+*
+* @return The day number on which the given month starts.
+*/
+int32_t IslamicCalendar::trueMonthStart(int32_t month) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t start = CalendarCache::get(&gMonthCache, month, status);
+
+ if (start==0) {
+ // Make a guess at when the month started, using the average length
+ UDate origin = HIJRA_MILLIS
+ + uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH - 1) * kOneDay;
+
+ double age = moonAge(origin);
+
+ if (moonAge(origin) >= 0) {
+ // The month has already started
+ do {
+ origin -= kOneDay;
+ age = moonAge(origin);
+ } while (age >= 0);
+ }
+ else {
+ // Preceding month has not ended yet.
+ do {
+ origin += kOneDay;
+ age = moonAge(origin);
+ } while (age < 0);
+ }
+ start = (int32_t)Math::floorDivide((origin - HIJRA_MILLIS), (double)kOneDay) + 1;
+ CalendarCache::put(&gMonthCache, month, start, status);
+ }
+ if(U_FAILURE(status)) {
+ start = 0;
+ }
+ return start;
+}
+
+/**
+* Return the "age" of the moon at the given time; this is the difference
+* in ecliptic latitude between the moon and the sun. This method simply
+* calls CalendarAstronomer.moonAge, converts to degrees,
+* and adjusts the result to be in the range [-180, 180].
+*
+* @param time The time at which the moon's age is desired,
+* in millis since 1/1/1970.
+*/
+double IslamicCalendar::moonAge(UDate time)
+{
+ double age = 0;
+
+ umtx_lock(&astroLock);
+ if(gIslamicCalendarAstro == NULL) {
+ gIslamicCalendarAstro = new CalendarAstronomer();
+ }
+ gIslamicCalendarAstro->setTime(time);
+ age = gIslamicCalendarAstro->getMoonAge();
+ ucln_i18n_registerCleanup(UCLN_I18N_ISLAMIC_CALENDAR, calendar_islamic_cleanup);
+ umtx_unlock(&astroLock);
+
+ // Convert to degrees and normalize...
+ age = age * 180 / CalendarAstronomer::PI;
+ if (age > 180) {
+ age = age - 360;
+ }
+
+ return age;
+}
+
+//----------------------------------------------------------------------
+// Calendar framework
+//----------------------------------------------------------------------
+
+/**
+* Return the length (in days) of the given month.
+*
+* @param year The hijri year
+* @param year The hijri month, 0-based
+* @draft ICU 2.4
+*/
+int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
+
+ int32_t length = 0;
+
+ if (civil == CIVIL) {
+ length = 29 + (month+1) % 2;
+ if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
+ length++;
+ }
+ } else {
+ month = 12*(extendedYear-1) + month;
+ length = trueMonthStart(month+1) - trueMonthStart(month) ;
+ }
+ return length;
+}
+
+/**
+* Return the number of days in the given Islamic year
+* @draft ICU 2.4
+*/
+int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const {
+ if (civil == CIVIL) {
+ return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
+ } else {
+ int32_t month = 12*(extendedYear-1);
+ return (trueMonthStart(month + 12) - trueMonthStart(month));
+ }
+}
+
+//-------------------------------------------------------------------------
+// Functions for converting from field values to milliseconds....
+//-------------------------------------------------------------------------
+
+// Return JD of start of given month/year
+/**
+* @draft ICU 2.4
+*/
+int32_t IslamicCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool /* useMonth */) const {
+ return monthStart(eyear, month) + 1948439;
+}
+
+//-------------------------------------------------------------------------
+// Functions for converting from milliseconds to field values
+//-------------------------------------------------------------------------
+
+/**
+* @draft ICU 2.4
+*/
+int32_t IslamicCalendar::handleGetExtendedYear() {
+ int32_t year;
+ if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
+ year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
+ } else {
+ year = internalGet(UCAL_YEAR, 1); // Default to year 1
+ }
+ return year;
+}
+
+/**
+* Override Calendar to compute several fields specific to the Islamic
+* calendar system. These are:
+*
+* <ul><li>ERA
+* <li>YEAR
+* <li>MONTH
+* <li>DAY_OF_MONTH
+* <li>DAY_OF_YEAR
+* <li>EXTENDED_YEAR</ul>
+*
+* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+* method is called. The getGregorianXxx() methods return Gregorian
+* calendar equivalents for the given Julian day.
+* @draft ICU 2.4
+*/
+void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/) {
+ int32_t year, month, dayOfMonth, dayOfYear;
+ UDate startDate;
+ int32_t days = julianDay - 1948440;
+
+ if (civil == CIVIL) {
+ // Use the civil calendar approximation, which is just arithmetic
+ year = (int)Math::floorDivide( (double)(30 * days + 10646) , 10631.0 );
+ month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
+ month = month<11?month:11;
+ startDate = monthStart(year, month);
+ } else {
+ // Guess at the number of elapsed full months since the epoch
+ int32_t months = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);
+
+ startDate = uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH - 1);
+
+ if ( days - startDate >= 28 && moonAge(internalGetTime()) > 0) {
+ // If we're near the end of the month, assume next month and search backwards
+ months++;
+ }
+
+ // Find out the last time that the new moon was actually visible at this longitude
+ // This returns midnight the night that the moon was visible at sunset.
+ while ((startDate = trueMonthStart(months)) > days) {
+ // If it was after the date in question, back up a month and try again
+ months--;
+ }
+
+ year = months / 12 + 1;
+ month = months % 12;
+ }
+
+ dayOfMonth = (days - monthStart(year, month)) + 1;
+
+ // Now figure out the day of the year.
+ dayOfYear = (days - monthStart(year, 0) + 1);
+
+ internalSet(UCAL_ERA, 0);
+ internalSet(UCAL_YEAR, year);
+ internalSet(UCAL_EXTENDED_YEAR, year);
+ internalSet(UCAL_MONTH, month);
+ internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
+ internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
+}
+
+UBool
+IslamicCalendar::inDaylightTime(UErrorCode& status) const
+{
+ // copied from GregorianCalendar
+ if (U_FAILURE(status) || !getTimeZone().useDaylightTime())
+ return FALSE;
+
+ // Force an update of the state of the Calendar.
+ ((IslamicCalendar*)this)->complete(status); // cast away const
+
+ return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
+}
+
+// default century
+const UDate IslamicCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t IslamicCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate IslamicCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t IslamicCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+
+UBool IslamicCalendar::haveDefaultCentury() const
+{
+ return TRUE;
+}
+
+UDate IslamicCalendar::defaultCenturyStart() const
+{
+ return internalGetDefaultCenturyStart();
+}
+
+int32_t IslamicCalendar::defaultCenturyStartYear() const
+{
+ return internalGetDefaultCenturyStartYear();
+}
+
+UDate
+IslamicCalendar::internalGetDefaultCenturyStart() const
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStart
+
+ return fgSystemDefaultCenturyStart;
+}
+
+int32_t
+IslamicCalendar::internalGetDefaultCenturyStartYear() const
+{
+ // lazy-evaluate systemDefaultCenturyStartYear
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStartYear
+
+ return fgSystemDefaultCenturyStartYear;
+}
+
+void
+IslamicCalendar::initializeSystemDefaultCentury()
+{
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ // No point in locking as it should be idempotent.
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ IslamicCalendar calendar(Locale("@calendar=islamic-civil"),status);
+ if (U_SUCCESS(status))
+ {
+ calendar.setTime(Calendar::getNow(), status);
+ calendar.add(UCAL_YEAR, -80, status);
+ UDate newStart = calendar.getTime(status);
+ int32_t newYear = calendar.get(UCAL_YEAR, status);
+ {
+ umtx_lock(NULL);
+ fgSystemDefaultCenturyStart = newStart;
+ fgSystemDefaultCenturyStartYear = newYear;
+ umtx_unlock(NULL);
+ }
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+ }
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar)
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/islamcal.h b/Build/source/libs/icu/icu-xetex/i18n/islamcal.h
new file mode 100644
index 00000000000..0b4080d35f1
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/islamcal.h
@@ -0,0 +1,463 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ******************************************************************************
+ *
+ * File ISLAMCAL.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 10/14/2003 srl ported from java IslamicCalendar
+ *****************************************************************************
+ */
+
+#ifndef ISLAMCAL_H
+#define ISLAMCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * <code>IslamicCalendar</code> is a subclass of <code>Calendar</code>
+ * that that implements the Islamic civil and religious calendars. It
+ * is used as the civil calendar in most of the Arab world and the
+ * liturgical calendar of the Islamic faith worldwide. This calendar
+ * is also known as the "Hijri" calendar, since it starts at the time
+ * of Mohammed's emigration (or "hijra") to Medinah on Thursday,
+ * July 15, 622 AD (Julian).
+ * <p>
+ * The Islamic calendar is strictly lunar, and thus an Islamic year of twelve
+ * lunar months does not correspond to the solar year used by most other
+ * calendar systems, including the Gregorian. An Islamic year is, on average,
+ * about 354 days long, so each successive Islamic year starts about 11 days
+ * earlier in the corresponding Gregorian year.
+ * <p>
+ * Each month of the calendar starts when the new moon's crescent is visible
+ * at sunset. However, in order to keep the time fields in this class
+ * synchronized with those of the other calendars and with local clock time,
+ * we treat days and months as beginning at midnight,
+ * roughly 6 hours after the corresponding sunset.
+ * <p>
+ * There are two main variants of the Islamic calendar in existence. The first
+ * is the <em>civil</em> calendar, which uses a fixed cycle of alternating 29-
+ * and 30-day months, with a leap day added to the last month of 11 out of
+ * every 30 years. This calendar is easily calculated and thus predictable in
+ * advance, so it is used as the civil calendar in a number of Arab countries.
+ * This is the default behavior of a newly-created <code>IslamicCalendar</code>
+ * object.
+ * <p>
+ * The Islamic <em>religious</em> calendar, however, is based on the <em>observation</em>
+ * of the crescent moon. It is thus affected by the position at which the
+ * observations are made, seasonal variations in the time of sunset, the
+ * eccentricities of the moon's orbit, and even the weather at the observation
+ * site. This makes it impossible to calculate in advance, and it causes the
+ * start of a month in the religious calendar to differ from the civil calendar
+ * by up to three days.
+ * <p>
+ * Using astronomical calculations for the position of the sun and moon, the
+ * moon's illumination, and other factors, it is possible to determine the start
+ * of a lunar month with a fairly high degree of certainty. However, these
+ * calculations are extremely complicated and thus slow, so most algorithms,
+ * including the one used here, are only approximations of the true astronical
+ * calculations. At present, the approximations used in this class are fairly
+ * simplistic; they will be improved in later versions of the code.
+ * <p>
+ * The {@link #setCivil setCivil} method determines
+ * which approach is used to determine the start of a month. By default, the
+ * fixed-cycle civil calendar is used. However, if <code>setCivil(false)</code>
+ * is called, an approximation of the true lunar calendar will be used.
+ *
+ * @see GregorianCalendar
+ *
+ * @author Laura Werner
+ * @author Alan Liu
+ * @author Steven R. Loomis
+ * @internal
+ */
+class IslamicCalendar : public Calendar {
+ public:
+ //-------------------------------------------------------------------------
+ // Constants...
+ //-------------------------------------------------------------------------
+ /**
+ * Calendar type - civil or religious
+ * @internal
+ */
+ enum ECivil {
+ ASTRONOMICAL,
+ CIVIL
+ };
+
+ /**
+ * Constants for the months
+ * @internal
+ */
+ enum EMonths {
+ /**
+ * Constant for Muharram, the 1st month of the Islamic year.
+ * @internal
+ */
+ MUHARRAM = 0,
+
+ /**
+ * Constant for Safar, the 2nd month of the Islamic year.
+ * @internal
+ */
+ SAFAR = 1,
+
+ /**
+ * Constant for Rabi' al-awwal (or Rabi' I), the 3rd month of the Islamic year.
+ * @internal
+ */
+ RABI_1 = 2,
+
+ /**
+ * Constant for Rabi' al-thani or (Rabi' II), the 4th month of the Islamic year.
+ * @internal
+ */
+ RABI_2 = 3,
+
+ /**
+ * Constant for Jumada al-awwal or (Jumada I), the 5th month of the Islamic year.
+ * @internal
+ */
+ JUMADA_1 = 4,
+
+ /**
+ * Constant for Jumada al-thani or (Jumada II), the 6th month of the Islamic year.
+ * @internal
+ */
+ JUMADA_2 = 5,
+
+ /**
+ * Constant for Rajab, the 7th month of the Islamic year.
+ * @internal
+ */
+ RAJAB = 6,
+
+ /**
+ * Constant for Sha'ban, the 8th month of the Islamic year.
+ * @internal
+ */
+ SHABAN = 7,
+
+ /**
+ * Constant for Ramadan, the 9th month of the Islamic year.
+ * @internal
+ */
+ RAMADAN = 8,
+
+ /**
+ * Constant for Shawwal, the 10th month of the Islamic year.
+ * @internal
+ */
+ SHAWWAL = 9,
+
+ /**
+ * Constant for Dhu al-Qi'dah, the 11th month of the Islamic year.
+ * @internal
+ */
+ DHU_AL_QIDAH = 10,
+
+ /**
+ * Constant for Dhu al-Hijjah, the 12th month of the Islamic year.
+ * @internal
+ */
+ DHU_AL_HIJJAH = 11,
+
+ ISLAMIC_MONTH_MAX
+ };
+
+
+
+ //-------------------------------------------------------------------------
+ // Constructors...
+ //-------------------------------------------------------------------------
+
+ /**
+ * Constructs an IslamicCalendar based on the current time in the default time zone
+ * with the given locale.
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the status of IslamicCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @param beCivil Whether the calendar should be civil (default-TRUE) or religious (FALSE)
+ * @internal
+ */
+ IslamicCalendar(const Locale& aLocale, UErrorCode &success, ECivil beCivil = CIVIL);
+
+ /**
+ * Copy Constructor
+ * @internal
+ */
+ IslamicCalendar(const IslamicCalendar& other);
+
+ /**
+ * Destructor.
+ * @internal
+ */
+ virtual ~IslamicCalendar();
+
+ /**
+ * Determines whether this object uses the fixed-cycle Islamic civil calendar
+ * or an approximation of the religious, astronomical calendar.
+ *
+ * @param beCivil <code>CIVIL</code> to use the civil calendar,
+ * <code>ASTRONOMICAL</code> to use the astronomical calendar.
+ * @internal
+ */
+ void setCivil(ECivil beCivil, UErrorCode &status);
+
+ /**
+ * Returns <code>true</code> if this object is using the fixed-cycle civil
+ * calendar, or <code>false</code> if using the religious, astronomical
+ * calendar.
+ * @internal
+ */
+ UBool isCivil();
+
+
+ // TODO: copy c'tor, etc
+
+ // clone
+ virtual Calendar* clone() const;
+
+ private:
+ /**
+ * Determine whether a year is a leap year in the Islamic civil calendar
+ */
+ static UBool civilLeapYear(int32_t year);
+
+ /**
+ * Return the day # on which the given year starts. Days are counted
+ * from the Hijri epoch, origin 0.
+ */
+ int32_t yearStart(int32_t year);
+
+ /**
+ * Return the day # on which the given month starts. Days are counted
+ * from the Hijri epoch, origin 0.
+ *
+ * @param year The hijri year
+ * @param year The hijri month, 0-based
+ */
+ int32_t monthStart(int32_t year, int32_t month) const;
+
+ /**
+ * Find the day number on which a particular month of the true/lunar
+ * Islamic calendar starts.
+ *
+ * @param month The month in question, origin 0 from the Hijri epoch
+ *
+ * @return The day number on which the given month starts.
+ */
+ int32_t trueMonthStart(int32_t month) const;
+
+ /**
+ * Return the "age" of the moon at the given time; this is the difference
+ * in ecliptic latitude between the moon and the sun. This method simply
+ * calls CalendarAstronomer.moonAge, converts to degrees,
+ * and adjusts the resultto be in the range [-180, 180].
+ *
+ * @param time The time at which the moon's age is desired,
+ * in millis since 1/1/1970.
+ */
+ static double moonAge(UDate time);
+
+ //-------------------------------------------------------------------------
+ // Internal data....
+ //
+
+ /**
+ * <code>CIVIL</code> if this object uses the fixed-cycle Islamic civil calendar,
+ * and <code>ASTRONOMICAL</code> if it approximates the true religious calendar using
+ * astronomical calculations for the time of the new moon.
+ */
+ ECivil civil;
+
+ //----------------------------------------------------------------------
+ // Calendar framework
+ //----------------------------------------------------------------------
+ protected:
+ /**
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+
+ /**
+ * Return the length (in days) of the given month.
+ *
+ * @param year The hijri year
+ * @param year The hijri month, 0-based
+ * @internal
+ */
+ virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const;
+
+ /**
+ * Return the number of days in the given Islamic year
+ * @internal
+ */
+ virtual int32_t handleGetYearLength(int32_t extendedYear) const;
+
+ //-------------------------------------------------------------------------
+ // Functions for converting from field values to milliseconds....
+ //-------------------------------------------------------------------------
+
+ // Return JD of start of given month/year
+ /**
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const;
+
+ //-------------------------------------------------------------------------
+ // Functions for converting from milliseconds to field values
+ //-------------------------------------------------------------------------
+
+ /**
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+
+ /**
+ * Override Calendar to compute several fields specific to the Islamic
+ * calendar system. These are:
+ *
+ * <ul><li>ERA
+ * <li>YEAR
+ * <li>MONTH
+ * <li>DAY_OF_MONTH
+ * <li>DAY_OF_YEAR
+ * <li>EXTENDED_YEAR</ul>
+ *
+ * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+ * method is called. The getGregorianXxx() methods return Gregorian
+ * calendar equivalents for the given Julian day.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
+
+ // UObject stuff
+ public:
+ /**
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @internal
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to a return
+ * value from getDynamicClassID(). For example:
+ *
+ * Base* polymorphic_pointer = createPolymorphicObject();
+ * if (polymorphic_pointer->getDynamicClassID() ==
+ * Derived::getStaticClassID()) ...
+ *
+ * @return The class ID for all objects of this class.
+ * @internal
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * return the calendar type, "buddhist".
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+ private:
+ IslamicCalendar(); // default constructor not implemented
+
+ // Default century.
+ protected:
+
+ /**
+ * (Overrides Calendar) Return true if the current date for this Calendar is in
+ * Daylight Savings Time. Recognizes DST_OFFSET, if it is set.
+ *
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return True if the current date for this Calendar is in Daylight Savings Time,
+ * false, otherwise.
+ * @internal
+ */
+ virtual UBool inDaylightTime(UErrorCode& status) const;
+
+
+ /**
+ * Returns TRUE because the Islamic Calendar does have a default century
+ * @internal
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * Returns the date of the start of the default century
+ * @return start of century - in milliseconds since epoch, 1970
+ * @internal
+ */
+ virtual UDate defaultCenturyStart() const;
+
+ /**
+ * Returns the year in which the default century begins
+ * @internal
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+ private: // default century stuff.
+ /**
+ * The system maintains a static default century start date. This is initialized
+ * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
+ * indicate an uninitialized state. Once the system default century date and year
+ * are set, they do not change.
+ */
+ static UDate fgSystemDefaultCenturyStart;
+
+ /**
+ * See documentation for systemDefaultCenturyStart.
+ */
+ static int32_t fgSystemDefaultCenturyStartYear;
+
+ /**
+ * Default value that indicates the defaultCenturyStartYear is unitialized
+ */
+ static const int32_t fgSystemDefaultCenturyYear;
+
+ /**
+ * start of default century, as a date
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * Returns the beginning date of the 100-year window that dates
+ * with 2-digit years are considered to fall within.
+ */
+ UDate internalGetDefaultCenturyStart(void) const;
+
+ /**
+ * Returns the first year of the 100-year window that dates with
+ * 2-digit years are considered to fall within.
+ */
+ int32_t internalGetDefaultCenturyStartYear(void) const;
+
+ /**
+ * Initializes the 100-year window that dates with 2-digit years
+ * are considered to fall within so that its start date is 80 years
+ * before the current time.
+ */
+ static void initializeSystemDefaultCentury(void);
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif
+
+
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/japancal.cpp b/Build/source/libs/icu/icu-xetex/i18n/japancal.cpp
new file mode 100644
index 00000000000..c06650b96a4
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/japancal.cpp
@@ -0,0 +1,545 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File JAPANCAL.CPP
+*
+* Modification History:
+* 05/16/2003 srl copied from buddhcal.cpp
+*
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "japancal.h"
+#include "unicode/gregocal.h"
+#include "umutex.h"
+#include "uassert.h"
+
+//#define U_DEBUG_JCAL
+
+#ifdef U_DEBUG_JCAL
+#include <stdio.h>
+#endif
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(JapaneseCalendar)
+
+// Gregorian date of each emperor's ascension
+// Years are AD, months are 1-based.
+static const struct {
+ int16_t year;
+ int8_t month;
+ int8_t day;
+} kEraInfo[] = {
+ // Year Month Day
+ { 645, 6, 19 }, // Taika 0
+ { 650, 2, 15 }, // Hakuchi 1
+ { 672, 1, 1 }, // Hakuho 2
+ { 686, 7, 20 }, // Shucho 3
+ { 701, 3, 21 }, // Taiho 4
+ { 704, 5, 10 }, // Keiun 5
+ { 708, 1, 11 }, // Wado 6
+ { 715, 9, 2 }, // Reiki 7
+ { 717, 11, 17 }, // Yoro 8
+ { 724, 2, 4 }, // Jinki 9
+ { 729, 8, 5 }, // Tempyo 10
+ { 749, 4, 14 }, // Tempyo-kampo 11
+ { 749, 7, 2 }, // Tempyo-shoho 12
+ { 757, 8, 18 }, // Tempyo-hoji 13
+ { 765, 1, 7 }, // Tempho-jingo 14
+ { 767, 8, 16 }, // Jingo-keiun 15
+ { 770, 10, 1 }, // Hoki 16
+ { 781, 1, 1 }, // Ten-o 17
+ { 782, 8, 19 }, // Enryaku 18
+ { 806, 5, 18 }, // Daido 19
+ { 810, 9, 19 }, // Konin 20
+ { 824, 1, 5 }, // Tencho
+ { 834, 1, 3 }, // Showa
+ { 848, 6, 13 }, // Kajo
+ { 851, 4, 28 }, // Ninju
+ { 854, 11, 30 }, // Saiko
+ { 857, 2, 21 }, // Tennan
+ { 859, 4, 15 }, // Jogan
+ { 877, 4, 16 }, // Genkei
+ { 885, 2, 21 }, // Ninna
+ { 889, 4, 27 }, // Kampyo 30
+ { 898, 4, 26 }, // Shotai
+ { 901, 7, 15 }, // Engi
+ { 923, 4, 11 }, // Encho
+ { 931, 4, 26 }, // Shohei
+ { 938, 5, 22 }, // Tengyo
+ { 947, 4, 22 }, // Tenryaku
+ { 957, 10, 27 }, // Tentoku
+ { 961, 2, 16 }, // Owa
+ { 964, 7, 10 }, // Koho
+ { 968, 8, 13 }, // Anna 40
+ { 970, 3, 25 }, // Tenroku
+ { 973, 12, 20 }, // Ten-en
+ { 976, 7, 13 }, // Jogen
+ { 978, 11, 29 }, // Tengen
+ { 983, 4, 15 }, // Eikan
+ { 985, 4, 27 }, // Kanna
+ { 987, 4, 5 }, // Ei-en
+ { 989, 8, 8 }, // Eiso
+ { 990, 11, 7 }, // Shoryaku
+ { 995, 2, 22 }, // Chotoku 50
+ { 999, 1, 13 }, // Choho
+ { 1004, 7, 20 }, // Kanko
+ { 1012, 12, 25 }, // Chowa
+ { 1017, 4, 23 }, // Kannin
+ { 1021, 2, 2 }, // Jian
+ { 1024, 7, 13 }, // Manju
+ { 1028, 7, 25 }, // Chogen
+ { 1037, 4, 21 }, // Choryaku
+ { 1040, 11, 10 }, // Chokyu
+ { 1044, 11, 24 }, // Kantoku 60
+ { 1046, 4, 14 }, // Eisho
+ { 1053, 1, 11 }, // Tengi
+ { 1058, 8, 29 }, // Kohei
+ { 1065, 8, 2 }, // Jiryaku
+ { 1069, 4, 13 }, // Enkyu
+ { 1074, 8, 23 }, // Shoho
+ { 1077, 11, 17 }, // Shoryaku
+ { 1081, 2, 10 }, // Eiho
+ { 1084, 2, 7 }, // Otoku
+ { 1087, 4, 7 }, // Kanji 70
+ { 1094, 12, 15 }, // Kaho
+ { 1096, 12, 17 }, // Eicho
+ { 1097, 11, 21 }, // Shotoku
+ { 1099, 8, 28 }, // Kowa
+ { 1104, 2, 10 }, // Choji
+ { 1106, 4, 9 }, // Kasho
+ { 1108, 8, 3 }, // Tennin
+ { 1110, 7, 13 }, // Ten-ei
+ { 1113, 7, 13 }, // Eikyu
+ { 1118, 4, 3 }, // Gen-ei 80
+ { 1120, 4, 10 }, // Hoan
+ { 1124, 4, 3 }, // Tenji
+ { 1126, 1, 22 }, // Daiji
+ { 1131, 1, 29 }, // Tensho
+ { 1132, 8, 11 }, // Chosho
+ { 1135, 4, 27 }, // Hoen
+ { 1141, 7, 10 }, // Eiji
+ { 1142, 4, 28 }, // Koji
+ { 1144, 2, 23 }, // Tenyo
+ { 1145, 7, 22 }, // Kyuan 90
+ { 1151, 1, 26 }, // Ninpei
+ { 1154, 10, 28 }, // Kyuju
+ { 1156, 4, 27 }, // Hogen
+ { 1159, 4, 20 }, // Heiji
+ { 1160, 1, 10 }, // Eiryaku
+ { 1161, 9, 4 }, // Oho
+ { 1163, 3, 29 }, // Chokan
+ { 1165, 6, 5 }, // Eiman
+ { 1166, 8, 27 }, // Nin-an
+ { 1169, 4, 8 }, // Kao 100
+ { 1171, 4, 21 }, // Shoan
+ { 1175, 7, 28 }, // Angen
+ { 1177, 8, 4 }, // Jisho
+ { 1181, 7, 14 }, // Yowa
+ { 1182, 5, 27 }, // Juei
+ { 1184, 4, 16 }, // Genryuku
+ { 1185, 8, 14 }, // Bunji
+ { 1190, 4, 11 }, // Kenkyu
+ { 1199, 4, 27 }, // Shoji
+ { 1201, 2, 13 }, // Kennin 110
+ { 1204, 2, 20 }, // Genkyu
+ { 1206, 4, 27 }, // Ken-ei
+ { 1207, 10, 25 }, // Shogen
+ { 1211, 3, 9 }, // Kenryaku
+ { 1213, 12, 6 }, // Kenpo
+ { 1219, 4, 12 }, // Shokyu
+ { 1222, 4, 13 }, // Joo
+ { 1224, 11, 20 }, // Gennin
+ { 1225, 4, 20 }, // Karoku
+ { 1227, 12, 10 }, // Antei 120
+ { 1229, 3, 5 }, // Kanki
+ { 1232, 4, 2 }, // Joei
+ { 1233, 4, 15 }, // Tempuku
+ { 1234, 11, 5 }, // Bunryaku
+ { 1235, 9, 19 }, // Katei
+ { 1238, 11, 23 }, // Ryakunin
+ { 1239, 2, 7 }, // En-o
+ { 1240, 7, 16 }, // Ninji
+ { 1243, 2, 26 }, // Kangen
+ { 1247, 2, 28 }, // Hoji 130
+ { 1249, 3, 18 }, // Kencho
+ { 1256, 10, 5 }, // Kogen
+ { 1257, 3, 14 }, // Shoka
+ { 1259, 3, 26 }, // Shogen
+ { 1260, 4, 13 }, // Bun-o
+ { 1261, 2, 20 }, // Kocho
+ { 1264, 2, 28 }, // Bun-ei
+ { 1275, 4, 25 }, // Kenji
+ { 1278, 2, 29 }, // Koan
+ { 1288, 4, 28 }, // Shoo 140
+ { 1293, 8, 55 }, // Einin
+ { 1299, 4, 25 }, // Shoan
+ { 1302, 11, 21 }, // Kengen
+ { 1303, 8, 5 }, // Kagen
+ { 1306, 12, 14 }, // Tokuji
+ { 1308, 10, 9 }, // Enkei
+ { 1311, 4, 28 }, // Ocho
+ { 1312, 3, 20 }, // Showa
+ { 1317, 2, 3 }, // Bunpo
+ { 1319, 4, 28 }, // Geno 150
+ { 1321, 2, 23 }, // Genkyo
+ { 1324, 12, 9 }, // Shochu
+ { 1326, 4, 26 }, // Kareki
+ { 1329, 8, 29 }, // Gentoku
+ { 1331, 8, 9 }, // Genko
+ { 1334, 1, 29 }, // Kemmu
+ { 1336, 2, 29 }, // Engen
+ { 1340, 4, 28 }, // Kokoku
+ { 1346, 12, 8 }, // Shohei
+ { 1370, 7, 24 }, // Kentoku 160
+ { 1372, 4, 1 }, // Bunch\u0169
+ { 1375, 5, 27 }, // Tenju
+ { 1379, 3, 22 }, // Koryaku
+ { 1381, 2, 10 }, // Kowa
+ { 1384, 4, 28 }, // Gench\u0169
+ { 1384, 2, 27 }, // Meitoku
+ { 1387, 8, 23 }, // Kakei
+ { 1389, 2, 9 }, // Koo
+ { 1390, 3, 26 }, // Meitoku
+ { 1394, 7, 5 }, // Oei 170
+ { 1428, 4, 27 }, // Shocho
+ { 1429, 9, 5 }, // Eikyo
+ { 1441, 2, 17 }, // Kakitsu
+ { 1444, 2, 5 }, // Bun-an
+ { 1449, 7, 28 }, // Hotoku
+ { 1452, 7, 25 }, // Kyotoku
+ { 1455, 7, 25 }, // Kosho
+ { 1457, 9, 28 }, // Choroku
+ { 1460, 12, 21 }, // Kansho
+ { 1466, 2, 28 }, // Bunsho 180
+ { 1467, 3, 3 }, // Onin
+ { 1469, 4, 28 }, // Bunmei
+ { 1487, 7, 29 }, // Chokyo
+ { 1489, 8, 21 }, // Entoku
+ { 1492, 7, 19 }, // Meio
+ { 1501, 2, 29 }, // Bunki
+ { 1504, 2, 30 }, // Eisho
+ { 1521, 8, 23 }, // Taiei
+ { 1528, 8, 20 }, // Kyoroku
+ { 1532, 7, 29 }, // Tenmon 190
+ { 1555, 10, 23 }, // Koji
+ { 1558, 2, 28 }, // Eiroku
+ { 1570, 4, 23 }, // Genki
+ { 1573, 7, 28 }, // Tensho
+ { 1592, 12, 8 }, // Bunroku
+ { 1596, 10, 27 }, // Keicho
+ { 1615, 7, 13 }, // Genwa
+ { 1624, 2, 30 }, // Kan-ei
+ { 1644, 12, 16 }, // Shoho
+ { 1648, 2, 15 }, // Keian 200
+ { 1652, 9, 18 }, // Shoo
+ { 1655, 4, 13 }, // Meiryaku
+ { 1658, 7, 23 }, // Manji
+ { 1661, 4, 25 }, // Kanbun
+ { 1673, 9, 21 }, // Enpo
+ { 1681, 9, 29 }, // Tenwa
+ { 1684, 2, 21 }, // Jokyo
+ { 1688, 9, 30 }, // Genroku
+ { 1704, 3, 13 }, // Hoei
+ { 1711, 4, 25 }, // Shotoku 210
+ { 1716, 6, 22 }, // Kyoho
+ { 1736, 4, 28 }, // Genbun
+ { 1741, 2, 27 }, // Kanpo
+ { 1744, 2, 21 }, // Enkyo
+ { 1748, 7, 12 }, // Kan-en
+ { 1751, 10, 27 }, // Horyaku
+ { 1764, 6, 2 }, // Meiwa
+ { 1772, 11, 16 }, // An-ei
+ { 1781, 4, 2 }, // Tenmei
+ { 1789, 1, 25 }, // Kansei 220
+ { 1801, 2, 5 }, // Kyowa
+ { 1804, 2, 11 }, // Bunka
+ { 1818, 4, 22 }, // Bunsei
+ { 1830, 12, 10 }, // Tenpo
+ { 1844, 12, 2 }, // Koka
+ { 1848, 2, 28 }, // Kaei
+ { 1854, 11, 27 }, // Ansei
+ { 1860, 3, 18 }, // Man-en
+ { 1861, 2, 19 }, // Bunkyu
+ { 1864, 2, 20 }, // Genji 230
+ { 1865, 4, 7 }, // Keio 231
+ { 1868, 9, 8 }, // Meiji 232
+ { 1912, 7, 30 }, // Taisho 233
+ { 1926, 12, 25 }, // Showa 234
+ { 1989, 1, 8 } // Heisei 235
+};
+
+#define kEraCount (sizeof(kEraInfo)/sizeof(kEraInfo[0]))
+
+static const uint32_t kCurrentEra = (kEraCount-1);
+
+static const int32_t kGregorianEpoch = 1970; // used as the default value of EXTENDED_YEAR
+
+/* Some platforms don't like to export constants, like old Palm OS and some z/OS configurations. */
+uint32_t JapaneseCalendar::getCurrentEra() {
+ return kCurrentEra;
+}
+
+JapaneseCalendar::JapaneseCalendar(const Locale& aLocale, UErrorCode& success)
+: GregorianCalendar(aLocale, success)
+{
+ setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
+}
+
+JapaneseCalendar::~JapaneseCalendar()
+{
+}
+
+JapaneseCalendar::JapaneseCalendar(const JapaneseCalendar& source)
+: GregorianCalendar(source)
+{
+}
+
+JapaneseCalendar& JapaneseCalendar::operator= ( const JapaneseCalendar& right)
+{
+ GregorianCalendar::operator=(right);
+ return *this;
+}
+
+Calendar* JapaneseCalendar::clone(void) const
+{
+ return new JapaneseCalendar(*this);
+}
+
+const char *JapaneseCalendar::getType() const
+{
+ return "japanese";
+}
+
+int32_t JapaneseCalendar::getDefaultMonthInYear()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t era = internalGetEra();
+ computeFields(status); // slow
+ int32_t year = getGregorianYear();
+ // TODO do we assume we can trust 'era'? What if it is denormalized?
+
+ int32_t month = GregorianCalendar::getDefaultMonthInYear();
+
+ // Find out if we are at the edge of an era
+
+ if(year == kEraInfo[era].year) {
+ // Yes, we're in the first year of this era.
+ return kEraInfo[era].month-1;
+ }
+
+ return month;
+}
+
+int32_t JapaneseCalendar::getDefaultDayInMonth(int32_t month)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t era = internalGetEra();
+ computeFields(status); // slow
+ int32_t year = getGregorianYear();
+ int32_t day = GregorianCalendar::getDefaultDayInMonth(month);
+
+ if(year == kEraInfo[era].year) {
+ if(month == (kEraInfo[era].month-1)) {
+ return kEraInfo[era].day;
+ }
+ }
+
+ return day;
+}
+
+
+int32_t JapaneseCalendar::internalGetEra() const
+{
+ return internalGet(UCAL_ERA, kCurrentEra);
+}
+
+int32_t JapaneseCalendar::handleGetExtendedYear()
+{
+ // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
+ // The default value of EXTENDED_YEAR is 1970 (Showa 45)
+ int32_t year;
+
+ if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
+ newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
+ year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
+ } else {
+ // Subtract one because year starts at 1
+ year = internalGet(UCAL_YEAR) + kEraInfo[internalGetEra()].year - 1;
+ }
+ return year;
+}
+
+
+void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
+{
+ //Calendar::timeToFields(theTime, quick, status);
+ GregorianCalendar::handleComputeFields(julianDay, status);
+ int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year
+
+ int32_t low = 0;
+
+ // Short circuit for recent years. Most modern computations will
+ // occur in the current era and won't require the binary search.
+ // Note that if the year is == the current era year, then we use
+ // the binary search to handle the month/dom comparison.
+#ifdef U_DEBUG_JCAL
+ fprintf(stderr, "== %d \n", year);
+#endif
+
+ if (year > kEraInfo[kCurrentEra].year) {
+ low = kCurrentEra;
+#ifdef U_DEBUG_JCAL
+ fprintf(stderr, " low=%d (special)\n", low);
+#endif
+ } else {
+ // Binary search
+ int32_t high = kEraCount;
+
+#ifdef U_DEBUG_JCAL
+ fprintf(stderr, " high=%d\n", high);
+#endif
+ while (low < high - 1) {
+ int32_t i = (low + high) / 2;
+ int32_t diff = year - kEraInfo[i].year;
+
+#ifdef U_DEBUG_JCAL
+ fprintf(stderr, " d=%d low=%d, high=%d. Considering %d:M%d D%d Y%d. { we are ?:M%d D%d Y%d }\n",
+ diff,low, high, i, kEraInfo[i].month-1, kEraInfo[i].day, kEraInfo[i].year, internalGet(UCAL_MONTH), internalGet(UCAL_DATE),year);
+#endif
+
+ // If years are the same, then compare the months, and if those
+ // are the same, compare days of month. In the ERAS array
+ // months are 1-based for easier maintenance.
+ if (diff == 0) {
+ diff = internalGet(UCAL_MONTH) - (kEraInfo[i].month - 1);
+#ifdef U_DEBUG_JCAL
+ fprintf(stderr, "diff now %d (M) = %d - %d - 1\n", diff, internalGet(UCAL_MONTH), kEraInfo[i].month);
+#endif
+ if (diff == 0) {
+ diff = internalGet(UCAL_DATE) - kEraInfo[i].day;
+#ifdef U_DEBUG_JCAL
+ fprintf(stderr, "diff now %d (D)\n", diff);
+#endif
+ }
+ }
+ if (diff >= 0) {
+ low = i;
+ } else {
+ high = i;
+ }
+#ifdef U_DEBUG_JCAL
+ fprintf(stderr, ". low=%d, high=%d, i=%d, diff=%d.. %d\n", low, high, i, diff, year);
+#endif
+
+ }
+ }
+
+#ifdef U_DEBUG_JCAL
+ fprintf(stderr, " low[era]=%d,.. %d\n", low, year);
+#endif
+ // Now we've found the last era that starts before this date, so
+ // adjust the year to count from the start of that era. Note that
+ // all dates before the first era will fall into the first era by
+ // the algorithm.
+
+ internalSet(UCAL_ERA, low);
+ internalSet(UCAL_YEAR, year - kEraInfo[low].year + 1);
+#ifdef U_DEBUG_JCAL
+ fprintf(stderr, " Set ERA=%d, year=%d\n", low, year-kEraInfo[low].year+1);
+#endif
+
+}
+
+/*
+Disable pivoting
+*/
+UBool JapaneseCalendar::haveDefaultCentury() const
+{
+ return FALSE;
+}
+
+UDate JapaneseCalendar::defaultCenturyStart() const
+{
+ return 0;// WRONG
+}
+
+int32_t JapaneseCalendar::defaultCenturyStartYear() const
+{
+ return 0;
+}
+
+static int32_t gJapanCalendarLimits[2][4] = {
+ // Minimum Greatest min Least max Greatest max
+ { 0, 0, kCurrentEra, kCurrentEra }, // ERA
+ { 1, 1, 0, 0 }, // YEAR least-max/greatest-max computed at runtime
+};
+
+static UBool gJapanYearLimitsKnown = FALSE;
+
+int32_t JapaneseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
+{
+ switch(field) {
+ case UCAL_YEAR:
+ {
+ UBool needCalc;
+ UMTX_CHECK(NULL, (gJapanYearLimitsKnown == FALSE), needCalc);
+ if(needCalc) {
+ int32_t min = kEraInfo[1].year - kEraInfo[0].year;
+ int32_t max = min;
+ for (uint32_t i=2; i<kEraCount; i++) { // counting by year, not field (3's)
+ int32_t d = kEraInfo[i].year - kEraInfo[i-1].year;
+ U_ASSERT(d >= 0);
+ if (d < min) {
+ min = d;
+ }
+ if (d > max) {
+ max = d;
+ }
+ }
+ U_ASSERT(min >= 0 && max > min);
+
+ umtx_lock(NULL);
+ if(gJapanYearLimitsKnown==FALSE) {
+ gJapanCalendarLimits[field][UCAL_LIMIT_LEAST_MAXIMUM] = ++min; // 1-based
+ gJapanCalendarLimits[field][UCAL_LIMIT_MAXIMUM] = ++max; // 1-based
+ gJapanYearLimitsKnown = TRUE;
+ }
+ umtx_unlock(NULL);
+ }
+ return gJapanCalendarLimits[field][limitType];
+ }
+
+ case UCAL_ERA:
+ return gJapanCalendarLimits[field][limitType];
+
+ case UCAL_EXTENDED_YEAR: // extended year limits
+ switch(limitType) {
+ case UCAL_LIMIT_GREATEST_MINIMUM:
+ case UCAL_LIMIT_MINIMUM:
+ return kEraInfo[0].year; /* minimum is 1st era year */
+
+ case UCAL_LIMIT_LEAST_MAXIMUM:
+ case UCAL_LIMIT_MAXIMUM:
+ /* use Gregorian calendar max */
+ default:
+ return GregorianCalendar::handleGetLimit(field,limitType);
+ }
+ break;
+
+ default:
+ return GregorianCalendar::handleGetLimit(field,limitType);
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/japancal.h b/Build/source/libs/icu/icu-xetex/i18n/japancal.h
new file mode 100644
index 00000000000..05749340bf3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/japancal.h
@@ -0,0 +1,207 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ********************************************************************************
+ *
+ * File JAPANCAL.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 05/13/2003 srl copied from gregocal.h
+ ********************************************************************************
+ */
+
+#ifndef JAPANCAL_H
+#define JAPANCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Concrete class which provides the Japanese calendar.
+ * <P>
+ * <code>JapaneseCalendar</code> is a subclass of <code>GregorianCalendar</code>
+ * that numbers years and eras based on the reigns of the Japanese emperors.
+ * The Japanese calendar is identical to the Gregorian calendar in all respects
+ * except for the year and era. The ascension of each emperor to the throne
+ * begins a new era, and the years of that era are numbered starting with the
+ * year of ascension as year 1.
+ * <p>
+ * Note that in the year of an imperial ascension, there are two possible sets
+ * of year and era values: that for the old era and for the new. For example, a
+ * new era began on January 7, 1989 AD. Strictly speaking, the first six days
+ * of that year were in the Showa era, e.g. "January 6, 64 Showa", while the rest
+ * of the year was in the Heisei era, e.g. "January 7, 1 Heisei". This class
+ * handles this distinction correctly when computing dates. However, in lenient
+ * mode either form of date is acceptable as input.
+ * <p>
+ * In modern times, eras have started on January 8, 1868 AD, Gregorian (Meiji),
+ * July 30, 1912 (Taisho), December 25, 1926 (Showa), and January 7, 1989 (Heisei). Constants
+ * for these eras, suitable for use in the <code>UCAL_ERA</code> field, are provided
+ * in this class. Note that the <em>number</em> used for each era is more or
+ * less arbitrary. Currently, the era starting in 1053 AD is era #0; however this
+ * may change in the future as we add more historical data. Use the predefined
+ * constants rather than using actual, absolute numbers.
+ * <p>
+ * @internal
+ */
+class JapaneseCalendar : public GregorianCalendar {
+public:
+
+ /**
+ * Useful constants for JapaneseCalendar.
+ * @internal
+ */
+ U_I18N_API static uint32_t U_EXPORT2 getCurrentEra(void); // the current era
+
+ /**
+ * Constructs a JapaneseCalendar based on the current time in the default time zone
+ * with the given locale.
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the status of JapaneseCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ JapaneseCalendar(const Locale& aLocale, UErrorCode& success);
+
+
+ /**
+ * Destructor
+ * @internal
+ */
+ virtual ~JapaneseCalendar();
+
+ /**
+ * Copy constructor
+ * @param source the object to be copied.
+ * @internal
+ */
+ JapaneseCalendar(const JapaneseCalendar& source);
+
+ /**
+ * Default assignment operator
+ * @param right the object to be copied.
+ * @internal
+ */
+ JapaneseCalendar& operator=(const JapaneseCalendar& right);
+
+ /**
+ * Create and return a polymorphic copy of this calendar.
+ * @return return a polymorphic copy of this calendar.
+ * @internal
+ */
+ virtual Calendar* clone(void) const;
+
+ /**
+ * Return the extended year defined by the current fields. In the
+ * Japanese calendar case, this is equal to the equivalent extended Gregorian year.
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+
+public:
+ /**
+ * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
+ * override. This method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
+ * this method.
+ *
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @internal
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to a return
+ * value from getDynamicClassID(). For example:
+ *
+ * Base* polymorphic_pointer = createPolymorphicObject();
+ * if (polymorphic_pointer->getDynamicClassID() ==
+ * Derived::getStaticClassID()) ...
+ *
+ * @return The class ID for all objects of this class.
+ * @internal
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * return the calendar type, "japanese".
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+ /**
+ * @return FALSE - no default century in Japanese
+ * @internal
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * Not used - no default century.
+ * @internal
+ */
+ virtual UDate defaultCenturyStart() const;
+ /**
+ * Not used - no default century.
+ * @internal
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+private:
+ JapaneseCalendar(); // default constructor not implemented
+
+protected:
+ /**
+ * Calculate the era for internal computation
+ * @internal
+ */
+ virtual int32_t internalGetEra() const;
+
+ /**
+ * Compute fields from the JD
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode& status);
+
+ /**
+ * Calculate the limit for a specified type of limit and field
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+
+ /***
+ * Called by computeJulianDay. Returns the default month (0-based) for the year,
+ * taking year and era into account. Will return the first month of the given era, if
+ * the current year is an ascension year.
+ * @internal
+ */
+ virtual int32_t getDefaultMonthInYear();
+
+ /***
+ * Called by computeJulianDay. Returns the default day (1-based) for the month,
+ * taking currently-set year and era into account. Will return the first day of the given
+ * era, if the current month is an ascension year and month.
+ * @internal
+ */
+ virtual int32_t getDefaultDayInMonth(int32_t month);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/measfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/measfmt.cpp
new file mode 100644
index 00000000000..eaa37a24850
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/measfmt.cpp
@@ -0,0 +1,44 @@
+/*
+**********************************************************************
+* Copyright (c) 2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 20, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/measfmt.h"
+#include "currfmt.h"
+
+U_NAMESPACE_BEGIN
+
+MeasureFormat::MeasureFormat() {}
+
+MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(const Locale& locale,
+ UErrorCode& ec) {
+ CurrencyFormat* fmt = NULL;
+ if (U_SUCCESS(ec)) {
+ fmt = new CurrencyFormat(locale, ec);
+ if (U_FAILURE(ec)) {
+ delete fmt;
+ fmt = NULL;
+ }
+ }
+ return fmt;
+}
+
+MeasureFormat* U_EXPORT2 MeasureFormat::createCurrencyFormat(UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+ return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/measure.cpp b/Build/source/libs/icu/icu-xetex/i18n/measure.cpp
new file mode 100644
index 00000000000..03e6a7cbab9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/measure.cpp
@@ -0,0 +1,65 @@
+/*
+**********************************************************************
+* Copyright (c) 2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 26, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/measure.h"
+#include "unicode/measunit.h"
+
+U_NAMESPACE_BEGIN
+
+Measure::Measure() {}
+
+Measure::Measure(const Formattable& _number, MeasureUnit* adoptedUnit,
+ UErrorCode& ec) :
+ number(_number), unit(adoptedUnit) {
+ if (U_SUCCESS(ec) &&
+ (!number.isNumeric() || adoptedUnit == 0)) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+Measure::Measure(const Measure& other) :
+ UObject(other), unit(0) {
+ *this = other;
+}
+
+Measure& Measure::operator=(const Measure& other) {
+ if (this != &other) {
+ delete unit;
+ number = other.number;
+ unit = (MeasureUnit*) other.unit->clone();
+ }
+ return *this;
+}
+
+Measure::~Measure() {
+ delete unit;
+}
+
+UBool Measure::operator==(const UObject& other) const {
+ const Measure* m = (const Measure*) &other;
+ return getDynamicClassID() == other.getDynamicClassID() &&
+ number == m->getNumber() &&
+ *unit == m->getUnit();
+}
+
+//----------------------------------------------------------------------
+// MeasureUnit implementation
+
+MeasureUnit:: MeasureUnit() {}
+
+MeasureUnit::~MeasureUnit() {}
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
diff --git a/Build/source/libs/icu/icu-xetex/i18n/msgfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/msgfmt.cpp
new file mode 100644
index 00000000000..9eb7bcb303a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/msgfmt.cpp
@@ -0,0 +1,1466 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File MSGFMT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/20/97 helena Finished first cut of implementation.
+* 04/10/97 aliu Made to work on AIX. Added stoi to replace wtoi.
+* 06/11/97 helena Fixed addPattern to take the pattern correctly.
+* 06/17/97 helena Fixed the getPattern to return the correct pattern.
+* 07/09/97 helena Made ParsePosition into a class.
+* 02/22/99 stephen Removed character literals for EBCDIC safety
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/msgfmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/choicfmt.h"
+#include "unicode/ustring.h"
+#include "unicode/ucnv_err.h"
+#include "unicode/uchar.h"
+#include "unicode/umsg.h"
+#include "unicode/rbnf.h"
+#include "ustrfmt.h"
+#include "cmemory.h"
+#include "util.h"
+#include "uassert.h"
+
+// *****************************************************************************
+// class MessageFormat
+// *****************************************************************************
+
+#define COMMA ((UChar)0x002C)
+#define SINGLE_QUOTE ((UChar)0x0027)
+#define LEFT_CURLY_BRACE ((UChar)0x007B)
+#define RIGHT_CURLY_BRACE ((UChar)0x007D)
+
+//---------------------------------------
+// static data
+
+static const UChar ID_EMPTY[] = {
+ 0 /* empty string, used for default so that null can mark end of list */
+};
+
+static const UChar ID_NUMBER[] = {
+ 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0 /* "number" */
+};
+static const UChar ID_DATE[] = {
+ 0x64, 0x61, 0x74, 0x65, 0 /* "date" */
+};
+static const UChar ID_TIME[] = {
+ 0x74, 0x69, 0x6D, 0x65, 0 /* "time" */
+};
+static const UChar ID_CHOICE[] = {
+ 0x63, 0x68, 0x6F, 0x69, 0x63, 0x65, 0 /* "choice" */
+};
+static const UChar ID_SPELLOUT[] = {
+ 0x73, 0x70, 0x65, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0 /* "spellout" */
+};
+static const UChar ID_ORDINAL[] = {
+ 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0 /* "ordinal" */
+};
+static const UChar ID_DURATION[] = {
+ 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0 /* "duration" */
+};
+
+// MessageFormat Type List Number, Date, Time or Choice
+static const UChar * const TYPE_IDS[] = {
+ ID_EMPTY,
+ ID_NUMBER,
+ ID_DATE,
+ ID_TIME,
+ ID_CHOICE,
+ ID_SPELLOUT,
+ ID_ORDINAL,
+ ID_DURATION,
+ NULL,
+};
+
+static const UChar ID_CURRENCY[] = {
+ 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x63, 0x79, 0 /* "currency" */
+};
+static const UChar ID_PERCENT[] = {
+ 0x70, 0x65, 0x72, 0x63, 0x65, 0x6E, 0x74, 0 /* "percent" */
+};
+static const UChar ID_INTEGER[] = {
+ 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0 /* "integer" */
+};
+
+// NumberFormat modifier list, default, currency, percent or integer
+static const UChar * const NUMBER_STYLE_IDS[] = {
+ ID_EMPTY,
+ ID_CURRENCY,
+ ID_PERCENT,
+ ID_INTEGER,
+ NULL,
+};
+
+static const UChar ID_SHORT[] = {
+ 0x73, 0x68, 0x6F, 0x72, 0x74, 0 /* "short" */
+};
+static const UChar ID_MEDIUM[] = {
+ 0x6D, 0x65, 0x64, 0x69, 0x75, 0x6D, 0 /* "medium" */
+};
+static const UChar ID_LONG[] = {
+ 0x6C, 0x6F, 0x6E, 0x67, 0 /* "long" */
+};
+static const UChar ID_FULL[] = {
+ 0x66, 0x75, 0x6C, 0x6C, 0 /* "full" */
+};
+
+// DateFormat modifier list, default, short, medium, long or full
+static const UChar * const DATE_STYLE_IDS[] = {
+ ID_EMPTY,
+ ID_SHORT,
+ ID_MEDIUM,
+ ID_LONG,
+ ID_FULL,
+ NULL,
+};
+
+static const U_NAMESPACE_QUALIFIER DateFormat::EStyle DATE_STYLES[] = {
+ U_NAMESPACE_QUALIFIER DateFormat::kDefault,
+ U_NAMESPACE_QUALIFIER DateFormat::kShort,
+ U_NAMESPACE_QUALIFIER DateFormat::kMedium,
+ U_NAMESPACE_QUALIFIER DateFormat::kLong,
+ U_NAMESPACE_QUALIFIER DateFormat::kFull,
+};
+
+static const int32_t DEFAULT_INITIAL_CAPACITY = 10;
+
+U_NAMESPACE_BEGIN
+
+// -------------------------------------
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MessageFormat)
+
+//--------------------------------------------------------------------
+
+/**
+ * Convert a string to an unsigned decimal, ignoring rule whitespace.
+ * @return a non-negative number if successful, or a negative number
+ * upon failure.
+ */
+static int32_t stou(const UnicodeString& string) {
+ int32_t n = 0;
+ int32_t count = 0;
+ UChar32 c;
+ for (int32_t i=0; i<string.length(); i+=U16_LENGTH(c)) {
+ c = string.char32At(i);
+ if (uprv_isRuleWhiteSpace(c)) {
+ continue;
+ }
+ int32_t d = u_digit(c, 10);
+ if (d < 0 || ++count > 10) {
+ return -1;
+ }
+ n = 10*n + d;
+ }
+ return n;
+}
+
+/**
+ * Convert an integer value to a string and append the result to
+ * the given UnicodeString.
+ */
+static UnicodeString& itos(int32_t i, UnicodeString& appendTo) {
+ UChar temp[16];
+ uprv_itou(temp,16,i,10,0); // 10 == radix
+ appendTo.append(temp);
+ return appendTo;
+}
+
+// -------------------------------------
+// Creates a MessageFormat instance based on the pattern.
+
+MessageFormat::MessageFormat(const UnicodeString& pattern,
+ UErrorCode& success)
+: fLocale(Locale::getDefault()), // Uses the default locale
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ subformats(NULL),
+ subformatCount(0),
+ subformatCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL)
+{
+ if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
+ !allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
+ success = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ applyPattern(pattern, success);
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+}
+
+MessageFormat::MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UErrorCode& success)
+: fLocale(newLocale),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ subformats(NULL),
+ subformatCount(0),
+ subformatCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL)
+{
+ if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
+ !allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
+ success = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ applyPattern(pattern, success);
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+}
+
+MessageFormat::MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UParseError& parseError,
+ UErrorCode& success)
+: fLocale(newLocale),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ subformats(NULL),
+ subformatCount(0),
+ subformatCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL)
+{
+ if (!allocateSubformats(DEFAULT_INITIAL_CAPACITY) ||
+ !allocateArgTypes(DEFAULT_INITIAL_CAPACITY)) {
+ success = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ applyPattern(pattern, parseError, success);
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+}
+
+MessageFormat::MessageFormat(const MessageFormat& that)
+: Format(that),
+ formatAliases(NULL),
+ formatAliasesCapacity(0),
+ subformats(NULL),
+ subformatCount(0),
+ subformatCapacity(0),
+ argTypes(NULL),
+ argTypeCount(0),
+ argTypeCapacity(0),
+ defaultNumberFormat(NULL),
+ defaultDateFormat(NULL)
+{
+ *this = that;
+}
+
+MessageFormat::~MessageFormat()
+{
+ int32_t idx;
+ for (idx = 0; idx < subformatCount; idx++) {
+ delete subformats[idx].format;
+ }
+ uprv_free(subformats);
+ subformats = NULL;
+ subformatCount = subformatCapacity = 0;
+
+ uprv_free(argTypes);
+ argTypes = NULL;
+ argTypeCount = argTypeCapacity = 0;
+
+ uprv_free(formatAliases);
+
+ delete defaultNumberFormat;
+ delete defaultDateFormat;
+}
+
+//--------------------------------------------------------------------
+// Variable-size array management
+
+/**
+ * Allocate subformats[] to at least the given capacity and return
+ * TRUE if successful. If not, leave subformats[] unchanged.
+ *
+ * If subformats is NULL, allocate it. If it is not NULL, enlarge it
+ * if necessary to be at least as large as specified.
+ */
+UBool MessageFormat::allocateSubformats(int32_t capacity) {
+ if (subformats == NULL) {
+ subformats = (Subformat*) uprv_malloc(sizeof(*subformats) * capacity);
+ subformatCapacity = capacity;
+ subformatCount = 0;
+ if (subformats == NULL) {
+ subformatCapacity = 0;
+ return FALSE;
+ }
+ } else if (subformatCapacity < capacity) {
+ if (capacity < 2*subformatCapacity) {
+ capacity = 2*subformatCapacity;
+ }
+ Subformat* a = (Subformat*)
+ uprv_realloc(subformats, sizeof(*subformats) * capacity);
+ if (a == NULL) {
+ return FALSE; // request failed
+ }
+ subformats = a;
+ subformatCapacity = capacity;
+ }
+ return TRUE;
+}
+
+/**
+ * Allocate argTypes[] to at least the given capacity and return
+ * TRUE if successful. If not, leave argTypes[] unchanged.
+ *
+ * If argTypes is NULL, allocate it. If it is not NULL, enlarge it
+ * if necessary to be at least as large as specified.
+ */
+UBool MessageFormat::allocateArgTypes(int32_t capacity) {
+ if (argTypes == NULL) {
+ argTypes = (Formattable::Type*) uprv_malloc(sizeof(*argTypes) * capacity);
+ argTypeCount = 0;
+ argTypeCapacity = capacity;
+ if (argTypes == NULL) {
+ argTypeCapacity = 0;
+ return FALSE;
+ }
+ for (int32_t i=0; i<capacity; ++i) {
+ argTypes[i] = Formattable::kString;
+ }
+ } else if (argTypeCapacity < capacity) {
+ if (capacity < 2*argTypeCapacity) {
+ capacity = 2*argTypeCapacity;
+ }
+ Formattable::Type* a = (Formattable::Type*)
+ uprv_realloc(argTypes, sizeof(*argTypes) * capacity);
+ if (a == NULL) {
+ return FALSE; // request failed
+ }
+ for (int32_t i=argTypeCapacity; i<capacity; ++i) {
+ a[i] = Formattable::kString;
+ }
+ argTypes = a;
+ argTypeCapacity = capacity;
+ }
+ return TRUE;
+}
+
+// -------------------------------------
+// assignment operator
+
+const MessageFormat&
+MessageFormat::operator=(const MessageFormat& that)
+{
+ // Reallocate the arrays BEFORE changing this object
+ if (this != &that &&
+ allocateSubformats(that.subformatCount) &&
+ allocateArgTypes(that.argTypeCount)) {
+
+ // Calls the super class for assignment first.
+ Format::operator=(that);
+
+ fPattern = that.fPattern;
+ setLocale(that.fLocale);
+
+ int32_t j;
+ for (j=0; j<subformatCount; ++j) {
+ delete subformats[j].format;
+ }
+ subformatCount = 0;
+
+ for (j=0; j<that.subformatCount; ++j) {
+ // Subformat::operator= does NOT delete this.format
+ subformats[j] = that.subformats[j];
+ }
+ subformatCount = that.subformatCount;
+
+ for (j=0; j<that.argTypeCount; ++j) {
+ argTypes[j] = that.argTypes[j];
+ }
+ argTypeCount = that.argTypeCount;
+ }
+ return *this;
+}
+
+UBool
+MessageFormat::operator==(const Format& rhs) const
+{
+ if (this == &rhs) return TRUE;
+
+ MessageFormat& that = (MessageFormat&)rhs;
+
+ // Check class ID before checking MessageFormat members
+ if (!Format::operator==(rhs) ||
+ fPattern != that.fPattern ||
+ fLocale != that.fLocale) {
+ return FALSE;
+ }
+
+ int32_t j;
+ for (j=0; j<subformatCount; ++j) {
+ if (subformats[j] != that.subformats[j]) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+// -------------------------------------
+// Creates a copy of this MessageFormat, the caller owns the copy.
+
+Format*
+MessageFormat::clone() const
+{
+ return new MessageFormat(*this);
+}
+
+// -------------------------------------
+// Sets the locale of this MessageFormat object to theLocale.
+
+void
+MessageFormat::setLocale(const Locale& theLocale)
+{
+ if (fLocale != theLocale) {
+ delete defaultNumberFormat;
+ defaultNumberFormat = NULL;
+ delete defaultDateFormat;
+ defaultDateFormat = NULL;
+ }
+ fLocale = theLocale;
+ setLocaleIDs(fLocale.getName(), fLocale.getName());
+}
+
+// -------------------------------------
+// Gets the locale of this MessageFormat object.
+
+const Locale&
+MessageFormat::getLocale() const
+{
+ return fLocale;
+}
+
+
+
+
+void
+MessageFormat::applyPattern(const UnicodeString& newPattern,
+ UErrorCode& status)
+{
+ UParseError parseError;
+ applyPattern(newPattern,parseError,status);
+}
+
+
+// -------------------------------------
+// Applies the new pattern and returns an error if the pattern
+// is not correct.
+void
+MessageFormat::applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& ec)
+{
+ if(U_FAILURE(ec)) {
+ return;
+ }
+ // The pattern is broken up into segments. Each time a subformat
+ // is encountered, 4 segments are recorded. For example, consider
+ // the pattern:
+ // "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}."
+ // The first set of segments is:
+ // segments[0] = "There "
+ // segments[1] = "0"
+ // segments[2] = "choice"
+ // segments[3] = "0.0#are no files|1.0#is one file|1.0<are {0, number} files"
+
+ // During parsing, the plain text is accumulated into segments[0].
+ // Segments 1..3 are used to parse each subpattern. Each time a
+ // subpattern is parsed, it creates a format object that is stored
+ // in the subformats array, together with an offset and argument
+ // number. The offset into the plain text stored in
+ // segments[0].
+
+ // Quotes in segment 0 are handled normally. They are removed.
+ // Quotes may not occur in segments 1 or 2.
+ // Quotes in segment 3 are parsed and _copied_. This makes
+ // subformat patterns work, e.g., {1,number,'#'.##} passes
+ // the pattern "'#'.##" to DecimalFormat.
+
+ UnicodeString segments[4];
+ int32_t part = 0; // segment we are in, 0..3
+ // Record the highest argument number in the pattern. (In the
+ // subpattern {3,number} the argument number is 3.)
+ int32_t formatNumber = 0;
+ UBool inQuote = FALSE;
+ int32_t braceStack = 0;
+ // Clear error struct
+ parseError.offset = -1;
+ parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
+ int32_t patLen = pattern.length();
+ int32_t i;
+
+ for (i=0; i<subformatCount; ++i) {
+ delete subformats[i].format;
+ }
+ subformatCount = 0;
+ argTypeCount = 0;
+
+ for (i=0; i<patLen; ++i) {
+ UChar ch = pattern[i];
+ if (part == 0) {
+ // In segment 0, recognize and remove quotes
+ if (ch == SINGLE_QUOTE) {
+ if (i+1 < patLen && pattern[i+1] == SINGLE_QUOTE) {
+ segments[0] += ch;
+ ++i;
+ } else {
+ inQuote = !inQuote;
+ }
+ } else if (ch == LEFT_CURLY_BRACE && !inQuote) {
+ // The only way we get from segment 0 to 1 is via an
+ // unquoted '{'.
+ part = 1;
+ } else {
+ segments[0] += ch;
+ }
+ } else if (inQuote) {
+ // In segments 1..3, recognize quoted matter, and copy it
+ // into the segment, together with the quotes. This takes
+ // care of '' as well.
+ segments[part] += ch;
+ if (ch == SINGLE_QUOTE) {
+ inQuote = FALSE;
+ }
+ } else {
+ // We have an unquoted character in segment 1..3
+ switch (ch) {
+ case COMMA:
+ // Commas bump us to the next segment, except for segment 3,
+ // which can contain commas. See example above.
+ if (part < 3)
+ part += 1;
+ else
+ segments[3] += ch;
+ break;
+ case LEFT_CURLY_BRACE:
+ // Handle '{' within segment 3. The initial '{'
+ // before segment 1 is handled above.
+ if (part != 3) {
+ ec = U_PATTERN_SYNTAX_ERROR;
+ goto SYNTAX_ERROR;
+ }
+ ++braceStack;
+ segments[part] += ch;
+ break;
+ case RIGHT_CURLY_BRACE:
+ if (braceStack == 0) {
+ makeFormat(formatNumber, segments, parseError,ec);
+ if (U_FAILURE(ec)){
+ goto SYNTAX_ERROR;
+ }
+ formatNumber++;
+ segments[1].remove();
+ segments[2].remove();
+ segments[3].remove();
+ part = 0;
+ } else {
+ --braceStack;
+ segments[part] += ch;
+ }
+ break;
+ case SINGLE_QUOTE:
+ inQuote = TRUE;
+ // fall through (copy quote chars in segments 1..3)
+ default:
+ segments[part] += ch;
+ break;
+ }
+ }
+ }
+ if (braceStack != 0 || part != 0) {
+ // Unmatched braces in the pattern
+ ec = U_UNMATCHED_BRACES;
+ goto SYNTAX_ERROR;
+ }
+ fPattern = segments[0];
+ return;
+
+ SYNTAX_ERROR:
+ syntaxError(pattern, i, parseError);
+ for (i=0; i<subformatCount; ++i) {
+ delete subformats[i].format;
+ }
+ argTypeCount = subformatCount = 0;
+}
+// -------------------------------------
+// Converts this MessageFormat instance to a pattern.
+
+UnicodeString&
+MessageFormat::toPattern(UnicodeString& appendTo) const {
+ // later, make this more extensible
+ int32_t lastOffset = 0;
+ int32_t i;
+ for (i=0; i<subformatCount; ++i) {
+ copyAndFixQuotes(fPattern, lastOffset, subformats[i].offset, appendTo);
+ lastOffset = subformats[i].offset;
+ appendTo += LEFT_CURLY_BRACE;
+ itos(subformats[i].arg, appendTo);
+ Format* fmt = subformats[i].format;
+ if (fmt == NULL) {
+ // do nothing, string format
+ }
+ else if (fmt->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+
+ UErrorCode ec = U_ZERO_ERROR;
+ NumberFormat& formatAlias = *(NumberFormat*)fmt;
+ NumberFormat *defaultTemplate = NumberFormat::createInstance(fLocale, ec);
+ NumberFormat *currencyTemplate = NumberFormat::createCurrencyInstance(fLocale, ec);
+ NumberFormat *percentTemplate = NumberFormat::createPercentInstance(fLocale, ec);
+ NumberFormat *integerTemplate = createIntegerFormat(fLocale, ec);
+
+ appendTo += COMMA;
+ appendTo += ID_NUMBER;
+ if (formatAlias != *defaultTemplate) {
+ appendTo += COMMA;
+ if (formatAlias == *currencyTemplate) {
+ appendTo += ID_CURRENCY;
+ }
+ else if (formatAlias == *percentTemplate) {
+ appendTo += ID_PERCENT;
+ }
+ else if (formatAlias == *integerTemplate) {
+ appendTo += ID_INTEGER;
+ }
+ else {
+ UnicodeString buffer;
+ appendTo += ((DecimalFormat*)fmt)->toPattern(buffer);
+ }
+ }
+
+ delete defaultTemplate;
+ delete currencyTemplate;
+ delete percentTemplate;
+ delete integerTemplate;
+ }
+ else if (fmt->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
+ DateFormat& formatAlias = *(DateFormat*)fmt;
+ DateFormat *defaultDateTemplate = DateFormat::createDateInstance(DateFormat::kDefault, fLocale);
+ DateFormat *shortDateTemplate = DateFormat::createDateInstance(DateFormat::kShort, fLocale);
+ DateFormat *longDateTemplate = DateFormat::createDateInstance(DateFormat::kLong, fLocale);
+ DateFormat *fullDateTemplate = DateFormat::createDateInstance(DateFormat::kFull, fLocale);
+ DateFormat *defaultTimeTemplate = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale);
+ DateFormat *shortTimeTemplate = DateFormat::createTimeInstance(DateFormat::kShort, fLocale);
+ DateFormat *longTimeTemplate = DateFormat::createTimeInstance(DateFormat::kLong, fLocale);
+ DateFormat *fullTimeTemplate = DateFormat::createTimeInstance(DateFormat::kFull, fLocale);
+
+
+ appendTo += COMMA;
+ if (formatAlias == *defaultDateTemplate) {
+ appendTo += ID_DATE;
+ }
+ else if (formatAlias == *shortDateTemplate) {
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += ID_SHORT;
+ }
+ else if (formatAlias == *defaultDateTemplate) {
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += ID_MEDIUM;
+ }
+ else if (formatAlias == *longDateTemplate) {
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += ID_LONG;
+ }
+ else if (formatAlias == *fullDateTemplate) {
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += ID_FULL;
+ }
+ else if (formatAlias == *defaultTimeTemplate) {
+ appendTo += ID_TIME;
+ }
+ else if (formatAlias == *shortTimeTemplate) {
+ appendTo += ID_TIME;
+ appendTo += COMMA;
+ appendTo += ID_SHORT;
+ }
+ else if (formatAlias == *defaultTimeTemplate) {
+ appendTo += ID_TIME;
+ appendTo += COMMA;
+ appendTo += ID_MEDIUM;
+ }
+ else if (formatAlias == *longTimeTemplate) {
+ appendTo += ID_TIME;
+ appendTo += COMMA;
+ appendTo += ID_LONG;
+ }
+ else if (formatAlias == *fullTimeTemplate) {
+ appendTo += ID_TIME;
+ appendTo += COMMA;
+ appendTo += ID_FULL;
+ }
+ else {
+ UnicodeString buffer;
+ appendTo += ID_DATE;
+ appendTo += COMMA;
+ appendTo += ((SimpleDateFormat*)fmt)->toPattern(buffer);
+ }
+
+ delete defaultDateTemplate;
+ delete shortDateTemplate;
+ delete longDateTemplate;
+ delete fullDateTemplate;
+ delete defaultTimeTemplate;
+ delete shortTimeTemplate;
+ delete longTimeTemplate;
+ delete fullTimeTemplate;
+ // {sfb} there should be a more efficient way to do this!
+ }
+ else if (fmt->getDynamicClassID() == ChoiceFormat::getStaticClassID()) {
+ UnicodeString buffer;
+ appendTo += COMMA;
+ appendTo += ID_CHOICE;
+ appendTo += COMMA;
+ appendTo += ((ChoiceFormat*)fmt)->toPattern(buffer);
+ }
+ else {
+ //appendTo += ", unknown";
+ }
+ appendTo += RIGHT_CURLY_BRACE;
+ }
+ copyAndFixQuotes(fPattern, lastOffset, fPattern.length(), appendTo);
+ return appendTo;
+}
+
+// -------------------------------------
+// Adopts the new formats array and updates the array count.
+// This MessageFormat instance owns the new formats.
+
+void
+MessageFormat::adoptFormats(Format** newFormats,
+ int32_t count) {
+ if (newFormats == NULL || count < 0) {
+ return;
+ }
+
+ int32_t i;
+ if (allocateSubformats(count)) {
+ for (i=0; i<subformatCount; ++i) {
+ delete subformats[i].format;
+ }
+ for (i=0; i<count; ++i) {
+ subformats[i].format = newFormats[i];
+ }
+ subformatCount = count;
+ } else {
+ // An adopt method must always take ownership. Delete
+ // the incoming format objects and return unchanged.
+ for (i=0; i<count; ++i) {
+ delete newFormats[i];
+ }
+ }
+
+ // TODO: What about the .offset and .arg fields?
+}
+
+// -------------------------------------
+// Sets the new formats array and updates the array count.
+// This MessageFormat instance maks a copy of the new formats.
+
+void
+MessageFormat::setFormats(const Format** newFormats,
+ int32_t count) {
+ if (newFormats == NULL || count < 0) {
+ return;
+ }
+
+ if (allocateSubformats(count)) {
+ int32_t i;
+ for (i=0; i<subformatCount; ++i) {
+ delete subformats[i].format;
+ }
+ subformatCount = 0;
+
+ for (i=0; i<count; ++i) {
+ subformats[i].format = newFormats[i] ? newFormats[i]->clone() : NULL;
+ }
+ subformatCount = count;
+ }
+
+ // TODO: What about the .offset and .arg fields?
+}
+
+// -------------------------------------
+// Adopt a single format.
+// Do nothing is the format number is not less than the array count.
+
+void
+MessageFormat::adoptFormat(int32_t n, Format *newFormat) {
+ if (n < 0 || n >= subformatCount) {
+ delete newFormat;
+ } else {
+ delete subformats[n].format;
+ subformats[n].format = newFormat;
+ }
+}
+
+// -------------------------------------
+// Set a single format.
+// Do nothing is the variable is not less than the array count.
+
+void
+MessageFormat::setFormat(int32_t n, const Format& newFormat) {
+ if (n >= 0 && n < subformatCount) {
+ delete subformats[n].format;
+ if (&newFormat == NULL) {
+ // This should never happen -- but we'll be nice if it does
+ subformats[n].format = NULL;
+ } else {
+ subformats[n].format = newFormat.clone();
+ }
+ }
+}
+
+// -------------------------------------
+// Gets the format array.
+
+const Format**
+MessageFormat::getFormats(int32_t& cnt) const
+{
+ // This old API returns an array (which we hold) of Format*
+ // pointers. The array is valid up to the next call to any
+ // method on this object. We construct and resize an array
+ // on demand that contains aliases to the subformats[i].format
+ // pointers.
+ MessageFormat* t = (MessageFormat*) this;
+ cnt = 0;
+ if (formatAliases == NULL) {
+ t->formatAliasesCapacity = (subformatCount<10) ? 10 : subformatCount;
+ Format** a = (Format**)
+ uprv_malloc(sizeof(Format*) * formatAliasesCapacity);
+ if (a == NULL) {
+ return NULL;
+ }
+ t->formatAliases = a;
+ } else if (subformatCount > formatAliasesCapacity) {
+ Format** a = (Format**)
+ uprv_realloc(formatAliases, sizeof(Format*) * subformatCount);
+ if (a == NULL) {
+ return NULL;
+ }
+ t->formatAliases = a;
+ t->formatAliasesCapacity = subformatCount;
+ }
+ for (int32_t i=0; i<subformatCount; ++i) {
+ t->formatAliases[i] = subformats[i].format;
+ }
+ cnt = subformatCount;
+ return (const Format**)formatAliases;
+}
+
+// -------------------------------------
+// Formats the source Formattable array and copy into the result buffer.
+// Ignore the FieldPosition result for error checking.
+
+UnicodeString&
+MessageFormat::format(const Formattable* source,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& ignore,
+ UErrorCode& success) const
+{
+ if (U_FAILURE(success))
+ return appendTo;
+
+ return format(source, cnt, appendTo, ignore, 0, success);
+}
+
+// -------------------------------------
+// Internally creates a MessageFormat instance based on the
+// pattern and formats the arguments Formattable array and
+// copy into the appendTo buffer.
+
+UnicodeString&
+MessageFormat::format( const UnicodeString& pattern,
+ const Formattable* arguments,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ UErrorCode& success)
+{
+ MessageFormat temp(pattern, success);
+ FieldPosition ignore(0);
+ temp.format(arguments, cnt, appendTo, ignore, success);
+ return appendTo;
+}
+
+// -------------------------------------
+// Formats the source Formattable object and copy into the
+// appendTo buffer. The Formattable object must be an array
+// of Formattable instances, returns error otherwise.
+
+UnicodeString&
+MessageFormat::format(const Formattable& source,
+ UnicodeString& appendTo,
+ FieldPosition& ignore,
+ UErrorCode& success) const
+{
+ int32_t cnt;
+
+ if (U_FAILURE(success))
+ return appendTo;
+ if (source.getType() != Formattable::kArray) {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+ const Formattable* tmpPtr = source.getArray(cnt);
+
+ return format(tmpPtr, cnt, appendTo, ignore, 0, success);
+}
+
+// -------------------------------------
+// Formats the arguments Formattable array and copy into the appendTo buffer.
+// Ignore the FieldPosition result for error checking.
+
+UnicodeString&
+MessageFormat::format(const Formattable* arguments,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& status,
+ int32_t recursionProtection,
+ UErrorCode& success) const
+{
+ // Allow NULL array only if cnt == 0
+ if (cnt < 0 || (cnt && arguments == NULL)) {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+
+ int32_t lastOffset = 0;
+ for (int32_t i=0; i<subformatCount; ++i) {
+ // Append the prefix of current format element.
+ appendTo.append(fPattern, lastOffset, subformats[i].offset - lastOffset);
+ lastOffset = subformats[i].offset;
+ int32_t argumentNumber = subformats[i].arg;
+ // Checks the scope of the argument number.
+ if (argumentNumber >= cnt) {
+ appendTo += LEFT_CURLY_BRACE;
+ itos(argumentNumber, appendTo);
+ appendTo += RIGHT_CURLY_BRACE;
+ continue;
+ }
+
+ const Formattable *obj = arguments + argumentNumber;
+ Formattable::Type type = obj->getType();
+
+ // Recursively calling the format process only if the current
+ // format argument refers to a ChoiceFormat object.
+ Format* fmt = subformats[i].format;
+ if (fmt != NULL) {
+ UnicodeString arg;
+ fmt->format(*obj, arg, success);
+
+ // Needs to reprocess the ChoiceFormat option by using the
+ // MessageFormat pattern application.
+ if (fmt->getDynamicClassID() == ChoiceFormat::getStaticClassID() &&
+ arg.indexOf(LEFT_CURLY_BRACE) >= 0) {
+ MessageFormat temp(arg, fLocale, success);
+ // TODO: Implement recursion protection
+ temp.format(arguments, cnt, appendTo, status, recursionProtection, success);
+ if (U_FAILURE(success)) {
+ return appendTo;
+ }
+ }
+ else {
+ appendTo += arg;
+ }
+ }
+ // If the obj data type is a number, use a NumberFormat instance.
+ else if ((type == Formattable::kDouble) ||
+ (type == Formattable::kLong) ||
+ (type == Formattable::kInt64)) {
+
+ const NumberFormat* nf = getDefaultNumberFormat(success);
+ if (nf == NULL) {
+ return appendTo;
+ }
+ if (type == Formattable::kDouble) {
+ nf->format(obj->getDouble(), appendTo);
+ } else if (type == Formattable::kLong) {
+ nf->format(obj->getLong(), appendTo);
+ } else {
+ nf->format(obj->getInt64(), appendTo);
+ }
+ }
+ // If the obj data type is a Date instance, use a DateFormat instance.
+ else if (type == Formattable::kDate) {
+ const DateFormat* df = getDefaultDateFormat(success);
+ if (df == NULL) {
+ return appendTo;
+ }
+ df->format(obj->getDate(), appendTo);
+ }
+ else if (type == Formattable::kString) {
+ appendTo += obj->getString();
+ }
+ else {
+ success = U_ILLEGAL_ARGUMENT_ERROR;
+ return appendTo;
+ }
+ }
+ // Appends the rest of the pattern characters after the real last offset.
+ appendTo.append(fPattern, lastOffset, 0x7fffffff);
+ return appendTo;
+}
+
+
+// -------------------------------------
+// Parses the source pattern and returns the Formattable objects array,
+// the array count and the ending parse position. The caller of this method
+// owns the array.
+
+Formattable*
+MessageFormat::parse(const UnicodeString& source,
+ ParsePosition& pos,
+ int32_t& count) const
+{
+ // Allocate at least one element. Allocating an array of length
+ // zero causes problems on some platforms (e.g. Win32).
+ Formattable *resultArray = new Formattable[argTypeCount ? argTypeCount : 1];
+ int32_t patternOffset = 0;
+ int32_t sourceOffset = pos.getIndex();
+ ParsePosition tempPos(0);
+ count = 0; // {sfb} reset to zero
+ int32_t len;
+ for (int32_t i = 0; i < subformatCount; ++i) {
+ // match up to format
+ len = subformats[i].offset - patternOffset;
+ if (len == 0 ||
+ fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
+ sourceOffset += len;
+ patternOffset += len;
+ }
+ else {
+ goto PARSE_ERROR;
+ }
+
+ // now use format
+ Format* fmt = subformats[i].format;
+ int32_t arg = subformats[i].arg;
+ if (fmt == NULL) { // string format
+ // if at end, use longest possible match
+ // otherwise uses first match to intervening string
+ // does NOT recursively try all possibilities
+ int32_t tempLength = (i+1<subformatCount) ?
+ subformats[i+1].offset : fPattern.length();
+
+ int32_t next;
+ if (patternOffset >= tempLength) {
+ next = source.length();
+ }
+ else {
+ UnicodeString buffer;
+ fPattern.extract(patternOffset,tempLength - patternOffset, buffer);
+ next = source.indexOf(buffer, sourceOffset);
+ }
+
+ if (next < 0) {
+ goto PARSE_ERROR;
+ }
+ else {
+ UnicodeString buffer;
+ source.extract(sourceOffset,next - sourceOffset, buffer);
+ UnicodeString strValue = buffer;
+ UnicodeString temp(LEFT_CURLY_BRACE);
+ // {sfb} check this later
+ itos(arg, temp);
+ temp += RIGHT_CURLY_BRACE;
+ if (strValue != temp) {
+ source.extract(sourceOffset,next - sourceOffset, buffer);
+ resultArray[arg].setString(buffer);
+ // {sfb} not sure about this
+ if ((arg + 1) > count) {
+ count = arg + 1;
+ }
+ }
+ sourceOffset = next;
+ }
+ }
+ else {
+ tempPos.setIndex(sourceOffset);
+ fmt->parseObject(source, resultArray[arg], tempPos);
+ if (tempPos.getIndex() == sourceOffset) {
+ goto PARSE_ERROR;
+ }
+
+ if ((arg + 1) > count) {
+ count = arg + 1;
+ }
+ sourceOffset = tempPos.getIndex(); // update
+ }
+ }
+ len = fPattern.length() - patternOffset;
+ if (len == 0 ||
+ fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) {
+ pos.setIndex(sourceOffset + len);
+ return resultArray;
+ }
+ // else fall through...
+
+ PARSE_ERROR:
+ pos.setErrorIndex(sourceOffset);
+ delete [] resultArray;
+ count = 0;
+ return NULL; // leave index as is to signal error
+}
+
+// -------------------------------------
+// Parses the source string and returns the array of
+// Formattable objects and the array count. The caller
+// owns the returned array.
+
+Formattable*
+MessageFormat::parse(const UnicodeString& source,
+ int32_t& cnt,
+ UErrorCode& success) const
+{
+ ParsePosition status(0);
+ // Calls the actual implementation method and starts
+ // from zero offset of the source text.
+ Formattable* result = parse(source, status, cnt);
+ if (status.getIndex() == 0) {
+ success = U_MESSAGE_PARSE_ERROR;
+ delete[] result;
+ return NULL;
+ }
+ return result;
+}
+
+// -------------------------------------
+// Parses the source text and copy into the result buffer.
+
+void
+MessageFormat::parseObject( const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& status) const
+{
+ int32_t cnt = 0;
+ Formattable* tmpResult = parse(source, status, cnt);
+ if (tmpResult != NULL)
+ result.adoptArray(tmpResult, cnt);
+}
+
+UnicodeString
+MessageFormat::autoQuoteApostrophe(const UnicodeString& pattern, UErrorCode& status) {
+ UnicodeString result;
+ if (U_SUCCESS(status)) {
+ int32_t plen = pattern.length();
+ const UChar* pat = pattern.getBuffer();
+ int32_t blen = plen * 2 + 1; // space for null termination, convenience
+ UChar* buf = result.getBuffer(blen);
+ if (buf == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ int32_t len = umsg_autoQuoteApostrophe(pat, plen, buf, blen, &status);
+ result.releaseBuffer(U_SUCCESS(status) ? len : 0);
+ }
+ }
+ if (U_FAILURE(status)) {
+ result.setToBogus();
+ }
+ return result;
+}
+
+// -------------------------------------
+
+static Format* makeRBNF(URBNFRuleSetTag tag, const Locale& locale, const UnicodeString& defaultRuleSet, UErrorCode& ec) {
+ RuleBasedNumberFormat* fmt = new RuleBasedNumberFormat(tag, locale, ec);
+ if (U_SUCCESS(ec) && defaultRuleSet.length() > 0) {
+ fmt->setDefaultRuleSet(defaultRuleSet, ec);
+ if (U_FAILURE(ec)) { // ignore unrecognized default rule set
+ ec = U_ZERO_ERROR;
+ }
+ }
+ return fmt;
+}
+
+/**
+ * Reads the segments[] array (see applyPattern()) and parses the
+ * segments[1..3] into a Format* object. Stores the format object in
+ * the subformats[] array. Updates the argTypes[] array type
+ * information for the corresponding argument.
+ *
+ * @param formatNumber index into subformats[] for this format
+ * @param segments array of strings with the parsed pattern segments
+ * @param parseError parse error data (output param)
+ * @param ec error code
+ */
+void
+MessageFormat::makeFormat(int32_t formatNumber,
+ UnicodeString* segments,
+ UParseError& parseError,
+ UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return;
+ }
+
+ // Parse the argument number
+ int32_t argumentNumber = stou(segments[1]); // always unlocalized!
+ if (argumentNumber < 0) {
+ ec = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+
+ // Parse the format, recording the argument type and creating a
+ // new Format object (except for string arguments).
+ Formattable::Type argType;
+ Format *fmt = NULL;
+ int32_t typeID, styleID;
+ DateFormat::EStyle style;
+
+ switch (typeID = findKeyword(segments[2], TYPE_IDS)) {
+
+ case 0: // string
+ argType = Formattable::kString;
+ break;
+
+ case 1: // number
+ argType = Formattable::kDouble;
+
+ switch (findKeyword(segments[3], NUMBER_STYLE_IDS)) {
+ case 0: // default
+ fmt = NumberFormat::createInstance(fLocale, ec);
+ break;
+ case 1: // currency
+ fmt = NumberFormat::createCurrencyInstance(fLocale, ec);
+ break;
+ case 2: // percent
+ fmt = NumberFormat::createPercentInstance(fLocale, ec);
+ break;
+ case 3: // integer
+ argType = Formattable::kLong;
+ fmt = createIntegerFormat(fLocale, ec);
+ break;
+ default: // pattern
+ fmt = NumberFormat::createInstance(fLocale, ec);
+ if (fmt &&
+ fmt->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ ((DecimalFormat*)fmt)->applyPattern(segments[3],parseError,ec);
+ }
+ break;
+ }
+ break;
+
+ case 2: // date
+ case 3: // time
+ argType = Formattable::kDate;
+ styleID = findKeyword(segments[3], DATE_STYLE_IDS);
+ style = (styleID >= 0) ? DATE_STYLES[styleID] : DateFormat::kDefault;
+
+ if (typeID == 2) {
+ fmt = DateFormat::createDateInstance(style, fLocale);
+ } else {
+ fmt = DateFormat::createTimeInstance(style, fLocale);
+ }
+
+ if (styleID < 0 &&
+ fmt != NULL &&
+ fmt->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
+ ((SimpleDateFormat*)fmt)->applyPattern(segments[3]);
+ }
+ break;
+
+ case 4: // choice
+ argType = Formattable::kDouble;
+
+ fmt = new ChoiceFormat(segments[3], parseError, ec);
+ break;
+
+ case 5: // spellout
+ argType = Formattable::kDouble;
+ fmt = makeRBNF(URBNF_SPELLOUT, fLocale, segments[3], ec);
+ break;
+ case 6: // ordinal
+ argType = Formattable::kDouble;
+ fmt = makeRBNF(URBNF_ORDINAL, fLocale, segments[3], ec);
+ break;
+ case 7: // duration
+ argType = Formattable::kDouble;
+ fmt = makeRBNF(URBNF_DURATION, fLocale, segments[3], ec);
+ break;
+ default:
+ argType = Formattable::kString;
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ break;
+ }
+
+ if (fmt==NULL && argType!=Formattable::kString && U_SUCCESS(ec)) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ if (!allocateSubformats(formatNumber+1) ||
+ !allocateArgTypes(argumentNumber+1)) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ if (U_FAILURE(ec)) {
+ delete fmt;
+ return;
+ }
+
+ // Parse succeeded; record results in our arrays
+ subformats[formatNumber].format = fmt;
+ subformats[formatNumber].offset = segments[0].length();
+ subformats[formatNumber].arg = argumentNumber;
+ subformatCount = formatNumber+1;
+
+ // Careful here: argumentNumber may in general arrive out of
+ // sequence, e.g., "There was {2} on {0,date} (see {1,number})."
+ argTypes[argumentNumber] = argType;
+ if (argumentNumber+1 > argTypeCount) {
+ argTypeCount = argumentNumber+1;
+ }
+}
+
+// -------------------------------------
+// Finds the string, s, in the string array, list.
+int32_t MessageFormat::findKeyword(const UnicodeString& s,
+ const UChar * const *list)
+{
+ if (s.length() == 0)
+ return 0; // default
+
+ UnicodeString buffer = s;
+ // Trims the space characters and turns all characters
+ // in s to lower case.
+ buffer.trim().toLower("");
+ for (int32_t i = 0; list[i]; ++i) {
+ if (!buffer.compare(list[i], u_strlen(list[i]))) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// -------------------------------------
+// Checks the range of the source text to quote the special
+// characters, { and ' and copy to target buffer.
+
+void
+MessageFormat::copyAndFixQuotes(const UnicodeString& source,
+ int32_t start,
+ int32_t end,
+ UnicodeString& appendTo)
+{
+ UBool gotLB = FALSE;
+
+ for (int32_t i = start; i < end; ++i) {
+ UChar ch = source[i];
+ if (ch == LEFT_CURLY_BRACE) {
+ appendTo += SINGLE_QUOTE;
+ appendTo += LEFT_CURLY_BRACE;
+ appendTo += SINGLE_QUOTE;
+ gotLB = TRUE;
+ }
+ else if (ch == RIGHT_CURLY_BRACE) {
+ if(gotLB) {
+ appendTo += RIGHT_CURLY_BRACE;
+ gotLB = FALSE;
+ }
+ else {
+ // orig code.
+ appendTo += SINGLE_QUOTE;
+ appendTo += RIGHT_CURLY_BRACE;
+ appendTo += SINGLE_QUOTE;
+ }
+ }
+ else if (ch == SINGLE_QUOTE) {
+ appendTo += SINGLE_QUOTE;
+ appendTo += SINGLE_QUOTE;
+ }
+ else {
+ appendTo += ch;
+ }
+ }
+}
+
+/**
+ * Convenience method that ought to be in NumberFormat
+ */
+NumberFormat*
+MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const {
+ NumberFormat *temp = NumberFormat::createInstance(locale, status);
+ if (temp != NULL && temp->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ DecimalFormat *temp2 = (DecimalFormat*) temp;
+ temp2->setMaximumFractionDigits(0);
+ temp2->setDecimalSeparatorAlwaysShown(FALSE);
+ temp2->setParseIntegerOnly(TRUE);
+ }
+
+ return temp;
+}
+
+/**
+ * Return the default number format. Used to format a numeric
+ * argument when subformats[i].format is NULL. Returns NULL
+ * on failure.
+ *
+ * Semantically const but may modify *this.
+ */
+const NumberFormat* MessageFormat::getDefaultNumberFormat(UErrorCode& ec) const {
+ if (defaultNumberFormat == NULL) {
+ MessageFormat* t = (MessageFormat*) this;
+ t->defaultNumberFormat = NumberFormat::createInstance(fLocale, ec);
+ if (U_FAILURE(ec)) {
+ delete t->defaultNumberFormat;
+ t->defaultNumberFormat = NULL;
+ } else if (t->defaultNumberFormat == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ return defaultNumberFormat;
+}
+
+/**
+ * Return the default date format. Used to format a date
+ * argument when subformats[i].format is NULL. Returns NULL
+ * on failure.
+ *
+ * Semantically const but may modify *this.
+ */
+const DateFormat* MessageFormat::getDefaultDateFormat(UErrorCode& ec) const {
+ if (defaultDateFormat == NULL) {
+ MessageFormat* t = (MessageFormat*) this;
+ t->defaultDateFormat = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale);
+ if (t->defaultDateFormat == NULL) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ return defaultDateFormat;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/name2uni.cpp b/Build/source/libs/icu/icu-xetex/i18n/name2uni.cpp
new file mode 100644
index 00000000000..6b9f2a3fb3c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/name2uni.cpp
@@ -0,0 +1,253 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 06/07/01 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifilt.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "name2uni.h"
+#include "cmemory.h"
+#include "uprops.h"
+#include "uinvchar.h"
+#include "util.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NameUnicodeTransliterator)
+
+static const UChar OPEN[] = {92,78,126,123,126,0}; // "\N~{~"
+static const UChar OPEN_DELIM = 92; // '\\' first char of OPEN
+static const UChar CLOSE_DELIM = 125; // '}'
+static const UChar SPACE = 32; // ' '
+
+U_CDECL_BEGIN
+
+// USetAdder implementation
+// Does not use uset.h to reduce code dependencies
+static void U_CALLCONV
+_set_add(USet *set, UChar32 c) {
+ uset_add(set, c);
+}
+
+// These functions aren't used.
+/*static void U_CALLCONV
+_set_addRange(USet *set, UChar32 start, UChar32 end) {
+ ((UnicodeSet *)set)->add(start, end);
+}
+
+static void U_CALLCONV
+_set_addString(USet *set, const UChar *str, int32_t length) {
+ ((UnicodeSet *)set)->add(UnicodeString((UBool)(length<0), str, length));
+}*/
+
+U_CDECL_END
+
+/**
+ * Constructs a transliterator with the default delimiters '{' and
+ * '}'.
+ */
+NameUnicodeTransliterator::NameUnicodeTransliterator(UnicodeFilter* adoptedFilter) :
+ Transliterator(UNICODE_STRING("Name-Any", 8), adoptedFilter) {
+
+ UnicodeSet *legalPtr = &legal;
+ // Get the legal character set
+ USetAdder sa = {
+ (USet *)legalPtr, // USet* == UnicodeSet*
+ _set_add,
+ NULL, // Don't need _set_addRange
+ NULL, // Don't need _set_addString
+ NULL // Don't need remove()
+ };
+ uprv_getCharNameCharacters(&sa);
+}
+
+/**
+ * Destructor.
+ */
+NameUnicodeTransliterator::~NameUnicodeTransliterator() {}
+
+/**
+ * Copy constructor.
+ */
+NameUnicodeTransliterator::NameUnicodeTransliterator(const NameUnicodeTransliterator& o) :
+ Transliterator(o), legal(o.legal) {}
+
+/**
+ * Assignment operator.
+ */
+/*NameUnicodeTransliterator& NameUnicodeTransliterator::operator=(
+ const NameUnicodeTransliterator& o) {
+ Transliterator::operator=(o);
+ // not necessary: the legal sets should all be the same -- legal=o.legal;
+ return *this;
+}*/
+
+/**
+ * Transliterator API.
+ */
+Transliterator* NameUnicodeTransliterator::clone(void) const {
+ return new NameUnicodeTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void NameUnicodeTransliterator::handleTransliterate(Replaceable& text, UTransPosition& offsets,
+ UBool isIncremental) const {
+ // The failure mode, here and below, is to behave like Any-Null,
+ // if either there is no name data (max len == 0) or there is no
+ // memory (malloc() => NULL).
+
+ int32_t maxLen = uprv_getMaxCharNameLength();
+ if (maxLen == 0) {
+ offsets.start = offsets.limit;
+ return;
+ }
+
+ // Accomodate the longest possible name
+ ++maxLen; // allow for temporary trailing space
+ char* cbuf = (char*) uprv_malloc(maxLen);
+ if (cbuf == NULL) {
+ offsets.start = offsets.limit;
+ return;
+ }
+
+ UnicodeString openPat(TRUE, OPEN, -1);
+ UnicodeString str, name;
+
+ int32_t cursor = offsets.start;
+ int32_t limit = offsets.limit;
+
+ // Modes:
+ // 0 - looking for open delimiter
+ // 1 - after open delimiter
+ int32_t mode = 0;
+ int32_t openPos = -1; // open delim candidate pos
+
+ UChar32 c;
+ while (cursor < limit) {
+ c = text.char32At(cursor);
+
+ switch (mode) {
+ case 0: // looking for open delimiter
+ if (c == OPEN_DELIM) { // quick check first
+ openPos = cursor;
+ int32_t i =
+ ICU_Utility::parsePattern(openPat, text, cursor, limit);
+ if (i >= 0 && i < limit) {
+ mode = 1;
+ name.truncate(0);
+ cursor = i;
+ continue; // *** reprocess char32At(cursor)
+ }
+ }
+ break;
+
+ case 1: // after open delimiter
+ // Look for legal chars. If \s+ is found, convert it
+ // to a single space. If closeDelimiter is found, exit
+ // the loop. If any other character is found, exit the
+ // loop. If the limit is reached, exit the loop.
+
+ // Convert \s+ => SPACE. This assumes there are no
+ // runs of >1 space characters in names.
+ if (uprv_isRuleWhiteSpace(c)) {
+ // Ignore leading whitespace
+ if (name.length() > 0 &&
+ name.charAt(name.length()-1) != SPACE) {
+ name.append(SPACE);
+ // If we are too long then abort. maxLen includes
+ // temporary trailing space, so use '>'.
+ if (name.length() > maxLen) {
+ mode = 0;
+ }
+ }
+ break;
+ }
+
+ if (c == CLOSE_DELIM) {
+ int32_t len = name.length();
+
+ // Delete trailing space, if any
+ if (len > 0 &&
+ name.charAt(len-1) == SPACE) {
+ --len;
+ }
+
+ if (uprv_isInvariantUString(name.getBuffer(), len)) {
+ name.extract(0, len, cbuf, maxLen, US_INV);
+
+ UErrorCode status = U_ZERO_ERROR;
+ c = u_charFromName(U_EXTENDED_CHAR_NAME, cbuf, &status);
+ if (U_SUCCESS(status)) {
+ // Lookup succeeded
+
+ // assert(UTF_CHAR_LENGTH(CLOSE_DELIM) == 1);
+ cursor++; // advance over CLOSE_DELIM
+
+ str.truncate(0);
+ str.append(c);
+ text.handleReplaceBetween(openPos, cursor, str);
+
+ // Adjust indices for the change in the length of
+ // the string. Do not assume that str.length() ==
+ // 1, in case of surrogates.
+ int32_t delta = cursor - openPos - str.length();
+ cursor -= delta;
+ limit -= delta;
+ // assert(cursor == openPos + str.length());
+ }
+ }
+ // If the lookup failed, we leave things as-is and
+ // still switch to mode 0 and continue.
+ mode = 0;
+ openPos = -1; // close off candidate
+ continue; // *** reprocess char32At(cursor)
+ }
+
+ // Check if c is a legal char. We assume here that
+ // legal.contains(OPEN_DELIM) is FALSE, so when we abort a
+ // name, we don't have to go back to openPos+1.
+ if (legal.contains(c)) {
+ name.append(c);
+ // If we go past the longest possible name then abort.
+ // maxLen includes temporary trailing space, so use '>='.
+ if (name.length() >= maxLen) {
+ mode = 0;
+ }
+ }
+
+ // Invalid character
+ else {
+ --cursor; // Backup and reprocess this character
+ mode = 0;
+ }
+
+ break;
+ }
+
+ cursor += UTF_CHAR_LENGTH(c);
+ }
+
+ offsets.contextLimit += limit - offsets.limit;
+ offsets.limit = limit;
+ // In incremental mode, only advance the cursor up to the last
+ // open delimiter candidate.
+ offsets.start = (isIncremental && openPos >= 0) ? openPos : cursor;
+
+ uprv_free(cbuf);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/name2uni.h b/Build/source/libs/icu/icu-xetex/i18n/name2uni.h
new file mode 100644
index 00000000000..1324ec3e8d2
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/name2uni.h
@@ -0,0 +1,91 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 06/07/01 aliu Creation.
+**********************************************************************
+*/
+#ifndef NAME2UNI_H
+#define NAME2UNI_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that performs name to character mapping.
+ * It recognizes the Perl syntax \N{name}.
+ * @author Alan Liu
+ */
+class NameUnicodeTransliterator : public Transliterator {
+public:
+
+ /**
+ * Constructs a transliterator.
+ * @param adoptedFilter the filter for this transliterator.
+ */
+ NameUnicodeTransliterator(UnicodeFilter* adoptedFilter = 0);
+
+ /**
+ * Destructor.
+ */
+ virtual ~NameUnicodeTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ NameUnicodeTransliterator(const NameUnicodeTransliterator&);
+
+ /**
+ * Transliterator API.
+ * @return A copy of the object.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+ protected:
+
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param offset the start and limit of the text, the position
+ * of the cursor, and the start and limit of transliteration.
+ * @param incremental if true, assume more text may be coming after
+ * pos.contextLimit. Otherwise, assume the text is complete.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& offset,
+ UBool isIncremental) const;
+
+ /**
+ * Set of characters which occur in Unicode character names.
+ */
+ UnicodeSet legal;
+private:
+ /**
+ * Assignment operator.
+ */
+ NameUnicodeTransliterator& operator=(const NameUnicodeTransliterator&);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nfrlist.h b/Build/source/libs/icu/icu-xetex/i18n/nfrlist.h
new file mode 100644
index 00000000000..1a334085802
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nfrlist.h
@@ -0,0 +1,89 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: nfrlist.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 10/11/2001 Doug Ported from ICU4J
+*/
+
+#ifndef NFRLIST_H
+#define NFRLIST_H
+
+#include "unicode/rbnf.h"
+
+#if U_HAVE_RBNF
+
+#include "unicode/uobject.h"
+#include "nfrule.h"
+
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+// unsafe class for internal use only. assume memory allocations succeed, indexes are valid.
+// should be a template, but we can't use them
+
+class NFRuleList : public UMemory {
+protected:
+ NFRule** fStuff;
+ uint32_t fCount;
+ uint32_t fCapacity;
+public:
+ NFRuleList(uint32_t capacity = 10)
+ : fStuff(capacity ? (NFRule**)uprv_malloc(capacity * sizeof(NFRule*)) : NULL)
+ , fCount(0)
+ , fCapacity(capacity) {};
+ ~NFRuleList() {
+ if (fStuff) {
+ for(uint32_t i = 0; i < fCount; ++i) {
+ delete fStuff[i];
+ }
+ uprv_free(fStuff);
+ }
+ }
+ NFRule* operator[](uint32_t index) const { return fStuff[index]; }
+ NFRule* remove(uint32_t index) {
+ NFRule* result = fStuff[index];
+ fCount -= 1;
+ for (uint32_t i = index; i < fCount; ++i) { // assumes small arrays
+ fStuff[i] = fStuff[i+1];
+ }
+ return result;
+ }
+ void add(NFRule* thing) {
+ if (fCount == fCapacity) {
+ fCapacity += 10;
+ fStuff = (NFRule**)uprv_realloc(fStuff, fCapacity * sizeof(NFRule*)); // assume success
+ }
+ fStuff[fCount++] = thing;
+ }
+ uint32_t size() const { return fCount; }
+ NFRule* last() const { return fCount > 0 ? fStuff[fCount-1] : NULL; }
+ NFRule** release() {
+ add(NULL); // ensure null termination
+ NFRule** result = fStuff;
+ fStuff = NULL;
+ fCount = 0;
+ fCapacity = 0;
+ return result;
+ }
+
+private:
+ NFRuleList(const NFRuleList &other); // forbid copying of this class
+ NFRuleList &operator=(const NFRuleList &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+
+/* U_HAVE_RBNF */
+#endif
+
+// NFRLIST_H
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nfrs.cpp b/Build/source/libs/icu/icu-xetex/i18n/nfrs.cpp
new file mode 100644
index 00000000000..ccf42b890d7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nfrs.cpp
@@ -0,0 +1,944 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: nfrs.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 10/11/2001 Doug Ported from ICU4J
+*/
+
+#include "nfrs.h"
+
+#if U_HAVE_RBNF
+
+#include "unicode/uchar.h"
+#include "nfrule.h"
+#include "nfrlist.h"
+
+#ifdef RBNF_DEBUG
+#include "cmemory.h"
+#endif
+
+#include "util.h"
+
+U_NAMESPACE_BEGIN
+
+#if 0
+// euclid's algorithm works with doubles
+// note, doubles only get us up to one quadrillion or so, which
+// isn't as much range as we get with longs. We probably still
+// want either 64-bit math, or BigInteger.
+
+static int64_t
+util_lcm(int64_t x, int64_t y)
+{
+ x.abs();
+ y.abs();
+
+ if (x == 0 || y == 0) {
+ return 0;
+ } else {
+ do {
+ if (x < y) {
+ int64_t t = x; x = y; y = t;
+ }
+ x -= y * (x/y);
+ } while (x != 0);
+
+ return y;
+ }
+}
+
+#else
+/**
+ * Calculates the least common multiple of x and y.
+ */
+static int64_t
+util_lcm(int64_t x, int64_t y)
+{
+ // binary gcd algorithm from Knuth, "The Art of Computer Programming,"
+ // vol. 2, 1st ed., pp. 298-299
+ int64_t x1 = x;
+ int64_t y1 = y;
+
+ int p2 = 0;
+ while ((x1 & 1) == 0 && (y1 & 1) == 0) {
+ ++p2;
+ x1 >>= 1;
+ y1 >>= 1;
+ }
+
+ int64_t t;
+ if ((x1 & 1) == 1) {
+ t = -y1;
+ } else {
+ t = x1;
+ }
+
+ while (t != 0) {
+ while ((t & 1) == 0) {
+ t = t >> 1;
+ }
+ if (t > 0) {
+ x1 = t;
+ } else {
+ y1 = -t;
+ }
+ t = x1 - y1;
+ }
+
+ int64_t gcd = x1 << p2;
+
+ // x * y == gcd(x, y) * lcm(x, y)
+ return x / gcd * y;
+}
+#endif
+
+static const UChar gPercent = 0x0025;
+static const UChar gColon = 0x003a;
+static const UChar gSemicolon = 0x003b;
+static const UChar gLineFeed = 0x000a;
+
+static const UChar gFourSpaces[] =
+{
+ 0x20, 0x20, 0x20, 0x20, 0
+}; /* " " */
+static const UChar gPercentPercent[] =
+{
+ 0x25, 0x25, 0
+}; /* "%%" */
+
+NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& status)
+ : name()
+ , rules(0)
+ , negativeNumberRule(NULL)
+ , fIsFractionRuleSet(FALSE)
+ , fIsPublic(FALSE)
+ , fRecursionCount(0)
+{
+ for (int i = 0; i < 3; ++i) {
+ fractionRules[i] = NULL;
+ }
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UnicodeString& description = descriptions[index]; // !!! make sure index is valid
+
+ if (description.length() == 0) {
+ // throw new IllegalArgumentException("Empty rule set description");
+ status = U_PARSE_ERROR;
+ return;
+ }
+
+ // if the description begins with a rule set name (the rule set
+ // name can be omitted in formatter descriptions that consist
+ // of only one rule set), copy it out into our "name" member
+ // and delete it from the description
+ if (description.charAt(0) == gPercent) {
+ int32_t pos = description.indexOf(gColon);
+ if (pos == -1) {
+ // throw new IllegalArgumentException("Rule set name doesn't end in colon");
+ status = U_PARSE_ERROR;
+ } else {
+ name.setTo(description, 0, pos);
+ while (pos < description.length() && uprv_isRuleWhiteSpace(description.charAt(++pos))) {
+ }
+ description.remove(0, pos);
+ }
+ } else {
+ name.setTo(UNICODE_STRING_SIMPLE("%default"));
+ }
+
+ if (description.length() == 0) {
+ // throw new IllegalArgumentException("Empty rule set description");
+ status = U_PARSE_ERROR;
+ }
+
+ fIsPublic = name.indexOf(gPercentPercent) != 0;
+
+ // all of the other members of NFRuleSet are initialized
+ // by parseRules()
+}
+
+void
+NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* owner, UErrorCode& status)
+{
+ // start by creating a Vector whose elements are Strings containing
+ // the descriptions of the rules (one rule per element). The rules
+ // are separated by semicolons (there's no escape facility: ALL
+ // semicolons are rule delimiters)
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // dlf - the original code kept a separate description array for no reason,
+ // so I got rid of it. The loop was too complex so I simplified it.
+
+ UnicodeString currentDescription;
+ int32_t oldP = 0;
+ while (oldP < description.length()) {
+ int32_t p = description.indexOf(gSemicolon, oldP);
+ if (p == -1) {
+ p = description.length();
+ }
+ currentDescription.setTo(description, oldP, p - oldP);
+ NFRule::makeRules(currentDescription, this, rules.last(), owner, rules, status);
+ oldP = p + 1;
+ }
+
+ // for rules that didn't specify a base value, their base values
+ // were initialized to 0. Make another pass through the list and
+ // set all those rules' base values. We also remove any special
+ // rules from the list and put them into their own member variables
+ int64_t defaultBaseValue = 0;
+
+ // (this isn't a for loop because we might be deleting items from
+ // the vector-- we want to make sure we only increment i when
+ // we _didn't_ delete aything from the vector)
+ uint32_t i = 0;
+ while (i < rules.size()) {
+ NFRule* rule = rules[i];
+
+ switch (rule->getType()) {
+ // if the rule's base value is 0, fill in a default
+ // base value (this will be 1 plus the preceding
+ // rule's base value for regular rule sets, and the
+ // same as the preceding rule's base value in fraction
+ // rule sets)
+ case NFRule::kNoBase:
+ rule->setBaseValue(defaultBaseValue, status);
+ if (!isFractionRuleSet()) {
+ ++defaultBaseValue;
+ }
+ ++i;
+ break;
+
+ // if it's the negative-number rule, copy it into its own
+ // data member and delete it from the list
+ case NFRule::kNegativeNumberRule:
+ negativeNumberRule = rules.remove(i);
+ break;
+
+ // if it's the improper fraction rule, copy it into the
+ // correct element of fractionRules
+ case NFRule::kImproperFractionRule:
+ fractionRules[0] = rules.remove(i);
+ break;
+
+ // if it's the proper fraction rule, copy it into the
+ // correct element of fractionRules
+ case NFRule::kProperFractionRule:
+ fractionRules[1] = rules.remove(i);
+ break;
+
+ // if it's the master rule, copy it into the
+ // correct element of fractionRules
+ case NFRule::kMasterRule:
+ fractionRules[2] = rules.remove(i);
+ break;
+
+ // if it's a regular rule that already knows its base value,
+ // check to make sure the rules are in order, and update
+ // the default base value for the next rule
+ default:
+ if (rule->getBaseValue() < defaultBaseValue) {
+ // throw new IllegalArgumentException("Rules are not in order");
+ status = U_PARSE_ERROR;
+ return;
+ }
+ defaultBaseValue = rule->getBaseValue();
+ if (!isFractionRuleSet()) {
+ ++defaultBaseValue;
+ }
+ ++i;
+ break;
+ }
+ }
+}
+
+NFRuleSet::~NFRuleSet()
+{
+ delete negativeNumberRule;
+ delete fractionRules[0];
+ delete fractionRules[1];
+ delete fractionRules[2];
+}
+
+static UBool
+util_equalRules(const NFRule* rule1, const NFRule* rule2)
+{
+ if (rule1) {
+ if (rule2) {
+ return *rule1 == *rule2;
+ }
+ } else if (!rule2) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+NFRuleSet::operator==(const NFRuleSet& rhs) const
+{
+ if (rules.size() == rhs.rules.size() &&
+ fIsFractionRuleSet == rhs.fIsFractionRuleSet &&
+ name == rhs.name &&
+ util_equalRules(negativeNumberRule, rhs.negativeNumberRule) &&
+ util_equalRules(fractionRules[0], rhs.fractionRules[0]) &&
+ util_equalRules(fractionRules[1], rhs.fractionRules[1]) &&
+ util_equalRules(fractionRules[2], rhs.fractionRules[2])) {
+
+ for (uint32_t i = 0; i < rules.size(); ++i) {
+ if (*rules[i] != *rhs.rules[i]) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define RECURSION_LIMIT 50
+
+void
+NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos) const
+{
+ NFRule *rule = findNormalRule(number);
+ if (rule) { // else error, but can't report it
+ NFRuleSet* ncThis = (NFRuleSet*)this;
+ if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) {
+ // stop recursion
+ ncThis->fRecursionCount = 0;
+ } else {
+ rule->doFormat(number, toAppendTo, pos);
+ ncThis->fRecursionCount--;
+ }
+ }
+}
+
+void
+NFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos) const
+{
+ NFRule *rule = findDoubleRule(number);
+ if (rule) { // else error, but can't report it
+ NFRuleSet* ncThis = (NFRuleSet*)this;
+ if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) {
+ // stop recursion
+ ncThis->fRecursionCount = 0;
+ } else {
+ rule->doFormat(number, toAppendTo, pos);
+ ncThis->fRecursionCount--;
+ }
+ }
+}
+
+NFRule*
+NFRuleSet::findDoubleRule(double number) const
+{
+ // if this is a fraction rule set, use findFractionRuleSetRule()
+ if (isFractionRuleSet()) {
+ return findFractionRuleSetRule(number);
+ }
+
+ // if the number is negative, return the negative number rule
+ // (if there isn't a negative-number rule, we pretend it's a
+ // positive number)
+ if (number < 0) {
+ if (negativeNumberRule) {
+ return negativeNumberRule;
+ } else {
+ number = -number;
+ }
+ }
+
+ // if the number isn't an integer, we use one of the fraction rules...
+ if (number != uprv_floor(number)) {
+ // if the number is between 0 and 1, return the proper
+ // fraction rule
+ if (number < 1 && fractionRules[1]) {
+ return fractionRules[1];
+ }
+ // otherwise, return the improper fraction rule
+ else if (fractionRules[0]) {
+ return fractionRules[0];
+ }
+ }
+
+ // if there's a master rule, use it to format the number
+ if (fractionRules[2]) {
+ return fractionRules[2];
+ }
+
+ // and if we haven't yet returned a rule, use findNormalRule()
+ // to find the applicable rule
+ int64_t r = util64_fromDouble(number + 0.5);
+ return findNormalRule(r);
+}
+
+NFRule *
+NFRuleSet::findNormalRule(int64_t number) const
+{
+ // if this is a fraction rule set, use findFractionRuleSetRule()
+ // to find the rule (we should only go into this clause if the
+ // value is 0)
+ if (fIsFractionRuleSet) {
+ return findFractionRuleSetRule((double)number);
+ }
+
+ // if the number is negative, return the negative-number rule
+ // (if there isn't one, pretend the number is positive)
+ if (number < 0) {
+ if (negativeNumberRule) {
+ return negativeNumberRule;
+ } else {
+ number = -number;
+ }
+ }
+
+ // we have to repeat the preceding two checks, even though we
+ // do them in findRule(), because the version of format() that
+ // takes a long bypasses findRule() and goes straight to this
+ // function. This function does skip the fraction rules since
+ // we know the value is an integer (it also skips the master
+ // rule, since it's considered a fraction rule. Skipping the
+ // master rule in this function is also how we avoid infinite
+ // recursion)
+
+ // {dlf} unfortunately this fails if there are no rules except
+ // special rules. If there are no rules, use the master rule.
+
+ // binary-search the rule list for the applicable rule
+ // (a rule is used for all values from its base value to
+ // the next rule's base value)
+ int32_t hi = rules.size();
+ if (hi > 0) {
+ int32_t lo = 0;
+
+ while (lo < hi) {
+ int32_t mid = (lo + hi) / 2;
+ if (rules[mid]->getBaseValue() == number) {
+ return rules[mid];
+ }
+ else if (rules[mid]->getBaseValue() > number) {
+ hi = mid;
+ }
+ else {
+ lo = mid + 1;
+ }
+ }
+ if (hi == 0) { // bad rule set, minimum base > 0
+ return NULL; // want to throw exception here
+ }
+
+ NFRule *result = rules[hi - 1];
+
+ // use shouldRollBack() to see whether we need to invoke the
+ // rollback rule (see shouldRollBack()'s documentation for
+ // an explanation of the rollback rule). If we do, roll back
+ // one rule and return that one instead of the one we'd normally
+ // return
+ if (result->shouldRollBack((double)number)) {
+ if (hi == 1) { // bad rule set, no prior rule to rollback to from this base
+ return NULL;
+ }
+ result = rules[hi - 2];
+ }
+ return result;
+ }
+ // else use the master rule
+ return fractionRules[2];
+}
+
+/**
+ * If this rule is a fraction rule set, this function is used by
+ * findRule() to select the most appropriate rule for formatting
+ * the number. Basically, the base value of each rule in the rule
+ * set is treated as the denominator of a fraction. Whichever
+ * denominator can produce the fraction closest in value to the
+ * number passed in is the result. If there's a tie, the earlier
+ * one in the list wins. (If there are two rules in a row with the
+ * same base value, the first one is used when the numerator of the
+ * fraction would be 1, and the second rule is used the rest of the
+ * time.
+ * @param number The number being formatted (which will always be
+ * a number between 0 and 1)
+ * @return The rule to use to format this number
+ */
+NFRule*
+NFRuleSet::findFractionRuleSetRule(double number) const
+{
+ // the obvious way to do this (multiply the value being formatted
+ // by each rule's base value until you get an integral result)
+ // doesn't work because of rounding error. This method is more
+ // accurate
+
+ // find the least common multiple of the rules' base values
+ // and multiply this by the number being formatted. This is
+ // all the precision we need, and we can do all of the rest
+ // of the math using integer arithmetic
+ int64_t leastCommonMultiple = rules[0]->getBaseValue();
+ int64_t numerator;
+ {
+ for (uint32_t i = 1; i < rules.size(); ++i) {
+ leastCommonMultiple = util_lcm(leastCommonMultiple, rules[i]->getBaseValue());
+ }
+ numerator = util64_fromDouble(number * (double)leastCommonMultiple + 0.5);
+ }
+ // for each rule, do the following...
+ int64_t tempDifference;
+ int64_t difference = util64_fromDouble(uprv_maxMantissa());
+ int32_t winner = 0;
+ for (uint32_t i = 0; i < rules.size(); ++i) {
+ // "numerator" is the numerator of the fraction if the
+ // denominator is the LCD. The numerator if the rule's
+ // base value is the denominator is "numerator" times the
+ // base value divided bythe LCD. Here we check to see if
+ // that's an integer, and if not, how close it is to being
+ // an integer.
+ tempDifference = numerator * rules[i]->getBaseValue() % leastCommonMultiple;
+
+
+ // normalize the result of the above calculation: we want
+ // the numerator's distance from the CLOSEST multiple
+ // of the LCD
+ if (leastCommonMultiple - tempDifference < tempDifference) {
+ tempDifference = leastCommonMultiple - tempDifference;
+ }
+
+ // if this is as close as we've come, keep track of how close
+ // that is, and the line number of the rule that did it. If
+ // we've scored a direct hit, we don't have to look at any more
+ // rules
+ if (tempDifference < difference) {
+ difference = tempDifference;
+ winner = i;
+ if (difference == 0) {
+ break;
+ }
+ }
+ }
+
+ // if we have two successive rules that both have the winning base
+ // value, then the first one (the one we found above) is used if
+ // the numerator of the fraction is 1 and the second one is used if
+ // the numerator of the fraction is anything else (this lets us
+ // do things like "one third"/"two thirds" without haveing to define
+ // a whole bunch of extra rule sets)
+ if ((unsigned)(winner + 1) < rules.size() &&
+ rules[winner + 1]->getBaseValue() == rules[winner]->getBaseValue()) {
+ double n = ((double)rules[winner]->getBaseValue()) * number;
+ if (n < 0.5 || n >= 2) {
+ ++winner;
+ }
+ }
+
+ // finally, return the winning rule
+ return rules[winner];
+}
+
+/**
+ * Parses a string. Matches the string to be parsed against each
+ * of its rules (with a base value less than upperBound) and returns
+ * the value produced by the rule that matched the most charcters
+ * in the source string.
+ * @param text The string to parse
+ * @param parsePosition The initial position is ignored and assumed
+ * to be 0. On exit, this object has been updated to point to the
+ * first character position this rule set didn't consume.
+ * @param upperBound Limits the rules that can be allowed to match.
+ * Only rules whose base values are strictly less than upperBound
+ * are considered.
+ * @return The numerical result of parsing this string. This will
+ * be the matching rule's base value, composed appropriately with
+ * the results of matching any of its substitutions. The object
+ * will be an instance of Long if it's an integral value; otherwise,
+ * it will be an instance of Double. This function always returns
+ * a valid object: If nothing matched the input string at all,
+ * this function returns new Long(0), and the parse position is
+ * left unchanged.
+ */
+#ifdef RBNF_DEBUG
+#include <stdio.h>
+
+static void dumpUS(FILE* f, const UnicodeString& us) {
+ int len = us.length();
+ char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1];
+ us.extract(0, len, buf);
+ buf[len] = 0;
+ fprintf(f, "%s", buf);
+ uprv_free(buf); //delete[] buf;
+}
+#endif
+
+UBool
+NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBound, Formattable& result) const
+{
+ // try matching each rule in the rule set against the text being
+ // parsed. Whichever one matches the most characters is the one
+ // that determines the value we return.
+
+ result.setLong(0);
+
+ // dump out if there's no text to parse
+ if (text.length() == 0) {
+ return 0;
+ }
+
+ ParsePosition highWaterMark;
+ ParsePosition workingPos = pos;
+
+#ifdef RBNF_DEBUG
+ fprintf(stderr, "<nfrs> %x '", this);
+ dumpUS(stderr, name);
+ fprintf(stderr, "' text '");
+ dumpUS(stderr, text);
+ fprintf(stderr, "'\n");
+ fprintf(stderr, " parse negative: %d\n", this, negativeNumberRule != 0);
+#endif
+
+ // start by trying the negative number rule (if there is one)
+ if (negativeNumberRule) {
+ Formattable tempResult;
+#ifdef RBNF_DEBUG
+ fprintf(stderr, " <nfrs before negative> %x ub: %g\n", negativeNumberRule, upperBound);
+#endif
+ UBool success = negativeNumberRule->doParse(text, workingPos, 0, upperBound, tempResult);
+#ifdef RBNF_DEBUG
+ fprintf(stderr, " <nfrs after negative> success: %d wpi: %d\n", success, workingPos.getIndex());
+#endif
+ if (success && workingPos.getIndex() > highWaterMark.getIndex()) {
+ result = tempResult;
+ highWaterMark = workingPos;
+ }
+ workingPos = pos;
+ }
+#ifdef RBNF_DEBUG
+ fprintf(stderr, "<nfrs> continue fractional with text '");
+ dumpUS(stderr, text);
+ fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex());
+#endif
+ // then try each of the fraction rules
+ {
+ for (int i = 0; i < 3; i++) {
+ if (fractionRules[i]) {
+ Formattable tempResult;
+ UBool success = fractionRules[i]->doParse(text, workingPos, 0, upperBound, tempResult);
+ if (success && (workingPos.getIndex() > highWaterMark.getIndex())) {
+ result = tempResult;
+ highWaterMark = workingPos;
+ }
+ workingPos = pos;
+ }
+ }
+ }
+#ifdef RBNF_DEBUG
+ fprintf(stderr, "<nfrs> continue other with text '");
+ dumpUS(stderr, text);
+ fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex());
+#endif
+
+ // finally, go through the regular rules one at a time. We start
+ // at the end of the list because we want to try matching the most
+ // sigificant rule first (this helps ensure that we parse
+ // "five thousand three hundred six" as
+ // "(five thousand) (three hundred) (six)" rather than
+ // "((five thousand three) hundred) (six)"). Skip rules whose
+ // base values are higher than the upper bound (again, this helps
+ // limit ambiguity by making sure the rules that match a rule's
+ // are less significant than the rule containing the substitutions)/
+ {
+ int64_t ub = util64_fromDouble(upperBound);
+#ifdef RBNF_DEBUG
+ {
+ char ubstr[64];
+ util64_toa(ub, ubstr, 64);
+ char ubstrhex[64];
+ util64_toa(ub, ubstrhex, 64, 16);
+ fprintf(stderr, "ub: %g, i64: %s (%s)\n", upperBound, ubstr, ubstrhex);
+ }
+#endif
+ for (int32_t i = rules.size(); --i >= 0 && highWaterMark.getIndex() < text.length();) {
+ if ((!fIsFractionRuleSet) && (rules[i]->getBaseValue() >= ub)) {
+ continue;
+ }
+ Formattable tempResult;
+ UBool success = rules[i]->doParse(text, workingPos, fIsFractionRuleSet, upperBound, tempResult);
+ if (success && workingPos.getIndex() > highWaterMark.getIndex()) {
+ result = tempResult;
+ highWaterMark = workingPos;
+ }
+ workingPos = pos;
+ }
+ }
+#ifdef RBNF_DEBUG
+ fprintf(stderr, "<nfrs> exit\n");
+#endif
+ // finally, update the parse postion we were passed to point to the
+ // first character we didn't use, and return the result that
+ // corresponds to that string of characters
+ pos = highWaterMark;
+
+ return 1;
+}
+
+void
+NFRuleSet::appendRules(UnicodeString& result) const
+{
+ // the rule set name goes first...
+ result.append(name);
+ result.append(gColon);
+ result.append(gLineFeed);
+
+ // followed by the regular rules...
+ for (uint32_t i = 0; i < rules.size(); i++) {
+ result.append(gFourSpaces);
+ rules[i]->_appendRuleText(result);
+ result.append(gLineFeed);
+ }
+
+ // followed by the special rules (if they exist)
+ if (negativeNumberRule) {
+ result.append(gFourSpaces);
+ negativeNumberRule->_appendRuleText(result);
+ result.append(gLineFeed);
+ }
+
+ {
+ for (uint32_t i = 0; i < 3; ++i) {
+ if (fractionRules[i]) {
+ result.append(gFourSpaces);
+ fractionRules[i]->_appendRuleText(result);
+ result.append(gLineFeed);
+ }
+ }
+ }
+}
+
+// utility functions
+
+int64_t util64_fromDouble(double d) {
+ int64_t result = 0;
+ if (!uprv_isNaN(d)) {
+ double mant = uprv_maxMantissa();
+ if (d < -mant) {
+ d = -mant;
+ } else if (d > mant) {
+ d = mant;
+ }
+ UBool neg = d < 0;
+ if (neg) {
+ d = -d;
+ }
+ result = (int64_t)uprv_floor(d);
+ if (neg) {
+ result = -result;
+ }
+ }
+ return result;
+}
+
+int64_t util64_pow(int32_t r, uint32_t e) {
+ if (r == 0) {
+ return 0;
+ } else if (e == 0) {
+ return 1;
+ } else {
+ int64_t n = r;
+ while (--e > 0) {
+ n *= r;
+ }
+ return n;
+ }
+}
+
+static const uint8_t asciiDigits[] = {
+ 0x30u, 0x31u, 0x32u, 0x33u, 0x34u, 0x35u, 0x36u, 0x37u,
+ 0x38u, 0x39u, 0x61u, 0x62u, 0x63u, 0x64u, 0x65u, 0x66u,
+ 0x67u, 0x68u, 0x69u, 0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu,
+ 0x6fu, 0x70u, 0x71u, 0x72u, 0x73u, 0x74u, 0x75u, 0x76u,
+ 0x77u, 0x78u, 0x79u, 0x7au,
+};
+
+static const UChar kUMinus = (UChar)0x002d;
+
+#ifdef RBNF_DEBUG
+static const char kMinus = '-';
+
+static const uint8_t digitInfo[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x80u, 0x81u, 0x82u, 0x83u, 0x84u, 0x85u, 0x86u, 0x87u,
+ 0x88u, 0x89u, 0, 0, 0, 0, 0, 0,
+ 0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u,
+ 0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u,
+ 0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u,
+ 0xa1u, 0xa2u, 0xa3u, 0, 0, 0, 0, 0,
+ 0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u,
+ 0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u,
+ 0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u,
+ 0xa1u, 0xa2u, 0xa3u, 0, 0, 0, 0, 0,
+};
+
+int64_t util64_atoi(const char* str, uint32_t radix)
+{
+ if (radix > 36) {
+ radix = 36;
+ } else if (radix < 2) {
+ radix = 2;
+ }
+ int64_t lradix = radix;
+
+ int neg = 0;
+ if (*str == kMinus) {
+ ++str;
+ neg = 1;
+ }
+ int64_t result = 0;
+ uint8_t b;
+ while ((b = digitInfo[*str++]) && ((b &= 0x7f) < radix)) {
+ result *= lradix;
+ result += (int32_t)b;
+ }
+ if (neg) {
+ result = -result;
+ }
+ return result;
+}
+
+int64_t util64_utoi(const UChar* str, uint32_t radix)
+{
+ if (radix > 36) {
+ radix = 36;
+ } else if (radix < 2) {
+ radix = 2;
+ }
+ int64_t lradix = radix;
+
+ int neg = 0;
+ if (*str == kUMinus) {
+ ++str;
+ neg = 1;
+ }
+ int64_t result = 0;
+ UChar c;
+ uint8_t b;
+ while (((c = *str++) < 0x0080) && (b = digitInfo[c]) && ((b &= 0x7f) < radix)) {
+ result *= lradix;
+ result += (int32_t)b;
+ }
+ if (neg) {
+ result = -result;
+ }
+ return result;
+}
+
+uint32_t util64_toa(int64_t w, char* buf, uint32_t len, uint32_t radix, UBool raw)
+{
+ if (radix > 36) {
+ radix = 36;
+ } else if (radix < 2) {
+ radix = 2;
+ }
+ int64_t base = radix;
+
+ char* p = buf;
+ if (len && (w < 0) && (radix == 10) && !raw) {
+ w = -w;
+ *p++ = kMinus;
+ --len;
+ } else if (len && (w == 0)) {
+ *p++ = (char)raw ? 0 : asciiDigits[0];
+ --len;
+ }
+
+ while (len && w != 0) {
+ int64_t n = w / base;
+ int64_t m = n * base;
+ int32_t d = (int32_t)(w-m);
+ *p++ = raw ? (char)d : asciiDigits[d];
+ w = n;
+ --len;
+ }
+ if (len) {
+ *p = 0; // null terminate if room for caller convenience
+ }
+
+ len = p - buf;
+ if (*buf == kMinus) {
+ ++buf;
+ }
+ while (--p > buf) {
+ char c = *p;
+ *p = *buf;
+ *buf = c;
+ ++buf;
+ }
+
+ return len;
+}
+#endif
+
+uint32_t util64_tou(int64_t w, UChar* buf, uint32_t len, uint32_t radix, UBool raw)
+{
+ if (radix > 36) {
+ radix = 36;
+ } else if (radix < 2) {
+ radix = 2;
+ }
+ int64_t base = radix;
+
+ UChar* p = buf;
+ if (len && (w < 0) && (radix == 10) && !raw) {
+ w = -w;
+ *p++ = kUMinus;
+ --len;
+ } else if (len && (w == 0)) {
+ *p++ = (UChar)raw ? 0 : asciiDigits[0];
+ --len;
+ }
+
+ while (len && (w != 0)) {
+ int64_t n = w / base;
+ int64_t m = n * base;
+ int32_t d = (int32_t)(w-m);
+ *p++ = (UChar)(raw ? d : asciiDigits[d]);
+ w = n;
+ --len;
+ }
+ if (len) {
+ *p = 0; // null terminate if room for caller convenience
+ }
+
+ len = (uint32_t)(p - buf);
+ if (*buf == kUMinus) {
+ ++buf;
+ }
+ while (--p > buf) {
+ UChar c = *p;
+ *p = *buf;
+ *buf = c;
+ ++buf;
+ }
+
+ return len;
+}
+
+
+U_NAMESPACE_END
+
+/* U_HAVE_RBNF */
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nfrs.h b/Build/source/libs/icu/icu-xetex/i18n/nfrs.h
new file mode 100644
index 00000000000..fcfe06be892
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nfrs.h
@@ -0,0 +1,97 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: nfrs.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 10/11/2001 Doug Ported from ICU4J
+*/
+
+#ifndef NFRS_H
+#define NFRS_H
+
+#include "unicode/uobject.h"
+#include "unicode/rbnf.h"
+
+#if U_HAVE_RBNF
+
+#include "unicode/utypes.h"
+#include "unicode/umisc.h"
+
+#include "nfrlist.h"
+
+U_NAMESPACE_BEGIN
+
+class NFRuleSet : public UMemory {
+ public:
+ NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& status);
+ void parseRules(UnicodeString& rules, const RuleBasedNumberFormat* owner, UErrorCode& status);
+ void makeIntoFractionRuleSet() { fIsFractionRuleSet = TRUE; }
+
+ ~NFRuleSet();
+
+ UBool operator==(const NFRuleSet& rhs) const;
+ UBool operator!=(const NFRuleSet& rhs) const { return !operator==(rhs); }
+
+ UBool isPublic() const { return fIsPublic; }
+ UBool isFractionRuleSet() const { return fIsFractionRuleSet; }
+
+ void getName(UnicodeString& result) const { result.setTo(name); }
+ UBool isNamed(const UnicodeString& _name) const { return this->name == _name; }
+
+ void format(int64_t number, UnicodeString& toAppendTo, int32_t pos) const;
+ void format(double number, UnicodeString& toAppendTo, int32_t pos) const;
+
+ UBool parse(const UnicodeString& text, ParsePosition& pos, double upperBound, Formattable& result) const;
+
+ void appendRules(UnicodeString& result) const; // toString
+
+ private:
+ NFRule * findNormalRule(int64_t number) const;
+ NFRule * findDoubleRule(double number) const;
+ NFRule * findFractionRuleSetRule(double number) const;
+
+ private:
+ UnicodeString name;
+ NFRuleList rules;
+ NFRule *negativeNumberRule;
+ NFRule *fractionRules[3];
+ UBool fIsFractionRuleSet;
+ UBool fIsPublic;
+ int32_t fRecursionCount;
+
+ NFRuleSet(const NFRuleSet &other); // forbid copying of this class
+ NFRuleSet &operator=(const NFRuleSet &other); // forbid copying of this class
+};
+
+// utilities from old llong.h
+// convert mantissa portion of double to int64
+int64_t util64_fromDouble(double d);
+
+// raise radix to the power exponent, only non-negative exponents
+int64_t util64_pow(int32_t radix, uint32_t exponent);
+
+// convert n to digit string in buffer, return length of string
+uint32_t util64_tou(int64_t n, UChar* buffer, uint32_t buflen, uint32_t radix = 10, UBool raw = FALSE);
+
+#ifdef RBNF_DEBUG
+int64_t util64_utoi(const UChar* str, uint32_t radix = 10);
+uint32_t util64_toa(int64_t n, char* buffer, uint32_t buflen, uint32_t radix = 10, UBool raw = FALSE);
+int64_t util64_atoi(const char* str, uint32_t radix);
+#endif
+
+
+U_NAMESPACE_END
+
+/* U_HAVE_RBNF */
+#endif
+
+// NFRS_H
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nfrule.cpp b/Build/source/libs/icu/icu-xetex/i18n/nfrule.cpp
new file mode 100644
index 00000000000..d6cf1850f48
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nfrule.cpp
@@ -0,0 +1,1446 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: nfrule.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 10/11/2001 Doug Ported from ICU4J
+*/
+
+#include "nfrule.h"
+
+#if U_HAVE_RBNF
+
+#include "unicode/rbnf.h"
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "unicode/uchar.h"
+#include "nfrs.h"
+#include "nfrlist.h"
+#include "nfsubs.h"
+
+#include "util.h"
+
+U_NAMESPACE_BEGIN
+
+NFRule::NFRule(const RuleBasedNumberFormat* _rbnf)
+ : baseValue((int32_t)0)
+ , radix(0)
+ , exponent(0)
+ , ruleText()
+ , sub1(NULL)
+ , sub2(NULL)
+ , formatter(_rbnf)
+{
+}
+
+NFRule::~NFRule()
+{
+ delete sub1;
+ delete sub2;
+}
+
+static const UChar gLeftBracket = 0x005b;
+static const UChar gRightBracket = 0x005d;
+static const UChar gColon = 0x003a;
+static const UChar gZero = 0x0030;
+static const UChar gNine = 0x0039;
+static const UChar gSpace = 0x0020;
+static const UChar gSlash = 0x002f;
+static const UChar gGreaterThan = 0x003e;
+static const UChar gLessThan = 0x003c;
+static const UChar gComma = 0x002c;
+static const UChar gDot = 0x002e;
+static const UChar gTick = 0x0027;
+//static const UChar gMinus = 0x002d;
+static const UChar gSemicolon = 0x003b;
+
+static const UChar gMinusX[] = {0x2D, 0x78, 0}; /* "-x" */
+static const UChar gXDotX[] = {0x78, 0x2E, 0x78, 0}; /* "x.x" */
+static const UChar gXDotZero[] = {0x78, 0x2E, 0x30, 0}; /* "x.0" */
+static const UChar gZeroDotX[] = {0x30, 0x2E, 0x78, 0}; /* "0.x" */
+
+static const UChar gLessLess[] = {0x3C, 0x3C, 0}; /* "<<" */
+static const UChar gLessPercent[] = {0x3C, 0x25, 0}; /* "<%" */
+static const UChar gLessHash[] = {0x3C, 0x23, 0}; /* "<#" */
+static const UChar gLessZero[] = {0x3C, 0x30, 0}; /* "<0" */
+static const UChar gGreaterGreater[] = {0x3E, 0x3E, 0}; /* ">>" */
+static const UChar gGreaterPercent[] = {0x3E, 0x25, 0}; /* ">%" */
+static const UChar gGreaterHash[] = {0x3E, 0x23, 0}; /* ">#" */
+static const UChar gGreaterZero[] = {0x3E, 0x30, 0}; /* ">0" */
+static const UChar gEqualPercent[] = {0x3D, 0x25, 0}; /* "=%" */
+static const UChar gEqualHash[] = {0x3D, 0x23, 0}; /* "=#" */
+static const UChar gEqualZero[] = {0x3D, 0x30, 0}; /* "=0" */
+static const UChar gEmptyString[] = {0}; /* "" */
+static const UChar gGreaterGreaterGreater[] = {0x3E, 0x3E, 0x3E, 0}; /* ">>>" */
+
+static const UChar * const tokenStrings[] = {
+ gLessLess, gLessPercent, gLessHash, gLessZero,
+ gGreaterGreater, gGreaterPercent,gGreaterHash, gGreaterZero,
+ gEqualPercent, gEqualHash, gEqualZero, NULL
+};
+
+void
+NFRule::makeRules(UnicodeString& description,
+ const NFRuleSet *ruleSet,
+ const NFRule *predecessor,
+ const RuleBasedNumberFormat *rbnf,
+ NFRuleList& rules,
+ UErrorCode& status)
+{
+ // we know we're making at least one rule, so go ahead and
+ // new it up and initialize its basevalue and divisor
+ // (this also strips the rule descriptor, if any, off the
+ // descripton string)
+ NFRule* rule1 = new NFRule(rbnf);
+ /* test for NULL */
+ if (rule1 == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ rule1->parseRuleDescriptor(description, status);
+
+ // check the description to see whether there's text enclosed
+ // in brackets
+ int32_t brack1 = description.indexOf(gLeftBracket);
+ int32_t brack2 = description.indexOf(gRightBracket);
+
+ // if the description doesn't contain a matched pair of brackets,
+ // or if it's of a type that doesn't recognize bracketed text,
+ // then leave the description alone, initialize the rule's
+ // rule text and substitutions, and return that rule
+ if (brack1 == -1 || brack2 == -1 || brack1 > brack2
+ || rule1->getType() == kProperFractionRule
+ || rule1->getType() == kNegativeNumberRule) {
+ rule1->ruleText = description;
+ rule1->extractSubstitutions(ruleSet, predecessor, rbnf, status);
+ rules.add(rule1);
+ } else {
+ // if the description does contain a matched pair of brackets,
+ // then it's really shorthand for two rules (with one exception)
+ NFRule* rule2 = NULL;
+ UnicodeString sbuf;
+
+ // we'll actually only split the rule into two rules if its
+ // base value is an even multiple of its divisor (or it's one
+ // of the special rules)
+ if ((rule1->baseValue > 0
+ && (rule1->baseValue % util64_pow(rule1->radix, rule1->exponent)) == 0)
+ || rule1->getType() == kImproperFractionRule
+ || rule1->getType() == kMasterRule) {
+
+ // if it passes that test, new up the second rule. If the
+ // rule set both rules will belong to is a fraction rule
+ // set, they both have the same base value; otherwise,
+ // increment the original rule's base value ("rule1" actually
+ // goes SECOND in the rule set's rule list)
+ rule2 = new NFRule(rbnf);
+ /* test for NULL */
+ if (rule2 == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (rule1->baseValue >= 0) {
+ rule2->baseValue = rule1->baseValue;
+ if (!ruleSet->isFractionRuleSet()) {
+ ++rule1->baseValue;
+ }
+ }
+
+ // if the description began with "x.x" and contains bracketed
+ // text, it describes both the improper fraction rule and
+ // the proper fraction rule
+ else if (rule1->getType() == kImproperFractionRule) {
+ rule2->setType(kProperFractionRule);
+ }
+
+ // if the description began with "x.0" and contains bracketed
+ // text, it describes both the master rule and the
+ // improper fraction rule
+ else if (rule1->getType() == kMasterRule) {
+ rule2->baseValue = rule1->baseValue;
+ rule1->setType(kImproperFractionRule);
+ }
+
+ // both rules have the same radix and exponent (i.e., the
+ // same divisor)
+ rule2->radix = rule1->radix;
+ rule2->exponent = rule1->exponent;
+
+ // rule2's rule text omits the stuff in brackets: initalize
+ // its rule text and substitutions accordingly
+ sbuf.append(description, 0, brack1);
+ if (brack2 + 1 < description.length()) {
+ sbuf.append(description, brack2 + 1, description.length() - brack2 - 1);
+ }
+ rule2->ruleText.setTo(sbuf);
+ rule2->extractSubstitutions(ruleSet, predecessor, rbnf, status);
+ }
+
+ // rule1's text includes the text in the brackets but omits
+ // the brackets themselves: initialize _its_ rule text and
+ // substitutions accordingly
+ sbuf.setTo(description, 0, brack1);
+ sbuf.append(description, brack1 + 1, brack2 - brack1 - 1);
+ if (brack2 + 1 < description.length()) {
+ sbuf.append(description, brack2 + 1, description.length() - brack2 - 1);
+ }
+ rule1->ruleText.setTo(sbuf);
+ rule1->extractSubstitutions(ruleSet, predecessor, rbnf, status);
+
+ // if we only have one rule, return it; if we have two, return
+ // a two-element array containing them (notice that rule2 goes
+ // BEFORE rule1 in the list: in all cases, rule2 OMITS the
+ // material in the brackets and rule1 INCLUDES the material
+ // in the brackets)
+ if (rule2 != NULL) {
+ rules.add(rule2);
+ }
+ rules.add(rule1);
+ }
+}
+
+/**
+ * This function parses the rule's rule descriptor (i.e., the base
+ * value and/or other tokens that precede the rule's rule text
+ * in the description) and sets the rule's base value, radix, and
+ * exponent according to the descriptor. (If the description doesn't
+ * include a rule descriptor, then this function sets everything to
+ * default values and the rule set sets the rule's real base value).
+ * @param description The rule's description
+ * @return If "description" included a rule descriptor, this is
+ * "description" with the descriptor and any trailing whitespace
+ * stripped off. Otherwise; it's "descriptor" unchangd.
+ */
+void
+NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
+{
+ // the description consists of a rule descriptor and a rule body,
+ // separated by a colon. The rule descriptor is optional. If
+ // it's omitted, just set the base value to 0.
+ int32_t p = description.indexOf(gColon);
+ if (p == -1) {
+ setBaseValue((int32_t)0, status);
+ } else {
+ // copy the descriptor out into its own string and strip it,
+ // along with any trailing whitespace, out of the original
+ // description
+ UnicodeString descriptor;
+ descriptor.setTo(description, 0, p);
+
+ ++p;
+ while (p < description.length() && uprv_isRuleWhiteSpace(description.charAt(p))) {
+ ++p;
+ }
+ description.removeBetween(0, p);
+
+ // check first to see if the rule descriptor matches the token
+ // for one of the special rules. If it does, set the base
+ // value to the correct identfier value
+ if (descriptor == gMinusX) {
+ setType(kNegativeNumberRule);
+ }
+ else if (descriptor == gXDotX) {
+ setType(kImproperFractionRule);
+ }
+ else if (descriptor == gZeroDotX) {
+ setType(kProperFractionRule);
+ }
+ else if (descriptor == gXDotZero) {
+ setType(kMasterRule);
+ }
+
+ // if the rule descriptor begins with a digit, it's a descriptor
+ // for a normal rule
+ // since we don't have Long.parseLong, and this isn't much work anyway,
+ // just build up the value as we encounter the digits.
+ else if (descriptor.charAt(0) >= gZero && descriptor.charAt(0) <= gNine) {
+ int64_t val = 0;
+ p = 0;
+ UChar c = gSpace;
+
+ // begin parsing the descriptor: copy digits
+ // into "tempValue", skip periods, commas, and spaces,
+ // stop on a slash or > sign (or at the end of the string),
+ // and throw an exception on any other character
+ int64_t ll_10 = 10;
+ while (p < descriptor.length()) {
+ c = descriptor.charAt(p);
+ if (c >= gZero && c <= gNine) {
+ val = val * ll_10 + (int32_t)(c - gZero);
+ }
+ else if (c == gSlash || c == gGreaterThan) {
+ break;
+ }
+ else if (uprv_isRuleWhiteSpace(c) || c == gComma || c == gDot) {
+ }
+ else {
+ // throw new IllegalArgumentException("Illegal character in rule descriptor");
+ status = U_PARSE_ERROR;
+ return;
+ }
+ ++p;
+ }
+
+ // we have the base value, so set it
+ setBaseValue(val, status);
+
+ // if we stopped the previous loop on a slash, we're
+ // now parsing the rule's radix. Again, accumulate digits
+ // in tempValue, skip punctuation, stop on a > mark, and
+ // throw an exception on anything else
+ if (c == gSlash) {
+ val = 0;
+ ++p;
+ int64_t ll_10 = 10;
+ while (p < descriptor.length()) {
+ c = descriptor.charAt(p);
+ if (c >= gZero && c <= gNine) {
+ val = val * ll_10 + (int32_t)(c - gZero);
+ }
+ else if (c == gGreaterThan) {
+ break;
+ }
+ else if (uprv_isRuleWhiteSpace(c) || c == gComma || c == gDot) {
+ }
+ else {
+ // throw new IllegalArgumentException("Illegal character is rule descriptor");
+ status = U_PARSE_ERROR;
+ return;
+ }
+ ++p;
+ }
+
+ // tempValue now contain's the rule's radix. Set it
+ // accordingly, and recalculate the rule's exponent
+ radix = (int32_t)val;
+ if (radix == 0) {
+ // throw new IllegalArgumentException("Rule can't have radix of 0");
+ status = U_PARSE_ERROR;
+ }
+
+ exponent = expectedExponent();
+ }
+
+ // if we stopped the previous loop on a > sign, then continue
+ // for as long as we still see > signs. For each one,
+ // decrement the exponent (unless the exponent is already 0).
+ // If we see another character before reaching the end of
+ // the descriptor, that's also a syntax error.
+ if (c == gGreaterThan) {
+ while (p < descriptor.length()) {
+ c = descriptor.charAt(p);
+ if (c == gGreaterThan && exponent > 0) {
+ --exponent;
+ } else {
+ // throw new IllegalArgumentException("Illegal character in rule descriptor");
+ status = U_PARSE_ERROR;
+ return;
+ }
+ ++p;
+ }
+ }
+ }
+ }
+
+ // finally, if the rule body begins with an apostrophe, strip it off
+ // (this is generally used to put whitespace at the beginning of
+ // a rule's rule text)
+ if (description.length() > 0 && description.charAt(0) == gTick) {
+ description.removeBetween(0, 1);
+ }
+
+ // return the description with all the stuff we've just waded through
+ // stripped off the front. It now contains just the rule body.
+ // return description;
+}
+
+/**
+* Searches the rule's rule text for the substitution tokens,
+* creates the substitutions, and removes the substitution tokens
+* from the rule's rule text.
+* @param owner The rule set containing this rule
+* @param predecessor The rule preseding this one in "owners" rule list
+* @param ownersOwner The RuleBasedFormat that owns this rule
+*/
+void
+NFRule::extractSubstitutions(const NFRuleSet* ruleSet,
+ const NFRule* predecessor,
+ const RuleBasedNumberFormat* rbnf,
+ UErrorCode& status)
+{
+ if (U_SUCCESS(status)) {
+ sub1 = extractSubstitution(ruleSet, predecessor, rbnf, status);
+ sub2 = extractSubstitution(ruleSet, predecessor, rbnf, status);
+ }
+}
+
+/**
+* Searches the rule's rule text for the first substitution token,
+* creates a substitution based on it, and removes the token from
+* the rule's rule text.
+* @param owner The rule set containing this rule
+* @param predecessor The rule preceding this one in the rule set's
+* rule list
+* @param ownersOwner The RuleBasedNumberFormat that owns this rule
+* @return The newly-created substitution. This is never null; if
+* the rule text doesn't contain any substitution tokens, this will
+* be a NullSubstitution.
+*/
+NFSubstitution *
+NFRule::extractSubstitution(const NFRuleSet* ruleSet,
+ const NFRule* predecessor,
+ const RuleBasedNumberFormat* rbnf,
+ UErrorCode& status)
+{
+ NFSubstitution* result = NULL;
+
+ // search the rule's rule text for the first two characters of
+ // a substitution token
+ int32_t subStart = indexOfAny(tokenStrings);
+ int32_t subEnd = subStart;
+
+ // if we didn't find one, create a null substitution positioned
+ // at the end of the rule text
+ if (subStart == -1) {
+ return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor,
+ ruleSet, rbnf, gEmptyString, status);
+ }
+
+ // special-case the ">>>" token, since searching for the > at the
+ // end will actually find the > in the middle
+ if (ruleText.indexOf(gGreaterGreaterGreater) == subStart) {
+ subEnd = subStart + 2;
+
+ // otherwise the substitution token ends with the same character
+ // it began with
+ } else {
+ UChar c = ruleText.charAt(subStart);
+ subEnd = ruleText.indexOf(c, subStart + 1);
+ // special case for '<%foo<<'
+ if (c == gLessThan && subEnd != -1 && subEnd < ruleText.length() - 1 && ruleText.charAt(subEnd+1) == c) {
+ // ordinals use "=#,##0==%abbrev=" as their rule. Notice that the '==' in the middle
+ // occurs because of the juxtaposition of two different rules. The check for '<' is a hack
+ // to get around this. Having the duplicate at the front would cause problems with
+ // rules like "<<%" to format, say, percents...
+ ++subEnd;
+ }
+ }
+
+ // if we don't find the end of the token (i.e., if we're on a single,
+ // unmatched token character), create a null substitution positioned
+ // at the end of the rule
+ if (subEnd == -1) {
+ return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor,
+ ruleSet, rbnf, gEmptyString, status);
+ }
+
+ // if we get here, we have a real substitution token (or at least
+ // some text bounded by substitution token characters). Use
+ // makeSubstitution() to create the right kind of substitution
+ UnicodeString subToken;
+ subToken.setTo(ruleText, subStart, subEnd + 1 - subStart);
+ result = NFSubstitution::makeSubstitution(subStart, this, predecessor, ruleSet,
+ rbnf, subToken, status);
+
+ // remove the substitution from the rule text
+ ruleText.removeBetween(subStart, subEnd+1);
+
+ return result;
+}
+
+/**
+ * Sets the rule's base value, and causes the radix and exponent
+ * to be recalculated. This is used during construction when we
+ * don't know the rule's base value until after it's been
+ * constructed. It should be used at any other time.
+ * @param The new base value for the rule.
+ */
+void
+NFRule::setBaseValue(int64_t newBaseValue, UErrorCode& status)
+{
+ // set the base value
+ baseValue = newBaseValue;
+
+ // if this isn't a special rule, recalculate the radix and exponent
+ // (the radix always defaults to 10; if it's supposed to be something
+ // else, it's cleaned up by the caller and the exponent is
+ // recalculated again-- the only function that does this is
+ // NFRule.parseRuleDescriptor() )
+ if (baseValue >= 1) {
+ radix = 10;
+ exponent = expectedExponent();
+
+ // this function gets called on a fully-constructed rule whose
+ // description didn't specify a base value. This means it
+ // has substitutions, and some substitutions hold on to copies
+ // of the rule's divisor. Fix their copies of the divisor.
+ if (sub1 != NULL) {
+ sub1->setDivisor(radix, exponent, status);
+ }
+ if (sub2 != NULL) {
+ sub2->setDivisor(radix, exponent, status);
+ }
+
+ // if this is a special rule, its radix and exponent are basically
+ // ignored. Set them to "safe" default values
+ } else {
+ radix = 10;
+ exponent = 0;
+ }
+}
+
+/**
+* This calculates the rule's exponent based on its radix and base
+* value. This will be the highest power the radix can be raised to
+* and still produce a result less than or equal to the base value.
+*/
+int16_t
+NFRule::expectedExponent() const
+{
+ // since the log of 0, or the log base 0 of something, causes an
+ // error, declare the exponent in these cases to be 0 (we also
+ // deal with the special-rule identifiers here)
+ if (radix == 0 || baseValue < 1) {
+ return 0;
+ }
+
+ // we get rounding error in some cases-- for example, log 1000 / log 10
+ // gives us 1.9999999996 instead of 2. The extra logic here is to take
+ // that into account
+ int16_t tempResult = (int16_t)(uprv_log((double)baseValue) / uprv_log((double)radix));
+ int64_t temp = util64_pow(radix, tempResult + 1);
+ if (temp <= baseValue) {
+ tempResult += 1;
+ }
+ return tempResult;
+}
+
+/**
+ * Searches the rule's rule text for any of the specified strings.
+ * @param strings An array of strings to search the rule's rule
+ * text for
+ * @return The index of the first match in the rule's rule text
+ * (i.e., the first substring in the rule's rule text that matches
+ * _any_ of the strings in "strings"). If none of the strings in
+ * "strings" is found in the rule's rule text, returns -1.
+ */
+int32_t
+NFRule::indexOfAny(const UChar* const strings[]) const
+{
+ int result = -1;
+ for (int i = 0; strings[i]; i++) {
+ int32_t pos = ruleText.indexOf(*strings[i]);
+ if (pos != -1 && (result == -1 || pos < result)) {
+ result = pos;
+ }
+ }
+ return result;
+}
+
+//-----------------------------------------------------------------------
+// boilerplate
+//-----------------------------------------------------------------------
+
+/**
+* Tests two rules for equality.
+* @param that The rule to compare this one against
+* @return True is the two rules are functionally equivalent
+*/
+UBool
+NFRule::operator==(const NFRule& rhs) const
+{
+ return baseValue == rhs.baseValue
+ && radix == rhs.radix
+ && exponent == rhs.exponent
+ && ruleText == rhs.ruleText
+ && *sub1 == *rhs.sub1
+ && *sub2 == *rhs.sub2;
+}
+
+/**
+* Returns a textual representation of the rule. This won't
+* necessarily be the same as the description that this rule
+* was created with, but it will produce the same result.
+* @return A textual description of the rule
+*/
+static void util_append64(UnicodeString& result, int64_t n)
+{
+ UChar buffer[256];
+ int32_t len = util64_tou(n, buffer, sizeof(buffer));
+ UnicodeString temp(buffer, len);
+ result.append(temp);
+}
+
+void
+NFRule::_appendRuleText(UnicodeString& result) const
+{
+ switch (getType()) {
+ case kNegativeNumberRule: result.append(gMinusX); break;
+ case kImproperFractionRule: result.append(gXDotX); break;
+ case kProperFractionRule: result.append(gZeroDotX); break;
+ case kMasterRule: result.append(gXDotZero); break;
+ default:
+ // for a normal rule, write out its base value, and if the radix is
+ // something other than 10, write out the radix (with the preceding
+ // slash, of course). Then calculate the expected exponent and if
+ // if isn't the same as the actual exponent, write an appropriate
+ // number of > signs. Finally, terminate the whole thing with
+ // a colon.
+ util_append64(result, baseValue);
+ if (radix != 10) {
+ result.append(gSlash);
+ util_append64(result, radix);
+ }
+ int numCarets = expectedExponent() - exponent;
+ for (int i = 0; i < numCarets; i++) {
+ result.append(gGreaterThan);
+ }
+ break;
+ }
+ result.append(gColon);
+ result.append(gSpace);
+
+ // if the rule text begins with a space, write an apostrophe
+ // (whitespace after the rule descriptor is ignored; the
+ // apostrophe is used to make the whitespace significant)
+ if (ruleText.startsWith(gSpace) && sub1->getPos() != 0) {
+ result.append(gTick);
+ }
+
+ // now, write the rule's rule text, inserting appropriate
+ // substitution tokens in the appropriate places
+ UnicodeString ruleTextCopy;
+ ruleTextCopy.setTo(ruleText);
+
+ UnicodeString temp;
+ sub2->toString(temp);
+ ruleTextCopy.insert(sub2->getPos(), temp);
+ sub1->toString(temp);
+ ruleTextCopy.insert(sub1->getPos(), temp);
+
+ result.append(ruleTextCopy);
+
+ // and finally, top the whole thing off with a semicolon and
+ // return the result
+ result.append(gSemicolon);
+}
+
+//-----------------------------------------------------------------------
+// formatting
+//-----------------------------------------------------------------------
+
+/**
+* Formats the number, and inserts the resulting text into
+* toInsertInto.
+* @param number The number being formatted
+* @param toInsertInto The string where the resultant text should
+* be inserted
+* @param pos The position in toInsertInto where the resultant text
+* should be inserted
+*/
+void
+NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos) const
+{
+ // first, insert the rule's rule text into toInsertInto at the
+ // specified position, then insert the results of the substitutions
+ // into the right places in toInsertInto (notice we do the
+ // substitutions in reverse order so that the offsets don't get
+ // messed up)
+ toInsertInto.insert(pos, ruleText);
+ sub2->doSubstitution(number, toInsertInto, pos);
+ sub1->doSubstitution(number, toInsertInto, pos);
+}
+
+/**
+* Formats the number, and inserts the resulting text into
+* toInsertInto.
+* @param number The number being formatted
+* @param toInsertInto The string where the resultant text should
+* be inserted
+* @param pos The position in toInsertInto where the resultant text
+* should be inserted
+*/
+void
+NFRule::doFormat(double number, UnicodeString& toInsertInto, int32_t pos) const
+{
+ // first, insert the rule's rule text into toInsertInto at the
+ // specified position, then insert the results of the substitutions
+ // into the right places in toInsertInto
+ // [again, we have two copies of this routine that do the same thing
+ // so that we don't sacrifice precision in a long by casting it
+ // to a double]
+ toInsertInto.insert(pos, ruleText);
+ sub2->doSubstitution(number, toInsertInto, pos);
+ sub1->doSubstitution(number, toInsertInto, pos);
+}
+
+/**
+* Used by the owning rule set to determine whether to invoke the
+* rollback rule (i.e., whether this rule or the one that precedes
+* it in the rule set's list should be used to format the number)
+* @param The number being formatted
+* @return True if the rule set should use the rule that precedes
+* this one in its list; false if it should use this rule
+*/
+UBool
+NFRule::shouldRollBack(double number) const
+{
+ // we roll back if the rule contains a modulus substitution,
+ // the number being formatted is an even multiple of the rule's
+ // divisor, and the rule's base value is NOT an even multiple
+ // of its divisor
+ // In other words, if the original description had
+ // 100: << hundred[ >>];
+ // that expands into
+ // 100: << hundred;
+ // 101: << hundred >>;
+ // internally. But when we're formatting 200, if we use the rule
+ // at 101, which would normally apply, we get "two hundred zero".
+ // To prevent this, we roll back and use the rule at 100 instead.
+ // This is the logic that makes this happen: the rule at 101 has
+ // a modulus substitution, its base value isn't an even multiple
+ // of 100, and the value we're trying to format _is_ an even
+ // multiple of 100. This is called the "rollback rule."
+ if ((sub1->isModulusSubstitution()) || (sub2->isModulusSubstitution())) {
+ int64_t re = util64_pow(radix, exponent);
+ return uprv_fmod(number, (double)re) == 0 && (baseValue % re) != 0;
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------
+// parsing
+//-----------------------------------------------------------------------
+
+/**
+* Attempts to parse the string with this rule.
+* @param text The string being parsed
+* @param parsePosition On entry, the value is ignored and assumed to
+* be 0. On exit, this has been updated with the position of the first
+* character not consumed by matching the text against this rule
+* (if this rule doesn't match the text at all, the parse position
+* if left unchanged (presumably at 0) and the function returns
+* new Long(0)).
+* @param isFractionRule True if this rule is contained within a
+* fraction rule set. This is only used if the rule has no
+* substitutions.
+* @return If this rule matched the text, this is the rule's base value
+* combined appropriately with the results of parsing the substitutions.
+* If nothing matched, this is new Long(0) and the parse position is
+* left unchanged. The result will be an instance of Long if the
+* result is an integer and Double otherwise. The result is never null.
+*/
+#ifdef RBNF_DEBUG
+#include <stdio.h>
+
+static void dumpUS(FILE* f, const UnicodeString& us) {
+ int len = us.length();
+ char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1];
+ us.extract(0, len, buf);
+ buf[len] = 0;
+ fprintf(f, "%s", buf);
+ uprv_free(buf); //delete[] buf;
+}
+#endif
+
+UBool
+NFRule::doParse(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ UBool isFractionRule,
+ double upperBound,
+ Formattable& resVal) const
+{
+ // internally we operate on a copy of the string being parsed
+ // (because we're going to change it) and use our own ParsePosition
+ ParsePosition pp;
+ UnicodeString workText(text);
+
+ // check to see whether the text before the first substitution
+ // matches the text at the beginning of the string being
+ // parsed. If it does, strip that off the front of workText;
+ // otherwise, dump out with a mismatch
+ UnicodeString prefix;
+ prefix.setTo(ruleText, 0, sub1->getPos());
+
+#ifdef RBNF_DEBUG
+ fprintf(stderr, "doParse %x ", this);
+ {
+ UnicodeString rt;
+ _appendRuleText(rt);
+ dumpUS(stderr, rt);
+ }
+
+ fprintf(stderr, " text: '", this);
+ dumpUS(stderr, text);
+ fprintf(stderr, "' prefix: '");
+ dumpUS(stderr, prefix);
+#endif
+ stripPrefix(workText, prefix, pp);
+ int32_t prefixLength = text.length() - workText.length();
+
+#ifdef RBNF_DEBUG
+ fprintf(stderr, "' pl: %d ppi: %d s1p: %d\n", prefixLength, pp.getIndex(), sub1->getPos());
+#endif
+
+ if (pp.getIndex() == 0 && sub1->getPos() != 0) {
+ // commented out because ParsePosition doesn't have error index in 1.1.x
+ // restored for ICU4C port
+ parsePosition.setErrorIndex(pp.getErrorIndex());
+ resVal.setLong(0);
+ return TRUE;
+ }
+
+ // this is the fun part. The basic guts of the rule-matching
+ // logic is matchToDelimiter(), which is called twice. The first
+ // time it searches the input string for the rule text BETWEEN
+ // the substitutions and tries to match the intervening text
+ // in the input string with the first substitution. If that
+ // succeeds, it then calls it again, this time to look for the
+ // rule text after the second substitution and to match the
+ // intervening input text against the second substitution.
+ //
+ // For example, say we have a rule that looks like this:
+ // first << middle >> last;
+ // and input text that looks like this:
+ // first one middle two last
+ // First we use stripPrefix() to match "first " in both places and
+ // strip it off the front, leaving
+ // one middle two last
+ // Then we use matchToDelimiter() to match " middle " and try to
+ // match "one" against a substitution. If it's successful, we now
+ // have
+ // two last
+ // We use matchToDelimiter() a second time to match " last" and
+ // try to match "two" against a substitution. If "two" matches
+ // the substitution, we have a successful parse.
+ //
+ // Since it's possible in many cases to find multiple instances
+ // of each of these pieces of rule text in the input string,
+ // we need to try all the possible combinations of these
+ // locations. This prevents us from prematurely declaring a mismatch,
+ // and makes sure we match as much input text as we can.
+ int highWaterMark = 0;
+ double result = 0;
+ int start = 0;
+ double tempBaseValue = (double)(baseValue <= 0 ? 0 : baseValue);
+
+ UnicodeString temp;
+ do {
+ // our partial parse result starts out as this rule's base
+ // value. If it finds a successful match, matchToDelimiter()
+ // will compose this in some way with what it gets back from
+ // the substitution, giving us a new partial parse result
+ pp.setIndex(0);
+
+ temp.setTo(ruleText, sub1->getPos(), sub2->getPos() - sub1->getPos());
+ double partialResult = matchToDelimiter(workText, start, tempBaseValue,
+ temp, pp, sub1,
+ upperBound);
+
+ // if we got a successful match (or were trying to match a
+ // null substitution), pp is now pointing at the first unmatched
+ // character. Take note of that, and try matchToDelimiter()
+ // on the input text again
+ if (pp.getIndex() != 0 || sub1->isNullSubstitution()) {
+ start = pp.getIndex();
+
+ UnicodeString workText2;
+ workText2.setTo(workText, pp.getIndex(), workText.length() - pp.getIndex());
+ ParsePosition pp2;
+
+ // the second matchToDelimiter() will compose our previous
+ // partial result with whatever it gets back from its
+ // substitution if there's a successful match, giving us
+ // a real result
+ temp.setTo(ruleText, sub2->getPos(), ruleText.length() - sub2->getPos());
+ partialResult = matchToDelimiter(workText2, 0, partialResult,
+ temp, pp2, sub2,
+ upperBound);
+
+ // if we got a successful match on this second
+ // matchToDelimiter() call, update the high-water mark
+ // and result (if necessary)
+ if (pp2.getIndex() != 0 || sub2->isNullSubstitution()) {
+ if (prefixLength + pp.getIndex() + pp2.getIndex() > highWaterMark) {
+ highWaterMark = prefixLength + pp.getIndex() + pp2.getIndex();
+ result = partialResult;
+ }
+ }
+ // commented out because ParsePosition doesn't have error index in 1.1.x
+ // restored for ICU4C port
+ else {
+ int32_t temp = pp2.getErrorIndex() + sub1->getPos() + pp.getIndex();
+ if (temp> parsePosition.getErrorIndex()) {
+ parsePosition.setErrorIndex(temp);
+ }
+ }
+ }
+ // commented out because ParsePosition doesn't have error index in 1.1.x
+ // restored for ICU4C port
+ else {
+ int32_t temp = sub1->getPos() + pp.getErrorIndex();
+ if (temp > parsePosition.getErrorIndex()) {
+ parsePosition.setErrorIndex(temp);
+ }
+ }
+ // keep trying to match things until the outer matchToDelimiter()
+ // call fails to make a match (each time, it picks up where it
+ // left off the previous time)
+ } while (sub1->getPos() != sub2->getPos()
+ && pp.getIndex() > 0
+ && pp.getIndex() < workText.length()
+ && pp.getIndex() != start);
+
+ // update the caller's ParsePosition with our high-water mark
+ // (i.e., it now points at the first character this function
+ // didn't match-- the ParsePosition is therefore unchanged if
+ // we didn't match anything)
+ parsePosition.setIndex(highWaterMark);
+ // commented out because ParsePosition doesn't have error index in 1.1.x
+ // restored for ICU4C port
+ if (highWaterMark > 0) {
+ parsePosition.setErrorIndex(0);
+ }
+
+ // this is a hack for one unusual condition: Normally, whether this
+ // rule belong to a fraction rule set or not is handled by its
+ // substitutions. But if that rule HAS NO substitutions, then
+ // we have to account for it here. By definition, if the matching
+ // rule in a fraction rule set has no substitutions, its numerator
+ // is 1, and so the result is the reciprocal of its base value.
+ if (isFractionRule &&
+ highWaterMark > 0 &&
+ sub1->isNullSubstitution()) {
+ result = 1 / result;
+ }
+
+ resVal.setDouble(result);
+ return TRUE; // ??? do we need to worry if it is a long or a double?
+}
+
+/**
+* This function is used by parse() to match the text being parsed
+* against a possible prefix string. This function
+* matches characters from the beginning of the string being parsed
+* to characters from the prospective prefix. If they match, pp is
+* updated to the first character not matched, and the result is
+* the unparsed part of the string. If they don't match, the whole
+* string is returned, and pp is left unchanged.
+* @param text The string being parsed
+* @param prefix The text to match against
+* @param pp On entry, ignored and assumed to be 0. On exit, points
+* to the first unmatched character (assuming the whole prefix matched),
+* or is unchanged (if the whole prefix didn't match).
+* @return If things match, this is the unparsed part of "text";
+* if they didn't match, this is "text".
+*/
+void
+NFRule::stripPrefix(UnicodeString& text, const UnicodeString& prefix, ParsePosition& pp) const
+{
+ // if the prefix text is empty, dump out without doing anything
+ if (prefix.length() != 0) {
+ // use prefixLength() to match the beginning of
+ // "text" against "prefix". This function returns the
+ // number of characters from "text" that matched (or 0 if
+ // we didn't match the whole prefix)
+ int32_t pfl = prefixLength(text, prefix);
+ if (pfl != 0) {
+ // if we got a successful match, update the parse position
+ // and strip the prefix off of "text"
+ pp.setIndex(pp.getIndex() + pfl);
+ text.remove(0, pfl);
+ }
+ }
+}
+
+/**
+* Used by parse() to match a substitution and any following text.
+* "text" is searched for instances of "delimiter". For each instance
+* of delimiter, the intervening text is tested to see whether it
+* matches the substitution. The longest match wins.
+* @param text The string being parsed
+* @param startPos The position in "text" where we should start looking
+* for "delimiter".
+* @param baseValue A partial parse result (often the rule's base value),
+* which is combined with the result from matching the substitution
+* @param delimiter The string to search "text" for.
+* @param pp Ignored and presumed to be 0 on entry. If there's a match,
+* on exit this will point to the first unmatched character.
+* @param sub If we find "delimiter" in "text", this substitution is used
+* to match the text between the beginning of the string and the
+* position of "delimiter." (If "delimiter" is the empty string, then
+* this function just matches against this substitution and updates
+* everything accordingly.)
+* @param upperBound When matching the substitution, it will only
+* consider rules with base values lower than this value.
+* @return If there's a match, this is the result of composing
+* baseValue with the result of matching the substitution. Otherwise,
+* this is new Long(0). It's never null. If the result is an integer,
+* this will be an instance of Long; otherwise, it's an instance of
+* Double.
+*
+* !!! note {dlf} in point of fact, in the java code the caller always converts
+* the result to a double, so we might as well return one.
+*/
+double
+NFRule::matchToDelimiter(const UnicodeString& text,
+ int32_t startPos,
+ double _baseValue,
+ const UnicodeString& delimiter,
+ ParsePosition& pp,
+ const NFSubstitution* sub,
+ double upperBound) const
+{
+ // if "delimiter" contains real (i.e., non-ignorable) text, search
+ // it for "delimiter" beginning at "start". If that succeeds, then
+ // use "sub"'s doParse() method to match the text before the
+ // instance of "delimiter" we just found.
+ if (!allIgnorable(delimiter)) {
+ ParsePosition tempPP;
+ Formattable result;
+
+ // use findText() to search for "delimiter". It returns a two-
+ // element array: element 0 is the position of the match, and
+ // element 1 is the number of characters that matched
+ // "delimiter".
+ int32_t dLen;
+ int32_t dPos = findText(text, delimiter, startPos, &dLen);
+
+ // if findText() succeeded, isolate the text preceding the
+ // match, and use "sub" to match that text
+ while (dPos >= 0) {
+ UnicodeString subText;
+ subText.setTo(text, 0, dPos);
+ if (subText.length() > 0) {
+ UBool success = sub->doParse(subText, tempPP, _baseValue, upperBound,
+#if UCONFIG_NO_COLLATION
+ FALSE,
+#else
+ formatter->isLenient(),
+#endif
+ result);
+
+ // if the substitution could match all the text up to
+ // where we found "delimiter", then this function has
+ // a successful match. Bump the caller's parse position
+ // to point to the first character after the text
+ // that matches "delimiter", and return the result
+ // we got from parsing the substitution.
+ if (success && tempPP.getIndex() == dPos) {
+ pp.setIndex(dPos + dLen);
+ return result.getDouble();
+ }
+ // commented out because ParsePosition doesn't have error index in 1.1.x
+ // restored for ICU4C port
+ else {
+ if (tempPP.getErrorIndex() > 0) {
+ pp.setErrorIndex(tempPP.getErrorIndex());
+ } else {
+ pp.setErrorIndex(tempPP.getIndex());
+ }
+ }
+ }
+
+ // if we didn't match the substitution, search for another
+ // copy of "delimiter" in "text" and repeat the loop if
+ // we find it
+ tempPP.setIndex(0);
+ dPos = findText(text, delimiter, dPos + dLen, &dLen);
+ }
+ // if we make it here, this was an unsuccessful match, and we
+ // leave pp unchanged and return 0
+ pp.setIndex(0);
+ return 0;
+
+ // if "delimiter" is empty, or consists only of ignorable characters
+ // (i.e., is semantically empty), thwe we obviously can't search
+ // for "delimiter". Instead, just use "sub" to parse as much of
+ // "text" as possible.
+ } else {
+ ParsePosition tempPP;
+ Formattable result;
+
+ // try to match the whole string against the substitution
+ UBool success = sub->doParse(text, tempPP, _baseValue, upperBound,
+#if UCONFIG_NO_COLLATION
+ FALSE,
+#else
+ formatter->isLenient(),
+#endif
+ result);
+ if (success && (tempPP.getIndex() != 0 || sub->isNullSubstitution())) {
+ // if there's a successful match (or it's a null
+ // substitution), update pp to point to the first
+ // character we didn't match, and pass the result from
+ // sub.doParse() on through to the caller
+ pp.setIndex(tempPP.getIndex());
+ return result.getDouble();
+ }
+ // commented out because ParsePosition doesn't have error index in 1.1.x
+ // restored for ICU4C port
+ else {
+ pp.setErrorIndex(tempPP.getErrorIndex());
+ }
+
+ // and if we get to here, then nothing matched, so we return
+ // 0 and leave pp alone
+ return 0;
+ }
+}
+
+/**
+* Used by stripPrefix() to match characters. If lenient parse mode
+* is off, this just calls startsWith(). If lenient parse mode is on,
+* this function uses CollationElementIterators to match characters in
+* the strings (only primary-order differences are significant in
+* determining whether there's a match).
+* @param str The string being tested
+* @param prefix The text we're hoping to see at the beginning
+* of "str"
+* @return If "prefix" is found at the beginning of "str", this
+* is the number of characters in "str" that were matched (this
+* isn't necessarily the same as the length of "prefix" when matching
+* text with a collator). If there's no match, this is 0.
+*/
+int32_t
+NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix) const
+{
+ // if we're looking for an empty prefix, it obviously matches
+ // zero characters. Just go ahead and return 0.
+ if (prefix.length() == 0) {
+ return 0;
+ }
+
+#if !UCONFIG_NO_COLLATION
+ // go through all this grief if we're in lenient-parse mode
+ if (formatter->isLenient()) {
+ // get the formatter's collator and use it to create two
+ // collation element iterators, one over the target string
+ // and another over the prefix (right now, we'll throw an
+ // exception if the collator we get back from the formatter
+ // isn't a RuleBasedCollator, because RuleBasedCollator defines
+ // the CollationElementIterator protocol. Hopefully, this
+ // will change someday.)
+ RuleBasedCollator* collator = (RuleBasedCollator*)formatter->getCollator();
+ CollationElementIterator* strIter = collator->createCollationElementIterator(str);
+ CollationElementIterator* prefixIter = collator->createCollationElementIterator(prefix);
+
+ UErrorCode err = U_ZERO_ERROR;
+
+ // The original code was problematic. Consider this match:
+ // prefix = "fifty-"
+ // string = " fifty-7"
+ // The intent is to match string up to the '7', by matching 'fifty-' at position 1
+ // in the string. Unfortunately, we were getting a match, and then computing where
+ // the match terminated by rematching the string. The rematch code was using as an
+ // initial guess the substring of string between 0 and prefix.length. Because of
+ // the leading space and trailing hyphen (both ignorable) this was succeeding, leaving
+ // the position before the hyphen in the string. Recursing down, we then parsed the
+ // remaining string '-7' as numeric. The resulting number turned out as 43 (50 - 7).
+ // This was not pretty, especially since the string "fifty-7" parsed just fine.
+ //
+ // We have newer APIs now, so we can use calls on the iterator to determine what we
+ // matched up to. If we terminate because we hit the last element in the string,
+ // our match terminates at this length. If we terminate because we hit the last element
+ // in the target, our match terminates at one before the element iterator position.
+
+ // match collation elements between the strings
+ int32_t oStr = strIter->next(err);
+ int32_t oPrefix = prefixIter->next(err);
+
+ while (oPrefix != CollationElementIterator::NULLORDER) {
+ // skip over ignorable characters in the target string
+ while (CollationElementIterator::primaryOrder(oStr) == 0
+ && oStr != CollationElementIterator::NULLORDER) {
+ oStr = strIter->next(err);
+ }
+
+ // skip over ignorable characters in the prefix
+ while (CollationElementIterator::primaryOrder(oPrefix) == 0
+ && oPrefix != CollationElementIterator::NULLORDER) {
+ oPrefix = prefixIter->next(err);
+ }
+
+ // dlf: move this above following test, if we consume the
+ // entire target, aren't we ok even if the source was also
+ // entirely consumed?
+
+ // if skipping over ignorables brought to the end of
+ // the prefix, we DID match: drop out of the loop
+ if (oPrefix == CollationElementIterator::NULLORDER) {
+ break;
+ }
+
+ // if skipping over ignorables brought us to the end
+ // of the target string, we didn't match and return 0
+ if (oStr == CollationElementIterator::NULLORDER) {
+ delete prefixIter;
+ delete strIter;
+ return 0;
+ }
+
+ // match collation elements from the two strings
+ // (considering only primary differences). If we
+ // get a mismatch, dump out and return 0
+ if (CollationElementIterator::primaryOrder(oStr)
+ != CollationElementIterator::primaryOrder(oPrefix)) {
+ delete prefixIter;
+ delete strIter;
+ return 0;
+
+ // otherwise, advance to the next character in each string
+ // and loop (we drop out of the loop when we exhaust
+ // collation elements in the prefix)
+ } else {
+ oStr = strIter->next(err);
+ oPrefix = prefixIter->next(err);
+ }
+ }
+
+ int32_t result = strIter->getOffset();
+ if (oStr != CollationElementIterator::NULLORDER) {
+ --result; // back over character that we don't want to consume;
+ }
+
+#ifdef RBNF_DEBUG
+ fprintf(stderr, "prefix length: %d\n", result);
+#endif
+ delete prefixIter;
+ delete strIter;
+
+ return result;
+#if 0
+ //----------------------------------------------------------------
+ // JDK 1.2-specific API call
+ // return strIter.getOffset();
+ //----------------------------------------------------------------
+ // JDK 1.1 HACK (take out for 1.2-specific code)
+
+ // if we make it to here, we have a successful match. Now we
+ // have to find out HOW MANY characters from the target string
+ // matched the prefix (there isn't necessarily a one-to-one
+ // mapping between collation elements and characters).
+ // In JDK 1.2, there's a simple getOffset() call we can use.
+ // In JDK 1.1, on the other hand, we have to go through some
+ // ugly contortions. First, use the collator to compare the
+ // same number of characters from the prefix and target string.
+ // If they're equal, we're done.
+ collator->setStrength(Collator::PRIMARY);
+ if (str.length() >= prefix.length()) {
+ UnicodeString temp;
+ temp.setTo(str, 0, prefix.length());
+ if (collator->equals(temp, prefix)) {
+#ifdef RBNF_DEBUG
+ fprintf(stderr, "returning: %d\n", prefix.length());
+#endif
+ return prefix.length();
+ }
+ }
+
+ // if they're not equal, then we have to compare successively
+ // larger and larger substrings of the target string until we
+ // get to one that matches the prefix. At that point, we know
+ // how many characters matched the prefix, and we can return.
+ int32_t p = 1;
+ while (p <= str.length()) {
+ UnicodeString temp;
+ temp.setTo(str, 0, p);
+ if (collator->equals(temp, prefix)) {
+ return p;
+ } else {
+ ++p;
+ }
+ }
+
+ // SHOULD NEVER GET HERE!!!
+ return 0;
+ //----------------------------------------------------------------
+#endif
+
+ // If lenient parsing is turned off, forget all that crap above.
+ // Just use String.startsWith() and be done with it.
+ } else
+#endif
+ {
+ if (str.startsWith(prefix)) {
+ return prefix.length();
+ } else {
+ return 0;
+ }
+ }
+}
+
+/**
+* Searches a string for another string. If lenient parsing is off,
+* this just calls indexOf(). If lenient parsing is on, this function
+* uses CollationElementIterator to match characters, and only
+* primary-order differences are significant in determining whether
+* there's a match.
+* @param str The string to search
+* @param key The string to search "str" for
+* @param startingAt The index into "str" where the search is to
+* begin
+* @return A two-element array of ints. Element 0 is the position
+* of the match, or -1 if there was no match. Element 1 is the
+* number of characters in "str" that matched (which isn't necessarily
+* the same as the length of "key")
+*/
+int32_t
+NFRule::findText(const UnicodeString& str,
+ const UnicodeString& key,
+ int32_t startingAt,
+ int32_t* length) const
+{
+#if !UCONFIG_NO_COLLATION
+ // if lenient parsing is turned off, this is easy: just call
+ // String.indexOf() and we're done
+ if (!formatter->isLenient()) {
+ *length = key.length();
+ return str.indexOf(key, startingAt);
+
+ // but if lenient parsing is turned ON, we've got some work
+ // ahead of us
+ } else
+#endif
+ {
+ //----------------------------------------------------------------
+ // JDK 1.1 HACK (take out of 1.2-specific code)
+
+ // in JDK 1.2, CollationElementIterator provides us with an
+ // API to map between character offsets and collation elements
+ // and we can do this by marching through the string comparing
+ // collation elements. We can't do that in JDK 1.1. Insted,
+ // we have to go through this horrible slow mess:
+ int32_t p = startingAt;
+ int32_t keyLen = 0;
+
+ // basically just isolate smaller and smaller substrings of
+ // the target string (each running to the end of the string,
+ // and with the first one running from startingAt to the end)
+ // and then use prefixLength() to see if the search key is at
+ // the beginning of each substring. This is excruciatingly
+ // slow, but it will locate the key and tell use how long the
+ // matching text was.
+ UnicodeString temp;
+ while (p < str.length() && keyLen == 0) {
+ temp.setTo(str, p, str.length() - p);
+ keyLen = prefixLength(temp, key);
+ if (keyLen != 0) {
+ *length = keyLen;
+ return p;
+ }
+ ++p;
+ }
+ // if we make it to here, we didn't find it. Return -1 for the
+ // location. The length should be ignored, but set it to 0,
+ // which should be "safe"
+ *length = 0;
+ return -1;
+
+ //----------------------------------------------------------------
+ // JDK 1.2 version of this routine
+ //RuleBasedCollator collator = (RuleBasedCollator)formatter.getCollator();
+ //
+ //CollationElementIterator strIter = collator.getCollationElementIterator(str);
+ //CollationElementIterator keyIter = collator.getCollationElementIterator(key);
+ //
+ //int keyStart = -1;
+ //
+ //str.setOffset(startingAt);
+ //
+ //int oStr = strIter.next();
+ //int oKey = keyIter.next();
+ //while (oKey != CollationElementIterator.NULLORDER) {
+ // while (oStr != CollationElementIterator.NULLORDER &&
+ // CollationElementIterator.primaryOrder(oStr) == 0)
+ // oStr = strIter.next();
+ //
+ // while (oKey != CollationElementIterator.NULLORDER &&
+ // CollationElementIterator.primaryOrder(oKey) == 0)
+ // oKey = keyIter.next();
+ //
+ // if (oStr == CollationElementIterator.NULLORDER) {
+ // return new int[] { -1, 0 };
+ // }
+ //
+ // if (oKey == CollationElementIterator.NULLORDER) {
+ // break;
+ // }
+ //
+ // if (CollationElementIterator.primaryOrder(oStr) ==
+ // CollationElementIterator.primaryOrder(oKey)) {
+ // keyStart = strIter.getOffset();
+ // oStr = strIter.next();
+ // oKey = keyIter.next();
+ // } else {
+ // if (keyStart != -1) {
+ // keyStart = -1;
+ // keyIter.reset();
+ // } else {
+ // oStr = strIter.next();
+ // }
+ // }
+ //}
+ //
+ //if (oKey == CollationElementIterator.NULLORDER) {
+ // return new int[] { keyStart, strIter.getOffset() - keyStart };
+ //} else {
+ // return new int[] { -1, 0 };
+ //}
+ }
+}
+
+/**
+* Checks to see whether a string consists entirely of ignorable
+* characters.
+* @param str The string to test.
+* @return true if the string is empty of consists entirely of
+* characters that the number formatter's collator says are
+* ignorable at the primary-order level. false otherwise.
+*/
+UBool
+NFRule::allIgnorable(const UnicodeString& str) const
+{
+ // if the string is empty, we can just return true
+ if (str.length() == 0) {
+ return TRUE;
+ }
+
+#if !UCONFIG_NO_COLLATION
+ // if lenient parsing is turned on, walk through the string with
+ // a collation element iterator and make sure each collation
+ // element is 0 (ignorable) at the primary level
+ if (formatter->isLenient()) {
+ RuleBasedCollator* collator = (RuleBasedCollator*)(formatter->getCollator());
+ CollationElementIterator* iter = collator->createCollationElementIterator(str);
+
+ UErrorCode err = U_ZERO_ERROR;
+ int32_t o = iter->next(err);
+ while (o != CollationElementIterator::NULLORDER
+ && CollationElementIterator::primaryOrder(o) == 0) {
+ o = iter->next(err);
+ }
+
+ delete iter;
+ return o == CollationElementIterator::NULLORDER;
+ }
+#endif
+
+ // if lenient parsing is turned off, there is no such thing as
+ // an ignorable character: return true only if the string is empty
+ return FALSE;
+}
+
+U_NAMESPACE_END
+
+/* U_HAVE_RBNF */
+#endif
+
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nfrule.h b/Build/source/libs/icu/icu-xetex/i18n/nfrule.h
new file mode 100644
index 00000000000..73e4fe16ef8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nfrule.h
@@ -0,0 +1,114 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#ifndef NFRULE_H
+#define NFRULE_H
+
+#include "unicode/rbnf.h"
+
+#if U_HAVE_RBNF
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "putilimp.h"
+
+U_NAMESPACE_BEGIN
+
+class FieldPosition;
+class Formattable;
+class NFRuleList;
+class NFRuleSet;
+class NFSubstitution;
+class ParsePosition;
+class RuleBasedNumberFormat;
+class UnicodeString;
+
+class NFRule : public UMemory {
+public:
+
+ enum ERuleType {
+ kNoBase = 0,
+ kNegativeNumberRule = -1,
+ kImproperFractionRule = -2,
+ kProperFractionRule = -3,
+ kMasterRule = -4,
+ kOtherRule = -5
+ };
+
+ static void makeRules(UnicodeString& definition,
+ const NFRuleSet* ruleSet,
+ const NFRule* predecessor,
+ const RuleBasedNumberFormat* rbnf,
+ NFRuleList& ruleList,
+ UErrorCode& status);
+
+ NFRule(const RuleBasedNumberFormat* rbnf);
+ ~NFRule();
+
+ UBool operator==(const NFRule& rhs) const;
+ UBool operator!=(const NFRule& rhs) const { return !operator==(rhs); }
+
+ ERuleType getType() const { return (ERuleType)(baseValue <= kNoBase ? (ERuleType)baseValue : kOtherRule); }
+ void setType(ERuleType ruleType) { baseValue = (int32_t)ruleType; }
+
+ int64_t getBaseValue() const { return baseValue; }
+ void setBaseValue(int64_t value, UErrorCode& status);
+
+ double getDivisor() const { return uprv_pow(radix, exponent); }
+
+ void doFormat(int64_t number, UnicodeString& toAppendTo, int32_t pos) const;
+ void doFormat(double number, UnicodeString& toAppendTo, int32_t pos) const;
+
+ UBool doParse(const UnicodeString& text,
+ ParsePosition& pos,
+ UBool isFractional,
+ double upperBound,
+ Formattable& result) const;
+
+ UBool shouldRollBack(double number) const;
+
+ void _appendRuleText(UnicodeString& result) const;
+
+private:
+ void parseRuleDescriptor(UnicodeString& descriptor, UErrorCode& status);
+ void extractSubstitutions(const NFRuleSet* ruleSet, const NFRule* predecessor, const RuleBasedNumberFormat* rbnf, UErrorCode& status);
+ NFSubstitution* extractSubstitution(const NFRuleSet* ruleSet, const NFRule* predecessor, const RuleBasedNumberFormat* rbnf, UErrorCode& status);
+
+ int16_t expectedExponent() const;
+ int32_t indexOfAny(const UChar* const strings[]) const;
+ double matchToDelimiter(const UnicodeString& text, int32_t startPos, double baseValue,
+ const UnicodeString& delimiter, ParsePosition& pp, const NFSubstitution* sub,
+ double upperBound) const;
+ void stripPrefix(UnicodeString& text, const UnicodeString& prefix, ParsePosition& pp) const;
+
+ int32_t prefixLength(const UnicodeString& str, const UnicodeString& prefix) const;
+ UBool allIgnorable(const UnicodeString& str) const;
+ int32_t findText(const UnicodeString& str, const UnicodeString& key,
+ int32_t startingAt, int32_t* resultCount) const;
+
+private:
+ int64_t baseValue;
+ int32_t radix;
+ int16_t exponent;
+ UnicodeString ruleText;
+ NFSubstitution* sub1;
+ NFSubstitution* sub2;
+ const RuleBasedNumberFormat* formatter;
+
+ NFRule(const NFRule &other); // forbid copying of this class
+ NFRule &operator=(const NFRule &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+
+/* U_HAVE_RBNF */
+#endif
+
+// NFRULE_H
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nfsubs.cpp b/Build/source/libs/icu/icu-xetex/i18n/nfsubs.cpp
new file mode 100644
index 00000000000..37de55a4a1c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nfsubs.cpp
@@ -0,0 +1,1319 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: nfsubs.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 10/11/2001 Doug Ported from ICU4J
+*/
+
+#include "nfsubs.h"
+#include "digitlst.h"
+
+#include <stdio.h>
+
+#if U_HAVE_RBNF
+
+static const UChar gLessThan = 0x003c;
+static const UChar gEquals = 0x003d;
+static const UChar gGreaterThan = 0x003e;
+static const UChar gPercent = 0x0025;
+static const UChar gPound = 0x0023;
+static const UChar gZero = 0x0030;
+static const UChar gSpace = 0x0020;
+
+static const UChar gEqualsEquals[] =
+{
+ 0x3D, 0x3D, 0
+}; /* "==" */
+static const UChar gGreaterGreaterGreaterThan[] =
+{
+ 0x3E, 0x3E, 0x3E, 0
+}; /* ">>>" */
+static const UChar gGreaterGreaterThan[] =
+{
+ 0x3E, 0x3E, 0
+}; /* ">>" */
+
+U_NAMESPACE_BEGIN
+
+class SameValueSubstitution : public NFSubstitution {
+public:
+ SameValueSubstitution(int32_t pos,
+ const NFRuleSet* ruleset,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status);
+
+ virtual int64_t transformNumber(int64_t number) const { return number; }
+ virtual double transformNumber(double number) const { return number; }
+ virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return newRuleValue; }
+ virtual double calcUpperBound(double oldUpperBound) const { return oldUpperBound; }
+ virtual UChar tokenChar() const { return (UChar)0x003d; } // '='
+
+public:
+ static UClassID getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+class MultiplierSubstitution : public NFSubstitution {
+ double divisor;
+ int64_t ldivisor;
+
+public:
+ MultiplierSubstitution(int32_t _pos,
+ double _divisor,
+ const NFRuleSet* _ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+ : NFSubstitution(_pos, _ruleSet, formatter, description, status), divisor(_divisor)
+ {
+ ldivisor = util64_fromDouble(divisor);
+ if (divisor == 0) {
+ status = U_PARSE_ERROR;
+ }
+ }
+
+ virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) {
+ divisor = uprv_pow(radix, exponent);
+ ldivisor = util64_fromDouble(divisor);
+
+ if(divisor == 0) {
+ status = U_PARSE_ERROR;
+ }
+ }
+
+ virtual UBool operator==(const NFSubstitution& rhs) const;
+
+ virtual int64_t transformNumber(int64_t number) const {
+ return number / ldivisor;
+ }
+
+ virtual double transformNumber(double number) const {
+ if (getRuleSet()) {
+ return uprv_floor(number / divisor);
+ } else {
+ return number/divisor;
+ }
+ }
+
+ virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const {
+ return newRuleValue * divisor;
+ }
+
+ virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; }
+
+ virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
+
+public:
+ static UClassID getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+class ModulusSubstitution : public NFSubstitution {
+ double divisor;
+ int64_t ldivisor;
+ const NFRule* ruleToUse;
+public:
+ ModulusSubstitution(int32_t pos,
+ double _divisor,
+ const NFRule* rulePredecessor,
+ const NFRuleSet* ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status);
+
+ virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) {
+ divisor = uprv_pow(radix, exponent);
+ ldivisor = util64_fromDouble(divisor);
+
+ if (divisor == 0) {
+ status = U_PARSE_ERROR;
+ }
+ }
+
+ virtual UBool operator==(const NFSubstitution& rhs) const;
+
+ virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos) const;
+ virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
+
+ virtual int64_t transformNumber(int64_t number) const { return number % ldivisor; }
+ virtual double transformNumber(double number) const { return uprv_fmod(number, divisor); }
+
+ virtual UBool doParse(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ double baseValue,
+ double upperBound,
+ UBool lenientParse,
+ Formattable& result) const;
+
+ virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const {
+ return oldRuleValue - uprv_fmod(oldRuleValue, divisor) + newRuleValue;
+ }
+
+ virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; }
+
+ virtual UBool isModulusSubstitution() const { return TRUE; }
+
+ virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
+
+public:
+ static UClassID getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+class IntegralPartSubstitution : public NFSubstitution {
+public:
+ IntegralPartSubstitution(int32_t _pos,
+ const NFRuleSet* _ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+ : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
+
+ virtual int64_t transformNumber(int64_t number) const { return number; }
+ virtual double transformNumber(double number) const { return uprv_floor(number); }
+ virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; }
+ virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; }
+ virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
+
+public:
+ static UClassID getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+class FractionalPartSubstitution : public NFSubstitution {
+ UBool byDigits;
+ UBool useSpaces;
+ enum { kMaxDecimalDigits = 8 };
+public:
+ FractionalPartSubstitution(int32_t pos,
+ const NFRuleSet* ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status);
+
+ virtual UBool operator==(const NFSubstitution& rhs) const;
+
+ virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
+ virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
+ virtual int64_t transformNumber(int64_t /*number*/) const { return 0; }
+ virtual double transformNumber(double number) const { return number - uprv_floor(number); }
+
+ virtual UBool doParse(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ double baseValue,
+ double upperBound,
+ UBool lenientParse,
+ Formattable& result) const;
+
+ virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; }
+ virtual double calcUpperBound(double /*oldUpperBound*/) const { return 0.0; }
+ virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
+
+public:
+ static UClassID getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+class AbsoluteValueSubstitution : public NFSubstitution {
+public:
+ AbsoluteValueSubstitution(int32_t _pos,
+ const NFRuleSet* _ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+ : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
+
+ virtual int64_t transformNumber(int64_t number) const { return number >= 0 ? number : -number; }
+ virtual double transformNumber(double number) const { return uprv_fabs(number); }
+ virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return -newRuleValue; }
+ virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; }
+ virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
+
+public:
+ static UClassID getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+class NumeratorSubstitution : public NFSubstitution {
+ double denominator;
+ int64_t ldenominator;
+ UBool withZeros;
+public:
+ static inline UnicodeString fixdesc(const UnicodeString& desc) {
+ if (desc.endsWith(LTLT, 2)) {
+ UnicodeString result(desc, 0, desc.length()-1);
+ return result;
+ }
+ return desc;
+ }
+ NumeratorSubstitution(int32_t _pos,
+ double _denominator,
+ const NFRuleSet* _ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+ : NFSubstitution(_pos, _ruleSet, formatter, fixdesc(description), status), denominator(_denominator)
+ {
+ ldenominator = util64_fromDouble(denominator);
+ withZeros = description.endsWith(LTLT, 2);
+ }
+
+ virtual UBool operator==(const NFSubstitution& rhs) const;
+
+ virtual int64_t transformNumber(int64_t number) const { return number * ldenominator; }
+ virtual double transformNumber(double number) const { return uprv_round(number * denominator); }
+
+ virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
+ virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
+ virtual UBool doParse(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ double baseValue,
+ double upperBound,
+ UBool /*lenientParse*/,
+ Formattable& result) const;
+
+ virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue / oldRuleValue; }
+ virtual double calcUpperBound(double /*oldUpperBound*/) const { return denominator; }
+ virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
+private:
+ static const UChar LTLT[2];
+
+public:
+ static UClassID getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+class NullSubstitution : public NFSubstitution {
+public:
+ NullSubstitution(int32_t _pos,
+ const NFRuleSet* _ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+ : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
+
+ virtual void toString(UnicodeString& /*result*/) const {}
+ virtual void doSubstitution(double /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
+ virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
+ virtual int64_t transformNumber(int64_t /*number*/) const { return 0; }
+ virtual double transformNumber(double /*number*/) const { return 0; }
+ virtual UBool doParse(const UnicodeString& /*text*/,
+ ParsePosition& /*parsePosition*/,
+ double baseValue,
+ double /*upperBound*/,
+ UBool /*lenientParse*/,
+ Formattable& result) const
+ { result.setDouble(baseValue); return TRUE; }
+ virtual double composeRuleValue(double /*newRuleValue*/, double /*oldRuleValue*/) const { return 0.0; } // never called
+ virtual double calcUpperBound(double /*oldUpperBound*/) const { return 0; } // never called
+ virtual UBool isNullSubstitution() const { return TRUE; }
+ virtual UChar tokenChar() const { return (UChar)0x0020; } // ' ' never called
+
+public:
+ static UClassID getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+NFSubstitution*
+NFSubstitution::makeSubstitution(int32_t pos,
+ const NFRule* rule,
+ const NFRule* predecessor,
+ const NFRuleSet* ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+{
+ // if the description is empty, return a NullSubstitution
+ if (description.length() == 0) {
+ return new NullSubstitution(pos, ruleSet, formatter, description, status);
+ }
+
+ switch (description.charAt(0)) {
+ // if the description begins with '<'...
+ case gLessThan:
+ // throw an exception if the rule is a negative number
+ // rule
+ if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
+ // throw new IllegalArgumentException("<< not allowed in negative-number rule");
+ status = U_PARSE_ERROR;
+ return NULL;
+ }
+
+ // if the rule is a fraction rule, return an
+ // IntegralPartSubstitution
+ else if (rule->getBaseValue() == NFRule::kImproperFractionRule
+ || rule->getBaseValue() == NFRule::kProperFractionRule
+ || rule->getBaseValue() == NFRule::kMasterRule) {
+ return new IntegralPartSubstitution(pos, ruleSet, formatter, description, status);
+ }
+
+ // if the rule set containing the rule is a fraction
+ // rule set, return a NumeratorSubstitution
+ else if (ruleSet->isFractionRuleSet()) {
+ return new NumeratorSubstitution(pos, (double)rule->getBaseValue(),
+ formatter->getDefaultRuleSet(), formatter, description, status);
+ }
+
+ // otherwise, return a MultiplierSubstitution
+ else {
+ return new MultiplierSubstitution(pos, rule->getDivisor(), ruleSet,
+ formatter, description, status);
+ }
+
+ // if the description begins with '>'...
+ case gGreaterThan:
+ // if the rule is a negative-number rule, return
+ // an AbsoluteValueSubstitution
+ if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
+ return new AbsoluteValueSubstitution(pos, ruleSet, formatter, description, status);
+ }
+
+ // if the rule is a fraction rule, return a
+ // FractionalPartSubstitution
+ else if (rule->getBaseValue() == NFRule::kImproperFractionRule
+ || rule->getBaseValue() == NFRule::kProperFractionRule
+ || rule->getBaseValue() == NFRule::kMasterRule) {
+ return new FractionalPartSubstitution(pos, ruleSet, formatter, description, status);
+ }
+
+ // if the rule set owning the rule is a fraction rule set,
+ // throw an exception
+ else if (ruleSet->isFractionRuleSet()) {
+ // throw new IllegalArgumentException(">> not allowed in fraction rule set");
+ status = U_PARSE_ERROR;
+ return NULL;
+ }
+
+ // otherwise, return a ModulusSubstitution
+ else {
+ return new ModulusSubstitution(pos, rule->getDivisor(), predecessor,
+ ruleSet, formatter, description, status);
+ }
+
+ // if the description begins with '=', always return a
+ // SameValueSubstitution
+ case gEquals:
+ return new SameValueSubstitution(pos, ruleSet, formatter, description, status);
+
+ // and if it's anything else, throw an exception
+ default:
+ // throw new IllegalArgumentException("Illegal substitution character");
+ status = U_PARSE_ERROR;
+ }
+ return NULL;
+}
+
+NFSubstitution::NFSubstitution(int32_t _pos,
+ const NFRuleSet* _ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+ : pos(_pos), ruleSet(NULL), numberFormat(NULL)
+{
+ // the description should begin and end with the same character.
+ // If it doesn't that's a syntax error. Otherwise,
+ // makeSubstitution() was the only thing that needed to know
+ // about these characters, so strip them off
+ UnicodeString workingDescription(description);
+ if (description.length() >= 2
+ && description.charAt(0) == description.charAt(description.length() - 1))
+ {
+ workingDescription.remove(description.length() - 1, 1);
+ workingDescription.remove(0, 1);
+ }
+ else if (description.length() != 0) {
+ // throw new IllegalArgumentException("Illegal substitution syntax");
+ status = U_PARSE_ERROR;
+ return;
+ }
+
+ // if the description was just two paired token characters
+ // (i.e., "<<" or ">>"), it uses the rule set it belongs to to
+ // format its result
+ if (workingDescription.length() == 0) {
+ this->ruleSet = _ruleSet;
+ }
+ // if the description contains a rule set name, that's the rule
+ // set we use to format the result: get a reference to the
+ // names rule set
+ else if (workingDescription.charAt(0) == gPercent) {
+ this->ruleSet = formatter->findRuleSet(workingDescription, status);
+ }
+ // if the description begins with 0 or #, treat it as a
+ // DecimalFormat pattern, and initialize a DecimalFormat with
+ // that pattern (then set it to use the DecimalFormatSymbols
+ // belonging to our formatter)
+ else if (workingDescription.charAt(0) == gPound || workingDescription.charAt(0) ==gZero) {
+ DecimalFormatSymbols* sym = formatter->getDecimalFormatSymbols();
+ if (!sym) {
+ status = U_MISSING_RESOURCE_ERROR;
+ return;
+ }
+ this->numberFormat = new DecimalFormat(workingDescription, *sym, status);
+ /* test for NULL */
+ if (this->numberFormat == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (U_FAILURE(status)) {
+ delete (DecimalFormat*)this->numberFormat;
+ this->numberFormat = NULL;
+ return;
+ }
+ // this->numberFormat->setDecimalFormatSymbols(formatter->getDecimalFormatSymbols());
+ }
+ // if the description is ">>>", this substitution bypasses the
+ // usual rule-search process and always uses the rule that precedes
+ // it in its own rule set's rule list (this is used for place-value
+ // notations: formats where you want to see a particular part of
+ // a number even when it's 0)
+ else if (workingDescription.charAt(0) == gGreaterThan) {
+ // this causes problems when >>> is used in a frationalPartSubstitution
+ // this->ruleSet = NULL;
+ this->ruleSet = _ruleSet;
+ this->numberFormat = NULL;
+ }
+ // and of the description is none of these things, it's a syntax error
+ else {
+ // throw new IllegalArgumentException("Illegal substitution syntax");
+ status = U_PARSE_ERROR;
+ }
+}
+
+NFSubstitution::~NFSubstitution()
+{
+ // cast away const
+ delete (NumberFormat*)numberFormat; numberFormat = NULL;
+}
+
+/**
+ * Set's the substitution's divisor. Used by NFRule.setBaseValue().
+ * A no-op for all substitutions except multiplier and modulus
+ * substitutions.
+ * @param radix The radix of the divisor
+ * @param exponent The exponent of the divisor
+ */
+void
+NFSubstitution::setDivisor(int32_t /*radix*/, int32_t /*exponent*/, UErrorCode& /*status*/) {
+ // a no-op for all substitutions except multiplier and modulus substitutions
+}
+
+
+//-----------------------------------------------------------------------
+// boilerplate
+//-----------------------------------------------------------------------
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NFSubstitution)
+
+/**
+ * Compares two substitutions for equality
+ * @param The substitution to compare this one to
+ * @return true if the two substitutions are functionally equivalent
+ */
+UBool
+NFSubstitution::operator==(const NFSubstitution& rhs) const
+{
+ // compare class and all of the fields all substitutions have
+ // in common
+ // this should be called by subclasses before their own equality tests
+ return getDynamicClassID() == rhs.getDynamicClassID()
+ && pos == rhs.pos
+ && (ruleSet == NULL) == (rhs.ruleSet == NULL)
+ // && ruleSet == rhs.ruleSet causes circularity, other checks to make instead?
+ && (numberFormat == NULL
+ ? (rhs.numberFormat == NULL)
+ : (*numberFormat == *rhs.numberFormat));
+}
+
+/**
+ * Returns a textual description of the substitution
+ * @return A textual description of the substitution. This might
+ * not be identical to the description it was created from, but
+ * it'll produce the same result.
+ */
+void
+NFSubstitution::toString(UnicodeString& text) const
+{
+ // use tokenChar() to get the character at the beginning and
+ // end of the substitutin token. In between them will go
+ // either the name of the rule set it uses, or the pattern of
+ // the DecimalFormat it uses
+ text.remove();
+ text.append(tokenChar());
+
+ UnicodeString temp;
+ if (ruleSet != NULL) {
+ ruleSet->getName(temp);
+ } else if (numberFormat != NULL) {
+ numberFormat->toPattern(temp);
+ }
+ text.append(temp);
+ text.append(tokenChar());
+}
+
+//-----------------------------------------------------------------------
+// formatting
+//-----------------------------------------------------------------------
+
+/**
+ * Performs a mathematical operation on the number, formats it using
+ * either ruleSet or decimalFormat, and inserts the result into
+ * toInsertInto.
+ * @param number The number being formatted.
+ * @param toInsertInto The string we insert the result into
+ * @param pos The position in toInsertInto where the owning rule's
+ * rule text begins (this value is added to this substitution's
+ * position to determine exactly where to insert the new text)
+ */
+void
+NFSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const
+{
+ if (ruleSet != NULL) {
+ // perform a transformation on the number that is dependent
+ // on the type of substitution this is, then just call its
+ // rule set's format() method to format the result
+ ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos);
+ } else if (numberFormat != NULL) {
+ // or perform the transformation on the number (preserving
+ // the result's fractional part if the formatter it set
+ // to show it), then use that formatter's format() method
+ // to format the result
+ double numberToFormat = transformNumber((double)number);
+ if (numberFormat->getMaximumFractionDigits() == 0) {
+ numberToFormat = uprv_floor(numberToFormat);
+ }
+
+ UnicodeString temp;
+ numberFormat->format(numberToFormat, temp);
+ toInsertInto.insert(_pos + this->pos, temp);
+ }
+}
+
+/**
+ * Performs a mathematical operation on the number, formats it using
+ * either ruleSet or decimalFormat, and inserts the result into
+ * toInsertInto.
+ * @param number The number being formatted.
+ * @param toInsertInto The string we insert the result into
+ * @param pos The position in toInsertInto where the owning rule's
+ * rule text begins (this value is added to this substitution's
+ * position to determine exactly where to insert the new text)
+ */
+void
+NFSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const {
+ // perform a transformation on the number being formatted that
+ // is dependent on the type of substitution this is
+ double numberToFormat = transformNumber(number);
+
+ // if the result is an integer, from here on out we work in integer
+ // space (saving time and memory and preserving accuracy)
+ if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL) {
+ ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos);
+
+ // if the result isn't an integer, then call either our rule set's
+ // format() method or our DecimalFormat's format() method to
+ // format the result
+ } else {
+ if (ruleSet != NULL) {
+ ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos);
+ } else if (numberFormat != NULL) {
+ UnicodeString temp;
+ numberFormat->format(numberToFormat, temp);
+ toInsertInto.insert(_pos + this->pos, temp);
+ }
+ }
+}
+
+
+ //-----------------------------------------------------------------------
+ // parsing
+ //-----------------------------------------------------------------------
+
+#ifdef RBNF_DEBUG
+#include <stdio.h>
+#endif
+
+/**
+ * Parses a string using the rule set or DecimalFormat belonging
+ * to this substitution. If there's a match, a mathematical
+ * operation (the inverse of the one used in formatting) is
+ * performed on the result of the parse and the value passed in
+ * and returned as the result. The parse position is updated to
+ * point to the first unmatched character in the string.
+ * @param text The string to parse
+ * @param parsePosition On entry, ignored, but assumed to be 0.
+ * On exit, this is updated to point to the first unmatched
+ * character (or 0 if the substitution didn't match)
+ * @param baseValue A partial parse result that should be
+ * combined with the result of this parse
+ * @param upperBound When searching the rule set for a rule
+ * matching the string passed in, only rules with base values
+ * lower than this are considered
+ * @param lenientParse If true and matching against rules fails,
+ * the substitution will also try matching the text against
+ * numerals using a default-costructed NumberFormat. If false,
+ * no extra work is done. (This value is false whenever the
+ * formatter isn't in lenient-parse mode, but is also false
+ * under some conditions even when the formatter _is_ in
+ * lenient-parse mode.)
+ * @return If there's a match, this is the result of composing
+ * baseValue with whatever was returned from matching the
+ * characters. This will be either a Long or a Double. If there's
+ * no match this is new Long(0) (not null), and parsePosition
+ * is left unchanged.
+ */
+UBool
+NFSubstitution::doParse(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ double baseValue,
+ double upperBound,
+ UBool lenientParse,
+ Formattable& result) const
+{
+#ifdef RBNF_DEBUG
+ fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound);
+#endif
+ // figure out the highest base value a rule can have and match
+ // the text being parsed (this varies according to the type of
+ // substitutions: multiplier, modulus, and numerator substitutions
+ // restrict the search to rules with base values lower than their
+ // own; same-value substitutions leave the upper bound wherever
+ // it was, and the others allow any rule to match
+ upperBound = calcUpperBound(upperBound);
+
+ // use our rule set to parse the text. If that fails and
+ // lenient parsing is enabled (this is always false if the
+ // formatter's lenient-parsing mode is off, but it may also
+ // be false even when the formatter's lenient-parse mode is
+ // on), then also try parsing the text using a default-
+ // constructed NumberFormat
+ if (ruleSet != NULL) {
+ ruleSet->parse(text, parsePosition, upperBound, result);
+ if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) {
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat* fmt = NumberFormat::createInstance(status);
+ if (U_SUCCESS(status)) {
+ fmt->parse(text, result, parsePosition);
+ }
+ delete fmt;
+ }
+
+ // ...or use our DecimalFormat to parse the text
+ } else if (numberFormat != NULL) {
+ numberFormat->parse(text, result, parsePosition);
+ }
+
+ // if the parse was successful, we've already advanced the caller's
+ // parse position (this is the one function that doesn't have one
+ // of its own). Derive a parse result and return it as a Long,
+ // if possible, or a Double
+ if (parsePosition.getIndex() != 0) {
+ UErrorCode status = U_ZERO_ERROR;
+ double tempResult = result.getDouble(status);
+
+ // composeRuleValue() produces a full parse result from
+ // the partial parse result passed to this function from
+ // the caller (this is either the owning rule's base value
+ // or the partial result obtained from composing the
+ // owning rule's base value with its other substitution's
+ // parse result) and the partial parse result obtained by
+ // matching the substitution (which will be the same value
+ // the caller would get by parsing just this part of the
+ // text with RuleBasedNumberFormat.parse() ). How the two
+ // values are used to derive the full parse result depends
+ // on the types of substitutions: For a regular rule, the
+ // ultimate result is its multiplier substitution's result
+ // times the rule's divisor (or the rule's base value) plus
+ // the modulus substitution's result (which will actually
+ // supersede part of the rule's base value). For a negative-
+ // number rule, the result is the negative of its substitution's
+ // result. For a fraction rule, it's the sum of its two
+ // substitution results. For a rule in a fraction rule set,
+ // it's the numerator substitution's result divided by
+ // the rule's base value. Results from same-value substitutions
+ // propagate back upard, and null substitutions don't affect
+ // the result.
+ tempResult = composeRuleValue(tempResult, baseValue);
+ result.setDouble(tempResult);
+ return TRUE;
+ // if the parse was UNsuccessful, return 0
+ } else {
+ result.setLong(0);
+ return FALSE;
+ }
+}
+
+UBool
+NFSubstitution::isNullSubstitution() const {
+ return FALSE;
+}
+
+ /**
+ * Returns true if this is a modulus substitution. (We didn't do this
+ * with instanceof partially because it causes source files to
+ * proliferate and partially because we have to port this to C++.)
+ * @return true if this object is an instance of ModulusSubstitution
+ */
+UBool
+NFSubstitution::isModulusSubstitution() const {
+ return FALSE;
+}
+
+//===================================================================
+// SameValueSubstitution
+//===================================================================
+
+/**
+ * A substitution that passes the value passed to it through unchanged.
+ * Represented by == in rule descriptions.
+ */
+SameValueSubstitution::SameValueSubstitution(int32_t _pos,
+ const NFRuleSet* _ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+: NFSubstitution(_pos, _ruleSet, formatter, description, status)
+{
+ if (description == gEqualsEquals) {
+ // throw new IllegalArgumentException("== is not a legal token");
+ status = U_PARSE_ERROR;
+ }
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SameValueSubstitution)
+
+//===================================================================
+// MultiplierSubstitution
+//===================================================================
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MultiplierSubstitution)
+
+UBool MultiplierSubstitution::operator==(const NFSubstitution& rhs) const
+{
+ return NFSubstitution::operator==(rhs) &&
+ divisor == ((const MultiplierSubstitution*)&rhs)->divisor;
+}
+
+
+//===================================================================
+// ModulusSubstitution
+//===================================================================
+
+/**
+ * A substitution that divides the number being formatted by the its rule's
+ * divisor and formats the remainder. Represented by "&gt;&gt;" in a
+ * regular rule.
+ */
+ModulusSubstitution::ModulusSubstitution(int32_t _pos,
+ double _divisor,
+ const NFRule* predecessor,
+ const NFRuleSet* _ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+ : NFSubstitution(_pos, _ruleSet, formatter, description, status)
+ , divisor(_divisor)
+ , ruleToUse(NULL)
+{
+ ldivisor = util64_fromDouble(_divisor);
+
+ // the owning rule's divisor controls the behavior of this
+ // substitution: rather than keeping a backpointer to the rule,
+ // we keep a copy of the divisor
+
+ if (ldivisor == 0) {
+ status = U_PARSE_ERROR;
+ }
+
+ if (description == gGreaterGreaterGreaterThan) {
+ // the >>> token doesn't alter how this substituion calculates the
+ // values it uses for formatting and parsing, but it changes
+ // what's done with that value after it's obtained: >>> short-
+ // circuits the rule-search process and goes straight to the
+ // specified rule to format the substitution value
+ ruleToUse = predecessor;
+ }
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ModulusSubstitution)
+
+UBool ModulusSubstitution::operator==(const NFSubstitution& rhs) const
+{
+ return NFSubstitution::operator==(rhs) &&
+ divisor == ((const ModulusSubstitution*)&rhs)->divisor &&
+ ruleToUse == ((const ModulusSubstitution*)&rhs)->ruleToUse;
+}
+
+//-----------------------------------------------------------------------
+// formatting
+//-----------------------------------------------------------------------
+
+
+/**
+ * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
+ * the substitution. Otherwise, just use the superclass function.
+ * @param number The number being formatted
+ * @toInsertInto The string to insert the result of this substitution
+ * into
+ * @param pos The position of the rule text in toInsertInto
+ */
+void
+ModulusSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const
+{
+ // if this isn't a >>> substitution, just use the inherited version
+ // of this function (which uses either a rule set or a DecimalFormat
+ // to format its substitution value)
+ if (ruleToUse == NULL) {
+ NFSubstitution::doSubstitution(number, toInsertInto, _pos);
+
+ // a >>> substitution goes straight to a particular rule to
+ // format the substitution value
+ } else {
+ int64_t numberToFormat = transformNumber(number);
+ ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
+ }
+}
+
+/**
+* If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
+* the substitution. Otherwise, just use the superclass function.
+* @param number The number being formatted
+* @toInsertInto The string to insert the result of this substitution
+* into
+* @param pos The position of the rule text in toInsertInto
+*/
+void
+ModulusSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const
+{
+ // if this isn't a >>> substitution, just use the inherited version
+ // of this function (which uses either a rule set or a DecimalFormat
+ // to format its substitution value)
+ if (ruleToUse == NULL) {
+ NFSubstitution::doSubstitution(number, toInsertInto, _pos);
+
+ // a >>> substitution goes straight to a particular rule to
+ // format the substitution value
+ } else {
+ double numberToFormat = transformNumber(number);
+
+ ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
+ }
+}
+
+//-----------------------------------------------------------------------
+// parsing
+//-----------------------------------------------------------------------
+
+/**
+ * If this is a &gt;&gt;&gt; substitution, match only against ruleToUse.
+ * Otherwise, use the superclass function.
+ * @param text The string to parse
+ * @param parsePosition Ignored on entry, updated on exit to point to
+ * the first unmatched character.
+ * @param baseValue The partial parse result prior to calling this
+ * routine.
+ */
+UBool
+ModulusSubstitution::doParse(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ double baseValue,
+ double upperBound,
+ UBool lenientParse,
+ Formattable& result) const
+{
+ // if this isn't a >>> substitution, we can just use the
+ // inherited parse() routine to do the parsing
+ if (ruleToUse == NULL) {
+ return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, result);
+
+ // but if it IS a >>> substitution, we have to do it here: we
+ // use the specific rule's doParse() method, and then we have to
+ // do some of the other work of NFRuleSet.parse()
+ } else {
+ ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result);
+
+ if (parsePosition.getIndex() != 0) {
+ UErrorCode status = U_ZERO_ERROR;
+ double tempResult = result.getDouble(status);
+ tempResult = composeRuleValue(tempResult, baseValue);
+ result.setDouble(tempResult);
+ }
+
+ return TRUE;
+ }
+}
+
+
+//===================================================================
+// IntegralPartSubstitution
+//===================================================================
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IntegralPartSubstitution)
+
+
+//===================================================================
+// FractionalPartSubstitution
+//===================================================================
+
+
+ /**
+ * Constructs a FractionalPartSubstitution. This object keeps a flag
+ * telling whether it should format by digits or not. In addition,
+ * it marks the rule set it calls (if any) as a fraction rule set.
+ */
+FractionalPartSubstitution::FractionalPartSubstitution(int32_t _pos,
+ const NFRuleSet* _ruleSet,
+ const RuleBasedNumberFormat* formatter,
+ const UnicodeString& description,
+ UErrorCode& status)
+ : NFSubstitution(_pos, _ruleSet, formatter, description, status)
+ , byDigits(FALSE)
+ , useSpaces(TRUE)
+
+{
+ // akk, ruleSet can change in superclass constructor
+ if (description == gGreaterGreaterThan ||
+ description == gGreaterGreaterGreaterThan ||
+ _ruleSet == getRuleSet()) {
+ byDigits = TRUE;
+ if (description == gGreaterGreaterGreaterThan) {
+ useSpaces = FALSE;
+ }
+ } else {
+ // cast away const
+ ((NFRuleSet*)getRuleSet())->makeIntoFractionRuleSet();
+ }
+}
+
+//-----------------------------------------------------------------------
+// formatting
+//-----------------------------------------------------------------------
+
+/**
+ * If in "by digits" mode, fills in the substitution one decimal digit
+ * at a time using the rule set containing this substitution.
+ * Otherwise, uses the superclass function.
+ * @param number The number being formatted
+ * @param toInsertInto The string to insert the result of formatting
+ * the substitution into
+ * @param pos The position of the owning rule's rule text in
+ * toInsertInto
+ */
+void
+FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const
+{
+ // if we're not in "byDigits" mode, just use the inherited
+ // doSubstitution() routine
+ if (!byDigits) {
+ NFSubstitution::doSubstitution(number, toInsertInto, _pos);
+
+ // if we're in "byDigits" mode, transform the value into an integer
+ // by moving the decimal point eight places to the right and
+ // pulling digits off the right one at a time, formatting each digit
+ // as an integer using this substitution's owning rule set
+ // (this is slower, but more accurate, than doing it from the
+ // other end)
+ } else {
+ // int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits));
+ // // this flag keeps us from formatting trailing zeros. It starts
+ // // out false because we're pulling from the right, and switches
+ // // to true the first time we encounter a non-zero digit
+ // UBool doZeros = FALSE;
+ // for (int32_t i = 0; i < kMaxDecimalDigits; i++) {
+ // int64_t digit = numberToFormat % 10;
+ // if (digit != 0 || doZeros) {
+ // if (doZeros && useSpaces) {
+ // toInsertInto.insert(_pos + getPos(), gSpace);
+ // }
+ // doZeros = TRUE;
+ // getRuleSet()->format(digit, toInsertInto, _pos + getPos());
+ // }
+ // numberToFormat /= 10;
+ // }
+
+ DigitList dl;
+ dl.set(number, 20, TRUE);
+
+ UBool pad = FALSE;
+ while (dl.fCount > (dl.fDecimalAt <= 0 ? 0 : dl.fDecimalAt)) {
+ if (pad && useSpaces) {
+ toInsertInto.insert(_pos + getPos(), gSpace);
+ } else {
+ pad = TRUE;
+ }
+ getRuleSet()->format((int64_t)(dl.fDigits[--dl.fCount] - '0'), toInsertInto, _pos + getPos());
+ }
+ while (dl.fDecimalAt < 0) {
+ if (pad && useSpaces) {
+ toInsertInto.insert(_pos + getPos(), gSpace);
+ } else {
+ pad = TRUE;
+ }
+ getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos());
+ ++dl.fDecimalAt;
+ }
+
+ if (!pad) {
+ // hack around lack of precision in digitlist. if we would end up with
+ // "foo point" make sure we add a " zero" to the end.
+ getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos());
+ }
+ }
+}
+
+//-----------------------------------------------------------------------
+// parsing
+//-----------------------------------------------------------------------
+
+/**
+ * If in "by digits" mode, parses the string as if it were a string
+ * of individual digits; otherwise, uses the superclass function.
+ * @param text The string to parse
+ * @param parsePosition Ignored on entry, but updated on exit to point
+ * to the first unmatched character
+ * @param baseValue The partial parse result prior to entering this
+ * function
+ * @param upperBound Only consider rules with base values lower than
+ * this when filling in the substitution
+ * @param lenientParse If true, try matching the text as numerals if
+ * matching as words doesn't work
+ * @return If the match was successful, the current partial parse
+ * result; otherwise new Long(0). The result is either a Long or
+ * a Double.
+ */
+
+UBool
+FractionalPartSubstitution::doParse(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ double baseValue,
+ double /*upperBound*/,
+ UBool lenientParse,
+ Formattable& resVal) const
+{
+ // if we're not in byDigits mode, we can just use the inherited
+ // doParse()
+ if (!byDigits) {
+ return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal);
+
+ // if we ARE in byDigits mode, parse the text one digit at a time
+ // using this substitution's owning rule set (we do this by setting
+ // upperBound to 10 when calling doParse() ) until we reach
+ // nonmatching text
+ } else {
+ UnicodeString workText(text);
+ ParsePosition workPos(1);
+ double result = 0;
+ int32_t digit;
+// double p10 = 0.1;
+
+ DigitList dl;
+ NumberFormat* fmt = NULL;
+ while (workText.length() > 0 && workPos.getIndex() != 0) {
+ workPos.setIndex(0);
+ Formattable temp;
+ getRuleSet()->parse(workText, workPos, 10, temp);
+ UErrorCode status = U_ZERO_ERROR;
+ digit = temp.getLong(status);
+// digit = temp.getType() == Formattable::kLong ?
+// temp.getLong() :
+// (int32_t)temp.getDouble();
+
+ if (lenientParse && workPos.getIndex() == 0) {
+ if (!fmt) {
+ status = U_ZERO_ERROR;
+ fmt = NumberFormat::createInstance(status);
+ if (U_FAILURE(status)) {
+ delete fmt;
+ fmt = NULL;
+ }
+ }
+ if (fmt) {
+ fmt->parse(workText, temp, workPos);
+ digit = temp.getLong(status);
+ }
+ }
+
+ if (workPos.getIndex() != 0) {
+ dl.append((char)('0' + digit));
+// result += digit * p10;
+// p10 /= 10;
+ parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
+ workText.removeBetween(0, workPos.getIndex());
+ while (workText.length() > 0 && workText.charAt(0) == gSpace) {
+ workText.removeBetween(0, 1);
+ parsePosition.setIndex(parsePosition.getIndex() + 1);
+ }
+ }
+ }
+ delete fmt;
+
+ result = dl.fCount == 0 ? 0 : dl.getDouble();
+ result = composeRuleValue(result, baseValue);
+ resVal.setDouble(result);
+ return TRUE;
+ }
+}
+
+UBool
+FractionalPartSubstitution::operator==(const NFSubstitution& rhs) const
+{
+ return NFSubstitution::operator==(rhs) &&
+ ((const FractionalPartSubstitution*)&rhs)->byDigits == byDigits;
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FractionalPartSubstitution)
+
+
+//===================================================================
+// AbsoluteValueSubstitution
+//===================================================================
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AbsoluteValueSubstitution)
+
+//===================================================================
+// NumeratorSubstitution
+//===================================================================
+
+void
+NumeratorSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t apos) const {
+ // perform a transformation on the number being formatted that
+ // is dependent on the type of substitution this is
+
+ double numberToFormat = transformNumber(number);
+ int64_t longNF = util64_fromDouble(numberToFormat);
+
+ const NFRuleSet* aruleSet = getRuleSet();
+ if (withZeros && aruleSet != NULL) {
+ // if there are leading zeros in the decimal expansion then emit them
+ int64_t nf =longNF;
+ int32_t len = toInsertInto.length();
+ while ((nf *= 10) < denominator) {
+ toInsertInto.insert(apos + getPos(), gSpace);
+ aruleSet->format((int64_t)0, toInsertInto, apos + getPos());
+ }
+ apos += toInsertInto.length() - len;
+ }
+
+ // if the result is an integer, from here on out we work in integer
+ // space (saving time and memory and preserving accuracy)
+ if (numberToFormat == longNF && aruleSet != NULL) {
+ aruleSet->format(longNF, toInsertInto, apos + getPos());
+
+ // if the result isn't an integer, then call either our rule set's
+ // format() method or our DecimalFormat's format() method to
+ // format the result
+ } else {
+ if (aruleSet != NULL) {
+ aruleSet->format(numberToFormat, toInsertInto, apos + getPos());
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString temp;
+ getNumberFormat()->format(numberToFormat, temp, status);
+ toInsertInto.insert(apos + getPos(), temp);
+ }
+ }
+}
+
+UBool
+NumeratorSubstitution::doParse(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ double baseValue,
+ double upperBound,
+ UBool /*lenientParse*/,
+ Formattable& result) const
+{
+ // we don't have to do anything special to do the parsing here,
+ // but we have to turn lenient parsing off-- if we leave it on,
+ // it SERIOUSLY messes up the algorithm
+
+ // if withZeros is true, we need to count the zeros
+ // and use that to adjust the parse result
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t zeroCount = 0;
+ UnicodeString workText(text);
+
+ if (withZeros) {
+ ParsePosition workPos(1);
+ Formattable temp;
+
+ while (workText.length() > 0 && workPos.getIndex() != 0) {
+ workPos.setIndex(0);
+ getRuleSet()->parse(workText, workPos, 1, temp); // parse zero or nothing at all
+ if (workPos.getIndex() == 0) {
+ // we failed, either there were no more zeros, or the number was formatted with digits
+ // either way, we're done
+ break;
+ }
+
+ ++zeroCount;
+ parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
+ workText.remove(0, workPos.getIndex());
+ while (workText.length() > 0 && workText.charAt(0) == gSpace) {
+ workText.remove(0, 1);
+ parsePosition.setIndex(parsePosition.getIndex() + 1);
+ }
+ }
+
+ workText = text;
+ workText.remove(0, (int32_t)parsePosition.getIndex());
+ parsePosition.setIndex(0);
+ }
+
+ // we've parsed off the zeros, now let's parse the rest from our current position
+ NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, result);
+
+ if (withZeros) {
+ // any base value will do in this case. is there a way to
+ // force this to not bother trying all the base values?
+
+ // compute the 'effective' base and prescale the value down
+ int64_t n = result.getLong(status); // force conversion!
+ int64_t d = 1;
+ int32_t pow = 0;
+ while (d <= n) {
+ d *= 10;
+ ++pow;
+ }
+ // now add the zeros
+ while (zeroCount > 0) {
+ d *= 10;
+ --zeroCount;
+ }
+ // d is now our true denominator
+ result.setDouble((double)n/(double)d);
+ }
+
+ return TRUE;
+}
+
+UBool
+NumeratorSubstitution::operator==(const NFSubstitution& rhs) const
+{
+ return NFSubstitution::operator==(rhs) &&
+ denominator == ((const NumeratorSubstitution*)&rhs)->denominator;
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumeratorSubstitution)
+
+const UChar NumeratorSubstitution::LTLT[] = { 0x003c, 0x003c };
+
+//===================================================================
+// NullSubstitution
+//===================================================================
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NullSubstitution)
+
+U_NAMESPACE_END
+
+/* U_HAVE_RBNF */
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nfsubs.h b/Build/source/libs/icu/icu-xetex/i18n/nfsubs.h
new file mode 100644
index 00000000000..644b4b2f6e1
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nfsubs.h
@@ -0,0 +1,266 @@
+/*
+******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: nfsubs.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 10/11/2001 Doug Ported from ICU4J
+*/
+
+#ifndef NFSUBS_H
+#define NFSUBS_H
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "nfrule.h"
+
+#if U_HAVE_RBNF
+
+#include "unicode/utypes.h"
+#include "unicode/decimfmt.h"
+#include "nfrs.h"
+#include <float.h>
+
+U_NAMESPACE_BEGIN
+
+class NFSubstitution : public UObject {
+ int32_t pos;
+ const NFRuleSet* ruleSet;
+ const DecimalFormat* numberFormat;
+
+protected:
+ NFSubstitution(int32_t pos,
+ const NFRuleSet* ruleSet,
+ const RuleBasedNumberFormat* rbnf,
+ const UnicodeString& description,
+ UErrorCode& status);
+
+ /**
+ * Get the Ruleset of the object.
+ * @return the Ruleset of the object.
+ */
+ const NFRuleSet* getRuleSet() const { return ruleSet; }
+
+ /**
+ * get the NumberFormat of this object.
+ * @return the numberformat of this object.
+ */
+ const DecimalFormat* getNumberFormat() const { return numberFormat; }
+
+public:
+ static NFSubstitution* makeSubstitution(int32_t pos,
+ const NFRule* rule,
+ const NFRule* predecessor,
+ const NFRuleSet* ruleSet,
+ const RuleBasedNumberFormat* rbnf,
+ const UnicodeString& description,
+ UErrorCode& status);
+
+ /**
+ * Destructor.
+ */
+ virtual ~NFSubstitution();
+
+ /**
+ * Return true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ * @param rhs the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ */
+ virtual UBool operator==(const NFSubstitution& rhs) const;
+
+ /**
+ * Return true if the given Format objects are semantically unequal.
+ * Objects of different subclasses are considered unequal.
+ * @param rhs the object to be compared with.
+ * @return true if the given Format objects are semantically unequal.
+ */
+ UBool operator!=(const NFSubstitution& rhs) const { return !operator==(rhs); }
+
+ /**
+ * Sets the substitution's divisor. Used by NFRule.setBaseValue().
+ * A no-op for all substitutions except multiplier and modulus
+ * substitutions.
+ * @param radix The radix of the divisor
+ * @param exponent The exponent of the divisor
+ */
+ virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status);
+
+ /**
+ * Replaces result with the string describing the substitution.
+ * @param result Output param which will receive the string.
+ */
+ virtual void toString(UnicodeString& result) const;
+
+ //-----------------------------------------------------------------------
+ // formatting
+ //-----------------------------------------------------------------------
+
+ /**
+ * Performs a mathematical operation on the number, formats it using
+ * either ruleSet or decimalFormat, and inserts the result into
+ * toInsertInto.
+ * @param number The number being formatted.
+ * @param toInsertInto The string we insert the result into
+ * @param pos The position in toInsertInto where the owning rule's
+ * rule text begins (this value is added to this substitution's
+ * position to determine exactly where to insert the new text)
+ */
+ virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos) const;
+
+ /**
+ * Performs a mathematical operation on the number, formats it using
+ * either ruleSet or decimalFormat, and inserts the result into
+ * toInsertInto.
+ * @param number The number being formatted.
+ * @param toInsertInto The string we insert the result into
+ * @param pos The position in toInsertInto where the owning rule's
+ * rule text begins (this value is added to this substitution's
+ * position to determine exactly where to insert the new text)
+ */
+ virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
+
+protected:
+ /**
+ * Subclasses override this function to perform some kind of
+ * mathematical operation on the number. The result of this operation
+ * is formatted using the rule set or DecimalFormat that this
+ * substitution refers to, and the result is inserted into the result
+ * string.
+ * @param The number being formatted
+ * @return The result of performing the opreration on the number
+ */
+ virtual int64_t transformNumber(int64_t number) const = 0;
+
+ /**
+ * Subclasses override this function to perform some kind of
+ * mathematical operation on the number. The result of this operation
+ * is formatted using the rule set or DecimalFormat that this
+ * substitution refers to, and the result is inserted into the result
+ * string.
+ * @param The number being formatted
+ * @return The result of performing the opreration on the number
+ */
+ virtual double transformNumber(double number) const = 0;
+
+public:
+ //-----------------------------------------------------------------------
+ // parsing
+ //-----------------------------------------------------------------------
+
+ /**
+ * Parses a string using the rule set or DecimalFormat belonging
+ * to this substitution. If there's a match, a mathematical
+ * operation (the inverse of the one used in formatting) is
+ * performed on the result of the parse and the value passed in
+ * and returned as the result. The parse position is updated to
+ * point to the first unmatched character in the string.
+ * @param text The string to parse
+ * @param parsePosition On entry, ignored, but assumed to be 0.
+ * On exit, this is updated to point to the first unmatched
+ * character (or 0 if the substitution didn't match)
+ * @param baseValue A partial parse result that should be
+ * combined with the result of this parse
+ * @param upperBound When searching the rule set for a rule
+ * matching the string passed in, only rules with base values
+ * lower than this are considered
+ * @param lenientParse If true and matching against rules fails,
+ * the substitution will also try matching the text against
+ * numerals using a default-costructed NumberFormat. If false,
+ * no extra work is done. (This value is false whenever the
+ * formatter isn't in lenient-parse mode, but is also false
+ * under some conditions even when the formatter _is_ in
+ * lenient-parse mode.)
+ * @return If there's a match, this is the result of composing
+ * baseValue with whatever was returned from matching the
+ * characters. This will be either a Long or a Double. If there's
+ * no match this is new Long(0) (not null), and parsePosition
+ * is left unchanged.
+ */
+ virtual UBool doParse(const UnicodeString& text,
+ ParsePosition& parsePosition,
+ double baseValue,
+ double upperBound,
+ UBool lenientParse,
+ Formattable& result) const;
+
+ /**
+ * Derives a new value from the two values passed in. The two values
+ * are typically either the base values of two rules (the one containing
+ * the substitution and the one matching the substitution) or partial
+ * parse results derived in some other way. The operation is generally
+ * the inverse of the operation performed by transformNumber().
+ * @param newRuleValue The value produced by matching this substitution
+ * @param oldRuleValue The value that was passed to the substitution
+ * by the rule that owns it
+ * @return A third value derived from the other two, representing a
+ * partial parse result
+ */
+ virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const = 0;
+
+ /**
+ * Calculates an upper bound when searching for a rule that matches
+ * this substitution. Rules with base values greater than or equal
+ * to upperBound are not considered.
+ * @param oldUpperBound The current upper-bound setting. The new
+ * upper bound can't be any higher.
+ * @return the upper bound when searching for a rule that matches
+ * this substitution.
+ */
+ virtual double calcUpperBound(double oldUpperBound) const = 0;
+
+ //-----------------------------------------------------------------------
+ // simple accessors
+ //-----------------------------------------------------------------------
+
+ /**
+ * Returns the substitution's position in the rule that owns it.
+ * @return The substitution's position in the rule that owns it.
+ */
+ int32_t getPos() const { return pos; }
+
+ /**
+ * Returns the character used in the textual representation of
+ * substitutions of this type. Used by toString().
+ * @return This substitution's token character.
+ */
+ virtual UChar tokenChar() const = 0;
+
+ /**
+ * Returns true if this is a null substitution. (We didn't do this
+ * with instanceof partially because it causes source files to
+ * proliferate and partially because we have to port this to C++.)
+ * @return true if this object is an instance of NullSubstitution
+ */
+ virtual UBool isNullSubstitution() const;
+
+ /**
+ * Returns true if this is a modulus substitution. (We didn't do this
+ * with instanceof partially because it causes source files to
+ * proliferate and partially because we have to port this to C++.)
+ * @return true if this object is an instance of ModulusSubstitution
+ */
+ virtual UBool isModulusSubstitution() const;
+
+private:
+ NFSubstitution(const NFSubstitution &other); // forbid copying of this class
+ NFSubstitution &operator=(const NFSubstitution &other); // forbid copying of this class
+
+public:
+ static UClassID getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+U_NAMESPACE_END
+
+/* U_HAVE_RBNF */
+#endif
+
+// NFSUBS_H
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nortrans.cpp b/Build/source/libs/icu/icu-xetex/i18n/nortrans.cpp
new file mode 100644
index 00000000000..f967f7dae5d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nortrans.cpp
@@ -0,0 +1,231 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 07/03/01 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uniset.h"
+#include "unicode/uiter.h"
+#include "nortrans.h"
+#include "unormimp.h"
+#include "ucln_in.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NormalizationTransliterator)
+
+/**
+ * System registration hook.
+ */
+void NormalizationTransliterator::registerIDs() {
+ UErrorCode errorCode = U_ZERO_ERROR;
+ if(!unorm_haveData(&errorCode)) {
+ return;
+ }
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-NFC"),
+ _create, integerToken(UNORM_NFC));
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-NFKC"),
+ _create, integerToken(UNORM_NFKC));
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-NFD"),
+ _create, integerToken(UNORM_NFD));
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Any-NFKD"),
+ _create, integerToken(UNORM_NFKD));
+ Transliterator::_registerSpecialInverse(UNICODE_STRING_SIMPLE("NFC"),
+ UNICODE_STRING_SIMPLE("NFD"), TRUE);
+ Transliterator::_registerSpecialInverse(UNICODE_STRING_SIMPLE("NFKC"),
+ UNICODE_STRING_SIMPLE("NFKD"), TRUE);
+}
+
+/**
+ * Factory methods
+ */
+Transliterator* NormalizationTransliterator::_create(const UnicodeString& ID,
+ Token context) {
+ return new NormalizationTransliterator(ID, (UNormalizationMode) context.integer, 0);
+}
+
+/**
+ * Constructs a transliterator.
+ */
+NormalizationTransliterator::NormalizationTransliterator(
+ const UnicodeString& id,
+ UNormalizationMode mode, int32_t opt) :
+ Transliterator(id, 0) {
+ fMode = mode;
+ options = opt;
+}
+
+/**
+ * Destructor.
+ */
+NormalizationTransliterator::~NormalizationTransliterator() {
+}
+
+/**
+ * Copy constructor.
+ */
+NormalizationTransliterator::NormalizationTransliterator(const NormalizationTransliterator& o) :
+Transliterator(o) {
+ fMode = o.fMode;
+ options = o.options;
+}
+
+/**
+ * Assignment operator.
+ */
+/*NormalizationTransliterator& NormalizationTransliterator::operator=(const NormalizationTransliterator& o) {
+ Transliterator::operator=(o);
+ fMode = o.fMode;
+ options = o.options;
+ return *this;
+}*/
+
+/**
+ * Transliterator API.
+ */
+Transliterator* NormalizationTransliterator::clone(void) const {
+ return new NormalizationTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void NormalizationTransliterator::handleTransliterate(Replaceable& text, UTransPosition& offsets,
+ UBool isIncremental) const {
+ // start and limit of the input range
+ int32_t start = offsets.start;
+ int32_t limit = offsets.limit;
+ int32_t length, delta;
+
+ if(start >= limit) {
+ return;
+ }
+
+ // a C code unit iterator, implemented around the Replaceable
+ UCharIterator iter;
+ uiter_setReplaceable(&iter, &text);
+
+ // the output string and buffer pointer
+ UnicodeString output;
+ UChar *buffer;
+ UBool neededToNormalize;
+
+ UErrorCode errorCode;
+
+ /*
+ * Normalize as short chunks at a time as possible even in
+ * bulk mode, so that styled text is minimally disrupted.
+ * In incremental mode, a chunk that ends with offsets.limit
+ * must not be normalized.
+ *
+ * If it was known that the input text is not styled, then
+ * a bulk mode normalization could look like this:
+ *
+
+ UChar staticChars[256];
+ UnicodeString input;
+
+ length = limit - start;
+ input.setTo(staticChars, 0, sizeof(staticChars)/U_SIZEOF_UCHAR); // writable alias
+
+ _Replaceable_extractBetween(text, start, limit, input.getBuffer(length));
+ input.releaseBuffer(length);
+
+ UErrorCode status = U_ZERO_ERROR;
+ Normalizer::normalize(input, fMode, options, output, status);
+
+ text.handleReplaceBetween(start, limit, output);
+
+ int32_t delta = output.length() - length;
+ offsets.contextLimit += delta;
+ offsets.limit += delta;
+ offsets.start = limit + delta;
+
+ *
+ */
+ while(start < limit) {
+ // set the iterator limits for the remaining input range
+ // this is a moving target because of the replacements in the text object
+ iter.start = iter.index = start;
+ iter.limit = limit;
+
+ // incrementally normalize a small chunk of the input
+ buffer = output.getBuffer(-1);
+ errorCode = U_ZERO_ERROR;
+ length = unorm_next(&iter, buffer, output.getCapacity(),
+ fMode, 0,
+ TRUE, &neededToNormalize,
+ &errorCode);
+ output.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+
+ if(errorCode == U_BUFFER_OVERFLOW_ERROR) {
+ // use a larger output string buffer and do it again from the start
+ iter.index = start;
+ buffer = output.getBuffer(length);
+ errorCode = U_ZERO_ERROR;
+ length = unorm_next(&iter, buffer, output.getCapacity(),
+ fMode, 0,
+ TRUE, &neededToNormalize,
+ &errorCode);
+ output.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
+ }
+
+ if(U_FAILURE(errorCode)) {
+ break;
+ }
+
+ limit = iter.index;
+ if(isIncremental && limit == iter.limit) {
+ // stop in incremental mode when we reach the input limit
+ // in case there are additional characters that could change the
+ // normalization result
+
+ // UNLESS all characters in the result of the normalization of
+ // the last run are in the skippable set
+ const UChar *s=output.getBuffer();
+ int32_t i=0, outLength=output.length();
+ UChar32 c;
+
+ while(i<outLength) {
+ U16_NEXT(s, i, outLength, c);
+ if(!unorm_isNFSkippable(c, fMode)) {
+ outLength=-1; // I wish C++ had labeled loops and break outer; ...
+ break;
+ }
+ }
+ if (outLength<0) {
+ break;
+ }
+ }
+
+ if(neededToNormalize) {
+ // replace the input chunk with its normalized form
+ text.handleReplaceBetween(start, limit, output);
+
+ // update all necessary indexes accordingly
+ delta = length - (limit - start); // length change in the text object
+ start = limit += delta; // the next chunk starts where this one ends, with adjustment
+ limit = offsets.limit += delta; // set the iteration limit to the adjusted end of the input range
+ offsets.contextLimit += delta;
+ } else {
+ // delta == 0
+ start = limit;
+ limit = offsets.limit;
+ }
+ }
+
+ offsets.start = start;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nortrans.h b/Build/source/libs/icu/icu-xetex/i18n/nortrans.h
new file mode 100644
index 00000000000..96bc7f00429
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nortrans.h
@@ -0,0 +1,110 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 07/03/01 aliu Creation.
+**********************************************************************
+*/
+#ifndef NORTRANS_H
+#define NORTRANS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "unicode/normlzr.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that performs normalization.
+ * @author Alan Liu
+ */
+class NormalizationTransliterator : public Transliterator {
+
+ /**
+ * The normalization mode of this transliterator.
+ */
+ UNormalizationMode fMode;
+
+ /**
+ * Normalization options for this transliterator.
+ */
+ int32_t options;
+
+ public:
+
+ /**
+ * Destructor.
+ */
+ virtual ~NormalizationTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ NormalizationTransliterator(const NormalizationTransliterator&);
+
+ /**
+ * Transliterator API.
+ * @return A copy of the object.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+ protected:
+
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param offset the start and limit of the text, the position
+ * of the cursor, and the start and limit of transliteration.
+ * @param incremental if true, assume more text may be coming after
+ * pos.contextLimit. Otherwise, assume the text is complete.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& offset,
+ UBool isIncremental) const;
+ public:
+
+ /**
+ * System registration hook. Public to Transliterator only.
+ */
+ static void registerIDs();
+
+ private:
+
+ // Transliterator::Factory methods
+ static Transliterator* _create(const UnicodeString& ID,
+ Token context);
+
+ /**
+ * Constructs a transliterator. This method is private.
+ * Public users must use the factory method createInstance().
+ */
+ NormalizationTransliterator(const UnicodeString& id,
+ UNormalizationMode mode, int32_t opt);
+
+private:
+ /**
+ * Assignment operator.
+ */
+ NormalizationTransliterator& operator=(const NormalizationTransliterator&);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nultrans.cpp b/Build/source/libs/icu/icu-xetex/i18n/nultrans.cpp
new file mode 100644
index 00000000000..820c43d07e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nultrans.cpp
@@ -0,0 +1,36 @@
+/*
+**********************************************************************
+* Copyright (c) 2000-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 01/11/2000 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "nultrans.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NullTransliterator)
+
+NullTransliterator::NullTransliterator() : Transliterator(UNICODE_STRING_SIMPLE("Any-Null"), 0) {}
+
+NullTransliterator::~NullTransliterator() {}
+
+Transliterator* NullTransliterator::clone(void) const {
+ return new NullTransliterator();
+}
+
+void NullTransliterator::handleTransliterate(Replaceable& /*text*/, UTransPosition& offsets,
+ UBool /*isIncremental*/) const {
+ offsets.start = offsets.limit;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/nultrans.h b/Build/source/libs/icu/icu-xetex/i18n/nultrans.h
new file mode 100644
index 00000000000..699c323f8c6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/nultrans.h
@@ -0,0 +1,71 @@
+/*
+**********************************************************************
+* Copyright (c) 2000-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 01/11/2000 aliu Creation.
+**********************************************************************
+*/
+#ifndef NULTRANS_H
+#define NULTRANS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that leaves text unchanged.
+ * @author Alan Liu
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+class NullTransliterator : public Transliterator {
+
+public:
+
+ /**
+ * Constructs a transliterator.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ NullTransliterator();
+
+ /**
+ * Destructor.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual ~NullTransliterator();
+
+ /**
+ * Transliterator API.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& offset,
+ UBool isIncremental) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/numfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/numfmt.cpp
new file mode 100644
index 00000000000..b2e6665b786
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/numfmt.cpp
@@ -0,0 +1,925 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File NUMFMT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/18/97 clhuang Implemented with C++ APIs.
+* 04/17/97 aliu Enlarged MAX_INTEGER_DIGITS to fully accomodate the
+* largest double, by default.
+* Changed DigitCount to int per code review.
+* 07/20/98 stephen Changed operator== to check for grouping
+* Changed setMaxIntegerDigits per Java implementation.
+* Changed setMinIntegerDigits per Java implementation.
+* Changed setMinFractionDigits per Java implementation.
+* Changed setMaxFractionDigits per Java implementation.
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/ustring.h"
+#include "unicode/ucurr.h"
+#include "unicode/curramt.h"
+#include "winnmfmt.h"
+#include "uresimp.h"
+#include "uhash.h"
+#include "cmemory.h"
+#include "servloc.h"
+#include "ucln_in.h"
+#include "cstring.h"
+#include "putilimp.h"
+#include <float.h>
+
+//#define FMT_DEBUG
+
+#ifdef FMT_DEBUG
+#include <stdio.h>
+static void debugout(UnicodeString s) {
+ char buf[2000];
+ s.extract((int32_t) 0, s.length(), buf);
+ printf("%s", buf);
+}
+#define debug(x) printf("%s", x);
+#else
+#define debugout(x)
+#define debug(x)
+#endif
+
+// If no number pattern can be located for a locale, this is the last
+// resort.
+static const UChar gLastResortDecimalPat[] = {
+ 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0x3B, 0x2D, 0x23, 0x30, 0x2E, 0x23, 0x23, 0x23, 0 /* "#0.###;-#0.###" */
+};
+static const UChar gLastResortCurrencyPat[] = {
+ 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x3B, 0x28, 0x24, 0x23, 0x30, 0x2E, 0x30, 0x30, 0x29, 0 /* "$#0.00;($#0.00)" */
+};
+static const UChar gLastResortPercentPat[] = {
+ 0x23, 0x30, 0x25, 0 /* "#0%" */
+};
+static const UChar gLastResortScientificPat[] = {
+ 0x23, 0x45, 0x30, 0 /* "#E0" */
+};
+
+// If the maximum base 10 exponent were 4, then the largest number would
+// be 99,999 which has 5 digits.
+// On IEEE754 systems gMaxIntegerDigits is 308 + possible denormalized 15 digits + rounding digit
+static const int32_t gMaxIntegerDigits = DBL_MAX_10_EXP + DBL_DIG + 1;
+static const int32_t gMinIntegerDigits = 127;
+
+static const UChar * const gLastResortNumberPatterns[] =
+{
+ gLastResortDecimalPat,
+ gLastResortCurrencyPat,
+ gLastResortPercentPat,
+ gLastResortScientificPat
+};
+
+// *****************************************************************************
+// class NumberFormat
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(NumberFormat)
+
+#if !UCONFIG_NO_SERVICE
+// -------------------------------------
+// SimpleNumberFormatFactory implementation
+NumberFormatFactory::~NumberFormatFactory() {}
+SimpleNumberFormatFactory::SimpleNumberFormatFactory(const Locale& locale, UBool visible)
+ : _visible(visible)
+{
+ LocaleUtility::initNameFromLocale(locale, _id);
+}
+
+SimpleNumberFormatFactory::~SimpleNumberFormatFactory() {}
+
+UBool SimpleNumberFormatFactory::visible(void) const {
+ return _visible;
+}
+
+const UnicodeString *
+SimpleNumberFormatFactory::getSupportedIDs(int32_t &count, UErrorCode& status) const
+{
+ if (U_SUCCESS(status)) {
+ count = 1;
+ return &_id;
+ }
+ count = 0;
+ return NULL;
+}
+#endif /* #if !UCONFIG_NO_SERVICE */
+
+// -------------------------------------
+// default constructor
+NumberFormat::NumberFormat()
+: fGroupingUsed(TRUE),
+ fMaxIntegerDigits(gMaxIntegerDigits),
+ fMinIntegerDigits(1),
+ fMaxFractionDigits(3), // invariant, >= minFractionDigits
+ fMinFractionDigits(0),
+ fParseIntegerOnly(FALSE)
+{
+ fCurrency[0] = 0;
+}
+
+// -------------------------------------
+
+NumberFormat::~NumberFormat()
+{
+}
+
+// -------------------------------------
+// copy constructor
+
+NumberFormat::NumberFormat(const NumberFormat &source)
+: Format(source)
+{
+ *this = source;
+}
+
+// -------------------------------------
+// assignment operator
+
+NumberFormat&
+NumberFormat::operator=(const NumberFormat& rhs)
+{
+ if (this != &rhs)
+ {
+ fGroupingUsed = rhs.fGroupingUsed;
+ fMaxIntegerDigits = rhs.fMaxIntegerDigits;
+ fMinIntegerDigits = rhs.fMinIntegerDigits;
+ fMaxFractionDigits = rhs.fMaxFractionDigits;
+ fMinFractionDigits = rhs.fMinFractionDigits;
+ fParseIntegerOnly = rhs.fParseIntegerOnly;
+ u_strncpy(fCurrency, rhs.fCurrency, 4);
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+UBool
+NumberFormat::operator==(const Format& that) const
+{
+ // Format::operator== guarantees this cast is safe
+ NumberFormat* other = (NumberFormat*)&that;
+
+#ifdef FMT_DEBUG
+ // This code makes it easy to determine why two format objects that should
+ // be equal aren't.
+ UBool first = TRUE;
+ if (!Format::operator==(that)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Format::!=");
+ }
+ if (!(fMaxIntegerDigits == other->fMaxIntegerDigits &&
+ fMinIntegerDigits == other->fMinIntegerDigits)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Integer digits !=");
+ }
+ if (!(fMaxFractionDigits == other->fMaxFractionDigits &&
+ fMinFractionDigits == other->fMinFractionDigits)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("Fraction digits !=");
+ }
+ if (!(fGroupingUsed == other->fGroupingUsed)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fGroupingUsed != ");
+ }
+ if (!(fParseIntegerOnly == other->fParseIntegerOnly)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fParseIntegerOnly != ");
+ }
+ if (!(u_strcmp(fCurrency, other->fCurrency) == 0)) {
+ if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
+ debug("fCurrency !=");
+ }
+ if (!first) { printf(" ]"); }
+#endif
+
+ return ((this == &that) ||
+ ((Format::operator==(that) &&
+ fMaxIntegerDigits == other->fMaxIntegerDigits &&
+ fMinIntegerDigits == other->fMinIntegerDigits &&
+ fMaxFractionDigits == other->fMaxFractionDigits &&
+ fMinFractionDigits == other->fMinFractionDigits &&
+ fGroupingUsed == other->fGroupingUsed &&
+ fParseIntegerOnly == other->fParseIntegerOnly &&
+ u_strcmp(fCurrency, other->fCurrency) == 0)));
+}
+
+// -------------------------------------x
+// Formats the number object and save the format
+// result in the toAppendTo string buffer.
+
+UnicodeString&
+NumberFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return appendTo;
+
+ NumberFormat* nonconst = (NumberFormat*) this;
+ const Formattable* n = &obj;
+
+ UChar save[4];
+ UBool setCurr = FALSE;
+ const UObject* o = obj.getObject(); // most commonly o==NULL
+ if (o != NULL &&
+ o->getDynamicClassID() == CurrencyAmount::getStaticClassID()) {
+ // getISOCurrency() returns a pointer to internal storage, so we
+ // copy it to retain it across the call to setCurrency().
+ const CurrencyAmount* amt = (const CurrencyAmount*) o;
+ const UChar* curr = amt->getISOCurrency();
+ u_strcpy(save, getCurrency());
+ setCurr = (u_strcmp(curr, save) != 0);
+ if (setCurr) {
+ nonconst->setCurrency(curr, status);
+ }
+ n = &amt->getNumber();
+ }
+
+ switch (n->getType()) {
+ case Formattable::kDouble:
+ format(n->getDouble(), appendTo, pos);
+ break;
+ case Formattable::kLong:
+ format(n->getLong(), appendTo, pos);
+ break;
+ case Formattable::kInt64:
+ format(n->getInt64(), appendTo, pos);
+ break;
+ default:
+ status = U_INVALID_FORMAT_ERROR;
+ break;
+ }
+
+ if (setCurr) {
+ UErrorCode ok = U_ZERO_ERROR;
+ nonconst->setCurrency(save, ok); // always restore currency
+ }
+ return appendTo;
+}
+
+// -------------------------------------
+
+UnicodeString&
+NumberFormat::format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const
+{
+ // default so we don't introduce a new abstract method
+ return format((int32_t)number, appendTo, pos);
+}
+
+// -------------------------------------
+// Parses the string and save the result object as well
+// as the final parsed position.
+
+void
+NumberFormat::parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& parse_pos) const
+{
+ parse(source, result, parse_pos);
+}
+
+// -------------------------------------
+// Formats a double number and save the result in a string.
+
+UnicodeString&
+NumberFormat::format(double number, UnicodeString& appendTo) const
+{
+ FieldPosition pos(0);
+ return format(number, appendTo, pos);
+}
+
+// -------------------------------------
+// Formats a long number and save the result in a string.
+
+UnicodeString&
+NumberFormat::format(int32_t number, UnicodeString& appendTo) const
+{
+ FieldPosition pos(0);
+ return format(number, appendTo, pos);
+}
+
+// -------------------------------------
+// Formats a long number and save the result in a string.
+
+UnicodeString&
+NumberFormat::format(int64_t number, UnicodeString& appendTo) const
+{
+ FieldPosition pos(0);
+ return format(number, appendTo, pos);
+}
+
+// -------------------------------------
+// Parses the text and save the result object. If the returned
+// parse position is 0, that means the parsing failed, the status
+// code needs to be set to failure. Ignores the returned parse
+// position, otherwise.
+
+void
+NumberFormat::parse(const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) return;
+
+ ParsePosition parsePosition(0);
+ parse(text, result, parsePosition);
+ if (parsePosition.getIndex() == 0) {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+}
+
+Formattable& NumberFormat::parseCurrency(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& pos) const {
+ // Default implementation only -- subclasses should override
+ int32_t start = pos.getIndex();
+ parse(text, result, pos);
+ if (pos.getIndex() != start) {
+ UChar curr[4];
+ UErrorCode ec = U_ZERO_ERROR;
+ getEffectiveCurrency(curr, ec);
+ if (U_SUCCESS(ec)) {
+ Formattable n(result);
+ result.adoptObject(new CurrencyAmount(n, curr, ec));
+ if (U_FAILURE(ec)) {
+ pos.setIndex(start); // indicate failure
+ }
+ }
+ }
+ return result;
+}
+
+// -------------------------------------
+// Sets to only parse integers.
+
+void
+NumberFormat::setParseIntegerOnly(UBool value)
+{
+ fParseIntegerOnly = value;
+}
+
+// -------------------------------------
+// Create a number style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createInstance(UErrorCode& status)
+{
+ return createInstance(Locale::getDefault(), kNumberStyle, status);
+}
+
+// -------------------------------------
+// Create a number style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, kNumberStyle, status);
+}
+
+// -------------------------------------
+// Create a currency style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createCurrencyInstance(UErrorCode& status)
+{
+ return createCurrencyInstance(Locale::getDefault(), status);
+}
+
+// -------------------------------------
+// Create a currency style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, kCurrencyStyle, status);
+}
+
+// -------------------------------------
+// Create a percent style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createPercentInstance(UErrorCode& status)
+{
+ return createInstance(Locale::getDefault(), kPercentStyle, status);
+}
+
+// -------------------------------------
+// Create a percent style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, kPercentStyle, status);
+}
+
+// -------------------------------------
+// Create a scientific style NumberFormat instance with the default locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createScientificInstance(UErrorCode& status)
+{
+ return createInstance(Locale::getDefault(), kScientificStyle, status);
+}
+
+// -------------------------------------
+// Create a scientific style NumberFormat instance with the inLocale locale.
+
+NumberFormat* U_EXPORT2
+NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
+{
+ return createInstance(inLocale, kScientificStyle, status);
+}
+
+// -------------------------------------
+
+const Locale* U_EXPORT2
+NumberFormat::getAvailableLocales(int32_t& count)
+{
+ return Locale::getAvailableLocales(count);
+}
+
+// ------------------------------------------
+//
+// Registration
+//
+//-------------------------------------------
+
+#if !UCONFIG_NO_SERVICE
+static ICULocaleService* gService = NULL;
+
+/**
+ * Release all static memory held by numberformat.
+ */
+U_CDECL_BEGIN
+static UBool U_CALLCONV numfmt_cleanup(void) {
+ if (gService) {
+ delete gService;
+ gService = NULL;
+ }
+ return TRUE;
+}
+U_CDECL_END
+
+// -------------------------------------
+
+class ICUNumberFormatFactory : public ICUResourceBundleFactory {
+protected:
+ virtual UObject* handleCreate(const Locale& loc, int32_t kind, const ICUService* /* service */, UErrorCode& status) const {
+ // !!! kind is not an EStyles, need to determine how to handle this
+ return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
+ }
+};
+
+// -------------------------------------
+
+class NFFactory : public LocaleKeyFactory {
+private:
+ NumberFormatFactory* _delegate;
+ Hashtable* _ids;
+
+public:
+ NFFactory(NumberFormatFactory* delegate)
+ : LocaleKeyFactory(delegate->visible() ? VISIBLE : INVISIBLE)
+ , _delegate(delegate)
+ , _ids(NULL)
+ {
+ }
+
+ virtual ~NFFactory()
+ {
+ delete _delegate;
+ delete _ids;
+ }
+
+ virtual UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const
+ {
+ if (handlesKey(key, status)) {
+ const LocaleKey& lkey = (const LocaleKey&)key;
+ Locale loc;
+ lkey.canonicalLocale(loc);
+ int32_t kind = lkey.kind();
+
+ UObject* result = _delegate->createFormat(loc, (UNumberFormatStyle)(kind+1));
+ if (result == NULL) {
+ result = service->getKey((ICUServiceKey&)key /* cast away const */, NULL, this, status);
+ }
+ return result;
+ }
+ return NULL;
+ }
+
+protected:
+ /**
+ * Return the set of ids that this factory supports (visible or
+ * otherwise). This can be called often and might need to be
+ * cached if it is expensive to create.
+ */
+ virtual const Hashtable* getSupportedIDs(UErrorCode& status) const
+ {
+ if (U_SUCCESS(status)) {
+ if (!_ids) {
+ int32_t count = 0;
+ const UnicodeString * const idlist = _delegate->getSupportedIDs(count, status);
+ ((NFFactory*)this)->_ids = new Hashtable(status); /* cast away const */
+ if (_ids) {
+ for (int i = 0; i < count; ++i) {
+ _ids->put(idlist[i], (void*)this, status);
+ }
+ }
+ }
+ return _ids;
+ }
+ return NULL;
+ }
+};
+
+class ICUNumberFormatService : public ICULocaleService {
+public:
+ ICUNumberFormatService()
+ : ICULocaleService(UNICODE_STRING_SIMPLE("Number Format"))
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ registerFactory(new ICUNumberFormatFactory(), status);
+ }
+
+ virtual UObject* cloneInstance(UObject* instance) const {
+ return ((NumberFormat*)instance)->clone();
+ }
+
+ virtual UObject* handleDefault(const ICUServiceKey& key, UnicodeString* /* actualID */, UErrorCode& status) const {
+ LocaleKey& lkey = (LocaleKey&)key;
+ int32_t kind = lkey.kind();
+ Locale loc;
+ lkey.currentLocale(loc);
+ return NumberFormat::makeInstance(loc, (NumberFormat::EStyles)kind, status);
+ }
+
+ virtual UBool isDefault() const {
+ return countFactories() == 1;
+ }
+};
+
+// -------------------------------------
+
+static ICULocaleService*
+getNumberFormatService(void)
+{
+ UBool needInit;
+ UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
+ if (needInit) {
+ ICULocaleService * newservice = new ICUNumberFormatService();
+ if (newservice) {
+ umtx_lock(NULL);
+ if (gService == NULL) {
+ gService = newservice;
+ newservice = NULL;
+ }
+ umtx_unlock(NULL);
+ }
+ if (newservice) {
+ delete newservice;
+ } else {
+ // we won the contention, this thread can register cleanup.
+ ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup);
+ }
+ }
+ return gService;
+}
+
+// -------------------------------------
+
+URegistryKey U_EXPORT2
+NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status)
+{
+ ICULocaleService *service = getNumberFormatService();
+ if (service) {
+ return service->registerFactory(new NFFactory(toAdopt), status);
+ }
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+}
+
+// -------------------------------------
+
+UBool U_EXPORT2
+NumberFormat::unregister(URegistryKey key, UErrorCode& status)
+{
+ if (U_SUCCESS(status)) {
+ UBool haveService;
+ UMTX_CHECK(NULL, gService != NULL, haveService);
+ if (haveService) {
+ return gService->unregister(key, status);
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return FALSE;
+}
+
+// -------------------------------------
+StringEnumeration* U_EXPORT2
+NumberFormat::getAvailableLocales(void)
+{
+ ICULocaleService *service = getNumberFormatService();
+ if (service) {
+ return service->getAvailableLocales();
+ }
+ return NULL; // no way to return error condition
+}
+#endif /* UCONFIG_NO_SERVICE */
+// -------------------------------------
+
+NumberFormat* U_EXPORT2
+NumberFormat::createInstance(const Locale& loc, EStyles kind, UErrorCode& status)
+{
+#if !UCONFIG_NO_SERVICE
+ UBool haveService;
+ UMTX_CHECK(NULL, gService != NULL, haveService);
+ if (haveService) {
+ return (NumberFormat*)gService->get(loc, kind, status);
+ }
+ else
+#endif
+ {
+ return makeInstance(loc, kind, status);
+ }
+}
+
+
+// -------------------------------------
+// Checks if the thousand/10 thousand grouping is used in the
+// NumberFormat instance.
+
+UBool
+NumberFormat::isGroupingUsed() const
+{
+ return fGroupingUsed;
+}
+
+// -------------------------------------
+// Sets to use the thousand/10 thousand grouping in the
+// NumberFormat instance.
+
+void
+NumberFormat::setGroupingUsed(UBool newValue)
+{
+ fGroupingUsed = newValue;
+}
+
+// -------------------------------------
+// Gets the maximum number of digits for the integral part for
+// this NumberFormat instance.
+
+int32_t NumberFormat::getMaximumIntegerDigits() const
+{
+ return fMaxIntegerDigits;
+}
+
+// -------------------------------------
+// Sets the maximum number of digits for the integral part for
+// this NumberFormat instance.
+
+void
+NumberFormat::setMaximumIntegerDigits(int32_t newValue)
+{
+ fMaxIntegerDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits));
+ if(fMinIntegerDigits > fMaxIntegerDigits)
+ fMinIntegerDigits = fMaxIntegerDigits;
+}
+
+// -------------------------------------
+// Gets the minimum number of digits for the integral part for
+// this NumberFormat instance.
+
+int32_t
+NumberFormat::getMinimumIntegerDigits() const
+{
+ return fMinIntegerDigits;
+}
+
+// -------------------------------------
+// Sets the minimum number of digits for the integral part for
+// this NumberFormat instance.
+
+void
+NumberFormat::setMinimumIntegerDigits(int32_t newValue)
+{
+ fMinIntegerDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits));
+ if(fMinIntegerDigits > fMaxIntegerDigits)
+ fMaxIntegerDigits = fMinIntegerDigits;
+}
+
+// -------------------------------------
+// Gets the maximum number of digits for the fractional part for
+// this NumberFormat instance.
+
+int32_t
+NumberFormat::getMaximumFractionDigits() const
+{
+ return fMaxFractionDigits;
+}
+
+// -------------------------------------
+// Sets the maximum number of digits for the fractional part for
+// this NumberFormat instance.
+
+void
+NumberFormat::setMaximumFractionDigits(int32_t newValue)
+{
+ fMaxFractionDigits = uprv_max(0, uprv_min(newValue, gMaxIntegerDigits));
+ if(fMaxFractionDigits < fMinFractionDigits)
+ fMinFractionDigits = fMaxFractionDigits;
+}
+
+// -------------------------------------
+// Gets the minimum number of digits for the fractional part for
+// this NumberFormat instance.
+
+int32_t
+NumberFormat::getMinimumFractionDigits() const
+{
+ return fMinFractionDigits;
+}
+
+// -------------------------------------
+// Sets the minimum number of digits for the fractional part for
+// this NumberFormat instance.
+
+void
+NumberFormat::setMinimumFractionDigits(int32_t newValue)
+{
+ fMinFractionDigits = uprv_max(0, uprv_min(newValue, gMinIntegerDigits));
+ if (fMaxFractionDigits < fMinFractionDigits)
+ fMaxFractionDigits = fMinFractionDigits;
+}
+
+// -------------------------------------
+
+void NumberFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ if (theCurrency) {
+ u_strncpy(fCurrency, theCurrency, 3);
+ fCurrency[3] = 0;
+ } else {
+ fCurrency[0] = 0;
+ }
+}
+
+const UChar* NumberFormat::getCurrency() const {
+ return fCurrency;
+}
+
+void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
+ const UChar* c = getCurrency();
+ if (*c != 0) {
+ u_strncpy(result, c, 3);
+ result[3] = 0;
+ } else {
+ const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec);
+ if (loc == NULL) {
+ loc = uloc_getDefault();
+ }
+ ucurr_forLocale(loc, result, 4, &ec);
+ }
+}
+
+// -------------------------------------
+// Creates the NumberFormat instance of the specified style (number, currency,
+// or percent) for the desired locale.
+
+NumberFormat*
+NumberFormat::makeInstance(const Locale& desiredLocale,
+ EStyles style,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status)) return NULL;
+
+ if (style < 0 || style >= kStyleCount) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+#ifdef U_WINDOWS
+ char buffer[8];
+ int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status);
+
+ // if the locale has "@compat=host", create a host-specific NumberFormat
+ if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
+ Win32NumberFormat *f = NULL;
+ UBool curr = TRUE;
+
+ switch (style) {
+ case kNumberStyle:
+ curr = FALSE;
+ // fall-through
+
+ case kCurrencyStyle:
+ f = new Win32NumberFormat(desiredLocale, curr, status);
+
+ if (U_SUCCESS(status)) {
+ return f;
+ }
+
+ delete f;
+ break;
+
+ default:
+ break;
+ }
+ }
+#endif
+
+ NumberFormat* f = NULL;
+ DecimalFormatSymbols* symbolsToAdopt = NULL;
+ UnicodeString pattern;
+ UResourceBundle *resource = ures_open((char *)0, desiredLocale.getName(), &status);
+ UResourceBundle *numberPatterns = ures_getByKey(resource, DecimalFormat::fgNumberPatterns, NULL, &status);
+
+ if (U_FAILURE(status)) {
+ // We don't appear to have resource data available -- use the last-resort data
+ status = U_USING_FALLBACK_WARNING;
+ // When the data is unavailable, and locale isn't passed in, last resort data is used.
+ symbolsToAdopt = new DecimalFormatSymbols(status);
+
+ // Creates a DecimalFormat instance with the last resort number patterns.
+ pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1);
+ }
+ else {
+ // If not all the styled patterns exists for the NumberFormat in this locale,
+ // sets the status code to failure and returns nil.
+ if (ures_getSize(numberPatterns) < (int32_t)(sizeof(gLastResortNumberPatterns)/sizeof(gLastResortNumberPatterns[0]))) {
+ status = U_INVALID_FORMAT_ERROR;
+ goto cleanup;
+ }
+
+ // Loads the decimal symbols of the desired locale.
+ symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
+
+ int32_t patLen = 0;
+ const UChar *patResStr = ures_getStringByIndex(numberPatterns, (int32_t)style, &patLen, &status);
+ // Creates the specified decimal format style of the desired locale.
+ pattern.setTo(TRUE, patResStr, patLen);
+ }
+ if (U_FAILURE(status) || symbolsToAdopt == NULL) {
+ goto cleanup;
+ }
+ if(style==kCurrencyStyle){
+ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern();
+ if(currPattern!=NULL){
+ pattern.setTo(currPattern, u_strlen(currPattern));
+ }
+ }
+ f = new DecimalFormat(pattern, symbolsToAdopt, status);
+ if (U_FAILURE(status) || f == NULL) {
+ goto cleanup;
+ }
+
+ f->setLocaleIDs(ures_getLocaleByType(numberPatterns, ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(numberPatterns, ULOC_ACTUAL_LOCALE, &status));
+cleanup:
+ ures_close(numberPatterns);
+ ures_close(resource);
+ if (U_FAILURE(status)) {
+ /* If f exists, then it will delete the symbols */
+ if (f==NULL) {
+ delete symbolsToAdopt;
+ }
+ else {
+ delete f;
+ }
+ return NULL;
+ }
+ if (f == NULL || symbolsToAdopt == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ f = NULL;
+ }
+ return f;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/olsontz.cpp b/Build/source/libs/icu/icu-xetex/i18n/olsontz.cpp
new file mode 100644
index 00000000000..e98b9ef6e40
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/olsontz.cpp
@@ -0,0 +1,959 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: July 21 2003
+* Since: ICU 2.8
+**********************************************************************
+*/
+
+#include "olsontz.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ures.h"
+#include "unicode/simpletz.h"
+#include "unicode/gregocal.h"
+#include "gregoimp.h"
+#include "cmemory.h"
+#include "uassert.h"
+#include "uvector.h"
+#include <float.h> // DBL_MAX
+
+#ifdef U_DEBUG_TZ
+# include <stdio.h>
+# include "uresimp.h" // for debugging
+
+static void debug_tz_loc(const char *f, int32_t l)
+{
+ fprintf(stderr, "%s:%d: ", f, l);
+}
+
+static void debug_tz_msg(const char *pat, ...)
+{
+ va_list ap;
+ va_start(ap, pat);
+ vfprintf(stderr, pat, ap);
+ fflush(stderr);
+}
+// must use double parens, i.e.: U_DEBUG_TZ_MSG(("four is: %d",4));
+#define U_DEBUG_TZ_MSG(x) {debug_tz_loc(__FILE__,__LINE__);debug_tz_msg x;}
+#else
+#define U_DEBUG_TZ_MSG(x)
+#endif
+
+U_NAMESPACE_BEGIN
+
+#define SECONDS_PER_DAY (24*60*60)
+
+static const int32_t ZEROS[] = {0,0};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone)
+
+/**
+ * Default constructor. Creates a time zone with an empty ID and
+ * a fixed GMT offset of zero.
+ */
+/*OlsonTimeZone::OlsonTimeZone() : finalYear(INT32_MAX), finalMillis(DBL_MAX), finalZone(0), transitionRulesInitialized(FALSE) {
+ clearTransitionRules();
+ constructEmpty();
+}*/
+
+/**
+ * Construct a GMT+0 zone with no transitions. This is done when a
+ * constructor fails so the resultant object is well-behaved.
+ */
+void OlsonTimeZone::constructEmpty() {
+ transitionCount = 0;
+ typeCount = 1;
+ transitionTimes = typeOffsets = ZEROS;
+ typeData = (const uint8_t*) ZEROS;
+}
+
+/**
+ * Construct from a resource bundle
+ * @param top the top-level zoneinfo resource bundle. This is used
+ * to lookup the rule that `res' may refer to, if there is one.
+ * @param res the resource bundle of the zone to be constructed
+ * @param ec input-output error code
+ */
+OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
+ const UResourceBundle* res,
+ UErrorCode& ec) :
+ finalYear(INT32_MAX), finalMillis(DBL_MAX), finalZone(0), transitionRulesInitialized(FALSE)
+{
+ clearTransitionRules();
+ U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res)));
+ if ((top == NULL || res == NULL) && U_SUCCESS(ec)) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ if (U_SUCCESS(ec)) {
+ // TODO -- clean up -- Doesn't work if res points to an alias
+ // // TODO remove nonconst casts below when ures_* API is fixed
+ // setID(ures_getKey((UResourceBundle*) res)); // cast away const
+
+ // Size 1 is an alias TO another zone (int)
+ // HOWEVER, the caller should dereference this and never pass it in to us
+ // Size 3 is a purely historical zone (no final rules)
+ // Size 4 is like size 3, but with an alias list at the end
+ // Size 5 is a hybrid zone, with historical and final elements
+ // Size 6 is like size 5, but with an alias list at the end
+ int32_t size = ures_getSize(res);
+ if (size < 3 || size > 6) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+
+ // Transitions list may be empty
+ int32_t i;
+ UResourceBundle* r = ures_getByIndex(res, 0, NULL, &ec);
+ transitionTimes = ures_getIntVector(r, &i, &ec);
+ if ((i<0 || i>0x7FFF) && U_SUCCESS(ec)) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+ transitionCount = (int16_t) i;
+
+ // Type offsets list must be of even size, with size >= 2
+ r = ures_getByIndex(res, 1, r, &ec);
+ typeOffsets = ures_getIntVector(r, &i, &ec);
+ if ((i<2 || i>0x7FFE || ((i&1)!=0)) && U_SUCCESS(ec)) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+ typeCount = (int16_t) i >> 1;
+
+ // Type data must be of the same size as the transitions list
+ r = ures_getByIndex(res, 2, r, &ec);
+ int32_t len;
+ typeData = ures_getBinary(r, &len, &ec);
+ ures_close(r);
+ if (len != transitionCount && U_SUCCESS(ec)) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+
+#if defined (U_DEBUG_TZ)
+ U_DEBUG_TZ_MSG(("OlsonTimeZone(%s) - size = %d, typecount %d transitioncount %d - err %s\n", ures_getKey((UResourceBundle*)res), size, typeCount, transitionCount, u_errorName(ec)));
+ if(U_SUCCESS(ec)) {
+ int32_t jj;
+ for(jj=0;jj<transitionCount;jj++) {
+ int32_t year, month, dom, dow;
+ double millis=0;
+ double days = Math::floorDivide(((double)transitionTimes[jj])*1000.0, (double)U_MILLIS_PER_DAY, millis);
+
+ Grego::dayToFields(days, year, month, dom, dow);
+ U_DEBUG_TZ_MSG((" Transition %d: time %d (%04d.%02d.%02d+%.1fh), typedata%d\n", jj, transitionTimes[jj],
+ year, month+1, dom, (millis/kOneHour), typeData[jj]));
+// U_DEBUG_TZ_MSG((" offset%d\n", typeOffsets[jj]));
+ int16_t f = jj;
+ f <<= 1;
+ U_DEBUG_TZ_MSG((" offsets[%d+%d]=(%d+%d)=(%d==%d)\n", (int)f,(int)f+1,(int)typeOffsets[f],(int)typeOffsets[f+1],(int)zoneOffset(jj),
+ (int)typeOffsets[f]+(int)typeOffsets[f+1]));
+ }
+ }
+#endif
+
+ // Process final rule and data, if any
+ if (size >= 5) {
+ int32_t ruleidLen = 0;
+ const UChar* idUStr = ures_getStringByIndex(res, 3, &ruleidLen, &ec);
+ UnicodeString ruleid(TRUE, idUStr, ruleidLen);
+ r = ures_getByIndex(res, 4, NULL, &ec);
+ const int32_t* data = ures_getIntVector(r, &len, &ec);
+#if defined U_DEBUG_TZ
+ const char *rKey = ures_getKey(r);
+ const char *zKey = ures_getKey((UResourceBundle*)res);
+#endif
+ ures_close(r);
+ if (U_SUCCESS(ec)) {
+ if (data != 0 && len == 2) {
+ int32_t rawOffset = data[0] * U_MILLIS_PER_SECOND;
+ // Subtract one from the actual final year; we
+ // actually store final year - 1, and compare
+ // using > rather than >=. This allows us to use
+ // INT32_MAX as an exclusive upper limit for all
+ // years, including INT32_MAX.
+ U_ASSERT(data[1] > INT32_MIN);
+ finalYear = data[1] - 1;
+ // Also compute the millis for Jan 1, 0:00 GMT of the
+ // finalYear. This reduces runtime computations.
+ finalMillis = Grego::fieldsToDay(data[1], 0, 1) * U_MILLIS_PER_DAY;
+ U_DEBUG_TZ_MSG(("zone%s|%s: {%d,%d}, finalYear%d, finalMillis%.1lf\n",
+ zKey,rKey, data[0], data[1], finalYear, finalMillis));
+ r = TimeZone::loadRule(top, ruleid, NULL, ec);
+ if (U_SUCCESS(ec)) {
+ // 3, 1, -1, 7200, 0, 9, -31, -1, 7200, 0, 3600
+ data = ures_getIntVector(r, &len, &ec);
+ if (U_SUCCESS(ec) && len == 11) {
+ UnicodeString emptyStr;
+ U_DEBUG_TZ_MSG(("zone%s, rule%s: {%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d}\n", zKey, ures_getKey(r),
+ data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10]));
+ finalZone = new SimpleTimeZone(rawOffset, emptyStr,
+ (int8_t)data[0], (int8_t)data[1], (int8_t)data[2],
+ data[3] * U_MILLIS_PER_SECOND,
+ (SimpleTimeZone::TimeMode) data[4],
+ (int8_t)data[5], (int8_t)data[6], (int8_t)data[7],
+ data[8] * U_MILLIS_PER_SECOND,
+ (SimpleTimeZone::TimeMode) data[9],
+ data[10] * U_MILLIS_PER_SECOND, ec);
+ } else {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ ures_close(r);
+ } else {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ }
+ }
+
+ if (U_FAILURE(ec)) {
+ constructEmpty();
+ }
+}
+
+/**
+ * Copy constructor
+ */
+OlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) :
+ BasicTimeZone(other), finalZone(0) {
+ *this = other;
+}
+
+/**
+ * Assignment operator
+ */
+OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
+ transitionCount = other.transitionCount;
+ typeCount = other.typeCount;
+ transitionTimes = other.transitionTimes;
+ typeOffsets = other.typeOffsets;
+ typeData = other.typeData;
+ finalYear = other.finalYear;
+ finalMillis = other.finalMillis;
+ delete finalZone;
+ finalZone = (other.finalZone != 0) ?
+ (SimpleTimeZone*) other.finalZone->clone() : 0;
+ clearTransitionRules();
+ return *this;
+}
+
+/**
+ * Destructor
+ */
+OlsonTimeZone::~OlsonTimeZone() {
+ deleteTransitionRules();
+ delete finalZone;
+}
+
+/**
+ * Returns true if the two TimeZone objects are equal.
+ */
+UBool OlsonTimeZone::operator==(const TimeZone& other) const {
+ return ((this == &other) ||
+ (getDynamicClassID() == other.getDynamicClassID() &&
+ TimeZone::operator==(other) &&
+ hasSameRules(other)));
+}
+
+/**
+ * TimeZone API.
+ */
+TimeZone* OlsonTimeZone::clone() const {
+ return new OlsonTimeZone(*this);
+}
+
+/**
+ * TimeZone API.
+ */
+int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
+ int32_t dom, uint8_t dow,
+ int32_t millis, UErrorCode& ec) const {
+ if (month < UCAL_JANUARY || month > UCAL_DECEMBER) {
+ if (U_SUCCESS(ec)) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return 0;
+ } else {
+ return getOffset(era, year, month, dom, dow, millis,
+ Grego::monthLength(year, month),
+ ec);
+ }
+}
+
+/**
+ * TimeZone API.
+ */
+int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
+ int32_t dom, uint8_t dow,
+ int32_t millis, int32_t monthLength,
+ UErrorCode& ec) const {
+ if (U_FAILURE(ec)) {
+ return 0;
+ }
+
+ if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC)
+ || month < UCAL_JANUARY
+ || month > UCAL_DECEMBER
+ || dom < 1
+ || dom > monthLength
+ || dow < UCAL_SUNDAY
+ || dow > UCAL_SATURDAY
+ || millis < 0
+ || millis >= U_MILLIS_PER_DAY
+ || monthLength < 28
+ || monthLength > 31) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ if (era == GregorianCalendar::BC) {
+ year = -year;
+ }
+
+ if (year > finalYear) { // [sic] >, not >=; see above
+ U_ASSERT(finalZone != 0);
+ return finalZone->getOffset(era, year, month, dom, dow,
+ millis, monthLength, ec);
+ }
+
+ // Compute local epoch millis from input fields
+ UDate date = (UDate)(Grego::fieldsToDay(year, month, dom) * U_MILLIS_PER_DAY + millis);
+ int32_t rawoff, dstoff;
+ getHistoricalOffset(date, TRUE, kDaylight, kStandard, rawoff, dstoff);
+ return rawoff + dstoff;
+}
+
+/**
+ * TimeZone API.
+ */
+void OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff,
+ int32_t& dstoff, UErrorCode& ec) const {
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ // The check against finalMillis will suffice most of the time, except
+ // for the case in which finalMillis == DBL_MAX, date == DBL_MAX,
+ // and finalZone == 0. For this case we add "&& finalZone != 0".
+ if (date >= finalMillis && finalZone != 0) {
+ finalZone->getOffset(date, local, rawoff, dstoff, ec);
+ } else {
+ getHistoricalOffset(date, local, kFormer, kLatter, rawoff, dstoff);
+ }
+}
+
+void
+OlsonTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) /*const*/ {
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ if (date >= finalMillis && finalZone != 0) {
+ finalZone->getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff, ec);
+ } else {
+ getHistoricalOffset(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff);
+ }
+}
+
+
+/**
+ * TimeZone API.
+ */
+void OlsonTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
+ // We don't support this operation, since OlsonTimeZones are
+ // immutable (except for the ID, which is in the base class).
+
+ // Nothing to do!
+}
+
+/**
+ * TimeZone API.
+ */
+int32_t OlsonTimeZone::getRawOffset() const {
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t raw, dst;
+ getOffset((double) uprv_getUTCtime() * U_MILLIS_PER_SECOND,
+ FALSE, raw, dst, ec);
+ return raw;
+}
+
+#if defined U_DEBUG_TZ
+void printTime(double ms) {
+ int32_t year, month, dom, dow;
+ double millis=0;
+ double days = Math::floorDivide(((double)ms), (double)U_MILLIS_PER_DAY, millis);
+
+ Grego::dayToFields(days, year, month, dom, dow);
+ U_DEBUG_TZ_MSG((" getHistoricalOffset: time %.1f (%04d.%02d.%02d+%.1fh)\n", ms,
+ year, month+1, dom, (millis/kOneHour)));
+ }
+#endif
+
+void
+OlsonTimeZone::getHistoricalOffset(UDate date, UBool local,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
+ int32_t& rawoff, int32_t& dstoff) const {
+ U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst)\n",
+ date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt));
+#if defined U_DEBUG_TZ
+ printTime(date*1000.0);
+#endif
+ if (transitionCount != 0) {
+ double sec = uprv_floor(date / U_MILLIS_PER_SECOND);
+ // Linear search from the end is the fastest approach, since
+ // most lookups will happen at/near the end.
+ int16_t i;
+ for (i = transitionCount - 1; i > 0; --i) {
+ int32_t transition = transitionTimes[i];
+
+ if (local) {
+ int32_t offsetBefore = zoneOffset(typeData[i-1]);
+ UBool dstBefore = dstOffset(typeData[i-1]) != 0;
+
+ int32_t offsetAfter = zoneOffset(typeData[i]);
+ UBool dstAfter = dstOffset(typeData[i]) != 0;
+
+ UBool dstToStd = dstBefore && !dstAfter;
+ UBool stdToDst = !dstBefore && dstAfter;
+
+ if (offsetAfter - offsetBefore >= 0) {
+ // Positive transition, which makes a non-existing local time range
+ if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
+ || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
+ transition += offsetBefore;
+ } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
+ || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
+ transition += offsetAfter;
+ } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
+ transition += offsetBefore;
+ } else {
+ // Interprets the time with rule before the transition,
+ // default for non-existing time range
+ transition += offsetAfter;
+ }
+ } else {
+ // Negative transition, which makes a duplicated local time range
+ if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
+ || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
+ transition += offsetAfter;
+ } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
+ || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
+ transition += offsetBefore;
+ } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
+ transition += offsetBefore;
+ } else {
+ // Interprets the time with rule after the transition,
+ // default for duplicated local time range
+ transition += offsetAfter;
+ }
+ }
+ }
+ if (sec >= transition) {
+ U_DEBUG_TZ_MSG(("Found@%d: time=%.1f, localtransition=%d (orig %d) dz %d\n", i, sec, transition, transitionTimes[i],
+ zoneOffset(typeData[i-1])));
+#if defined U_DEBUG_TZ
+ printTime(transition*1000.0);
+ printTime(transitionTimes[i]*1000.0);
+#endif
+ break;
+ } else {
+ U_DEBUG_TZ_MSG(("miss@%d: time=%.1f, localtransition=%d (orig %d) dz %d\n", i, sec, transition, transitionTimes[i],
+ zoneOffset(typeData[i-1])));
+#if defined U_DEBUG_TZ
+ printTime(transition*1000.0);
+ printTime(transitionTimes[i]*1000.0);
+#endif
+ }
+ }
+
+ U_ASSERT(i>=0 && i<transitionCount);
+
+ // Check invariants for GMT times; if these pass for GMT times
+ // the local logic should be working too.
+ U_ASSERT(local || sec < transitionTimes[0] || sec >= transitionTimes[i]);
+ U_ASSERT(local || i == transitionCount-1 || sec < transitionTimes[i+1]);
+
+ U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - trans %d\n",
+ date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, i));
+
+ // Since ICU tzdata 2007c, the first transition data is actually not a
+ // transition, but used for representing the initial offset. So the code
+ // below works even if i == 0.
+ int16_t index = typeData[i];
+ rawoff = rawOffset(index) * U_MILLIS_PER_SECOND;
+ dstoff = dstOffset(index) * U_MILLIS_PER_SECOND;
+ } else {
+ // No transitions, single pair of offsets only
+ rawoff = rawOffset(0) * U_MILLIS_PER_SECOND;
+ dstoff = dstOffset(0) * U_MILLIS_PER_SECOND;
+ }
+ U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - raw=%d, dst=%d\n",
+ date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, rawoff, dstoff));
+}
+
+/**
+ * TimeZone API.
+ */
+UBool OlsonTimeZone::useDaylightTime() const {
+ // If DST was observed in 1942 (for example) but has never been
+ // observed from 1943 to the present, most clients will expect
+ // this method to return FALSE. This method determines whether
+ // DST is in use in the current year (at any point in the year)
+ // and returns TRUE if so.
+
+ int32_t days = (int32_t)Math::floorDivide(uprv_getUTCtime(), (double)U_MILLIS_PER_DAY); // epoch days
+
+ int32_t year, month, dom, dow;
+
+ Grego::dayToFields(days, year, month, dom, dow);
+
+ if (year > finalYear) { // [sic] >, not >=; see above
+ U_ASSERT(finalZone != 0 && finalZone->useDaylightTime());
+ return TRUE;
+ }
+
+ // Find start of this year, and start of next year
+ int32_t start = (int32_t) Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
+ int32_t limit = (int32_t) Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY;
+
+ // Return TRUE if DST is observed at any time during the current
+ // year.
+ for (int16_t i=0; i<transitionCount; ++i) {
+ if (transitionTimes[i] >= limit) {
+ break;
+ }
+ if (transitionTimes[i] >= start &&
+ dstOffset(typeData[i]) != 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+int32_t
+OlsonTimeZone::getDSTSavings() const{
+ if(finalZone!=NULL){
+ return finalZone->getDSTSavings();
+ }
+ return TimeZone::getDSTSavings();
+}
+/**
+ * TimeZone API.
+ */
+UBool OlsonTimeZone::inDaylightTime(UDate date, UErrorCode& ec) const {
+ int32_t raw, dst;
+ getOffset(date, FALSE, raw, dst, ec);
+ return dst != 0;
+}
+
+UBool
+OlsonTimeZone::hasSameRules(const TimeZone &other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ if (other.getDynamicClassID() != OlsonTimeZone::getStaticClassID()) {
+ return FALSE;
+ }
+ const OlsonTimeZone* z = (const OlsonTimeZone*) &other;
+
+ // [sic] pointer comparison: typeData points into
+ // memory-mapped or DLL space, so if two zones have the same
+ // pointer, they are equal.
+ if (typeData == z->typeData) {
+ return TRUE;
+ }
+
+ // If the pointers are not equal, the zones may still
+ // be equal if their rules and transitions are equal
+ return
+ (finalYear == z->finalYear &&
+ // Don't compare finalMillis; if finalYear is ==, so is finalMillis
+ ((finalZone == 0 && z->finalZone == 0) ||
+ (finalZone != 0 && z->finalZone != 0 && *finalZone == *z->finalZone)) &&
+
+ transitionCount == z->transitionCount &&
+ typeCount == z->typeCount &&
+ uprv_memcmp(transitionTimes, z->transitionTimes,
+ sizeof(transitionTimes[0]) * transitionCount) == 0 &&
+ uprv_memcmp(typeOffsets, z->typeOffsets,
+ (sizeof(typeOffsets[0]) * typeCount) << 1) == 0 &&
+ uprv_memcmp(typeData, z->typeData,
+ (sizeof(typeData[0]) * typeCount)) == 0);
+}
+
+void
+OlsonTimeZone::clearTransitionRules(void) {
+ initialRule = NULL;
+ firstTZTransition = NULL;
+ firstFinalTZTransition = NULL;
+ historicRules = NULL;
+ historicRuleCount = 0;
+ finalZoneWithStartYear = NULL;
+ firstTZTransitionIdx = 0;
+ transitionRulesInitialized = FALSE;
+}
+
+void
+OlsonTimeZone::deleteTransitionRules(void) {
+ if (initialRule != NULL) {
+ delete initialRule;
+ }
+ if (firstTZTransition != NULL) {
+ delete firstTZTransition;
+ }
+ if (firstFinalTZTransition != NULL) {
+ delete firstFinalTZTransition;
+ }
+ if (finalZoneWithStartYear != NULL) {
+ delete finalZoneWithStartYear;
+ }
+ if (historicRules != NULL) {
+ for (int i = 0; i < historicRuleCount; i++) {
+ if (historicRules[i] != NULL) {
+ delete historicRules[i];
+ }
+ }
+ uprv_free(historicRules);
+ }
+ clearTransitionRules();
+}
+
+void
+OlsonTimeZone::initTransitionRules(UErrorCode& status) {
+ if(U_FAILURE(status)) {
+ return;
+ }
+ if (transitionRulesInitialized) {
+ return;
+ }
+ deleteTransitionRules();
+ UnicodeString tzid;
+ getID(tzid);
+
+ UnicodeString stdName = tzid + UNICODE_STRING_SIMPLE("(STD)");
+ UnicodeString dstName = tzid + UNICODE_STRING_SIMPLE("(DST)");
+
+ int32_t raw, dst;
+ if (transitionCount > 0) {
+ int16_t transitionIdx, typeIdx;
+
+ // Note: Since 2007c, the very first transition data is a dummy entry
+ // added for resolving a offset calculation problem.
+
+ // Create initial rule
+ typeIdx = (int16_t)typeData[0]; // initial type
+ raw = rawOffset(typeIdx) * U_MILLIS_PER_SECOND;
+ dst = dstOffset(typeIdx) * U_MILLIS_PER_SECOND;
+ initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
+
+ firstTZTransitionIdx = 0;
+ for (transitionIdx = 1; transitionIdx < transitionCount; transitionIdx++) {
+ firstTZTransitionIdx++;
+ if (typeIdx != (int16_t)typeData[transitionIdx]) {
+ break;
+ }
+ }
+ if (transitionIdx == transitionCount) {
+ // Actually no transitions...
+ } else {
+ // Build historic rule array
+ UDate* times = (UDate*)uprv_malloc(sizeof(UDate)*transitionCount); /* large enough to store all transition times */
+ if (times == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ for (typeIdx = 0; typeIdx < typeCount; typeIdx++) {
+ // Gather all start times for each pair of offsets
+ int32_t nTimes = 0;
+ for (transitionIdx = firstTZTransitionIdx; transitionIdx < transitionCount; transitionIdx++) {
+ if (typeIdx == (int16_t)typeData[transitionIdx]) {
+ UDate tt = ((UDate)transitionTimes[transitionIdx]) * U_MILLIS_PER_SECOND;
+ if (tt < finalMillis) {
+ // Exclude transitions after finalMillis
+ times[nTimes++] = tt;
+ }
+ }
+ }
+ if (nTimes > 0) {
+ // Create a TimeArrayTimeZoneRule
+ raw = rawOffset(typeIdx) * U_MILLIS_PER_SECOND;
+ dst = dstOffset(typeIdx) * U_MILLIS_PER_SECOND;
+ if (historicRules == NULL) {
+ historicRuleCount = typeCount;
+ historicRules = (TimeArrayTimeZoneRule**)uprv_malloc(sizeof(TimeArrayTimeZoneRule*)*historicRuleCount);
+ if (historicRules == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ uprv_free(times);
+ return;
+ }
+ for (int i = 0; i < historicRuleCount; i++) {
+ // Initialize TimeArrayTimeZoneRule pointers as NULL
+ historicRules[i] = NULL;
+ }
+ }
+ historicRules[typeIdx] = new TimeArrayTimeZoneRule((dst == 0 ? stdName : dstName),
+ raw, dst, times, nTimes, DateTimeRule::UTC_TIME);
+ }
+ }
+ uprv_free(times);
+
+ // Create initial transition
+ typeIdx = (int16_t)typeData[firstTZTransitionIdx];
+ firstTZTransition = new TimeZoneTransition(((UDate)transitionTimes[firstTZTransitionIdx]) * U_MILLIS_PER_SECOND,
+ *initialRule, *historicRules[typeIdx]);
+ }
+ }
+ if (initialRule == NULL) {
+ // No historic transitions
+ raw = rawOffset(0) * U_MILLIS_PER_SECOND;
+ dst = dstOffset(0) * U_MILLIS_PER_SECOND;
+ initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
+ }
+ if (finalZone != NULL) {
+ // Get the first occurence of final rule starts
+ UDate startTime = (UDate)finalMillis;
+ TimeZoneRule *firstFinalRule = NULL;
+ if (finalZone->useDaylightTime()) {
+ /*
+ * Note: When an OlsonTimeZone is constructed, we should set the final year
+ * as the start year of finalZone. However, the bounday condition used for
+ * getting offset from finalZone has some problems. So setting the start year
+ * in the finalZone will cause a problem. For now, we do not set the valid
+ * start year when the construction time and create a clone and set the
+ * start year when extracting rules.
+ */
+ finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
+ // finalYear is 1 year before the actual final year.
+ // See the comment in the construction method.
+ finalZoneWithStartYear->setStartYear(finalYear + 1);
+
+ TimeZoneTransition tzt;
+ finalZoneWithStartYear->getNextTransition(startTime, false, tzt);
+ firstFinalRule = tzt.getTo()->clone();
+ startTime = tzt.getTime();
+ } else {
+ finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
+ finalZone->getID(tzid);
+ firstFinalRule = new TimeArrayTimeZoneRule(tzid,
+ finalZone->getRawOffset(), 0, &startTime, 1, DateTimeRule::UTC_TIME);
+ }
+ TimeZoneRule *prevRule = NULL;
+ if (transitionCount > 0) {
+ prevRule = historicRules[typeData[transitionCount - 1]];
+ }
+ if (prevRule == NULL) {
+ // No historic transitions, but only finalZone available
+ prevRule = initialRule;
+ }
+ firstFinalTZTransition = new TimeZoneTransition();
+ firstFinalTZTransition->setTime(startTime);
+ firstFinalTZTransition->adoptFrom(prevRule->clone());
+ firstFinalTZTransition->adoptTo(firstFinalRule);
+ }
+ transitionRulesInitialized = TRUE;
+}
+
+UBool
+OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+ UErrorCode status = U_ZERO_ERROR;
+ initTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ if (finalZone != NULL) {
+ if (inclusive && base == firstFinalTZTransition->getTime()) {
+ result = *firstFinalTZTransition;
+ return TRUE;
+ } else if (base >= firstFinalTZTransition->getTime()) {
+ if (finalZone->useDaylightTime()) {
+ //return finalZone->getNextTransition(base, inclusive, result);
+ return finalZoneWithStartYear->getNextTransition(base, inclusive, result);
+ } else {
+ // No more transitions
+ return FALSE;
+ }
+ }
+ }
+ if (historicRules != NULL) {
+ // Find a historical transition
+ int16_t ttidx = transitionCount - 1;
+ for (; ttidx >= firstTZTransitionIdx; ttidx--) {
+ UDate t = ((UDate)transitionTimes[ttidx]) * U_MILLIS_PER_SECOND;
+ if (base > t || (!inclusive && base == t)) {
+ break;
+ }
+ }
+ if (ttidx == transitionCount - 1) {
+ if (firstFinalTZTransition != NULL) {
+ result = *firstFinalTZTransition;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if (ttidx < firstTZTransitionIdx) {
+ result = *firstTZTransition;
+ return TRUE;
+ } else {
+ // Create a TimeZoneTransition
+ TimeZoneRule *to = historicRules[typeData[ttidx + 1]];
+ TimeZoneRule *from = historicRules[typeData[ttidx]];
+ UDate startTime = ((UDate)transitionTimes[ttidx+1]) * U_MILLIS_PER_SECOND;
+
+ // The transitions loaded from zoneinfo.res may contain non-transition data
+ UnicodeString fromName, toName;
+ from->getName(fromName);
+ to->getName(toName);
+ if (fromName == toName && from->getRawOffset() == to->getRawOffset()
+ && from->getDSTSavings() == to->getDSTSavings()) {
+ return getNextTransition(startTime, false, result);
+ }
+ result.setTime(startTime);
+ result.adoptFrom(from->clone());
+ result.adoptTo(to->clone());
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+UBool
+OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+ UErrorCode status = U_ZERO_ERROR;
+ initTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ if (finalZone != NULL) {
+ if (inclusive && base == firstFinalTZTransition->getTime()) {
+ result = *firstFinalTZTransition;
+ return TRUE;
+ } else if (base > firstFinalTZTransition->getTime()) {
+ if (finalZone->useDaylightTime()) {
+ //return finalZone->getPreviousTransition(base, inclusive, result);
+ return finalZoneWithStartYear->getPreviousTransition(base, inclusive, result);
+ } else {
+ result = *firstFinalTZTransition;
+ return TRUE;
+ }
+ }
+ }
+
+ if (historicRules != NULL) {
+ // Find a historical transition
+ int16_t ttidx = transitionCount - 1;
+ for (; ttidx >= firstTZTransitionIdx; ttidx--) {
+ UDate t = ((UDate)transitionTimes[ttidx]) * U_MILLIS_PER_SECOND;
+ if (base > t || (inclusive && base == t)) {
+ break;
+ }
+ }
+ if (ttidx < firstTZTransitionIdx) {
+ // No more transitions
+ return FALSE;
+ } else if (ttidx == firstTZTransitionIdx) {
+ result = *firstTZTransition;
+ return TRUE;
+ } else {
+ // Create a TimeZoneTransition
+ TimeZoneRule *to = historicRules[typeData[ttidx]];
+ TimeZoneRule *from = historicRules[typeData[ttidx-1]];
+ UDate startTime = ((UDate)transitionTimes[ttidx]) * U_MILLIS_PER_SECOND;
+
+ // The transitions loaded from zoneinfo.res may contain non-transition data
+ UnicodeString fromName, toName;
+ from->getName(fromName);
+ to->getName(toName);
+ if (fromName == toName && from->getRawOffset() == to->getRawOffset()
+ && from->getDSTSavings() == to->getDSTSavings()) {
+ return getPreviousTransition(startTime, false, result);
+ }
+ result.setTime(startTime);
+ result.adoptFrom(from->clone());
+ result.adoptTo(to->clone());
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+int32_t
+OlsonTimeZone::countTransitionRules(UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ initTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ int32_t count = 0;
+ if (historicRules != NULL) {
+ // historicRules may contain null entries when original zoneinfo data
+ // includes non transition data.
+ for (int32_t i = 0; i < historicRuleCount; i++) {
+ if (historicRules[i] != NULL) {
+ count++;
+ }
+ }
+ }
+ if (finalZone != NULL) {
+ if (finalZone->useDaylightTime()) {
+ count += 2;
+ } else {
+ count++;
+ }
+ }
+ return count;
+}
+
+void
+OlsonTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[],
+ int32_t& trscount,
+ UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ initTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Initial rule
+ initial = initialRule;
+
+ // Transition rules
+ int32_t cnt = 0;
+ if (historicRules != NULL && trscount > cnt) {
+ // historicRules may contain null entries when original zoneinfo data
+ // includes non transition data.
+ for (int32_t i = 0; i < historicRuleCount; i++) {
+ if (historicRules[i] != NULL) {
+ trsrules[cnt++] = historicRules[i];
+ if (cnt >= trscount) {
+ break;
+ }
+ }
+ }
+ }
+ if (finalZoneWithStartYear != NULL && trscount > cnt) {
+ const InitialTimeZoneRule *tmpini;
+ int32_t tmpcnt = trscount - cnt;
+ finalZoneWithStartYear->getTimeZoneRules(tmpini, &trsrules[cnt], tmpcnt, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ cnt += tmpcnt;
+ }
+ // Set the result length
+ trscount = cnt;
+}
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/olsontz.h b/Build/source/libs/icu/icu-xetex/i18n/olsontz.h
new file mode 100644
index 00000000000..64f8c0d774a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/olsontz.h
@@ -0,0 +1,382 @@
+/*
+**********************************************************************
+* Copyright (c) 2003-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: July 21 2003
+* Since: ICU 2.8
+**********************************************************************
+*/
+#ifndef OLSONTZ_H
+#define OLSONTZ_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/basictz.h"
+
+struct UResourceBundle;
+
+U_NAMESPACE_BEGIN
+
+class SimpleTimeZone;
+
+/**
+ * A time zone based on the Olson database. Olson time zones change
+ * behavior over time. The raw offset, rules, presence or absence of
+ * daylight savings time, and even the daylight savings amount can all
+ * vary.
+ *
+ * This class uses a resource bundle named "zoneinfo". Zoneinfo is a
+ * table containing different kinds of resources. In several places,
+ * zones are referred to using integers. A zone's integer is a number
+ * from 0..n-1, where n is the number of zones, with the zones sorted
+ * in lexicographic order.
+ *
+ * 1. Zones. These have keys corresponding to the Olson IDs, e.g.,
+ * "Asia/Shanghai". Each resource describes the behavior of the given
+ * zone. Zones come in several formats, which are differentiated
+ * based on length.
+ *
+ * a. Alias (int, length 1). An alias zone is an int resource. The
+ * integer is the zone number of the target zone. The key of this
+ * resource is an alternate name for the target zone. Aliases
+ * represent Olson links and ICU compatibility IDs.
+ *
+ * b. Simple zone (array, length 3). The three subelements are:
+ *
+ * i. An intvector of transitions. These are given in epoch
+ * seconds. This may be an empty invector (length 0). If the
+ * transtions list is empty, then the zone's behavior is fixed and
+ * given by the offset list, which will contain exactly one pair.
+ * Otherwise each transtion indicates a time after which (inclusive)
+ * the associated offset pair is in effect.
+ *
+ * ii. An intvector of offsets. These are in pairs of raw offset /
+ * DST offset, in units of seconds. There will be at least one pair
+ * (length >= 2 && length % 2 == 0).
+ *
+ * iii. A binary resource. This is of the same length as the
+ * transitions vector, so length may be zero. Each unsigned byte
+ * corresponds to one transition, and has a value of 0..n-1, where n
+ * is the number of pairs in the offset vector. This forms a map
+ * between transitions and offset pairs.
+ *
+ * c. Simple zone with aliases (array, length 4). This is like a
+ * simple zone, but also contains a fourth element:
+ *
+ * iv. An intvector of aliases. This list includes this zone
+ * itself, and lists all aliases of this zone.
+ *
+ * d. Complex zone (array, length 5). This is like a simple zone,
+ * but contains two more elements:
+ *
+ * iv. A string, giving the name of a rule. This is the "final
+ * rule", which governs the zone's behavior beginning in the "final
+ * year". The rule ID is given without leading underscore, e.g.,
+ * "EU".
+ *
+ * v. An intvector of length 2, containing the raw offset for the
+ * final rule (in seconds), and the final year. The final rule
+ * takes effect for years >= the final year.
+ *
+ * e. Complex zone with aliases (array, length 6). This is like a
+ * complex zone, but also contains a sixth element:
+ *
+ * vi. An intvector of aliases. This list includes this zone
+ * itself, and lists all aliases of this zone.
+ *
+ * 2. Rules. These have keys corresponding to the Olson rule IDs,
+ * with an underscore prepended, e.g., "_EU". Each resource describes
+ * the behavior of the given rule using an intvector, containing the
+ * onset list, the cessation list, and the DST savings. The onset and
+ * cessation lists consist of the month, dowim, dow, time, and time
+ * mode. The end result is that the 11 integers describing the rule
+ * can be passed directly into the SimpleTimeZone 13-argument
+ * constructor (the other two arguments will be the raw offset, taken
+ * from the complex zone element 5, and the ID string, which is not
+ * used), with the times and the DST savings multiplied by 1000 to
+ * scale from seconds to milliseconds.
+ *
+ * 3. Countries. These have keys corresponding to the 2-letter ISO
+ * country codes, with a percent sign prepended, e.g., "%US". Each
+ * resource is an intvector listing the zones associated with the
+ * given country. The special entry "%" corresponds to "no country",
+ * that is, the category of zones assigned to no country in the Olson
+ * DB.
+ *
+ * 4. Metadata. Metadata is stored under the key "_". It is an
+ * intvector of length three containing the number of zones resources,
+ * rule resources, and country resources. For the purposes of this
+ * count, the metadata entry itself is considered a rule resource,
+ * since its key begins with an underscore.
+ */
+class OlsonTimeZone: public BasicTimeZone {
+ public:
+ /**
+ * Construct from a resource bundle.
+ * @param top the top-level zoneinfo resource bundle. This is used
+ * to lookup the rule that `res' may refer to, if there is one.
+ * @param res the resource bundle of the zone to be constructed
+ * @param ec input-output error code
+ */
+ OlsonTimeZone(const UResourceBundle* top,
+ const UResourceBundle* res, UErrorCode& ec);
+
+ /**
+ * Copy constructor
+ */
+ OlsonTimeZone(const OlsonTimeZone& other);
+
+ /**
+ * Destructor
+ */
+ virtual ~OlsonTimeZone();
+
+ /**
+ * Assignment operator
+ */
+ OlsonTimeZone& operator=(const OlsonTimeZone& other);
+
+ /**
+ * Returns true if the two TimeZone objects are equal.
+ */
+ virtual UBool operator==(const TimeZone& other) const;
+
+ /**
+ * TimeZone API.
+ */
+ virtual TimeZone* clone() const;
+
+ /**
+ * TimeZone API.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * TimeZone API.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * TimeZone API. Do not call this; prefer getOffset(UDate,...).
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month,
+ int32_t day, uint8_t dayOfWeek,
+ int32_t millis, UErrorCode& ec) const;
+
+ /**
+ * TimeZone API. Do not call this; prefer getOffset(UDate,...).
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month,
+ int32_t day, uint8_t dayOfWeek,
+ int32_t millis, int32_t monthLength,
+ UErrorCode& ec) const;
+
+ /**
+ * TimeZone API.
+ */
+ virtual void getOffset(UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& ec) const;
+
+ /**
+ * BasicTimeZone API.
+ */
+ virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) /*const*/;
+
+ /**
+ * TimeZone API. This method has no effect since objects of this
+ * class are quasi-immutable (the base class allows the ID to be
+ * changed).
+ */
+ virtual void setRawOffset(int32_t offsetMillis);
+
+ /**
+ * TimeZone API. For a historical zone, the raw offset can change
+ * over time, so this API is not useful. In order to approximate
+ * expected behavior, this method returns the raw offset for the
+ * current moment in time.
+ */
+ virtual int32_t getRawOffset() const;
+
+ /**
+ * TimeZone API. For a historical zone, whether DST is used or
+ * not varies over time. In order to approximate expected
+ * behavior, this method returns TRUE if DST is observed at any
+ * point in the current year.
+ */
+ virtual UBool useDaylightTime() const;
+
+ /**
+ * TimeZone API.
+ */
+ virtual UBool inDaylightTime(UDate date, UErrorCode& ec) const;
+
+ /**
+ * TimeZone API.
+ */
+ virtual int32_t getDSTSavings() const;
+
+ /**
+ * TimeZone API. Also comare historic transitions.
+ */
+ virtual UBool hasSameRules(const TimeZone& other) const;
+
+ /**
+ * BasicTimeZone API.
+ * Gets the first time zone transition after the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the first transition after the base time.
+ * @return TRUE if the transition is found.
+ */
+ virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * BasicTimeZone API.
+ * Gets the most recent time zone transition before the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the most recent transition before the base time.
+ * @return TRUE if the transition is found.
+ */
+ virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * BasicTimeZone API.
+ * Returns the number of <code>TimeZoneRule</code>s which represents time transitions,
+ * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except
+ * <code>InitialTimeZoneRule</code>. The return value range is 0 or any positive value.
+ * @param status Receives error status code.
+ * @return The number of <code>TimeZoneRule</code>s representing time transitions.
+ */
+ virtual int32_t countTransitionRules(UErrorCode& status) /*const*/;
+
+ /**
+ * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code>
+ * which represent time transitions for this time zone. On successful return,
+ * the argument initial points to non-NULL <code>InitialTimeZoneRule</code> and
+ * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code>
+ * instances up to the size specified by trscount. The results are referencing the
+ * rule instance held by this time zone instance. Therefore, after this time zone
+ * is destructed, they are no longer available.
+ * @param initial Receives the initial timezone rule
+ * @param trsrules Receives the timezone transition rules
+ * @param trscount On input, specify the size of the array 'transitions' receiving
+ * the timezone transition rules. On output, actual number of
+ * rules filled in the array will be set.
+ * @param status Receives error status code.
+ * @draft ICU 3.8
+ */
+ virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/;
+
+private:
+ /**
+ * Default constructor. Creates a time zone with an empty ID and
+ * a fixed GMT offset of zero.
+ */
+ OlsonTimeZone();
+
+private:
+
+ void constructEmpty();
+
+ void getHistoricalOffset(UDate date, UBool local,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
+ int32_t& rawoff, int32_t& dstoff) const;
+
+ int32_t zoneOffset(int16_t index) const;
+ int32_t rawOffset(int16_t index) const;
+ int32_t dstOffset(int16_t index) const;
+
+ /**
+ * Number of transitions, 0..~370
+ */
+ int16_t transitionCount;
+
+ /**
+ * Number of types, 1..255
+ */
+ int16_t typeCount;
+
+ /**
+ * Time of each transition in seconds from 1970 epoch.
+ * Length is transitionCount int32_t's.
+ */
+ const int32_t *transitionTimes; // alias into res; do not delete
+
+ /**
+ * Offset from GMT in seconds for each type.
+ * Length is typeCount int32_t's.
+ */
+ const int32_t *typeOffsets; // alias into res; do not delete
+
+ /**
+ * Type description data, consisting of transitionCount uint8_t
+ * type indices (from 0..typeCount-1).
+ * Length is transitionCount int8_t's.
+ */
+ const uint8_t *typeData; // alias into res; do not delete
+
+ /**
+ * The last year for which the transitions data are to be used
+ * rather than the finalZone. If there is no finalZone, then this
+ * is set to INT32_MAX. NOTE: This corresponds to the year _before_
+ * the one indicated by finalMillis.
+ */
+ int32_t finalYear;
+
+ /**
+ * The millis for the start of the first year for which finalZone
+ * is to be used, or DBL_MAX if finalZone is 0. NOTE: This is
+ * 0:00 GMT Jan 1, <finalYear + 1> (not <finalMillis>).
+ */
+ double finalMillis;
+
+ /**
+ * A SimpleTimeZone that governs the behavior for years > finalYear.
+ * If and only if finalYear == INT32_MAX then finalZone == 0.
+ */
+ SimpleTimeZone *finalZone; // owned, may be NULL
+
+ /* BasicTimeZone support */
+ void clearTransitionRules(void);
+ void deleteTransitionRules(void);
+ void initTransitionRules(UErrorCode& status);
+
+ InitialTimeZoneRule *initialRule;
+ TimeZoneTransition *firstTZTransition;
+ int16_t firstTZTransitionIdx;
+ TimeZoneTransition *firstFinalTZTransition;
+ TimeArrayTimeZoneRule **historicRules;
+ int16_t historicRuleCount;
+ SimpleTimeZone *finalZoneWithStartYear; // hack
+ UBool transitionRulesInitialized;
+};
+
+inline int32_t
+OlsonTimeZone::zoneOffset(int16_t index) const {
+ index <<= 1;
+ return typeOffsets[index] + typeOffsets[index+1];
+}
+
+inline int32_t
+OlsonTimeZone::rawOffset(int16_t index) const {
+ return typeOffsets[(uint32_t)(index << 1)];
+}
+
+inline int32_t
+OlsonTimeZone::dstOffset(int16_t index) const {
+ return typeOffsets[(uint32_t)((index << 1) + 1)];
+}
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
+#endif // OLSONTZ_H
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/persncal.cpp b/Build/source/libs/icu/icu-xetex/i18n/persncal.cpp
new file mode 100644
index 00000000000..5660163d007
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/persncal.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ******************************************************************************
+ *
+ * File PERSNCAL.CPP
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 9/23/2003 mehran posted to icu-design
+ *****************************************************************************
+ */
+#include "persncal.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+static const int monthDays[] = { 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 };
+
+static int32_t
+jalali_to_julian(int year, int month, int day)
+{
+ int32_t daysNo=0;
+ int i;
+
+ year = year -475+2820;
+ month -= 1;
+
+ daysNo=(year/2820)*1029983;
+ year=year % 2820;
+
+ daysNo+=(year/128)* 46751;
+ if((year/128)>21)
+ {
+ daysNo-=46751;
+ year=(year%128)+128;
+ }
+ else
+ year=year%128;
+
+ if(year>=29)
+ {
+ year-=29;
+ daysNo+=10592;
+ }
+
+ if(year>=66)
+ {
+ year-=66;
+ daysNo+=24106;
+ }
+ else if( year>=33)
+ {
+ daysNo+=(year/33)* 12053;
+ year=year%33;
+ }
+
+ if (year >= 5)
+ {
+ daysNo += 1826;
+ year -=5;
+ }
+ else if (year == 4)
+ {
+ daysNo += 1460;
+ year -=4;
+ }
+
+ daysNo += 1461 * (year/4);
+ year %= 4;
+ daysNo += 365 * year;
+
+ for (i = 0; i < month; i++) {
+ daysNo += monthDays[i];
+ }
+
+ daysNo += day;
+
+ return daysNo-856493;
+}
+
+static void julian_to_jalali (int32_t daysNo, int *h_y, int *h_m, int *h_d)
+{
+ int year=0, month=0, day=0,scalarDays=0;
+ int i;
+
+ daysNo+=856493;
+ scalarDays=daysNo;
+ year=(daysNo/1029983)*2820;
+ daysNo=daysNo%1029983;
+
+ if((daysNo/46751)<=21)
+ {
+ year+=(daysNo/46751)* 128;
+ daysNo=daysNo%46751;
+ }
+ else
+ {
+ year+=(daysNo/46751)* 128;
+ daysNo=daysNo%46751;
+ year-=128;
+ daysNo+=46751;
+ }
+
+ if (daysNo >= 10592)
+ {
+ year+= 29;
+ daysNo -= 10592;
+ }
+
+ if(daysNo>=24106)
+ {
+ daysNo-=24106;
+ year+=66;
+ }
+
+ if(daysNo>=12053)
+ {
+ daysNo-=12053;
+ year+=33;
+ }
+
+
+ if (daysNo >= 1826)
+ {
+ year+= 5;
+ daysNo -= 1826;
+ }
+ else if (daysNo > 1095)
+ {
+ year+= 3;
+ daysNo -= 1095;
+
+ }
+
+ year +=(4 * (daysNo/1461));
+ daysNo %= 1461;
+
+ if (daysNo == 0)
+ {
+ year -= 1;
+ daysNo = 366;
+ }
+ else
+ {
+ year += daysNo/365;
+ daysNo = daysNo % 365;
+ if (daysNo == 0)
+ {
+ year -= 1;
+ daysNo = 365;
+ }
+
+ }
+
+ for (i = 0; i < 11 && daysNo > monthDays[i]; ++i) {
+ daysNo -= monthDays[i];
+ }
+
+ month = i + 1;
+
+ day = daysNo;
+
+ *h_d = day;
+ *h_m = month;
+ *h_y = year-2345;
+}
+
+U_NAMESPACE_BEGIN
+
+// Implementation of the PersianCalendar class
+
+//-------------------------------------------------------------------------
+// Constructors...
+//-------------------------------------------------------------------------
+
+const char *PersianCalendar::getType() const {
+ return "persian";
+}
+
+Calendar* PersianCalendar::clone() const {
+ return new PersianCalendar(*this);
+}
+
+PersianCalendar::PersianCalendar(const Locale& aLocale, UErrorCode& success)
+ : Calendar(TimeZone::createDefault(), aLocale, success)
+{
+ setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
+}
+
+PersianCalendar::PersianCalendar(const PersianCalendar& other) : Calendar(other) {
+}
+
+PersianCalendar::~PersianCalendar()
+{
+}
+
+//-------------------------------------------------------------------------
+// Minimum / Maximum access functions
+//-------------------------------------------------------------------------
+
+static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
+ // Minimum Greatest Least Maximum
+ // Minimum Maximum
+ { 0, 0, 0, 0 }, // ERA
+ { -2500, -2500, 2500, 2500 }, // YEAR
+ { 0, 0, 11, 11 }, // MONTH
+ { 1, 1, 52, 53 }, // WEEK_OF_YEAR
+ { 0, 0, 5, 6 }, // WEEK_OF_MONTH
+ { 1, 1, 29, 31 }, // DAY_OF_MONTH
+ { 1, 1, 365, 366 }, // DAY_OF_YEAR
+ { 0, 0, 6, 6 }, // DAY_OF_WEEK
+ { 1, 1, 4, 6 }, // DAY_OF_WEEK_IN_MONTH
+ { 0, 0, 1, 1 }, // AM_PM
+ { 0, 0, 11, 11 }, // HOUR
+ { 0, 0, 23, 23 }, // HOUR_OF_DAY
+ { 0, 0, 59, 59 }, // MINUTE
+ { 0, 0, 59, 59 }, // SECOND
+ { 0, 0, 999, 999 }, // MILLISECOND
+ { -12, -12, 12, 12 }, // ZONE_OFFSET
+ { 0, 0, 1, 1 }, // DST_OFFSET
+ { -140742, -140742, 144683, 140742 }, // YEAR_WOY
+ { 0, 0, 6, 6 }, // DOW_LOCAL
+ { -2500, -2500, 2500, 2500 }, // EXTENDED_YEAR
+ {/* -1, -1, -1, -1 */}, // JULIAN_DAY
+ {/* -1, -1, -1, -1 */}, // MILLISECONDS_IN_DAY
+};
+static const int32_t MONTH_COUNT[12][4] = {
+ //len len2 st st2
+ { 31, 31, 0, 0 }, // Farvardin
+ { 31, 31, 31, 31 }, // Ordibehesht
+ { 31, 31, 62, 62 }, // Khordad
+ { 31, 31, 93, 93 }, // Tir
+ { 31, 31, 124, 124 }, // Mordad
+ { 31, 31, 155, 155 }, // Shahrivar
+ { 30, 30, 186, 186 }, // Mehr
+ { 30, 30, 216, 216 }, // Aban
+ { 30, 30, 246, 246 }, // Azar
+ { 30, 30, 276, 276 }, // Dey
+ { 30, 30, 306, 306 }, // Bahman
+ { 29, 30, 336, 336 } // Esfand
+ // len length of month
+ // len2 length of month in a leap year
+ // st days in year before start of month
+ // st2 days in year before month in leap year
+};
+
+int32_t PersianCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
+ return LIMITS[field][limitType];
+}
+
+//-------------------------------------------------------------------------
+// Assorted calculation utilities
+//
+
+/**
+ * Determine whether a year is a leap year in the Persian calendar
+ */
+UBool PersianCalendar::isLeapYear(int32_t year)
+{
+ return jalali_to_julian(year+1,1,1)-jalali_to_julian(year,1,1) == 366;
+}
+
+/**
+ * Return the day # on which the given year starts. Days are counted
+ * from the Hijri epoch, origin 0.
+ */
+int32_t PersianCalendar::yearStart(int32_t year) {
+ return handleComputeMonthStart(year,1,FALSE);
+}
+
+/**
+ * Return the day # on which the given month starts. Days are counted
+ * from the Hijri epoch, origin 0.
+ *
+ * @param year The hijri shamsi year
+ * @param year The hijri shamsi month, 0-based
+ */
+int32_t PersianCalendar::monthStart(int32_t year, int32_t month) const {
+ return handleComputeMonthStart(year,month,FALSE);
+}
+
+//----------------------------------------------------------------------
+// Calendar framework
+//----------------------------------------------------------------------
+
+/**
+ * Return the length (in days) of the given month.
+ *
+ * @param year The hijri shamsi year
+ * @param year The hijri shamsi month, 0-based
+ */
+int32_t PersianCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
+ return MONTH_COUNT[month][PersianCalendar::isLeapYear(extendedYear)?1:0];
+}
+
+/**
+ * Return the number of days in the given Persian year
+ */
+int32_t PersianCalendar::handleGetYearLength(int32_t extendedYear) const {
+ return 365 + (PersianCalendar::isLeapYear(extendedYear) ? 1 : 0);
+}
+
+//-------------------------------------------------------------------------
+// Functions for converting from field values to milliseconds....
+//-------------------------------------------------------------------------
+
+// Return JD of start of given month/year
+int32_t PersianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const {
+ // If the month is out of range, adjust it into range, and
+ // modify the extended year value accordingly.
+ if (month < 0 || month > 11) {
+ eyear += month / 12;
+ month = month % 12;
+ }
+ return jalali_to_julian(eyear,(useMonth?month+1:1),1)-1+1947955;
+}
+
+//-------------------------------------------------------------------------
+// Functions for converting from milliseconds to field values
+//-------------------------------------------------------------------------
+
+int32_t PersianCalendar::handleGetExtendedYear() {
+ int32_t year;
+ if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
+ year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
+ } else {
+ year = internalGet(UCAL_YEAR, 1); // Default to year 1
+ }
+ return year;
+}
+
+/**
+ * Override Calendar to compute several fields specific to the Persian
+ * calendar system. These are:
+ *
+ * <ul><li>ERA
+ * <li>YEAR
+ * <li>MONTH
+ * <li>DAY_OF_MONTH
+ * <li>DAY_OF_YEAR
+ * <li>EXTENDED_YEAR</ul>
+ *
+ * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+ * method is called. The getGregorianXxx() methods return Gregorian
+ * calendar equivalents for the given Julian day.
+ */
+void PersianCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/) {
+ int jy,jm,jd;
+ julian_to_jalali(julianDay-1947955,&jy,&jm,&jd);
+ internalSet(UCAL_ERA, 0);
+ internalSet(UCAL_YEAR, jy);
+ internalSet(UCAL_EXTENDED_YEAR, jy);
+ internalSet(UCAL_MONTH, jm-1);
+ internalSet(UCAL_DAY_OF_MONTH, jd);
+ internalSet(UCAL_DAY_OF_YEAR, jd + MONTH_COUNT[jm-1][2]);
+}
+
+UBool
+PersianCalendar::inDaylightTime(UErrorCode& status) const
+{
+ // copied from GregorianCalendar
+ if (U_FAILURE(status) || !getTimeZone().useDaylightTime())
+ return FALSE;
+
+ // Force an update of the state of the Calendar.
+ ((PersianCalendar*)this)->complete(status); // cast away const
+
+ return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
+}
+
+UBool PersianCalendar::haveDefaultCentury() const
+{
+ return FALSE;
+}
+
+UDate PersianCalendar::defaultCenturyStart() const
+{
+ return -1;
+}
+
+int32_t PersianCalendar::defaultCenturyStartYear() const
+{
+ return -1;
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PersianCalendar)
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/persncal.h b/Build/source/libs/icu/icu-xetex/i18n/persncal.h
new file mode 100644
index 00000000000..8314b543a39
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/persncal.h
@@ -0,0 +1,325 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ******************************************************************************
+ *
+ * File PERSNCAL.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 9/23/2003 mehran posted to icu-design
+ *****************************************************************************
+ */
+
+#ifndef PERSNCAL_H
+#define PERSNCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * <code>PersianCalendar</code> is a subclass of <code>Calendar</code>
+ * that implements the Persian calendar. It is used as the official
+ * calendar in Iran. This calendar is also known as the "Hijri Shamsi"
+ * calendar, since it starts at the time of Mohammed's emigration (or
+ * "hijra") to Medinah on Thursday, July 15, 622 AD (Julian) and is a
+ * solar calendar system (or "shamsi").
+ * <p>
+ * The Persian calendar is strictly solar, and thus a Persian year has twelve
+ * solar months. A Persian year is about 365 days long, except in leap years
+ * which is 366 days long.
+ * <p>
+ * The six first months of Persian Calendar are 31 days long. The next five
+ * months are 30 days long. The last month is 29 days long in normal years,
+ * and 30 days long in leap years.
+ *
+ * @see GregorianCalendar
+ *
+ * @author Mehran Mehr
+ * @internal
+ */
+class PersianCalendar : public Calendar {
+ public:
+ //-------------------------------------------------------------------------
+ // Constants...
+ //-------------------------------------------------------------------------
+ /**
+ * Constants for the months
+ * @internal
+ */
+ enum EMonths {
+ /**
+ * Constant for Farvardin, the 1st month of the Persian year.
+ * @internal
+ */
+ FARVARDIN = 0,
+
+ /**
+ * Constant for Ordibehesht, the 2nd month of the Persian year.
+ * @internal
+ */
+ ORDIBEHESHT = 1,
+
+ /**
+ * Constant for Khordad, the 3rd month of the Persian year.
+ * @internal
+ */
+ KHORDAD = 2,
+
+ /**
+ * Constant for Tir, the 4th month of the Persian year.
+ * @internal
+ */
+ TIR = 3,
+
+ /**
+ * Constant for Mordad, the 5th month of the Persian year.
+ * @internal
+ */
+ MORDAD = 4,
+
+ /**
+ * Constant for Shahrivar, the 6th month of the Persian year.
+ * @internal
+ */
+ SHAHRIVAR = 5,
+
+ /**
+ * Constant for Mehr, the 7th month of the Persian year.
+ * @internal
+ */
+ MEHR = 6,
+
+ /**
+ * Constant for Aban, the 8th month of the Persian year.
+ * @internal
+ */
+ ABAN = 7,
+
+ /**
+ * Constant for Azar, the 9th month of the Persian year.
+ * @internal
+ */
+ AZAR = 8,
+
+ /**
+ * Constant for Dei, the 10th month of the Persian year.
+ * @internal
+ */
+ DEI = 9,
+
+ /**
+ * Constant for Bahman, the 11th month of the Persian year.
+ * @internal
+ */
+ BAHMAN = 10,
+
+ /**
+ * Constant for Esfand, the 12th month of the Persian year.
+ * @internal
+ */
+ ESFAND = 11,
+
+ PERSIAN_MONTH_MAX
+ };
+
+
+
+ //-------------------------------------------------------------------------
+ // Constructors...
+ //-------------------------------------------------------------------------
+
+ /**
+ * Constructs a PersianCalendar based on the current time in the default time zone
+ * with the given locale.
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the status of PersianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @internal
+ */
+ PersianCalendar(const Locale& aLocale, UErrorCode &success);
+
+ /**
+ * Copy Constructor
+ * @internal
+ */
+ PersianCalendar(const PersianCalendar& other);
+
+ /**
+ * Destructor.
+ * @internal
+ */
+ virtual ~PersianCalendar();
+
+ // TODO: copy c'tor, etc
+
+ // clone
+ virtual Calendar* clone() const;
+
+ private:
+ /**
+ * Determine whether a year is a leap year in the Persian calendar
+ */
+ static UBool isLeapYear(int32_t year);
+
+ /**
+ * Return the day # on which the given year starts. Days are counted
+ * from the Hijri epoch, origin 0.
+ */
+ int32_t yearStart(int32_t year);
+
+ /**
+ * Return the day # on which the given month starts. Days are counted
+ * from the Hijri epoch, origin 0.
+ *
+ * @param year The hijri shamsi year
+ * @param year The hijri shamsi month, 0-based
+ */
+ int32_t monthStart(int32_t year, int32_t month) const;
+
+ //----------------------------------------------------------------------
+ // Calendar framework
+ //----------------------------------------------------------------------
+ protected:
+ /**
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+
+ /**
+ * Return the length (in days) of the given month.
+ *
+ * @param year The hijri shamsi year
+ * @param year The hijri shamsi month, 0-based
+ * @internal
+ */
+ virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const;
+
+ /**
+ * Return the number of days in the given Persian year
+ * @internal
+ */
+ virtual int32_t handleGetYearLength(int32_t extendedYear) const;
+
+ //-------------------------------------------------------------------------
+ // Functions for converting from field values to milliseconds....
+ //-------------------------------------------------------------------------
+
+ // Return JD of start of given month/year
+ /**
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const;
+
+ //-------------------------------------------------------------------------
+ // Functions for converting from milliseconds to field values
+ //-------------------------------------------------------------------------
+
+ /**
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+
+ /**
+ * Override Calendar to compute several fields specific to the Persian
+ * calendar system. These are:
+ *
+ * <ul><li>ERA
+ * <li>YEAR
+ * <li>MONTH
+ * <li>DAY_OF_MONTH
+ * <li>DAY_OF_YEAR
+ * <li>EXTENDED_YEAR</ul>
+ *
+ * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+ * method is called. The getGregorianXxx() methods return Gregorian
+ * calendar equivalents for the given Julian day.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
+
+ // UObject stuff
+ public:
+ /**
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @internal
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to a return
+ * value from getDynamicClassID(). For example:
+ *
+ * Base* polymorphic_pointer = createPolymorphicObject();
+ * if (polymorphic_pointer->getDynamicClassID() ==
+ * Derived::getStaticClassID()) ...
+ *
+ * @return The class ID for all objects of this class.
+ * @internal
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * return the calendar type, "persian".
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+ private:
+ PersianCalendar(); // default constructor not implemented
+
+ // Default century.
+ protected:
+
+ /**
+ * (Overrides Calendar) Return true if the current date for this Calendar is in
+ * Daylight Savings Time. Recognizes DST_OFFSET, if it is set.
+ *
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return True if the current date for this Calendar is in Daylight Savings Time,
+ * false, otherwise.
+ * @internal
+ */
+ virtual UBool inDaylightTime(UErrorCode& status) const;
+
+
+
+ /**
+ * Returns FALSE because the Persian Calendar does not have a default century
+ * @internal
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * Returns -1
+ * @return -1
+ * @internal
+ */
+ virtual UDate defaultCenturyStart() const;
+
+ /**
+ * Returns -1
+ * @internal
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif
+
+
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/quant.cpp b/Build/source/libs/icu/icu-xetex/i18n/quant.cpp
new file mode 100644
index 00000000000..bb34cebd380
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/quant.cpp
@@ -0,0 +1,146 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 07/26/01 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "quant.h"
+#include "unicode/unistr.h"
+#include "util.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Quantifier)
+
+Quantifier::Quantifier(UnicodeFunctor *adoptedMatcher,
+ uint32_t _minCount, uint32_t _maxCount) {
+ // assert(adopted != 0);
+ // assert(minCount <= maxCount);
+ matcher = adoptedMatcher;
+ this->minCount = _minCount;
+ this->maxCount = _maxCount;
+}
+
+Quantifier::Quantifier(const Quantifier& o) :
+ UnicodeFunctor(o),
+ UnicodeMatcher(o),
+ matcher(o.matcher->clone()),
+ minCount(o.minCount),
+ maxCount(o.maxCount)
+{
+}
+
+Quantifier::~Quantifier() {
+ delete matcher;
+}
+
+/**
+ * Implement UnicodeFunctor
+ */
+UnicodeFunctor* Quantifier::clone() const {
+ return new Quantifier(*this);
+}
+
+/**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeMatcher* pointer
+ * and return the pointer.
+ */
+UnicodeMatcher* Quantifier::toMatcher() const {
+ return (UnicodeMatcher*) this;
+}
+
+UMatchDegree Quantifier::matches(const Replaceable& text,
+ int32_t& offset,
+ int32_t limit,
+ UBool incremental) {
+ int32_t start = offset;
+ uint32_t count = 0;
+ while (count < maxCount) {
+ int32_t pos = offset;
+ UMatchDegree m = matcher->toMatcher()->matches(text, offset, limit, incremental);
+ if (m == U_MATCH) {
+ ++count;
+ if (pos == offset) {
+ // If offset has not moved we have a zero-width match.
+ // Don't keep matching it infinitely.
+ break;
+ }
+ } else if (incremental && m == U_PARTIAL_MATCH) {
+ return U_PARTIAL_MATCH;
+ } else {
+ break;
+ }
+ }
+ if (incremental && offset == limit) {
+ return U_PARTIAL_MATCH;
+ }
+ if (count >= minCount) {
+ return U_MATCH;
+ }
+ offset = start;
+ return U_MISMATCH;
+}
+
+/**
+ * Implement UnicodeMatcher
+ */
+UnicodeString& Quantifier::toPattern(UnicodeString& result,
+ UBool escapeUnprintable) const {
+ result.truncate(0);
+ matcher->toMatcher()->toPattern(result, escapeUnprintable);
+ if (minCount == 0) {
+ if (maxCount == 1) {
+ return result.append((UChar)63); /*?*/
+ } else if (maxCount == MAX) {
+ return result.append((UChar)42); /***/
+ }
+ // else fall through
+ } else if (minCount == 1 && maxCount == MAX) {
+ return result.append((UChar)43); /*+*/
+ }
+ result.append((UChar)123); /*{*/
+ ICU_Utility::appendNumber(result, minCount);
+ result.append((UChar)44); /*,*/
+ if (maxCount != MAX) {
+ ICU_Utility::appendNumber(result, maxCount);
+ }
+ result.append((UChar)125); /*}*/
+ return result;
+}
+
+/**
+ * Implement UnicodeMatcher
+ */
+UBool Quantifier::matchesIndexValue(uint8_t v) const {
+ return (minCount == 0) || matcher->toMatcher()->matchesIndexValue(v);
+}
+
+/**
+ * Implement UnicodeMatcher
+ */
+void Quantifier::addMatchSetTo(UnicodeSet& toUnionTo) const {
+ if (maxCount > 0) {
+ matcher->toMatcher()->addMatchSetTo(toUnionTo);
+ }
+}
+
+/**
+ * Implement UnicodeFunctor
+ */
+void Quantifier::setData(const TransliterationRuleData* d) {
+ matcher->setData(d);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/quant.h b/Build/source/libs/icu/icu-xetex/i18n/quant.h
new file mode 100644
index 00000000000..79388953172
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/quant.h
@@ -0,0 +1,128 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2001-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 07/26/01 aliu Creation.
+ **********************************************************************
+ */
+#ifndef QUANT_H
+#define QUANT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifunct.h"
+#include "unicode/unimatch.h"
+
+U_NAMESPACE_BEGIN
+
+class Quantifier : public UnicodeFunctor, public UnicodeMatcher {
+
+ public:
+
+ enum { MAX = 0x7FFFFFFF };
+
+ Quantifier(UnicodeFunctor *adoptedMatcher,
+ uint32_t minCount, uint32_t maxCount);
+
+ Quantifier(const Quantifier& o);
+
+ virtual ~Quantifier();
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeMatcher* pointer
+ * and return the pointer.
+ * @return the UnicodeMatcher pointer.
+ */
+ virtual UnicodeMatcher* toMatcher() const;
+
+ /**
+ * Implement UnicodeFunctor
+ * @return a copy of the object.
+ */
+ virtual UnicodeFunctor* clone() const;
+
+ /**
+ * Implement UnicodeMatcher
+ * @param text the text to be matched
+ * @param offset on input, the index into text at which to begin
+ * matching. On output, the limit of the matched text. The
+ * number of matched characters is the output value of offset
+ * minus the input value. Offset should always point to the
+ * HIGH SURROGATE (leading code unit) of a pair of surrogates,
+ * both on entry and upon return.
+ * @param limit the limit index of text to be matched. Greater
+ * than offset for a forward direction match, less than offset for
+ * a backward direction match. The last character to be
+ * considered for matching will be text.charAt(limit-1) in the
+ * forward direction or text.charAt(limit+1) in the backward
+ * direction.
+ * @param incremental if TRUE, then assume further characters may
+ * be inserted at limit and check for partial matching. Otherwise
+ * assume the text as given is complete.
+ * @return a match degree value indicating a full match, a partial
+ * match, or a mismatch. If incremental is FALSE then
+ * U_PARTIAL_MATCH should never be returned.
+ */
+ virtual UMatchDegree matches(const Replaceable& text,
+ int32_t& offset,
+ int32_t limit,
+ UBool incremental);
+
+ /**
+ * Implement UnicodeMatcher
+ * @param result Output param to receive the pattern.
+ * @param escapeUnprintable if True then escape the unprintable characters.
+ * @return A reference to 'result'.
+ */
+ virtual UnicodeString& toPattern(UnicodeString& result,
+ UBool escapeUnprintable = FALSE) const;
+
+ /**
+ * Implement UnicodeMatcher
+ * @param v the given index value.
+ * @return true if this rule matches the given index value.
+ */
+ virtual UBool matchesIndexValue(uint8_t v) const;
+
+ /**
+ * Implement UnicodeMatcher
+ */
+ virtual void addMatchSetTo(UnicodeSet& toUnionTo) const;
+
+ /**
+ * UnicodeFunctor API
+ */
+ virtual void setData(const TransliterationRuleData*);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ private:
+
+ UnicodeFunctor* matcher; // owned
+
+ uint32_t minCount;
+
+ uint32_t maxCount;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbnf.cpp b/Build/source/libs/icu/icu-xetex/i18n/rbnf.cpp
new file mode 100644
index 00000000000..f9a9ae3d671
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbnf.cpp
@@ -0,0 +1,1542 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2006, International Business Machines Corporation
+* and others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include "unicode/rbnf.h"
+
+#if U_HAVE_RBNF
+
+#include "unicode/normlzr.h"
+#include "unicode/tblcoll.h"
+#include "unicode/uchar.h"
+#include "unicode/ucol.h"
+#include "unicode/uloc.h"
+#include "unicode/unum.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "unicode/utf16.h"
+#include "unicode/udata.h"
+#include "nfrs.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+#include "util.h"
+
+// debugging
+// #define DEBUG
+
+#ifdef DEBUG
+#include "stdio.h"
+#endif
+
+#define U_ICUDATA_RBNF U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "rbnf"
+
+static const UChar gPercentPercent[] =
+{
+ 0x25, 0x25, 0
+}; /* "%%" */
+
+// All urbnf objects are created through openRules, so we init all of the
+// Unicode string constants required by rbnf, nfrs, or nfr here.
+static const UChar gLenientParse[] =
+{
+ 0x25, 0x25, 0x6C, 0x65, 0x6E, 0x69, 0x65, 0x6E, 0x74, 0x2D, 0x70, 0x61, 0x72, 0x73, 0x65, 0x3A, 0
+}; /* "%%lenient-parse:" */
+static const UChar gSemiColon = 0x003B;
+static const UChar gSemiPercent[] =
+{
+ 0x3B, 0x25, 0
+}; /* ";%" */
+
+#define kSomeNumberOfBitsDiv2 22
+#define kHalfMaxDouble (double)(1 << kSomeNumberOfBitsDiv2)
+#define kMaxDouble (kHalfMaxDouble * kHalfMaxDouble)
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedNumberFormat)
+
+/*
+This is a utility class. It does not use ICU's RTTI.
+If ICU's RTTI is needed again, you can uncomment the RTTI code and derive from UObject.
+Please make sure that intltest passes on Windows in Release mode,
+since the string pooling per compilation unit will mess up how RTTI works.
+The RTTI code was also removed due to lack of code coverage.
+*/
+class LocalizationInfo : public UMemory {
+protected:
+ virtual ~LocalizationInfo() {};
+ uint32_t refcount;
+
+public:
+ LocalizationInfo() : refcount(0) {}
+
+ LocalizationInfo* ref(void) {
+ ++refcount;
+ return this;
+ }
+
+ LocalizationInfo* unref(void) {
+ if (refcount && --refcount == 0) {
+ delete this;
+ }
+ return NULL;
+ }
+
+ virtual UBool operator==(const LocalizationInfo* rhs) const;
+ inline UBool operator!=(const LocalizationInfo* rhs) const { return !operator==(rhs); }
+
+ virtual int32_t getNumberOfRuleSets(void) const = 0;
+ virtual const UChar* getRuleSetName(int32_t index) const = 0;
+ virtual int32_t getNumberOfDisplayLocales(void) const = 0;
+ virtual const UChar* getLocaleName(int32_t index) const = 0;
+ virtual const UChar* getDisplayName(int32_t localeIndex, int32_t ruleIndex) const = 0;
+
+ virtual int32_t indexForLocale(const UChar* locale) const;
+ virtual int32_t indexForRuleSet(const UChar* ruleset) const;
+
+// virtual UClassID getDynamicClassID() const = 0;
+// static UClassID getStaticClassID(void);
+};
+
+//UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(LocalizationInfo)
+
+// if both strings are NULL, this returns TRUE
+static UBool
+streq(const UChar* lhs, const UChar* rhs) {
+ if (rhs == lhs) {
+ return TRUE;
+ }
+ if (lhs && rhs) {
+ return u_strcmp(lhs, rhs) == 0;
+ }
+ return FALSE;
+}
+
+UBool
+LocalizationInfo::operator==(const LocalizationInfo* rhs) const {
+ if (rhs) {
+ if (this == rhs) {
+ return TRUE;
+ }
+
+ int32_t rsc = getNumberOfRuleSets();
+ if (rsc == rhs->getNumberOfRuleSets()) {
+ for (int i = 0; i < rsc; ++i) {
+ if (!streq(getRuleSetName(i), rhs->getRuleSetName(i))) {
+ return FALSE;
+ }
+ }
+ int32_t dlc = getNumberOfDisplayLocales();
+ if (dlc == rhs->getNumberOfDisplayLocales()) {
+ for (int i = 0; i < dlc; ++i) {
+ const UChar* locale = getLocaleName(i);
+ int32_t ix = rhs->indexForLocale(locale);
+ // if no locale, ix is -1, getLocaleName returns null, so streq returns false
+ if (!streq(locale, rhs->getLocaleName(ix))) {
+ return FALSE;
+ }
+ for (int j = 0; j < rsc; ++j) {
+ if (!streq(getDisplayName(i, j), rhs->getDisplayName(ix, j))) {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+int32_t
+LocalizationInfo::indexForLocale(const UChar* locale) const {
+ for (int i = 0; i < getNumberOfDisplayLocales(); ++i) {
+ if (streq(locale, getLocaleName(i))) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int32_t
+LocalizationInfo::indexForRuleSet(const UChar* ruleset) const {
+ if (ruleset) {
+ for (int i = 0; i < getNumberOfRuleSets(); ++i) {
+ if (streq(ruleset, getRuleSetName(i))) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+
+typedef void (*Fn_Deleter)(void*);
+
+class VArray {
+ void** buf;
+ int32_t cap;
+ int32_t size;
+ Fn_Deleter deleter;
+public:
+ VArray() : buf(NULL), cap(0), size(0), deleter(NULL) {}
+
+ VArray(Fn_Deleter del) : buf(NULL), cap(0), size(0), deleter(del) {}
+
+ ~VArray() {
+ if (deleter) {
+ for (int i = 0; i < size; ++i) {
+ (*deleter)(buf[i]);
+ }
+ }
+ uprv_free(buf);
+ }
+
+ int32_t length() {
+ return size;
+ }
+
+ void add(void* elem, UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ if (size == cap) {
+ if (cap == 0) {
+ cap = 1;
+ } else if (cap < 256) {
+ cap *= 2;
+ } else {
+ cap += 256;
+ }
+ if (buf == NULL) {
+ buf = (void**)uprv_malloc(cap * sizeof(void*));
+ } else {
+ buf = (void**)uprv_realloc(buf, cap * sizeof(void*));
+ }
+ if (buf == NULL) {
+ // if we couldn't realloc, we leak the memory we've already allocated, but we're in deep trouble anyway
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ void* start = &buf[size];
+ size_t count = (cap - size) * sizeof(void*);
+ uprv_memset(start, 0, count); // fill with nulls, just because
+ }
+ buf[size++] = elem;
+ }
+ }
+
+ void** release(void) {
+ void** result = buf;
+ buf = NULL;
+ cap = 0;
+ size = 0;
+ return result;
+ }
+};
+
+class LocDataParser;
+
+class StringLocalizationInfo : public LocalizationInfo {
+ UChar* info;
+ UChar*** data;
+ int32_t numRuleSets;
+ int32_t numLocales;
+
+friend class LocDataParser;
+
+ StringLocalizationInfo(UChar* i, UChar*** d, int32_t numRS, int32_t numLocs)
+ : info(i), data(d), numRuleSets(numRS), numLocales(numLocs)
+ {
+ }
+
+public:
+ static StringLocalizationInfo* create(const UnicodeString& info, UParseError& perror, UErrorCode& status);
+
+ virtual ~StringLocalizationInfo();
+ virtual int32_t getNumberOfRuleSets(void) const { return numRuleSets; }
+ virtual const UChar* getRuleSetName(int32_t index) const;
+ virtual int32_t getNumberOfDisplayLocales(void) const { return numLocales; }
+ virtual const UChar* getLocaleName(int32_t index) const;
+ virtual const UChar* getDisplayName(int32_t localeIndex, int32_t ruleIndex) const;
+
+// virtual UClassID getDynamicClassID() const;
+// static UClassID getStaticClassID(void);
+
+private:
+ void init(UErrorCode& status) const;
+};
+
+
+enum {
+ OPEN_ANGLE = 0x003c, /* '<' */
+ CLOSE_ANGLE = 0x003e, /* '>' */
+ COMMA = 0x002c,
+ TICK = 0x0027,
+ QUOTE = 0x0022,
+ SPACE = 0x0020
+};
+
+/**
+ * Utility for parsing a localization string and returning a StringLocalizationInfo*.
+ */
+class LocDataParser {
+ UChar* data;
+ const UChar* e;
+ UChar* p;
+ UChar ch;
+ UParseError& pe;
+ UErrorCode& ec;
+
+public:
+ LocDataParser(UParseError& parseError, UErrorCode& status)
+ : data(NULL), e(NULL), p(NULL), ch(0xffff), pe(parseError), ec(status) {}
+ ~LocDataParser() {}
+
+ /*
+ * On a successful parse, return a StringLocalizationInfo*, otherwise delete locData, set perror and status,
+ * and return NULL. The StringLocalizationInfo will adopt locData if it is created.
+ */
+ StringLocalizationInfo* parse(UChar* data, int32_t len);
+
+private:
+
+ void inc(void) { ++p; ch = 0xffff; }
+ UBool checkInc(UChar c) { if (p < e && (ch == c || *p == c)) { inc(); return TRUE; } return FALSE; }
+ UBool check(UChar c) { return p < e && (ch == c || *p == c); }
+ void skipWhitespace(void) { while (p < e && uprv_isRuleWhiteSpace(ch != 0xffff ? ch : *p)) inc();}
+ UBool inList(UChar c, const UChar* list) const {
+ if (*list == SPACE && uprv_isRuleWhiteSpace(c)) return TRUE;
+ while (*list && *list != c) ++list; return *list == c;
+ }
+ void parseError(const char* msg);
+
+ StringLocalizationInfo* doParse(void);
+
+ UChar** nextArray(int32_t& requiredLength);
+ UChar* nextString(void);
+};
+
+#ifdef DEBUG
+#define ERROR(msg) parseError(msg); return NULL;
+#else
+#define ERROR(msg) parseError(NULL); return NULL;
+#endif
+
+
+static const UChar DQUOTE_STOPLIST[] = {
+ QUOTE, 0
+};
+
+static const UChar SQUOTE_STOPLIST[] = {
+ TICK, 0
+};
+
+static const UChar NOQUOTE_STOPLIST[] = {
+ SPACE, COMMA, CLOSE_ANGLE, OPEN_ANGLE, TICK, QUOTE, 0
+};
+
+static void
+DeleteFn(void* p) {
+ uprv_free(p);
+}
+
+StringLocalizationInfo*
+LocDataParser::parse(UChar* _data, int32_t len) {
+ if (U_FAILURE(ec)) {
+ if (_data) uprv_free(_data);
+ return NULL;
+ }
+
+ pe.line = 0;
+ pe.offset = -1;
+ pe.postContext[0] = 0;
+ pe.preContext[0] = 0;
+
+ if (_data == NULL) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ if (len <= 0) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ uprv_free(_data);
+ return NULL;
+ }
+
+ data = _data;
+ e = data + len;
+ p = _data;
+ ch = 0xffff;
+
+ return doParse();
+}
+
+
+StringLocalizationInfo*
+LocDataParser::doParse(void) {
+ skipWhitespace();
+ if (!checkInc(OPEN_ANGLE)) {
+ ERROR("Missing open angle");
+ } else {
+ VArray array(DeleteFn);
+ UBool mightHaveNext = TRUE;
+ int32_t requiredLength = -1;
+ while (mightHaveNext) {
+ mightHaveNext = FALSE;
+ UChar** elem = nextArray(requiredLength);
+ skipWhitespace();
+ UBool haveComma = check(COMMA);
+ if (elem) {
+ array.add(elem, ec);
+ if (haveComma) {
+ inc();
+ mightHaveNext = TRUE;
+ }
+ } else if (haveComma) {
+ ERROR("Unexpected character");
+ }
+ }
+
+ skipWhitespace();
+ if (!checkInc(CLOSE_ANGLE)) {
+ if (check(OPEN_ANGLE)) {
+ ERROR("Missing comma in outer array");
+ } else {
+ ERROR("Missing close angle bracket in outer array");
+ }
+ }
+
+ skipWhitespace();
+ if (p != e) {
+ ERROR("Extra text after close of localization data");
+ }
+
+ array.add(NULL, ec);
+ if (U_SUCCESS(ec)) {
+ int32_t numLocs = array.length() - 2; // subtract first, NULL
+ UChar*** result = (UChar***)array.release();
+
+ return new StringLocalizationInfo(data, result, requiredLength-2, numLocs); // subtract first, NULL
+ }
+ }
+
+ ERROR("Unknown error");
+}
+
+UChar**
+LocDataParser::nextArray(int32_t& requiredLength) {
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+
+ skipWhitespace();
+ if (!checkInc(OPEN_ANGLE)) {
+ ERROR("Missing open angle");
+ }
+
+ VArray array;
+ UBool mightHaveNext = TRUE;
+ while (mightHaveNext) {
+ mightHaveNext = FALSE;
+ UChar* elem = nextString();
+ skipWhitespace();
+ UBool haveComma = check(COMMA);
+ if (elem) {
+ array.add(elem, ec);
+ if (haveComma) {
+ inc();
+ mightHaveNext = TRUE;
+ }
+ } else if (haveComma) {
+ ERROR("Unexpected comma");
+ }
+ }
+ skipWhitespace();
+ if (!checkInc(CLOSE_ANGLE)) {
+ if (check(OPEN_ANGLE)) {
+ ERROR("Missing close angle bracket in inner array");
+ } else {
+ ERROR("Missing comma in inner array");
+ }
+ }
+
+ array.add(NULL, ec);
+ if (U_SUCCESS(ec)) {
+ if (requiredLength == -1) {
+ requiredLength = array.length() + 1;
+ } else if (array.length() != requiredLength) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ ERROR("Array not of required length");
+ }
+
+ return (UChar**)array.release();
+ }
+ ERROR("Unknown Error");
+}
+
+UChar*
+LocDataParser::nextString() {
+ UChar* result = NULL;
+
+ skipWhitespace();
+ if (p < e) {
+ const UChar* terminators;
+ UChar c = *p;
+ UBool haveQuote = c == QUOTE || c == TICK;
+ if (haveQuote) {
+ inc();
+ terminators = c == QUOTE ? DQUOTE_STOPLIST : SQUOTE_STOPLIST;
+ } else {
+ terminators = NOQUOTE_STOPLIST;
+ }
+ UChar* start = p;
+ while (p < e && !inList(*p, terminators)) ++p;
+ if (p == e) {
+ ERROR("Unexpected end of data");
+ }
+
+ UChar x = *p;
+ if (p > start) {
+ ch = x;
+ *p = 0x0; // terminate by writing to data
+ result = start; // just point into data
+ }
+ if (haveQuote) {
+ if (x != c) {
+ ERROR("Missing matching quote");
+ } else if (p == start) {
+ ERROR("Empty string");
+ }
+ inc();
+ } else if (x == OPEN_ANGLE || x == TICK || x == QUOTE) {
+ ERROR("Unexpected character in string");
+ }
+ }
+
+ // ok for there to be no next string
+ return result;
+}
+
+void
+LocDataParser::parseError(const char* /*str*/) {
+ if (!data) {
+ return;
+ }
+
+ const UChar* start = p - U_PARSE_CONTEXT_LEN - 1;
+ if (start < data) {
+ start = data;
+ }
+ for (UChar* x = p; --x >= start;) {
+ if (!*x) {
+ start = x+1;
+ break;
+ }
+ }
+ const UChar* limit = p + U_PARSE_CONTEXT_LEN - 1;
+ if (limit > e) {
+ limit = e;
+ }
+ u_strncpy(pe.preContext, start, (int32_t)(p-start));
+ pe.preContext[p-start] = 0;
+ u_strncpy(pe.postContext, p, (int32_t)(limit-p));
+ pe.postContext[limit-p] = 0;
+ pe.offset = (int32_t)(p - data);
+
+#ifdef DEBUG
+ fprintf(stderr, "%s at or near character %d: ", str, p-data);
+
+ UnicodeString msg;
+ msg.append(start, p - start);
+ msg.append((UChar)0x002f); /* SOLIDUS/SLASH */
+ msg.append(p, limit-p);
+ msg.append("'");
+
+ char buf[128];
+ int32_t len = msg.extract(0, msg.length(), buf, 128);
+ if (len >= 128) {
+ buf[127] = 0;
+ } else {
+ buf[len] = 0;
+ }
+ fprintf(stderr, "%s\n", buf);
+ fflush(stderr);
+#endif
+
+ uprv_free(data);
+ data = NULL;
+ p = NULL;
+ e = NULL;
+
+ if (U_SUCCESS(ec)) {
+ ec = U_PARSE_ERROR;
+ }
+}
+
+//UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringLocalizationInfo)
+
+StringLocalizationInfo*
+StringLocalizationInfo::create(const UnicodeString& info, UParseError& perror, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ int32_t len = info.length();
+ if (len == 0) {
+ return NULL; // no error;
+ }
+
+ UChar* p = (UChar*)uprv_malloc(len * sizeof(UChar));
+ if (!p) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ info.extract(p, len, status);
+ if (!U_FAILURE(status)) {
+ status = U_ZERO_ERROR; // clear warning about non-termination
+ }
+
+ LocDataParser parser(perror, status);
+ return parser.parse(p, len);
+}
+
+StringLocalizationInfo::~StringLocalizationInfo() {
+ for (UChar*** p = (UChar***)data; *p; ++p) {
+ // remaining data is simply pointer into our unicode string data.
+ if (*p) uprv_free(*p);
+ }
+ if (data) uprv_free(data);
+ if (info) uprv_free(info);
+}
+
+
+const UChar*
+StringLocalizationInfo::getRuleSetName(int32_t index) const {
+ if (index >= 0 && index < getNumberOfRuleSets()) {
+ return data[0][index];
+ }
+ return NULL;
+}
+
+const UChar*
+StringLocalizationInfo::getLocaleName(int32_t index) const {
+ if (index >= 0 && index < getNumberOfDisplayLocales()) {
+ return data[index+1][0];
+ }
+ return NULL;
+}
+
+const UChar*
+StringLocalizationInfo::getDisplayName(int32_t localeIndex, int32_t ruleIndex) const {
+ if (localeIndex >= 0 && localeIndex < getNumberOfDisplayLocales() &&
+ ruleIndex >= 0 && ruleIndex < getNumberOfRuleSets()) {
+ return data[localeIndex+1][ruleIndex+1];
+ }
+ return NULL;
+}
+
+// ----------
+
+RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
+ const UnicodeString& locs,
+ const Locale& alocale, UParseError& perror, UErrorCode& status)
+ : ruleSets(NULL)
+ , defaultRuleSet(NULL)
+ , locale(alocale)
+ , collator(NULL)
+ , decimalFormatSymbols(NULL)
+ , lenient(FALSE)
+ , lenientParseRules(NULL)
+ , localizations(NULL)
+{
+ LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
+ init(description, locinfo, perror, status);
+}
+
+RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
+ const UnicodeString& locs,
+ UParseError& perror, UErrorCode& status)
+ : ruleSets(NULL)
+ , defaultRuleSet(NULL)
+ , locale(Locale::getDefault())
+ , collator(NULL)
+ , decimalFormatSymbols(NULL)
+ , lenient(FALSE)
+ , lenientParseRules(NULL)
+ , localizations(NULL)
+{
+ LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
+ init(description, locinfo, perror, status);
+}
+
+RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
+ LocalizationInfo* info,
+ const Locale& alocale, UParseError& perror, UErrorCode& status)
+ : ruleSets(NULL)
+ , defaultRuleSet(NULL)
+ , locale(alocale)
+ , collator(NULL)
+ , decimalFormatSymbols(NULL)
+ , lenient(FALSE)
+ , lenientParseRules(NULL)
+ , localizations(NULL)
+{
+ init(description, info, perror, status);
+}
+
+RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
+ UParseError& perror,
+ UErrorCode& status)
+ : ruleSets(NULL)
+ , defaultRuleSet(NULL)
+ , locale(Locale::getDefault())
+ , collator(NULL)
+ , decimalFormatSymbols(NULL)
+ , lenient(FALSE)
+ , lenientParseRules(NULL)
+ , localizations(NULL)
+{
+ init(description, NULL, perror, status);
+}
+
+RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
+ const Locale& aLocale,
+ UParseError& perror,
+ UErrorCode& status)
+ : ruleSets(NULL)
+ , defaultRuleSet(NULL)
+ , locale(aLocale)
+ , collator(NULL)
+ , decimalFormatSymbols(NULL)
+ , lenient(FALSE)
+ , lenientParseRules(NULL)
+ , localizations(NULL)
+{
+ init(description, NULL, perror, status);
+}
+
+RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& alocale, UErrorCode& status)
+ : ruleSets(NULL)
+ , defaultRuleSet(NULL)
+ , locale(alocale)
+ , collator(NULL)
+ , decimalFormatSymbols(NULL)
+ , lenient(FALSE)
+ , lenientParseRules(NULL)
+ , localizations(NULL)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ const char* fmt_tag = "";
+ switch (tag) {
+ case URBNF_SPELLOUT: fmt_tag = "SpelloutRules"; break;
+ case URBNF_ORDINAL: fmt_tag = "OrdinalRules"; break;
+ case URBNF_DURATION: fmt_tag = "DurationRules"; break;
+ default: status = U_ILLEGAL_ARGUMENT_ERROR; return;
+ }
+
+ // TODO: read localization info from resource
+ LocalizationInfo* locinfo = NULL;
+
+ int32_t len = 0;
+ UResourceBundle* nfrb = ures_open(U_ICUDATA_RBNF, locale.getName(), &status);
+ if (U_SUCCESS(status)) {
+ setLocaleIDs(ures_getLocaleByType(nfrb, ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(nfrb, ULOC_ACTUAL_LOCALE, &status));
+ const UChar* description = ures_getStringByKey(nfrb, fmt_tag, &len, &status);
+ UnicodeString desc(description, len);
+ UParseError perror;
+ init (desc, locinfo, perror, status);
+ }
+ ures_close(nfrb);
+}
+
+RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs)
+ : NumberFormat(rhs)
+ , ruleSets(NULL)
+ , defaultRuleSet(NULL)
+ , locale(rhs.locale)
+ , collator(NULL)
+ , decimalFormatSymbols(NULL)
+ , lenient(FALSE)
+ , lenientParseRules(NULL)
+ , localizations(NULL)
+{
+ this->operator=(rhs);
+}
+
+// --------
+
+RuleBasedNumberFormat&
+RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat& rhs)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ dispose();
+ locale = rhs.locale;
+ lenient = rhs.lenient;
+
+ UnicodeString rules = rhs.getRules();
+ UParseError perror;
+ init(rules, rhs.localizations ? rhs.localizations->ref() : NULL, perror, status);
+
+ return *this;
+}
+
+RuleBasedNumberFormat::~RuleBasedNumberFormat()
+{
+ dispose();
+}
+
+Format*
+RuleBasedNumberFormat::clone(void) const
+{
+ RuleBasedNumberFormat * result = NULL;
+ UnicodeString rules = getRules();
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError perror;
+ result = new RuleBasedNumberFormat(rules, localizations, locale, perror, status);
+ /* test for NULL */
+ if (result == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ if (U_FAILURE(status)) {
+ delete result;
+ result = 0;
+ } else {
+ result->lenient = lenient;
+ }
+ return result;
+}
+
+UBool
+RuleBasedNumberFormat::operator==(const Format& other) const
+{
+ if (this == &other) {
+ return TRUE;
+ }
+
+ if (other.getDynamicClassID() == getStaticClassID()) {
+ const RuleBasedNumberFormat& rhs = (const RuleBasedNumberFormat&)other;
+ if (locale == rhs.locale &&
+ lenient == rhs.lenient &&
+ (localizations == NULL
+ ? rhs.localizations == NULL
+ : (rhs.localizations == NULL
+ ? FALSE
+ : *localizations == rhs.localizations))) {
+
+ NFRuleSet** p = ruleSets;
+ NFRuleSet** q = rhs.ruleSets;
+ if (p == NULL) {
+ return q == NULL;
+ } else if (q == NULL) {
+ return FALSE;
+ }
+ while (*p && *q && (**p == **q)) {
+ ++p;
+ ++q;
+ }
+ return *q == NULL && *p == NULL;
+ }
+ }
+
+ return FALSE;
+}
+
+UnicodeString
+RuleBasedNumberFormat::getRules() const
+{
+ UnicodeString result;
+ if (ruleSets != NULL) {
+ for (NFRuleSet** p = ruleSets; *p; ++p) {
+ (*p)->appendRules(result);
+ }
+ }
+ return result;
+}
+
+UnicodeString
+RuleBasedNumberFormat::getRuleSetName(int32_t index) const
+{
+ if (localizations) {
+ UnicodeString string(TRUE, localizations->getRuleSetName(index), (int32_t)-1);
+ return string;
+ } else if (ruleSets) {
+ UnicodeString result;
+ for (NFRuleSet** p = ruleSets; *p; ++p) {
+ NFRuleSet* rs = *p;
+ if (rs->isPublic()) {
+ if (--index == -1) {
+ rs->getName(result);
+ return result;
+ }
+ }
+ }
+ }
+ UnicodeString empty;
+ return empty;
+}
+
+int32_t
+RuleBasedNumberFormat::getNumberOfRuleSetNames() const
+{
+ int32_t result = 0;
+ if (localizations) {
+ result = localizations->getNumberOfRuleSets();
+ } else if (ruleSets) {
+ for (NFRuleSet** p = ruleSets; *p; ++p) {
+ if ((**p).isPublic()) {
+ ++result;
+ }
+ }
+ }
+ return result;
+}
+
+int32_t
+RuleBasedNumberFormat::getNumberOfRuleSetDisplayNameLocales(void) const {
+ if (localizations) {
+ return localizations->getNumberOfDisplayLocales();
+ }
+ return 0;
+}
+
+Locale
+RuleBasedNumberFormat::getRuleSetDisplayNameLocale(int32_t index, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return Locale("");
+ }
+ if (localizations && index >= 0 && index < localizations->getNumberOfDisplayLocales()) {
+ UnicodeString name(TRUE, localizations->getLocaleName(index), -1);
+ char buffer[64];
+ int32_t cap = name.length() + 1;
+ char* bp = buffer;
+ if (cap > 64) {
+ bp = (char *)uprv_malloc(cap);
+ if (bp == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return Locale("");
+ }
+ }
+ name.extract(0, name.length(), bp, cap, UnicodeString::kInvariant);
+ Locale retLocale(bp);
+ if (bp != buffer) {
+ uprv_free(bp);
+ }
+ return retLocale;
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ Locale retLocale;
+ return retLocale;
+}
+
+UnicodeString
+RuleBasedNumberFormat::getRuleSetDisplayName(int32_t index, const Locale& localeParam) {
+ if (localizations && index >= 0 && index < localizations->getNumberOfRuleSets()) {
+ UnicodeString localeName(localeParam.getBaseName(), -1, UnicodeString::kInvariant);
+ int32_t len = localeName.length();
+ UChar* localeStr = localeName.getBuffer(len + 1);
+ while (len >= 0) {
+ localeStr[len] = 0;
+ int32_t ix = localizations->indexForLocale(localeStr);
+ if (ix >= 0) {
+ UnicodeString name(TRUE, localizations->getDisplayName(ix, index), -1);
+ return name;
+ }
+
+ // trim trailing portion, skipping over ommitted sections
+ do { --len;} while (len > 0 && localeStr[len] != 0x005f); // underscore
+ while (len > 0 && localeStr[len-1] == 0x005F) --len;
+ }
+ UnicodeString name(TRUE, localizations->getRuleSetName(index), -1);
+ return name;
+ }
+ UnicodeString bogus;
+ bogus.setToBogus();
+ return bogus;
+}
+
+UnicodeString
+RuleBasedNumberFormat::getRuleSetDisplayName(const UnicodeString& ruleSetName, const Locale& localeParam) {
+ if (localizations) {
+ UnicodeString rsn(ruleSetName);
+ int32_t ix = localizations->indexForRuleSet(rsn.getTerminatedBuffer());
+ return getRuleSetDisplayName(ix, localeParam);
+ }
+ UnicodeString bogus;
+ bogus.setToBogus();
+ return bogus;
+}
+
+NFRuleSet*
+RuleBasedNumberFormat::findRuleSet(const UnicodeString& name, UErrorCode& status) const
+{
+ if (U_SUCCESS(status) && ruleSets) {
+ for (NFRuleSet** p = ruleSets; *p; ++p) {
+ NFRuleSet* rs = *p;
+ if (rs->isNamed(name)) {
+ return rs;
+ }
+ }
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return NULL;
+}
+
+UnicodeString&
+RuleBasedNumberFormat::format(int32_t number,
+ UnicodeString& toAppendTo,
+ FieldPosition& /* pos */) const
+{
+ if (defaultRuleSet) defaultRuleSet->format((int64_t)number, toAppendTo, toAppendTo.length());
+ return toAppendTo;
+}
+
+
+UnicodeString&
+RuleBasedNumberFormat::format(int64_t number,
+ UnicodeString& toAppendTo,
+ FieldPosition& /* pos */) const
+{
+ if (defaultRuleSet) defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
+ return toAppendTo;
+}
+
+
+UnicodeString&
+RuleBasedNumberFormat::format(double number,
+ UnicodeString& toAppendTo,
+ FieldPosition& /* pos */) const
+{
+ if (defaultRuleSet) defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
+ return toAppendTo;
+}
+
+
+UnicodeString&
+RuleBasedNumberFormat::format(int32_t number,
+ const UnicodeString& ruleSetName,
+ UnicodeString& toAppendTo,
+ FieldPosition& /* pos */,
+ UErrorCode& status) const
+{
+ // return format((int64_t)number, ruleSetName, toAppendTo, pos, status);
+ if (U_SUCCESS(status)) {
+ if (ruleSetName.indexOf(gPercentPercent) == 0) {
+ // throw new IllegalArgumentException("Can't use internal rule set");
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ NFRuleSet *rs = findRuleSet(ruleSetName, status);
+ if (rs) {
+ rs->format((int64_t)number, toAppendTo, toAppendTo.length());
+ }
+ }
+ }
+ return toAppendTo;
+}
+
+
+UnicodeString&
+RuleBasedNumberFormat::format(int64_t number,
+ const UnicodeString& ruleSetName,
+ UnicodeString& toAppendTo,
+ FieldPosition& /* pos */,
+ UErrorCode& status) const
+{
+ if (U_SUCCESS(status)) {
+ if (ruleSetName.indexOf(gPercentPercent) == 0) {
+ // throw new IllegalArgumentException("Can't use internal rule set");
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ NFRuleSet *rs = findRuleSet(ruleSetName, status);
+ if (rs) {
+ rs->format(number, toAppendTo, toAppendTo.length());
+ }
+ }
+ }
+ return toAppendTo;
+}
+
+
+// make linker happy
+UnicodeString&
+RuleBasedNumberFormat::format(const Formattable& obj,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ return NumberFormat::format(obj, toAppendTo, pos, status);
+}
+
+UnicodeString&
+RuleBasedNumberFormat::format(double number,
+ const UnicodeString& ruleSetName,
+ UnicodeString& toAppendTo,
+ FieldPosition& /* pos */,
+ UErrorCode& status) const
+{
+ if (U_SUCCESS(status)) {
+ if (ruleSetName.indexOf(gPercentPercent) == 0) {
+ // throw new IllegalArgumentException("Can't use internal rule set");
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ NFRuleSet *rs = findRuleSet(ruleSetName, status);
+ if (rs) {
+ rs->format(number, toAppendTo, toAppendTo.length());
+ }
+ }
+ }
+ return toAppendTo;
+}
+
+void
+RuleBasedNumberFormat::parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& parsePosition) const
+{
+ if (!ruleSets) {
+ parsePosition.setErrorIndex(0);
+ return;
+ }
+
+ UnicodeString workingText(text, parsePosition.getIndex());
+ ParsePosition workingPos(0);
+
+ ParsePosition high_pp(0);
+ Formattable high_result;
+
+ for (NFRuleSet** p = ruleSets; *p; ++p) {
+ NFRuleSet *rp = *p;
+ if (rp->isPublic()) {
+ ParsePosition working_pp(0);
+ Formattable working_result;
+
+ rp->parse(workingText, working_pp, kMaxDouble, working_result);
+ if (working_pp.getIndex() > high_pp.getIndex()) {
+ high_pp = working_pp;
+ high_result = working_result;
+
+ if (high_pp.getIndex() == workingText.length()) {
+ break;
+ }
+ }
+ }
+ }
+
+ parsePosition.setIndex(parsePosition.getIndex() + high_pp.getIndex());
+ if (high_pp.getIndex() > 0) {
+ parsePosition.setErrorIndex(-1);
+ }
+ result = high_result;
+ if (result.getType() == Formattable::kDouble) {
+ int32_t r = (int32_t)result.getDouble();
+ if ((double)r == result.getDouble()) {
+ result.setLong(r);
+ }
+ }
+}
+
+#if !UCONFIG_NO_COLLATION
+
+void
+RuleBasedNumberFormat::setLenient(UBool enabled)
+{
+ lenient = enabled;
+ if (!enabled && collator) {
+ delete collator;
+ collator = NULL;
+ }
+}
+
+#endif
+
+void
+RuleBasedNumberFormat::setDefaultRuleSet(const UnicodeString& ruleSetName, UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ if (ruleSetName.isEmpty()) {
+ if (localizations) {
+ UnicodeString name(TRUE, localizations->getRuleSetName(0), -1);
+ defaultRuleSet = findRuleSet(name, status);
+ } else {
+ initDefaultRuleSet();
+ }
+ } else if (ruleSetName.startsWith(UNICODE_STRING_SIMPLE("%%"))) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ NFRuleSet* result = findRuleSet(ruleSetName, status);
+ if (result != NULL) {
+ defaultRuleSet = result;
+ }
+ }
+ }
+}
+
+UnicodeString
+RuleBasedNumberFormat::getDefaultRuleSetName() const {
+ UnicodeString result;
+ if (defaultRuleSet && defaultRuleSet->isPublic()) {
+ defaultRuleSet->getName(result);
+ } else {
+ result.setToBogus();
+ }
+ return result;
+}
+
+void
+RuleBasedNumberFormat::initDefaultRuleSet()
+{
+ defaultRuleSet = NULL;
+ if (!ruleSets) {
+ return;
+ }
+
+ NFRuleSet**p = &ruleSets[0];
+ while (*p) {
+ ++p;
+ }
+
+ defaultRuleSet = *--p;
+ if (!defaultRuleSet->isPublic()) {
+ while (p != ruleSets) {
+ if ((*--p)->isPublic()) {
+ defaultRuleSet = *p;
+ break;
+ }
+ }
+ }
+}
+
+
+void
+RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* localizationInfos,
+ UParseError& pErr, UErrorCode& status)
+{
+ // TODO: implement UParseError
+ uprv_memset(&pErr, 0, sizeof(UParseError));
+ // Note: this can leave ruleSets == NULL, so remaining code should check
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ this->localizations = localizationInfos == NULL ? NULL : localizationInfos->ref();
+
+ UnicodeString description(rules);
+ if (!description.length()) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ // start by stripping the trailing whitespace from all the rules
+ // (this is all the whitespace follwing each semicolon in the
+ // description). This allows us to look for rule-set boundaries
+ // by searching for ";%" without having to worry about whitespace
+ // between the ; and the %
+ stripWhitespace(description);
+
+ // check to see if there's a set of lenient-parse rules. If there
+ // is, pull them out into our temporary holding place for them,
+ // and delete them from the description before the real desciption-
+ // parsing code sees them
+ int32_t lp = description.indexOf(gLenientParse);
+ if (lp != -1) {
+ // we've got to make sure we're not in the middle of a rule
+ // (where "%%lenient-parse" would actually get treated as
+ // rule text)
+ if (lp == 0 || description.charAt(lp - 1) == gSemiColon) {
+ // locate the beginning and end of the actual collation
+ // rules (there may be whitespace between the name and
+ // the first token in the description)
+ int lpEnd = description.indexOf(gSemiPercent, lp);
+
+ if (lpEnd == -1) {
+ lpEnd = description.length() - 1;
+ }
+ int lpStart = lp + u_strlen(gLenientParse);
+ while (uprv_isRuleWhiteSpace(description.charAt(lpStart))) {
+ ++lpStart;
+ }
+
+ // copy out the lenient-parse rules and delete them
+ // from the description
+ lenientParseRules = new UnicodeString();
+ /* test for NULL */
+ if (lenientParseRules == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ lenientParseRules->setTo(description, lpStart, lpEnd - lpStart);
+
+ description.remove(lp, lpEnd + 1 - lp);
+ }
+ }
+
+ // pre-flight parsing the description and count the number of
+ // rule sets (";%" marks the end of one rule set and the beginning
+ // of the next)
+ int numRuleSets = 0;
+ for (int32_t p = description.indexOf(gSemiPercent); p != -1; p = description.indexOf(gSemiPercent, p)) {
+ ++numRuleSets;
+ ++p;
+ }
+ ++numRuleSets;
+
+ // our rule list is an array of the appropriate size
+ ruleSets = (NFRuleSet **)uprv_malloc((numRuleSets + 1) * sizeof(NFRuleSet *));
+ /* test for NULL */
+ if (ruleSets == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ for (int i = 0; i <= numRuleSets; ++i) {
+ ruleSets[i] = NULL;
+ }
+
+ // divide up the descriptions into individual rule-set descriptions
+ // and store them in a temporary array. At each step, we also
+ // new up a rule set, but all this does is initialize its name
+ // and remove it from its description. We can't actually parse
+ // the rest of the descriptions and finish initializing everything
+ // because we have to know the names and locations of all the rule
+ // sets before we can actually set everything up
+ if(!numRuleSets) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ UnicodeString* ruleSetDescriptions = new UnicodeString[numRuleSets];
+ /* test for NULL */
+ if (ruleSetDescriptions == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ {
+ int curRuleSet = 0;
+ int32_t start = 0;
+ for (int32_t p = description.indexOf(gSemiPercent); p != -1; p = description.indexOf(gSemiPercent, start)) {
+ ruleSetDescriptions[curRuleSet].setTo(description, start, p + 1 - start);
+ ruleSets[curRuleSet] = new NFRuleSet(ruleSetDescriptions, curRuleSet, status);
+ /* test for NULL */
+ if (ruleSets[curRuleSet] == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ ++curRuleSet;
+ start = p + 1;
+ }
+ ruleSetDescriptions[curRuleSet].setTo(description, start, description.length() - start);
+ ruleSets[curRuleSet] = new NFRuleSet(ruleSetDescriptions, curRuleSet, status);
+ /* test for NULL */
+ if (ruleSets[curRuleSet] == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ // now we can take note of the formatter's default rule set, which
+ // is the last public rule set in the description (it's the last
+ // rather than the first so that a user can create a new formatter
+ // from an existing formatter and change its default behavior just
+ // by appending more rule sets to the end)
+
+ // {dlf} Initialization of a fraction rule set requires the default rule
+ // set to be known. For purposes of initialization, this is always the
+ // last public rule set, no matter what the localization data says.
+ initDefaultRuleSet();
+
+ // finally, we can go back through the temporary descriptions
+ // list and finish seting up the substructure (and we throw
+ // away the temporary descriptions as we go)
+ {
+ for (int i = 0; i < numRuleSets; i++) {
+ ruleSets[i]->parseRules(ruleSetDescriptions[i], this, status);
+ }
+ }
+
+ delete[] ruleSetDescriptions;
+
+ // Now that the rules are initialized, the 'real' default rule
+ // set can be adjusted by the localization data.
+
+ // The C code keeps the localization array as is, rather than building
+ // a separate array of the public rule set names, so we have less work
+ // to do here-- but we still need to check the names.
+
+ if (localizationInfos) {
+ // confirm the names, if any aren't in the rules, that's an error
+ // it is ok if the rules contain public rule sets that are not in this list
+ for (int32_t i = 0; i < localizationInfos->getNumberOfRuleSets(); ++i) {
+ UnicodeString name(TRUE, localizationInfos->getRuleSetName(i), -1);
+ NFRuleSet* rs = findRuleSet(name, status);
+ if (rs == NULL) {
+ break; // error
+ }
+ if (i == 0) {
+ defaultRuleSet = rs;
+ }
+ }
+ } else {
+ defaultRuleSet = getDefaultRuleSet();
+ }
+}
+
+void
+RuleBasedNumberFormat::stripWhitespace(UnicodeString& description)
+{
+ // iterate through the characters...
+ UnicodeString result;
+
+ int start = 0;
+ while (start != -1 && start < description.length()) {
+ // seek to the first non-whitespace character...
+ while (start < description.length()
+ && uprv_isRuleWhiteSpace(description.charAt(start))) {
+ ++start;
+ }
+
+ // locate the next semicolon in the text and copy the text from
+ // our current position up to that semicolon into the result
+ int32_t p = description.indexOf(gSemiColon, start);
+ if (p == -1) {
+ // or if we don't find a semicolon, just copy the rest of
+ // the string into the result
+ result.append(description, start, description.length() - start);
+ start = -1;
+ }
+ else if (p < description.length()) {
+ result.append(description, start, p + 1 - start);
+ start = p + 1;
+ }
+
+ // when we get here, we've seeked off the end of the sring, and
+ // we terminate the loop (we continue until *start* is -1 rather
+ // than until *p* is -1, because otherwise we'd miss the last
+ // rule in the description)
+ else {
+ start = -1;
+ }
+ }
+
+ description.setTo(result);
+}
+
+
+void
+RuleBasedNumberFormat::dispose()
+{
+ if (ruleSets) {
+ for (NFRuleSet** p = ruleSets; *p; ++p) {
+ delete *p;
+ }
+ uprv_free(ruleSets);
+ ruleSets = NULL;
+ }
+
+#if !UCONFIG_NO_COLLATION
+ delete collator;
+#endif
+ collator = NULL;
+
+ delete decimalFormatSymbols;
+ decimalFormatSymbols = NULL;
+
+ delete lenientParseRules;
+ lenientParseRules = NULL;
+
+ if (localizations) localizations = localizations->unref();
+}
+
+
+//-----------------------------------------------------------------------
+// package-internal API
+//-----------------------------------------------------------------------
+
+/**
+ * Returns the collator to use for lenient parsing. The collator is lazily created:
+ * this function creates it the first time it's called.
+ * @return The collator to use for lenient parsing, or null if lenient parsing
+ * is turned off.
+*/
+Collator*
+RuleBasedNumberFormat::getCollator() const
+{
+#if !UCONFIG_NO_COLLATION
+ if (!ruleSets) {
+ return NULL;
+ }
+
+ // lazy-evaulate the collator
+ if (collator == NULL && lenient) {
+ // create a default collator based on the formatter's locale,
+ // then pull out that collator's rules, append any additional
+ // rules specified in the description, and create a _new_
+ // collator based on the combinaiton of those rules
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ Collator* temp = Collator::createInstance(locale, status);
+ if (U_SUCCESS(status) &&
+ temp->getDynamicClassID() == RuleBasedCollator::getStaticClassID()) {
+
+ RuleBasedCollator* newCollator = (RuleBasedCollator*)temp;
+ if (lenientParseRules) {
+ UnicodeString rules(newCollator->getRules());
+ rules.append(*lenientParseRules);
+
+ newCollator = new RuleBasedCollator(rules, status);
+ } else {
+ temp = NULL;
+ }
+ if (U_SUCCESS(status)) {
+ newCollator->setAttribute(UCOL_DECOMPOSITION_MODE, UCOL_ON, status);
+ // cast away const
+ ((RuleBasedNumberFormat*)this)->collator = newCollator;
+ } else {
+ delete newCollator;
+ }
+ }
+ delete temp;
+ }
+#endif
+
+ // if lenient-parse mode is off, this will be null
+ // (see setLenientParseMode())
+ return collator;
+}
+
+
+/**
+ * Returns the DecimalFormatSymbols object that should be used by all DecimalFormat
+ * instances owned by this formatter. This object is lazily created: this function
+ * creates it the first time it's called.
+ * @return The DecimalFormatSymbols object that should be used by all DecimalFormat
+ * instances owned by this formatter.
+*/
+DecimalFormatSymbols*
+RuleBasedNumberFormat::getDecimalFormatSymbols() const
+{
+ // lazy-evaluate the DecimalFormatSymbols object. This object
+ // is shared by all DecimalFormat instances belonging to this
+ // formatter
+ if (decimalFormatSymbols == NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols* temp = new DecimalFormatSymbols(locale, status);
+ if (U_SUCCESS(status)) {
+ ((RuleBasedNumberFormat*)this)->decimalFormatSymbols = temp;
+ } else {
+ delete temp;
+ }
+ }
+ return decimalFormatSymbols;
+}
+
+U_NAMESPACE_END
+
+/* U_HAVE_RBNF */
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt.cpp b/Build/source/libs/icu/icu-xetex/i18n/rbt.cpp
new file mode 100644
index 00000000000..1664577b938
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt.cpp
@@ -0,0 +1,293 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/rep.h"
+#include "unicode/uniset.h"
+#include "rbt_pars.h"
+#include "rbt_data.h"
+#include "rbt_rule.h"
+#include "rbt.h"
+#include "umutex.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTransliterator)
+
+static UMTX transliteratorDataMutex = NULL;
+static Replaceable *gLockedText = NULL;
+
+void RuleBasedTransliterator::_construct(const UnicodeString& rules,
+ UTransDirection direction,
+ UParseError& parseError,
+ UErrorCode& status) {
+ fData = 0;
+ isDataOwned = TRUE;
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ TransliteratorParser parser(status);
+ parser.parse(rules, direction, parseError, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (parser.idBlockVector.size() != 0 ||
+ parser.compoundFilter != NULL ||
+ parser.dataVector.size() == 0) {
+ status = U_INVALID_RBT_SYNTAX; // ::ID blocks disallowed in RBT
+ return;
+ }
+
+ fData = (TransliterationRuleData*)parser.dataVector.orphanElementAt(0);
+ setMaximumContextLength(fData->ruleSet.getMaximumContextLength());
+}
+
+/**
+ * Constructs a new transliterator from the given rules.
+ * @param id the id for the transliterator.
+ * @param rules rules, separated by ';'
+ * @param direction either FORWARD or REVERSE.
+ * @param adoptedFilter the filter for this transliterator.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered
+ * @param status Output param set to success/failure code.
+ * @exception IllegalArgumentException if rules are malformed
+ * or direction is invalid.
+ */
+RuleBasedTransliterator::RuleBasedTransliterator(
+ const UnicodeString& id,
+ const UnicodeString& rules,
+ UTransDirection direction,
+ UnicodeFilter* adoptedFilter,
+ UParseError& parseError,
+ UErrorCode& status) :
+ Transliterator(id, adoptedFilter) {
+ _construct(rules, direction,parseError,status);
+}
+
+/**
+ * Constructs a new transliterator from the given rules.
+ * @param id the id for the transliterator.
+ * @param rules rules, separated by ';'
+ * @param direction either FORWARD or REVERSE.
+ * @param adoptedFilter the filter for this transliterator.
+ * @param status Output param set to success/failure code.
+ * @exception IllegalArgumentException if rules are malformed
+ * or direction is invalid.
+ */
+/*RuleBasedTransliterator::RuleBasedTransliterator(
+ const UnicodeString& id,
+ const UnicodeString& rules,
+ UTransDirection direction,
+ UnicodeFilter* adoptedFilter,
+ UErrorCode& status) :
+ Transliterator(id, adoptedFilter) {
+ UParseError parseError;
+ _construct(rules, direction,parseError, status);
+}*/
+
+/**
+ * Covenience constructor with no filter.
+ */
+/*RuleBasedTransliterator::RuleBasedTransliterator(
+ const UnicodeString& id,
+ const UnicodeString& rules,
+ UTransDirection direction,
+ UErrorCode& status) :
+ Transliterator(id, 0) {
+ UParseError parseError;
+ _construct(rules, direction,parseError, status);
+}*/
+
+/**
+ * Covenience constructor with no filter and FORWARD direction.
+ */
+/*RuleBasedTransliterator::RuleBasedTransliterator(
+ const UnicodeString& id,
+ const UnicodeString& rules,
+ UErrorCode& status) :
+ Transliterator(id, 0) {
+ UParseError parseError;
+ _construct(rules, UTRANS_FORWARD, parseError, status);
+}*/
+
+/**
+ * Covenience constructor with FORWARD direction.
+ */
+/*RuleBasedTransliterator::RuleBasedTransliterator(
+ const UnicodeString& id,
+ const UnicodeString& rules,
+ UnicodeFilter* adoptedFilter,
+ UErrorCode& status) :
+ Transliterator(id, adoptedFilter) {
+ UParseError parseError;
+ _construct(rules, UTRANS_FORWARD,parseError, status);
+}*/
+
+RuleBasedTransliterator::RuleBasedTransliterator(const UnicodeString& id,
+ const TransliterationRuleData* theData,
+ UnicodeFilter* adoptedFilter) :
+ Transliterator(id, adoptedFilter),
+ fData((TransliterationRuleData*)theData), // cast away const
+ isDataOwned(FALSE) {
+ setMaximumContextLength(fData->ruleSet.getMaximumContextLength());
+}
+
+/**
+ * Internal constructor.
+ */
+RuleBasedTransliterator::RuleBasedTransliterator(const UnicodeString& id,
+ TransliterationRuleData* theData,
+ UBool isDataAdopted) :
+ Transliterator(id, 0),
+ fData(theData),
+ isDataOwned(isDataAdopted) {
+ setMaximumContextLength(fData->ruleSet.getMaximumContextLength());
+}
+
+/**
+ * Copy constructor.
+ */
+RuleBasedTransliterator::RuleBasedTransliterator(
+ const RuleBasedTransliterator& other) :
+ Transliterator(other), fData(other.fData),
+ isDataOwned(other.isDataOwned) {
+
+ // The data object may or may not be owned. If it is not owned we
+ // share it; it is invariant. If it is owned, it's still
+ // invariant, but we need to copy it to prevent double-deletion.
+ // If this becomes a performance issue (if people do a lot of RBT
+ // copying -- unlikely) we can reference count the data object.
+
+ // Only do a deep copy if this is owned data, that is, data that
+ // will be later deleted. System transliterators contain
+ // non-owned data.
+ if (isDataOwned) {
+ fData = new TransliterationRuleData(*other.fData);
+ }
+}
+
+/**
+ * Destructor.
+ */
+RuleBasedTransliterator::~RuleBasedTransliterator() {
+ // Delete the data object only if we own it.
+ if (isDataOwned) {
+ delete fData;
+ }
+}
+
+Transliterator* // Covariant return NOT ALLOWED (for portability)
+RuleBasedTransliterator::clone(void) const {
+ return new RuleBasedTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void
+RuleBasedTransliterator::handleTransliterate(Replaceable& text, UTransPosition& index,
+ UBool isIncremental) const {
+ /* We keep contextStart and contextLimit fixed the entire time,
+ * relative to the text -- contextLimit may move numerically if
+ * text is inserted or removed. The start offset moves toward
+ * limit, with replacements happening under it.
+ *
+ * Example: rules 1. ab>x|y
+ * 2. yc>z
+ *
+ * |eabcd begin - no match, advance start
+ * e|abcd match rule 1 - change text & adjust start
+ * ex|ycd match rule 2 - change text & adjust start
+ * exz|d no match, advance start
+ * exzd| done
+ */
+
+ /* A rule like
+ * a>b|a
+ * creates an infinite loop. To prevent that, we put an arbitrary
+ * limit on the number of iterations that we take, one that is
+ * high enough that any reasonable rules are ok, but low enough to
+ * prevent a server from hanging. The limit is 16 times the
+ * number of characters n, unless n is so large that 16n exceeds a
+ * uint32_t.
+ */
+ uint32_t loopCount = 0;
+ uint32_t loopLimit = index.limit - index.start;
+ if (loopLimit >= 0x10000000) {
+ loopLimit = 0xFFFFFFFF;
+ } else {
+ loopLimit <<= 4;
+ }
+
+ // Transliterator locking. Rule-based Transliterators are not thread safe; concurrent
+ // operations must be prevented.
+ // A Complication: compound transliterators can result in recursive entries to this
+ // function, sometimes with different "This" objects, always with the same text.
+ // Double-locking must be prevented in these cases.
+ //
+
+ // If the transliteration data is exclusively owned by this transliterator object,
+ // we don't need to do any locking. No sharing between transliterators is possible,
+ // so no concurrent access from multiple threads is possible.
+ UBool lockedMutexAtThisLevel = FALSE;
+ if (isDataOwned == FALSE) {
+ // Test whether this request is operating on the same text string as some
+ // some other transliteration that is still in progress and holding the
+ // transliteration mutex. If so, do not lock the transliteration
+ // mutex again.
+ UBool needToLock;
+ UMTX_CHECK(NULL, (&text != gLockedText), needToLock);
+ if (needToLock) {
+ umtx_lock(&transliteratorDataMutex);
+ gLockedText = &text;
+ lockedMutexAtThisLevel = TRUE;
+ }
+ }
+
+
+ while (index.start < index.limit &&
+ loopCount <= loopLimit &&
+ fData->ruleSet.transliterate(text, index, isIncremental)) {
+ ++loopCount;
+ }
+ if (lockedMutexAtThisLevel) {
+ gLockedText = NULL;
+ umtx_unlock(&transliteratorDataMutex);
+ }
+}
+
+UnicodeString& RuleBasedTransliterator::toRules(UnicodeString& rulesSource,
+ UBool escapeUnprintable) const {
+ return fData->ruleSet.toRules(rulesSource, escapeUnprintable);
+}
+
+/**
+ * Implement Transliterator framework
+ */
+void RuleBasedTransliterator::handleGetSourceSet(UnicodeSet& result) const {
+ fData->ruleSet.getSourceTargetSet(result, FALSE);
+}
+
+/**
+ * Override Transliterator framework
+ */
+UnicodeSet& RuleBasedTransliterator::getTargetSet(UnicodeSet& result) const {
+ return fData->ruleSet.getSourceTargetSet(result, TRUE);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt.h b/Build/source/libs/icu/icu-xetex/i18n/rbt.h
new file mode 100644
index 00000000000..d061de6e637
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt.h
@@ -0,0 +1,473 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+#ifndef RBT_H
+#define RBT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "unicode/utypes.h"
+#include "unicode/parseerr.h"
+#include "unicode/udata.h"
+
+#define U_ICUDATA_TRANSLIT U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "translit"
+
+U_NAMESPACE_BEGIN
+
+class TransliterationRuleData;
+
+/**
+ * <code>RuleBasedTransliterator</code> is a transliterator
+ * that reads a set of rules in order to determine how to perform
+ * translations. Rule sets are stored in resource bundles indexed by
+ * name. Rules within a rule set are separated by semicolons (';').
+ * To include a literal semicolon, prefix it with a backslash ('\').
+ * Whitespace, as defined by <code>Character.isWhitespace()</code>,
+ * is ignored. If the first non-blank character on a line is '#',
+ * the entire line is ignored as a comment. </p>
+ *
+ * <p>Each set of rules consists of two groups, one forward, and one
+ * reverse. This is a convention that is not enforced; rules for one
+ * direction may be omitted, with the result that translations in
+ * that direction will not modify the source text. In addition,
+ * bidirectional forward-reverse rules may be specified for
+ * symmetrical transformations.</p>
+ *
+ * <p><b>Rule syntax</b> </p>
+ *
+ * <p>Rule statements take one of the following forms: </p>
+ *
+ * <dl>
+ * <dt><code>$alefmadda=\u0622;</code></dt>
+ * <dd><strong>Variable definition.</strong> The name on the
+ * left is assigned the text on the right. In this example,
+ * after this statement, instances of the left hand name,
+ * &quot;<code>$alefmadda</code>&quot;, will be replaced by
+ * the Unicode character U+0622. Variable names must begin
+ * with a letter and consist only of letters, digits, and
+ * underscores. Case is significant. Duplicate names cause
+ * an exception to be thrown, that is, variables cannot be
+ * redefined. The right hand side may contain well-formed
+ * text of any length, including no text at all (&quot;<code>$empty=;</code>&quot;).
+ * The right hand side may contain embedded <code>UnicodeSet</code>
+ * patterns, for example, &quot;<code>$softvowel=[eiyEIY]</code>&quot;.</dd>
+ * <dd>&nbsp;</dd>
+ * <dt><code>ai&gt;$alefmadda;</code></dt>
+ * <dd><strong>Forward translation rule.</strong> This rule
+ * states that the string on the left will be changed to the
+ * string on the right when performing forward
+ * transliteration.</dd>
+ * <dt>&nbsp;</dt>
+ * <dt><code>ai<$alefmadda;</code></dt>
+ * <dd><strong>Reverse translation rule.</strong> This rule
+ * states that the string on the right will be changed to
+ * the string on the left when performing reverse
+ * transliteration.</dd>
+ * </dl>
+ *
+ * <dl>
+ * <dt><code>ai<>$alefmadda;</code></dt>
+ * <dd><strong>Bidirectional translation rule.</strong> This
+ * rule states that the string on the right will be changed
+ * to the string on the left when performing forward
+ * transliteration, and vice versa when performing reverse
+ * transliteration.</dd>
+ * </dl>
+ *
+ * <p>Translation rules consist of a <em>match pattern</em> and an <em>output
+ * string</em>. The match pattern consists of literal characters,
+ * optionally preceded by context, and optionally followed by
+ * context. Context characters, like literal pattern characters,
+ * must be matched in the text being transliterated. However, unlike
+ * literal pattern characters, they are not replaced by the output
+ * text. For example, the pattern &quot;<code>abc{def}</code>&quot;
+ * indicates the characters &quot;<code>def</code>&quot; must be
+ * preceded by &quot;<code>abc</code>&quot; for a successful match.
+ * If there is a successful match, &quot;<code>def</code>&quot; will
+ * be replaced, but not &quot;<code>abc</code>&quot;. The final '<code>}</code>'
+ * is optional, so &quot;<code>abc{def</code>&quot; is equivalent to
+ * &quot;<code>abc{def}</code>&quot;. Another example is &quot;<code>{123}456</code>&quot;
+ * (or &quot;<code>123}456</code>&quot;) in which the literal
+ * pattern &quot;<code>123</code>&quot; must be followed by &quot;<code>456</code>&quot;.
+ * </p>
+ *
+ * <p>The output string of a forward or reverse rule consists of
+ * characters to replace the literal pattern characters. If the
+ * output string contains the character '<code>|</code>', this is
+ * taken to indicate the location of the <em>cursor</em> after
+ * replacement. The cursor is the point in the text at which the
+ * next replacement, if any, will be applied. The cursor is usually
+ * placed within the replacement text; however, it can actually be
+ * placed into the precending or following context by using the
+ * special character '<code>@</code>'. Examples:</p>
+ *
+ * <blockquote>
+ * <p><code>a {foo} z &gt; | @ bar; # foo -&gt; bar, move cursor
+ * before a<br>
+ * {foo} xyz &gt; bar @@|; #&nbsp;foo -&gt; bar, cursor between
+ * y and z</code></p>
+ * </blockquote>
+ *
+ * <p><b>UnicodeSet</b></p>
+ *
+ * <p><code>UnicodeSet</code> patterns may appear anywhere that
+ * makes sense. They may appear in variable definitions.
+ * Contrariwise, <code>UnicodeSet</code> patterns may themselves
+ * contain variable references, such as &quot;<code>$a=[a-z];$not_a=[^$a]</code>&quot;,
+ * or &quot;<code>$range=a-z;$ll=[$range]</code>&quot;.</p>
+ *
+ * <p><code>UnicodeSet</code> patterns may also be embedded directly
+ * into rule strings. Thus, the following two rules are equivalent:</p>
+ *
+ * <blockquote>
+ * <p><code>$vowel=[aeiou]; $vowel&gt;'*'; # One way to do this<br>
+ * [aeiou]&gt;'*';
+ * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
+ * Another way</code></p>
+ * </blockquote>
+ *
+ * <p>See {@link UnicodeSet} for more documentation and examples.</p>
+ *
+ * <p><b>Segments</b></p>
+ *
+ * <p>Segments of the input string can be matched and copied to the
+ * output string. This makes certain sets of rules simpler and more
+ * general, and makes reordering possible. For example:</p>
+ *
+ * <blockquote>
+ * <p><code>([a-z]) &gt; $1 $1;
+ * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#
+ * double lowercase letters<br>
+ * ([:Lu:]) ([:Ll:]) &gt; $2 $1; # reverse order of Lu-Ll pairs</code></p>
+ * </blockquote>
+ *
+ * <p>The segment of the input string to be copied is delimited by
+ * &quot;<code>(</code>&quot; and &quot;<code>)</code>&quot;. Up to
+ * nine segments may be defined. Segments may not overlap. In the
+ * output string, &quot;<code>$1</code>&quot; through &quot;<code>$9</code>&quot;
+ * represent the input string segments, in left-to-right order of
+ * definition.</p>
+ *
+ * <p><b>Anchors</b></p>
+ *
+ * <p>Patterns can be anchored to the beginning or the end of the text. This is done with the
+ * special characters '<code>^</code>' and '<code>$</code>'. For example:</p>
+ *
+ * <blockquote>
+ * <p><code>^ a&nbsp;&nbsp; &gt; 'BEG_A'; &nbsp;&nbsp;# match 'a' at start of text<br>
+ * &nbsp; a&nbsp;&nbsp; &gt; 'A';&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # match other instances
+ * of 'a'<br>
+ * &nbsp; z $ &gt; 'END_Z'; &nbsp;&nbsp;# match 'z' at end of text<br>
+ * &nbsp; z&nbsp;&nbsp; &gt; 'Z';&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # match other instances
+ * of 'z'</code></p>
+ * </blockquote>
+ *
+ * <p>It is also possible to match the beginning or the end of the text using a <code>UnicodeSet</code>.
+ * This is done by including a virtual anchor character '<code>$</code>' at the end of the
+ * set pattern. Although this is usually the match chafacter for the end anchor, the set will
+ * match either the beginning or the end of the text, depending on its placement. For
+ * example:</p>
+ *
+ * <blockquote>
+ * <p><code>$x = [a-z$]; &nbsp;&nbsp;# match 'a' through 'z' OR anchor<br>
+ * $x 1&nbsp;&nbsp;&nbsp; &gt; 2;&nbsp;&nbsp; # match '1' after a-z or at the start<br>
+ * &nbsp;&nbsp; 3 $x &gt; 4; &nbsp;&nbsp;# match '3' before a-z or at the end</code></p>
+ * </blockquote>
+ *
+ * <p><b>Example</b> </p>
+ *
+ * <p>The following example rules illustrate many of the features of
+ * the rule language. </p>
+ *
+ * <table border="0" cellpadding="4">
+ * <tr>
+ * <td valign="top">Rule 1.</td>
+ * <td valign="top" nowrap><code>abc{def}&gt;x|y</code></td>
+ * </tr>
+ * <tr>
+ * <td valign="top">Rule 2.</td>
+ * <td valign="top" nowrap><code>xyz&gt;r</code></td>
+ * </tr>
+ * <tr>
+ * <td valign="top">Rule 3.</td>
+ * <td valign="top" nowrap><code>yz&gt;q</code></td>
+ * </tr>
+ * </table>
+ *
+ * <p>Applying these rules to the string &quot;<code>adefabcdefz</code>&quot;
+ * yields the following results: </p>
+ *
+ * <table border="0" cellpadding="4">
+ * <tr>
+ * <td valign="top" nowrap><code>|adefabcdefz</code></td>
+ * <td valign="top">Initial state, no rules match. Advance
+ * cursor.</td>
+ * </tr>
+ * <tr>
+ * <td valign="top" nowrap><code>a|defabcdefz</code></td>
+ * <td valign="top">Still no match. Rule 1 does not match
+ * because the preceding context is not present.</td>
+ * </tr>
+ * <tr>
+ * <td valign="top" nowrap><code>ad|efabcdefz</code></td>
+ * <td valign="top">Still no match. Keep advancing until
+ * there is a match...</td>
+ * </tr>
+ * <tr>
+ * <td valign="top" nowrap><code>ade|fabcdefz</code></td>
+ * <td valign="top">...</td>
+ * </tr>
+ * <tr>
+ * <td valign="top" nowrap><code>adef|abcdefz</code></td>
+ * <td valign="top">...</td>
+ * </tr>
+ * <tr>
+ * <td valign="top" nowrap><code>adefa|bcdefz</code></td>
+ * <td valign="top">...</td>
+ * </tr>
+ * <tr>
+ * <td valign="top" nowrap><code>adefab|cdefz</code></td>
+ * <td valign="top">...</td>
+ * </tr>
+ * <tr>
+ * <td valign="top" nowrap><code>adefabc|defz</code></td>
+ * <td valign="top">Rule 1 matches; replace &quot;<code>def</code>&quot;
+ * with &quot;<code>xy</code>&quot; and back up the cursor
+ * to before the '<code>y</code>'.</td>
+ * </tr>
+ * <tr>
+ * <td valign="top" nowrap><code>adefabcx|yz</code></td>
+ * <td valign="top">Although &quot;<code>xyz</code>&quot; is
+ * present, rule 2 does not match because the cursor is
+ * before the '<code>y</code>', not before the '<code>x</code>'.
+ * Rule 3 does match. Replace &quot;<code>yz</code>&quot;
+ * with &quot;<code>q</code>&quot;.</td>
+ * </tr>
+ * <tr>
+ * <td valign="top" nowrap><code>adefabcxq|</code></td>
+ * <td valign="top">The cursor is at the end;
+ * transliteration is complete.</td>
+ * </tr>
+ * </table>
+ *
+ * <p>The order of rules is significant. If multiple rules may match
+ * at some point, the first matching rule is applied. </p>
+ *
+ * <p>Forward and reverse rules may have an empty output string.
+ * Otherwise, an empty left or right hand side of any statement is a
+ * syntax error. </p>
+ *
+ * <p>Single quotes are used to quote any character other than a
+ * digit or letter. To specify a single quote itself, inside or
+ * outside of quotes, use two single quotes in a row. For example,
+ * the rule &quot;<code>'&gt;'&gt;o''clock</code>&quot; changes the
+ * string &quot;<code>&gt;</code>&quot; to the string &quot;<code>o'clock</code>&quot;.
+ * </p>
+ *
+ * <p><b>Notes</b> </p>
+ *
+ * <p>While a RuleBasedTransliterator is being built, it checks that
+ * the rules are added in proper order. For example, if the rule
+ * &quot;a&gt;x&quot; is followed by the rule &quot;ab&gt;y&quot;,
+ * then the second rule will throw an exception. The reason is that
+ * the second rule can never be triggered, since the first rule
+ * always matches anything it matches. In other words, the first
+ * rule <em>masks</em> the second rule. </p>
+ *
+ * @author Alan Liu
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+class RuleBasedTransliterator : public Transliterator {
+private:
+ /**
+ * The data object is immutable, so we can freely share it with
+ * other instances of RBT, as long as we do NOT own this object.
+ * TODO: data is no longer immutable. See bugs #1866, 2155
+ */
+ TransliterationRuleData* fData;
+
+ /**
+ * If true, we own the data object and must delete it.
+ */
+ UBool isDataOwned;
+
+public:
+
+ /**
+ * Constructs a new transliterator from the given rules.
+ * @param rules rules, separated by ';'
+ * @param direction either FORWARD or REVERSE.
+ * @exception IllegalArgumentException if rules are malformed.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ RuleBasedTransliterator(const UnicodeString& id,
+ const UnicodeString& rules,
+ UTransDirection direction,
+ UnicodeFilter* adoptedFilter,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ /**
+ * Constructs a new transliterator from the given rules.
+ * @param rules rules, separated by ';'
+ * @param direction either FORWARD or REVERSE.
+ * @exception IllegalArgumentException if rules are malformed.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ /*RuleBasedTransliterator(const UnicodeString& id,
+ const UnicodeString& rules,
+ UTransDirection direction,
+ UnicodeFilter* adoptedFilter,
+ UErrorCode& status);*/
+
+ /**
+ * Covenience constructor with no filter.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ /*RuleBasedTransliterator(const UnicodeString& id,
+ const UnicodeString& rules,
+ UTransDirection direction,
+ UErrorCode& status);*/
+
+ /**
+ * Covenience constructor with no filter and FORWARD direction.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ /*RuleBasedTransliterator(const UnicodeString& id,
+ const UnicodeString& rules,
+ UErrorCode& status);*/
+
+ /**
+ * Covenience constructor with FORWARD direction.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ /*RuleBasedTransliterator(const UnicodeString& id,
+ const UnicodeString& rules,
+ UnicodeFilter* adoptedFilter,
+ UErrorCode& status);*/
+private:
+
+ friend class TransliteratorRegistry; // to access TransliterationRuleData convenience ctor
+ /**
+ * Covenience constructor.
+ * @param id the id for the transliterator.
+ * @param theData the rule data for the transliterator.
+ * @param adoptedFilter the filter for the transliterator
+ */
+ RuleBasedTransliterator(const UnicodeString& id,
+ const TransliterationRuleData* theData,
+ UnicodeFilter* adoptedFilter = 0);
+
+
+ friend class Transliterator; // to access following ct
+
+ /**
+ * Internal constructor.
+ * @param id the id for the transliterator.
+ * @param theData the rule data for the transliterator.
+ * @param isDataAdopted determine who will own the 'data' object. True, the caller should not delete 'data'.
+ */
+ RuleBasedTransliterator(const UnicodeString& id,
+ TransliterationRuleData* data,
+ UBool isDataAdopted);
+
+public:
+
+ /**
+ * Copy constructor.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ RuleBasedTransliterator(const RuleBasedTransliterator&);
+
+ virtual ~RuleBasedTransliterator();
+
+ /**
+ * Implement Transliterator API.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual Transliterator* clone(void) const;
+
+protected:
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& offsets,
+ UBool isIncremental) const;
+
+public:
+ /**
+ * Return a representation of this transliterator as source rules.
+ * These rules will produce an equivalent transliterator if used
+ * to construct a new transliterator.
+ * @param result the string to receive the rules. Previous
+ * contents will be deleted.
+ * @param escapeUnprintable if TRUE then convert unprintable
+ * character to their hex escape representations, \uxxxx or
+ * \Uxxxxxxxx. Unprintable characters are those other than
+ * U+000A, U+0020..U+007E.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ virtual UnicodeString& toRules(UnicodeString& result,
+ UBool escapeUnprintable) const;
+
+protected:
+ /**
+ * Implement Transliterator framework
+ */
+ virtual void handleGetSourceSet(UnicodeSet& result) const;
+
+public:
+ /**
+ * Override Transliterator framework
+ */
+ virtual UnicodeSet& getTargetSet(UnicodeSet& result) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for
+ * comparing to a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . Derived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @internal Use transliterator factory methods instead since this class will be removed in that release.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID <b>polymorphically</b>. This method
+ * is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and
+ * clone() methods call this method.
+ *
+ * @return The class ID for this object. All objects of a given
+ * class have the same class ID. Objects of other classes have
+ * different class IDs.
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+private:
+
+ void _construct(const UnicodeString& rules,
+ UTransDirection direction,
+ UParseError& parseError,
+ UErrorCode& status);
+};
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt_data.cpp b/Build/source/libs/icu/icu-xetex/i18n/rbt_data.cpp
new file mode 100644
index 00000000000..bec4b48ce80
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt_data.cpp
@@ -0,0 +1,99 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "umutex.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#include "rbt_data.h"
+#include "hash.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+TransliterationRuleData::TransliterationRuleData(UErrorCode& status)
+ : UMemory(), ruleSet(status), variableNames(status),
+ variables(0), variablesAreOwned(TRUE)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ variableNames.setValueDeleter(uhash_deleteUnicodeString);
+ variables = 0;
+ variablesLength = 0;
+}
+
+TransliterationRuleData::TransliterationRuleData(const TransliterationRuleData& other) :
+ UMemory(other), ruleSet(other.ruleSet),
+ variablesAreOwned(TRUE),
+ variablesBase(other.variablesBase),
+ variablesLength(other.variablesLength)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ variableNames.setValueDeleter(uhash_deleteUnicodeString);
+ int32_t pos = -1;
+ const UHashElement *e;
+ while ((e = other.variableNames.nextElement(pos)) != 0) {
+ UnicodeString* value =
+ new UnicodeString(*(const UnicodeString*)e->value.pointer);
+ variableNames.put(*(UnicodeString*)e->key.pointer, value, status);
+ }
+
+ variables = 0;
+ if (other.variables != 0) {
+ variables = (UnicodeFunctor **)uprv_malloc(variablesLength * sizeof(UnicodeFunctor *));
+ /* test for NULL */
+ if (variables == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (int32_t i=0; i<variablesLength; ++i) {
+ variables[i] = other.variables[i]->clone();
+ }
+ }
+
+ // Do this last, _after_ setting up variables[].
+ ruleSet.setData(this); // ruleSet must already be frozen
+}
+
+TransliterationRuleData::~TransliterationRuleData() {
+ if (variablesAreOwned && variables != 0) {
+ for (int32_t i=0; i<variablesLength; ++i) {
+ delete variables[i];
+ }
+ }
+ uprv_free(variables);
+}
+
+UnicodeFunctor*
+TransliterationRuleData::lookup(UChar32 standIn) const {
+ int32_t i = standIn - variablesBase;
+ return (i >= 0 && i < variablesLength) ? variables[i] : 0;
+}
+
+UnicodeMatcher*
+TransliterationRuleData::lookupMatcher(UChar32 standIn) const {
+ UnicodeFunctor *f = lookup(standIn);
+ return (f != 0) ? f->toMatcher() : 0;
+}
+
+UnicodeReplacer*
+TransliterationRuleData::lookupReplacer(UChar32 standIn) const {
+ UnicodeFunctor *f = lookup(standIn);
+ return (f != 0) ? f->toReplacer() : 0;
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt_data.h b/Build/source/libs/icu/icu-xetex/i18n/rbt_data.h
new file mode 100644
index 00000000000..ce833dc26dd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt_data.h
@@ -0,0 +1,152 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2007, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+#ifndef RBT_DATA_H
+#define RBT_DATA_H
+
+#include "unicode/utypes.h"
+#include "unicode/uclean.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uobject.h"
+#include "rbt_set.h"
+#include "hash.h"
+
+U_NAMESPACE_BEGIN
+
+class UnicodeFunctor;
+class UnicodeMatcher;
+class UnicodeReplacer;
+
+/**
+ * The rule data for a RuleBasedTransliterators. RBT objects hold
+ * a const pointer to a TRD object that they do not own. TRD objects
+ * are essentially the parsed rules in compact, usable form. The
+ * TRD objects themselves are held for the life of the process in
+ * a static cache owned by Transliterator.
+ *
+ * This class' API is a little asymmetric. There is a method to
+ * define a variable, but no way to define a set. This is because the
+ * sets are defined by the parser in a UVector, and the vector is
+ * copied into a fixed-size array here. Once this is done, no new
+ * sets may be defined. In practice, there is no need to do so, since
+ * generating the data and using it are discrete phases. When there
+ * is a need to access the set data during the parse phase, another
+ * data structure handles this. See the parsing code for more
+ * details.
+ */
+class TransliterationRuleData : public UMemory {
+
+public:
+
+ // PUBLIC DATA MEMBERS
+
+ /**
+ * Rule table. May be empty.
+ */
+ TransliterationRuleSet ruleSet;
+
+ /**
+ * Map variable name (String) to variable (UnicodeString). A variable name
+ * corresponds to zero or more characters, stored in a UnicodeString in
+ * this hash. One or more of these chars may also correspond to a
+ * UnicodeMatcher, in which case the character in the UnicodeString in this hash is
+ * a stand-in: it is an index for a secondary lookup in
+ * data.variables. The stand-in also represents the UnicodeMatcher in
+ * the stored rules.
+ */
+ Hashtable variableNames;
+
+ /**
+ * Map category variable (UChar) to set (UnicodeFunctor).
+ * Variables that correspond to a set of characters are mapped
+ * from variable name to a stand-in character in data.variableNames.
+ * The stand-in then serves as a key in this hash to lookup the
+ * actual UnicodeFunctor object. In addition, the stand-in is
+ * stored in the rule text to represent the set of characters.
+ * variables[i] represents character (variablesBase + i).
+ */
+ UnicodeFunctor** variables;
+
+ /**
+ * Flag that indicates whether the variables are owned (if a single
+ * call to Transliterator::createFromRules() produces a CompoundTransliterator
+ * with more than one RuleBasedTransliterator as children, they all share
+ * the same variables list, so only the first one is considered to own
+ * the variables)
+ */
+ UBool variablesAreOwned;
+
+ /**
+ * The character that represents variables[0]. Characters
+ * variablesBase through variablesBase +
+ * variablesLength - 1 represent UnicodeFunctor objects.
+ */
+ UChar variablesBase;
+
+ /**
+ * The length of variables.
+ */
+ int32_t variablesLength;
+
+public:
+
+ /**
+ * Constructor
+ * @param status Output param set to success/failure code on exit.
+ */
+ TransliterationRuleData(UErrorCode& status);
+
+ /**
+ * Copy Constructor
+ */
+ TransliterationRuleData(const TransliterationRuleData&);
+
+ /**
+ * destructor
+ */
+ ~TransliterationRuleData();
+
+ /**
+ * Given a stand-in character, return the UnicodeFunctor that it
+ * represents, or NULL if it doesn't represent anything.
+ * @param standIn the given stand-in character.
+ * @return the UnicodeFunctor that 'standIn' represents
+ */
+ UnicodeFunctor* lookup(UChar32 standIn) const;
+
+ /**
+ * Given a stand-in character, return the UnicodeMatcher that it
+ * represents, or NULL if it doesn't represent anything or if it
+ * represents something that is not a matcher.
+ * @param standIn the given stand-in character.
+ * @return return the UnicodeMatcher that 'standIn' represents
+ */
+ UnicodeMatcher* lookupMatcher(UChar32 standIn) const;
+
+ /**
+ * Given a stand-in character, return the UnicodeReplacer that it
+ * represents, or NULL if it doesn't represent anything or if it
+ * represents something that is not a replacer.
+ * @param standIn the given stand-in character.
+ * @return return the UnicodeReplacer that 'standIn' represents
+ */
+ UnicodeReplacer* lookupReplacer(UChar32 standIn) const;
+
+
+private:
+ TransliterationRuleData &operator=(const TransliterationRuleData &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt_pars.cpp b/Build/source/libs/icu/icu-xetex/i18n/rbt_pars.cpp
new file mode 100644
index 00000000000..83eccf54eaf
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt_pars.cpp
@@ -0,0 +1,1667 @@
+/*
+ **********************************************************************
+ * Copyright (C) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 11/17/99 aliu Creation.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uobject.h"
+#include "unicode/parseerr.h"
+#include "unicode/parsepos.h"
+#include "unicode/putil.h"
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "unicode/uniset.h"
+#include "cstring.h"
+#include "funcrepl.h"
+#include "hash.h"
+#include "quant.h"
+#include "rbt.h"
+#include "rbt_data.h"
+#include "rbt_pars.h"
+#include "rbt_rule.h"
+#include "strmatch.h"
+#include "strrepl.h"
+#include "unicode/symtable.h"
+#include "tridpars.h"
+#include "uvector.h"
+#include "hash.h"
+#include "util.h"
+#include "cmemory.h"
+#include "uprops.h"
+#include "putilimp.h"
+
+// Operators
+#define VARIABLE_DEF_OP ((UChar)0x003D) /*=*/
+#define FORWARD_RULE_OP ((UChar)0x003E) /*>*/
+#define REVERSE_RULE_OP ((UChar)0x003C) /*<*/
+#define FWDREV_RULE_OP ((UChar)0x007E) /*~*/ // internal rep of <> op
+
+// Other special characters
+#define QUOTE ((UChar)0x0027) /*'*/
+#define ESCAPE ((UChar)0x005C) /*\*/
+#define END_OF_RULE ((UChar)0x003B) /*;*/
+#define RULE_COMMENT_CHAR ((UChar)0x0023) /*#*/
+
+#define SEGMENT_OPEN ((UChar)0x0028) /*(*/
+#define SEGMENT_CLOSE ((UChar)0x0029) /*)*/
+#define CONTEXT_ANTE ((UChar)0x007B) /*{*/
+#define CONTEXT_POST ((UChar)0x007D) /*}*/
+#define CURSOR_POS ((UChar)0x007C) /*|*/
+#define CURSOR_OFFSET ((UChar)0x0040) /*@*/
+#define ANCHOR_START ((UChar)0x005E) /*^*/
+#define KLEENE_STAR ((UChar)0x002A) /***/
+#define ONE_OR_MORE ((UChar)0x002B) /*+*/
+#define ZERO_OR_ONE ((UChar)0x003F) /*?*/
+
+#define DOT ((UChar)46) /*.*/
+
+static const UChar DOT_SET[] = { // "[^[:Zp:][:Zl:]\r\n$]";
+ 91, 94, 91, 58, 90, 112, 58, 93, 91, 58, 90,
+ 108, 58, 93, 92, 114, 92, 110, 36, 93, 0
+};
+
+// A function is denoted &Source-Target/Variant(text)
+#define FUNCTION ((UChar)38) /*&*/
+
+// Aliases for some of the syntax characters. These are provided so
+// transliteration rules can be expressed in XML without clashing with
+// XML syntax characters '<', '>', and '&'.
+#define ALT_REVERSE_RULE_OP ((UChar)0x2190) // Left Arrow
+#define ALT_FORWARD_RULE_OP ((UChar)0x2192) // Right Arrow
+#define ALT_FWDREV_RULE_OP ((UChar)0x2194) // Left Right Arrow
+#define ALT_FUNCTION ((UChar)0x2206) // Increment (~Greek Capital Delta)
+
+// Special characters disallowed at the top level
+static const UChar ILLEGAL_TOP[] = {41,0}; // ")"
+
+// Special characters disallowed within a segment
+static const UChar ILLEGAL_SEG[] = {123,125,124,64,0}; // "{}|@"
+
+// Special characters disallowed within a function argument
+static const UChar ILLEGAL_FUNC[] = {94,40,46,42,43,63,123,125,124,64,0}; // "^(.*+?{}|@"
+
+// By definition, the ANCHOR_END special character is a
+// trailing SymbolTable.SYMBOL_REF character.
+// private static final char ANCHOR_END = '$';
+
+static const UChar gOPERATORS[] = { // "=><"
+ VARIABLE_DEF_OP, FORWARD_RULE_OP, REVERSE_RULE_OP,
+ ALT_FORWARD_RULE_OP, ALT_REVERSE_RULE_OP, ALT_FWDREV_RULE_OP,
+ 0
+};
+
+static const UChar HALF_ENDERS[] = { // "=><;"
+ VARIABLE_DEF_OP, FORWARD_RULE_OP, REVERSE_RULE_OP,
+ ALT_FORWARD_RULE_OP, ALT_REVERSE_RULE_OP, ALT_FWDREV_RULE_OP,
+ END_OF_RULE,
+ 0
+};
+
+// These are also used in Transliterator::toRules()
+static const int32_t ID_TOKEN_LEN = 2;
+static const UChar ID_TOKEN[] = { 0x3A, 0x3A }; // ':', ':'
+
+/*
+commented out until we do real ::BEGIN/::END functionality
+static const int32_t BEGIN_TOKEN_LEN = 5;
+static const UChar BEGIN_TOKEN[] = { 0x42, 0x45, 0x47, 0x49, 0x4e }; // 'BEGIN'
+
+static const int32_t END_TOKEN_LEN = 3;
+static const UChar END_TOKEN[] = { 0x45, 0x4e, 0x44 }; // 'END'
+*/
+
+U_NAMESPACE_BEGIN
+
+//----------------------------------------------------------------------
+// BEGIN ParseData
+//----------------------------------------------------------------------
+
+/**
+ * This class implements the SymbolTable interface. It is used
+ * during parsing to give UnicodeSet access to variables that
+ * have been defined so far. Note that it uses variablesVector,
+ * _not_ data.setVariables.
+ */
+class ParseData : public UMemory, public SymbolTable {
+public:
+ const TransliterationRuleData* data; // alias
+
+ const UVector* variablesVector; // alias
+
+ const Hashtable* variableNames; // alias
+
+ ParseData(const TransliterationRuleData* data = 0,
+ const UVector* variablesVector = 0,
+ const Hashtable* variableNames = 0);
+
+ virtual const UnicodeString* lookup(const UnicodeString& s) const;
+
+ virtual const UnicodeFunctor* lookupMatcher(UChar32 ch) const;
+
+ virtual UnicodeString parseReference(const UnicodeString& text,
+ ParsePosition& pos, int32_t limit) const;
+ /**
+ * Return true if the given character is a matcher standin or a plain
+ * character (non standin).
+ */
+ UBool isMatcher(UChar32 ch);
+
+ /**
+ * Return true if the given character is a replacer standin or a plain
+ * character (non standin).
+ */
+ UBool isReplacer(UChar32 ch);
+
+private:
+ ParseData(const ParseData &other); // forbid copying of this class
+ ParseData &operator=(const ParseData &other); // forbid copying of this class
+};
+
+ParseData::ParseData(const TransliterationRuleData* d,
+ const UVector* sets,
+ const Hashtable* vNames) :
+ data(d), variablesVector(sets), variableNames(vNames) {}
+
+/**
+ * Implement SymbolTable API.
+ */
+const UnicodeString* ParseData::lookup(const UnicodeString& name) const {
+ return (const UnicodeString*) variableNames->get(name);
+}
+
+/**
+ * Implement SymbolTable API.
+ */
+const UnicodeFunctor* ParseData::lookupMatcher(UChar32 ch) const {
+ // Note that we cannot use data.lookupSet() because the
+ // set array has not been constructed yet.
+ const UnicodeFunctor* set = NULL;
+ int32_t i = ch - data->variablesBase;
+ if (i >= 0 && i < variablesVector->size()) {
+ int32_t i = ch - data->variablesBase;
+ set = (i < variablesVector->size()) ?
+ (UnicodeFunctor*) variablesVector->elementAt(i) : 0;
+ }
+ return set;
+}
+
+/**
+ * Implement SymbolTable API. Parse out a symbol reference
+ * name.
+ */
+UnicodeString ParseData::parseReference(const UnicodeString& text,
+ ParsePosition& pos, int32_t limit) const {
+ int32_t start = pos.getIndex();
+ int32_t i = start;
+ UnicodeString result;
+ while (i < limit) {
+ UChar c = text.charAt(i);
+ if ((i==start && !u_isIDStart(c)) || !u_isIDPart(c)) {
+ break;
+ }
+ ++i;
+ }
+ if (i == start) { // No valid name chars
+ return result; // Indicate failure with empty string
+ }
+ pos.setIndex(i);
+ text.extractBetween(start, i, result);
+ return result;
+}
+
+UBool ParseData::isMatcher(UChar32 ch) {
+ // Note that we cannot use data.lookup() because the
+ // set array has not been constructed yet.
+ int32_t i = ch - data->variablesBase;
+ if (i >= 0 && i < variablesVector->size()) {
+ UnicodeFunctor *f = (UnicodeFunctor*) variablesVector->elementAt(i);
+ return f != NULL && f->toMatcher() != NULL;
+ }
+ return TRUE;
+}
+
+/**
+ * Return true if the given character is a replacer standin or a plain
+ * character (non standin).
+ */
+UBool ParseData::isReplacer(UChar32 ch) {
+ // Note that we cannot use data.lookup() because the
+ // set array has not been constructed yet.
+ int i = ch - data->variablesBase;
+ if (i >= 0 && i < variablesVector->size()) {
+ UnicodeFunctor *f = (UnicodeFunctor*) variablesVector->elementAt(i);
+ return f != NULL && f->toReplacer() != NULL;
+ }
+ return TRUE;
+}
+
+//----------------------------------------------------------------------
+// BEGIN RuleHalf
+//----------------------------------------------------------------------
+
+/**
+ * A class representing one side of a rule. This class knows how to
+ * parse half of a rule. It is tightly coupled to the method
+ * RuleBasedTransliterator.Parser.parseRule().
+ */
+class RuleHalf : public UMemory {
+
+public:
+
+ UnicodeString text;
+
+ int32_t cursor; // position of cursor in text
+ int32_t ante; // position of ante context marker '{' in text
+ int32_t post; // position of post context marker '}' in text
+
+ // Record the offset to the cursor either to the left or to the
+ // right of the key. This is indicated by characters on the output
+ // side that allow the cursor to be positioned arbitrarily within
+ // the matching text. For example, abc{def} > | @@@ xyz; changes
+ // def to xyz and moves the cursor to before abc. Offset characters
+ // must be at the start or end, and they cannot move the cursor past
+ // the ante- or postcontext text. Placeholders are only valid in
+ // output text. The length of the ante and post context is
+ // determined at runtime, because of supplementals and quantifiers.
+ int32_t cursorOffset; // only nonzero on output side
+
+ // Position of first CURSOR_OFFSET on _right_. This will be -1
+ // for |@, -2 for |@@, etc., and 1 for @|, 2 for @@|, etc.
+ int32_t cursorOffsetPos;
+
+ UBool anchorStart;
+ UBool anchorEnd;
+
+ /**
+ * The segment number from 1..n of the next '(' we see
+ * during parsing; 1-based.
+ */
+ int32_t nextSegmentNumber;
+
+ TransliteratorParser& parser;
+
+ //--------------------------------------------------
+ // Methods
+
+ RuleHalf(TransliteratorParser& parser);
+ ~RuleHalf();
+
+ int32_t parse(const UnicodeString& rule, int32_t pos, int32_t limit, UErrorCode& status);
+
+ int32_t parseSection(const UnicodeString& rule, int32_t pos, int32_t limit,
+ UnicodeString& buf,
+ const UnicodeString& illegal,
+ UBool isSegment,
+ UErrorCode& status);
+
+ /**
+ * Remove context.
+ */
+ void removeContext();
+
+ /**
+ * Return true if this half looks like valid output, that is, does not
+ * contain quantifiers or other special input-only elements.
+ */
+ UBool isValidOutput(TransliteratorParser& parser);
+
+ /**
+ * Return true if this half looks like valid input, that is, does not
+ * contain functions or other special output-only elements.
+ */
+ UBool isValidInput(TransliteratorParser& parser);
+
+ int syntaxError(UErrorCode code,
+ const UnicodeString& rule,
+ int32_t start,
+ UErrorCode& status) {
+ return parser.syntaxError(code, rule, start, status);
+ }
+
+private:
+ // Disallowed methods; no impl.
+ RuleHalf(const RuleHalf&);
+ RuleHalf& operator=(const RuleHalf&);
+};
+
+RuleHalf::RuleHalf(TransliteratorParser& p) :
+ parser(p)
+{
+ cursor = -1;
+ ante = -1;
+ post = -1;
+ cursorOffset = 0;
+ cursorOffsetPos = 0;
+ anchorStart = anchorEnd = FALSE;
+ nextSegmentNumber = 1;
+}
+
+RuleHalf::~RuleHalf() {
+}
+
+/**
+ * Parse one side of a rule, stopping at either the limit,
+ * the END_OF_RULE character, or an operator.
+ * @return the index after the terminating character, or
+ * if limit was reached, limit
+ */
+int32_t RuleHalf::parse(const UnicodeString& rule, int32_t pos, int32_t limit, UErrorCode& status) {
+ int32_t start = pos;
+ text.truncate(0);
+ pos = parseSection(rule, pos, limit, text, ILLEGAL_TOP, FALSE, status);
+
+ if (cursorOffset > 0 && cursor != cursorOffsetPos) {
+ return syntaxError(U_MISPLACED_CURSOR_OFFSET, rule, start, status);
+ }
+
+ return pos;
+}
+
+/**
+ * Parse a section of one side of a rule, stopping at either
+ * the limit, the END_OF_RULE character, an operator, or a
+ * segment close character. This method parses both a
+ * top-level rule half and a segment within such a rule half.
+ * It calls itself recursively to parse segments and nested
+ * segments.
+ * @param buf buffer into which to accumulate the rule pattern
+ * characters, either literal characters from the rule or
+ * standins for UnicodeMatcher objects including segments.
+ * @param illegal the set of special characters that is illegal during
+ * this parse.
+ * @param isSegment if true, then we've already seen a '(' and
+ * pos on entry points right after it. Accumulate everything
+ * up to the closing ')', put it in a segment matcher object,
+ * generate a standin for it, and add the standin to buf. As
+ * a side effect, update the segments vector with a reference
+ * to the segment matcher. This works recursively for nested
+ * segments. If isSegment is false, just accumulate
+ * characters into buf.
+ * @return the index after the terminating character, or
+ * if limit was reached, limit
+ */
+int32_t RuleHalf::parseSection(const UnicodeString& rule, int32_t pos, int32_t limit,
+ UnicodeString& buf,
+ const UnicodeString& illegal,
+ UBool isSegment, UErrorCode& status) {
+ int32_t start = pos;
+ ParsePosition pp;
+ UnicodeString scratch;
+ UBool done = FALSE;
+ int32_t quoteStart = -1; // Most recent 'single quoted string'
+ int32_t quoteLimit = -1;
+ int32_t varStart = -1; // Most recent $variableReference
+ int32_t varLimit = -1;
+ int32_t bufStart = buf.length();
+
+ while (pos < limit && !done) {
+ // Since all syntax characters are in the BMP, fetching
+ // 16-bit code units suffices here.
+ UChar c = rule.charAt(pos++);
+ if (uprv_isRuleWhiteSpace(c)) {
+ // Ignore whitespace. Note that this is not Unicode
+ // spaces, but Java spaces -- a subset, representing
+ // whitespace likely to be seen in code.
+ continue;
+ }
+ if (u_strchr(HALF_ENDERS, c) != NULL) {
+ if (isSegment) {
+ // Unclosed segment
+ return syntaxError(U_UNCLOSED_SEGMENT, rule, start, status);
+ }
+ break;
+ }
+ if (anchorEnd) {
+ // Text after a presumed end anchor is a syntax err
+ return syntaxError(U_MALFORMED_VARIABLE_REFERENCE, rule, start, status);
+ }
+ if (UnicodeSet::resemblesPattern(rule, pos-1)) {
+ pp.setIndex(pos-1); // Backup to opening '['
+ buf.append(parser.parseSet(rule, pp, status));
+ if (U_FAILURE(status)) {
+ return syntaxError(U_MALFORMED_SET, rule, start, status);
+ }
+ pos = pp.getIndex();
+ continue;
+ }
+ // Handle escapes
+ if (c == ESCAPE) {
+ if (pos == limit) {
+ return syntaxError(U_TRAILING_BACKSLASH, rule, start, status);
+ }
+ UChar32 escaped = rule.unescapeAt(pos); // pos is already past '\\'
+ if (escaped == (UChar32) -1) {
+ return syntaxError(U_MALFORMED_UNICODE_ESCAPE, rule, start, status);
+ }
+ if (!parser.checkVariableRange(escaped)) {
+ return syntaxError(U_VARIABLE_RANGE_OVERLAP, rule, start, status);
+ }
+ buf.append(escaped);
+ continue;
+ }
+ // Handle quoted matter
+ if (c == QUOTE) {
+ int32_t iq = rule.indexOf(QUOTE, pos);
+ if (iq == pos) {
+ buf.append(c); // Parse [''] outside quotes as [']
+ ++pos;
+ } else {
+ /* This loop picks up a run of quoted text of the
+ * form 'aaaa' each time through. If this run
+ * hasn't really ended ('aaaa''bbbb') then it keeps
+ * looping, each time adding on a new run. When it
+ * reaches the final quote it breaks.
+ */
+ quoteStart = buf.length();
+ for (;;) {
+ if (iq < 0) {
+ return syntaxError(U_UNTERMINATED_QUOTE, rule, start, status);
+ }
+ scratch.truncate(0);
+ rule.extractBetween(pos, iq, scratch);
+ buf.append(scratch);
+ pos = iq+1;
+ if (pos < limit && rule.charAt(pos) == QUOTE) {
+ // Parse [''] inside quotes as [']
+ iq = rule.indexOf(QUOTE, pos+1);
+ // Continue looping
+ } else {
+ break;
+ }
+ }
+ quoteLimit = buf.length();
+
+ for (iq=quoteStart; iq<quoteLimit; ++iq) {
+ if (!parser.checkVariableRange(buf.charAt(iq))) {
+ return syntaxError(U_VARIABLE_RANGE_OVERLAP, rule, start, status);
+ }
+ }
+ }
+ continue;
+ }
+
+ if (!parser.checkVariableRange(c)) {
+ return syntaxError(U_VARIABLE_RANGE_OVERLAP, rule, start, status);
+ }
+
+ if (illegal.indexOf(c) >= 0) {
+ syntaxError(U_ILLEGAL_CHARACTER, rule, start, status);
+ }
+
+ switch (c) {
+
+ //------------------------------------------------------
+ // Elements allowed within and out of segments
+ //------------------------------------------------------
+ case ANCHOR_START:
+ if (buf.length() == 0 && !anchorStart) {
+ anchorStart = TRUE;
+ } else {
+ return syntaxError(U_MISPLACED_ANCHOR_START,
+ rule, start, status);
+ }
+ break;
+ case SEGMENT_OPEN:
+ {
+ // bufSegStart is the offset in buf to the first
+ // character of the segment we are parsing.
+ int32_t bufSegStart = buf.length();
+
+ // Record segment number now, since nextSegmentNumber
+ // will be incremented during the call to parseSection
+ // if there are nested segments.
+ int32_t segmentNumber = nextSegmentNumber++; // 1-based
+
+ // Parse the segment
+ pos = parseSection(rule, pos, limit, buf, ILLEGAL_SEG, TRUE, status);
+
+ // After parsing a segment, the relevant characters are
+ // in buf, starting at offset bufSegStart. Extract them
+ // into a string matcher, and replace them with a
+ // standin for that matcher.
+ StringMatcher* m =
+ new StringMatcher(buf, bufSegStart, buf.length(),
+ segmentNumber, *parser.curData);
+
+ // Record and associate object and segment number
+ parser.setSegmentObject(segmentNumber, m, status);
+ buf.truncate(bufSegStart);
+ buf.append(parser.getSegmentStandin(segmentNumber, status));
+ }
+ break;
+ case FUNCTION:
+ case ALT_FUNCTION:
+ {
+ int32_t iref = pos;
+ TransliteratorIDParser::SingleID* single =
+ TransliteratorIDParser::parseFilterID(rule, iref);
+ // The next character MUST be a segment open
+ if (single == NULL ||
+ !ICU_Utility::parseChar(rule, iref, SEGMENT_OPEN)) {
+ return syntaxError(U_INVALID_FUNCTION, rule, start, status);
+ }
+
+ Transliterator *t = single->createInstance();
+ delete single;
+ if (t == NULL) {
+ return syntaxError(U_INVALID_FUNCTION, rule, start, status);
+ }
+
+ // bufSegStart is the offset in buf to the first
+ // character of the segment we are parsing.
+ int32_t bufSegStart = buf.length();
+
+ // Parse the segment
+ pos = parseSection(rule, iref, limit, buf, ILLEGAL_FUNC, TRUE, status);
+
+ // After parsing a segment, the relevant characters are
+ // in buf, starting at offset bufSegStart.
+ UnicodeString output;
+ buf.extractBetween(bufSegStart, buf.length(), output);
+ FunctionReplacer *r =
+ new FunctionReplacer(t, new StringReplacer(output, parser.curData));
+
+ // Replace the buffer contents with a stand-in
+ buf.truncate(bufSegStart);
+ buf.append(parser.generateStandInFor(r, status));
+ }
+ break;
+ case SymbolTable::SYMBOL_REF:
+ // Handle variable references and segment references "$1" .. "$9"
+ {
+ // A variable reference must be followed immediately
+ // by a Unicode identifier start and zero or more
+ // Unicode identifier part characters, or by a digit
+ // 1..9 if it is a segment reference.
+ if (pos == limit) {
+ // A variable ref character at the end acts as
+ // an anchor to the context limit, as in perl.
+ anchorEnd = TRUE;
+ break;
+ }
+ // Parse "$1" "$2" .. "$9" .. (no upper limit)
+ c = rule.charAt(pos);
+ int32_t r = u_digit(c, 10);
+ if (r >= 1 && r <= 9) {
+ r = ICU_Utility::parseNumber(rule, pos, 10);
+ if (r < 0) {
+ return syntaxError(U_UNDEFINED_SEGMENT_REFERENCE,
+ rule, start, status);
+ }
+ buf.append(parser.getSegmentStandin(r, status));
+ } else {
+ pp.setIndex(pos);
+ UnicodeString name = parser.parseData->
+ parseReference(rule, pp, limit);
+ if (name.length() == 0) {
+ // This means the '$' was not followed by a
+ // valid name. Try to interpret it as an
+ // end anchor then. If this also doesn't work
+ // (if we see a following character) then signal
+ // an error.
+ anchorEnd = TRUE;
+ break;
+ }
+ pos = pp.getIndex();
+ // If this is a variable definition statement,
+ // then the LHS variable will be undefined. In
+ // that case appendVariableDef() will append the
+ // special placeholder char variableLimit-1.
+ varStart = buf.length();
+ parser.appendVariableDef(name, buf, status);
+ varLimit = buf.length();
+ }
+ }
+ break;
+ case DOT:
+ buf.append(parser.getDotStandIn(status));
+ break;
+ case KLEENE_STAR:
+ case ONE_OR_MORE:
+ case ZERO_OR_ONE:
+ // Quantifiers. We handle single characters, quoted strings,
+ // variable references, and segments.
+ // a+ matches aaa
+ // 'foo'+ matches foofoofoo
+ // $v+ matches xyxyxy if $v == xy
+ // (seg)+ matches segsegseg
+ {
+ if (isSegment && buf.length() == bufStart) {
+ // The */+ immediately follows '('
+ return syntaxError(U_MISPLACED_QUANTIFIER, rule, start, status);
+ }
+
+ int32_t qstart, qlimit;
+ // The */+ follows an isolated character or quote
+ // or variable reference
+ if (buf.length() == quoteLimit) {
+ // The */+ follows a 'quoted string'
+ qstart = quoteStart;
+ qlimit = quoteLimit;
+ } else if (buf.length() == varLimit) {
+ // The */+ follows a $variableReference
+ qstart = varStart;
+ qlimit = varLimit;
+ } else {
+ // The */+ follows a single character, possibly
+ // a segment standin
+ qstart = buf.length() - 1;
+ qlimit = qstart + 1;
+ }
+
+ UnicodeFunctor *m =
+ new StringMatcher(buf, qstart, qlimit, 0, *parser.curData);
+ int32_t min = 0;
+ int32_t max = Quantifier::MAX;
+ switch (c) {
+ case ONE_OR_MORE:
+ min = 1;
+ break;
+ case ZERO_OR_ONE:
+ min = 0;
+ max = 1;
+ break;
+ // case KLEENE_STAR:
+ // do nothing -- min, max already set
+ }
+ m = new Quantifier(m, min, max);
+ buf.truncate(qstart);
+ buf.append(parser.generateStandInFor(m, status));
+ }
+ break;
+
+ //------------------------------------------------------
+ // Elements allowed ONLY WITHIN segments
+ //------------------------------------------------------
+ case SEGMENT_CLOSE:
+ // assert(isSegment);
+ // We're done parsing a segment.
+ done = TRUE;
+ break;
+
+ //------------------------------------------------------
+ // Elements allowed ONLY OUTSIDE segments
+ //------------------------------------------------------
+ case CONTEXT_ANTE:
+ if (ante >= 0) {
+ return syntaxError(U_MULTIPLE_ANTE_CONTEXTS, rule, start, status);
+ }
+ ante = buf.length();
+ break;
+ case CONTEXT_POST:
+ if (post >= 0) {
+ return syntaxError(U_MULTIPLE_POST_CONTEXTS, rule, start, status);
+ }
+ post = buf.length();
+ break;
+ case CURSOR_POS:
+ if (cursor >= 0) {
+ return syntaxError(U_MULTIPLE_CURSORS, rule, start, status);
+ }
+ cursor = buf.length();
+ break;
+ case CURSOR_OFFSET:
+ if (cursorOffset < 0) {
+ if (buf.length() > 0) {
+ return syntaxError(U_MISPLACED_CURSOR_OFFSET, rule, start, status);
+ }
+ --cursorOffset;
+ } else if (cursorOffset > 0) {
+ if (buf.length() != cursorOffsetPos || cursor >= 0) {
+ return syntaxError(U_MISPLACED_CURSOR_OFFSET, rule, start, status);
+ }
+ ++cursorOffset;
+ } else {
+ if (cursor == 0 && buf.length() == 0) {
+ cursorOffset = -1;
+ } else if (cursor < 0) {
+ cursorOffsetPos = buf.length();
+ cursorOffset = 1;
+ } else {
+ return syntaxError(U_MISPLACED_CURSOR_OFFSET, rule, start, status);
+ }
+ }
+ break;
+
+
+ //------------------------------------------------------
+ // Non-special characters
+ //------------------------------------------------------
+ default:
+ // Disallow unquoted characters other than [0-9A-Za-z]
+ // in the printable ASCII range. These characters are
+ // reserved for possible future use.
+ if (c >= 0x0021 && c <= 0x007E &&
+ !((c >= 0x0030/*'0'*/ && c <= 0x0039/*'9'*/) ||
+ (c >= 0x0041/*'A'*/ && c <= 0x005A/*'Z'*/) ||
+ (c >= 0x0061/*'a'*/ && c <= 0x007A/*'z'*/))) {
+ return syntaxError(U_UNQUOTED_SPECIAL, rule, start, status);
+ }
+ buf.append(c);
+ break;
+ }
+ }
+
+ return pos;
+}
+
+/**
+ * Remove context.
+ */
+void RuleHalf::removeContext() {
+ //text = text.substring(ante < 0 ? 0 : ante,
+ // post < 0 ? text.length() : post);
+ if (post >= 0) {
+ text.remove(post);
+ }
+ if (ante >= 0) {
+ text.removeBetween(0, ante);
+ }
+ ante = post = -1;
+ anchorStart = anchorEnd = FALSE;
+}
+
+/**
+ * Return true if this half looks like valid output, that is, does not
+ * contain quantifiers or other special input-only elements.
+ */
+UBool RuleHalf::isValidOutput(TransliteratorParser& transParser) {
+ for (int32_t i=0; i<text.length(); ) {
+ UChar32 c = text.char32At(i);
+ i += UTF_CHAR_LENGTH(c);
+ if (!transParser.parseData->isReplacer(c)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ * Return true if this half looks like valid input, that is, does not
+ * contain functions or other special output-only elements.
+ */
+UBool RuleHalf::isValidInput(TransliteratorParser& transParser) {
+ for (int32_t i=0; i<text.length(); ) {
+ UChar32 c = text.char32At(i);
+ i += UTF_CHAR_LENGTH(c);
+ if (!transParser.parseData->isMatcher(c)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+//----------------------------------------------------------------------
+// PUBLIC API
+//----------------------------------------------------------------------
+
+/**
+ * Constructor.
+ */
+TransliteratorParser::TransliteratorParser(UErrorCode &statusReturn) :
+dataVector(statusReturn),
+idBlockVector(statusReturn),
+variablesVector(statusReturn),
+segmentObjects(statusReturn)
+{
+ idBlockVector.setDeleter(uhash_deleteUnicodeString);
+ curData = NULL;
+ compoundFilter = NULL;
+ parseData = NULL;
+ variableNames.setValueDeleter(uhash_deleteUnicodeString);
+}
+
+/**
+ * Destructor.
+ */
+TransliteratorParser::~TransliteratorParser() {
+ while (!dataVector.isEmpty())
+ delete (TransliterationRuleData*)(dataVector.orphanElementAt(0));
+ delete compoundFilter;
+ delete parseData;
+ while (!variablesVector.isEmpty())
+ delete (UnicodeFunctor*)variablesVector.orphanElementAt(0);
+}
+
+void
+TransliteratorParser::parse(const UnicodeString& rules,
+ UTransDirection transDirection,
+ UParseError& pe,
+ UErrorCode& ec) {
+ if (U_SUCCESS(ec)) {
+ parseRules(rules, transDirection, ec);
+ pe = parseError;
+ }
+}
+
+/**
+ * Return the compound filter parsed by parse(). Caller owns result.
+ */
+UnicodeSet* TransliteratorParser::orphanCompoundFilter() {
+ UnicodeSet* f = compoundFilter;
+ compoundFilter = NULL;
+ return f;
+}
+
+//----------------------------------------------------------------------
+// Private implementation
+//----------------------------------------------------------------------
+
+/**
+ * Parse the given string as a sequence of rules, separated by newline
+ * characters ('\n'), and cause this object to implement those rules. Any
+ * previous rules are discarded. Typically this method is called exactly
+ * once, during construction.
+ * @exception IllegalArgumentException if there is a syntax error in the
+ * rules
+ */
+void TransliteratorParser::parseRules(const UnicodeString& rule,
+ UTransDirection theDirection,
+ UErrorCode& status)
+{
+ // Clear error struct
+ uprv_memset(&parseError, 0, sizeof(parseError));
+ parseError.line = parseError.offset = -1;
+
+ UBool parsingIDs = TRUE;
+ int32_t ruleCount = 0;
+
+ while (!dataVector.isEmpty()) {
+ delete (TransliterationRuleData*)(dataVector.orphanElementAt(0));
+ }
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ idBlockVector.removeAllElements();
+ curData = NULL;
+ direction = theDirection;
+ ruleCount = 0;
+
+ delete compoundFilter;
+ compoundFilter = NULL;
+
+ while (!variablesVector.isEmpty()) {
+ delete (UnicodeFunctor*)variablesVector.orphanElementAt(0);
+ }
+ variableNames.removeAll();
+ parseData = new ParseData(0, &variablesVector, &variableNames);
+ if (parseData == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ dotStandIn = (UChar) -1;
+
+ UnicodeString str; // scratch
+ UnicodeString idBlockResult;
+ int32_t pos = 0;
+ int32_t limit = rule.length();
+
+ // The compound filter offset is an index into idBlockResult.
+ // If it is 0, then the compound filter occurred at the start,
+ // and it is the offset to the _start_ of the compound filter
+ // pattern. Otherwise it is the offset to the _limit_ of the
+ // compound filter pattern within idBlockResult.
+ compoundFilter = NULL;
+ int32_t compoundFilterOffset = -1;
+
+ while (pos < limit && U_SUCCESS(status)) {
+ UChar c = rule.charAt(pos++);
+ if (uprv_isRuleWhiteSpace(c)) {
+ // Ignore leading whitespace.
+ continue;
+ }
+ // Skip lines starting with the comment character
+ if (c == RULE_COMMENT_CHAR) {
+ pos = rule.indexOf((UChar)0x000A /*\n*/, pos) + 1;
+ if (pos == 0) {
+ break; // No "\n" found; rest of rule is a commnet
+ }
+ continue; // Either fall out or restart with next line
+ }
+
+ // skip empty rules
+ if (c == END_OF_RULE)
+ continue;
+
+ // keep track of how many rules we've seen
+ ++ruleCount;
+
+ // We've found the start of a rule or ID. c is its first
+ // character, and pos points past c.
+ --pos;
+ // Look for an ID token. Must have at least ID_TOKEN_LEN + 1
+ // chars left.
+ if ((pos + ID_TOKEN_LEN + 1) <= limit &&
+ rule.compare(pos, ID_TOKEN_LEN, ID_TOKEN) == 0) {
+ pos += ID_TOKEN_LEN;
+ c = rule.charAt(pos);
+ while (uprv_isRuleWhiteSpace(c) && pos < limit) {
+ ++pos;
+ c = rule.charAt(pos);
+ }
+
+ int32_t p = pos;
+
+ if (!parsingIDs) {
+ if (curData != NULL) {
+ if (direction == UTRANS_FORWARD)
+ dataVector.addElement(curData, status);
+ else
+ dataVector.insertElementAt(curData, 0, status);
+ curData = NULL;
+ }
+ parsingIDs = TRUE;
+ }
+
+ TransliteratorIDParser::SingleID* id =
+ TransliteratorIDParser::parseSingleID(rule, p, direction, status);
+ if (p != pos && ICU_Utility::parseChar(rule, p, END_OF_RULE)) {
+ // Successful ::ID parse.
+
+ if (direction == UTRANS_FORWARD) {
+ idBlockResult.append(id->canonID).append(END_OF_RULE);
+ } else {
+ idBlockResult.insert(0, END_OF_RULE);
+ idBlockResult.insert(0, id->canonID);
+ }
+
+ } else {
+ // Couldn't parse an ID. Try to parse a global filter
+ int32_t withParens = -1;
+ UnicodeSet* f = TransliteratorIDParser::parseGlobalFilter(rule, p, direction, withParens, NULL);
+ if (f != NULL) {
+ if (ICU_Utility::parseChar(rule, p, END_OF_RULE)
+ && (direction == UTRANS_FORWARD) == (withParens == 0))
+ {
+ if (compoundFilter != NULL) {
+ // Multiple compound filters
+ syntaxError(U_MULTIPLE_COMPOUND_FILTERS, rule, pos, status);
+ delete f;
+ } else {
+ compoundFilter = f;
+ compoundFilterOffset = ruleCount;
+ }
+ } else {
+ delete f;
+ }
+ } else {
+ // Invalid ::id
+ // Can be parsed as neither an ID nor a global filter
+ syntaxError(U_INVALID_ID, rule, pos, status);
+ }
+ }
+ delete id;
+ pos = p;
+ } else {
+ if (parsingIDs) {
+ if (direction == UTRANS_FORWARD)
+ idBlockVector.addElement(new UnicodeString(idBlockResult), status);
+ else
+ idBlockVector.insertElementAt(new UnicodeString(idBlockResult), 0, status);
+ idBlockResult.remove();
+ parsingIDs = FALSE;
+ curData = new TransliterationRuleData(status);
+ parseData->data = curData;
+
+ // By default, rules use part of the private use area
+ // E000..F8FF for variables and other stand-ins. Currently
+ // the range F000..F8FF is typically sufficient. The 'use
+ // variable range' pragma allows rule sets to modify this.
+ setVariableRange(0xF000, 0xF8FF, status);
+ }
+
+ if (resemblesPragma(rule, pos, limit)) {
+ int32_t ppp = parsePragma(rule, pos, limit, status);
+ if (ppp < 0) {
+ syntaxError(U_MALFORMED_PRAGMA, rule, pos, status);
+ }
+ pos = ppp;
+ // Parse a rule
+ } else {
+ pos = parseRule(rule, pos, limit, status);
+ }
+ }
+ }
+
+ if (parsingIDs && idBlockResult.length() > 0) {
+ if (direction == UTRANS_FORWARD)
+ idBlockVector.addElement(new UnicodeString(idBlockResult), status);
+ else
+ idBlockVector.insertElementAt(new UnicodeString(idBlockResult), 0, status);
+ }
+ else if (!parsingIDs && curData != NULL) {
+ if (direction == UTRANS_FORWARD)
+ dataVector.addElement(curData, status);
+ else
+ dataVector.insertElementAt(curData, 0, status);
+ }
+
+ if (U_SUCCESS(status)) {
+ // Convert the set vector to an array
+ int32_t i, dataVectorSize = dataVector.size();
+ for (i = 0; i < dataVectorSize; i++) {
+ TransliterationRuleData* data = (TransliterationRuleData*)dataVector.elementAt(i);
+ data->variablesLength = variablesVector.size();
+ if (data->variablesLength == 0) {
+ data->variables = 0;
+ } else {
+ data->variables = (UnicodeFunctor**)uprv_malloc(data->variablesLength * sizeof(UnicodeFunctor*));
+ data->variablesAreOwned = (i == 0);
+ }
+
+ for (int32_t j = 0; j < data->variablesLength; j++) {
+ data->variables[j] =
+ ((UnicodeSet*)variablesVector.elementAt(j));
+ }
+
+ data->variableNames.removeAll();
+ int32_t pos = -1;
+ const UHashElement* he = variableNames.nextElement(pos);
+ while (he != NULL) {
+ data->variableNames.put(*((UnicodeString*)(he->key.pointer)),
+ ((UnicodeString*)(he->value.pointer))->clone(), status);
+ he = variableNames.nextElement(pos);
+ }
+ }
+ variablesVector.removeAllElements(); // keeps them from getting deleted when we succeed
+
+ // Index the rules
+ if (compoundFilter != NULL) {
+ if ((direction == UTRANS_FORWARD && compoundFilterOffset != 1) ||
+ (direction == UTRANS_REVERSE && compoundFilterOffset != ruleCount)) {
+ status = U_MISPLACED_COMPOUND_FILTER;
+ }
+ }
+
+ for (i = 0; i < dataVectorSize; i++) {
+ TransliterationRuleData* data = (TransliterationRuleData*)dataVector.elementAt(i);
+ data->ruleSet.freeze(parseError, status);
+ }
+ if (idBlockVector.size() == 1 && ((UnicodeString*)idBlockVector.elementAt(0))->isEmpty()) {
+ idBlockVector.removeElementAt(0);
+ }
+ }
+}
+
+/**
+ * Set the variable range to [start, end] (inclusive).
+ */
+void TransliteratorParser::setVariableRange(int32_t start, int32_t end, UErrorCode& status) {
+ if (start > end || start < 0 || end > 0xFFFF) {
+ status = U_MALFORMED_PRAGMA;
+ return;
+ }
+
+ curData->variablesBase = (UChar) start;
+ if (dataVector.size() == 0) {
+ variableNext = (UChar) start;
+ variableLimit = (UChar) (end + 1);
+ }
+}
+
+/**
+ * Assert that the given character is NOT within the variable range.
+ * If it is, return FALSE. This is neccesary to ensure that the
+ * variable range does not overlap characters used in a rule.
+ */
+UBool TransliteratorParser::checkVariableRange(UChar32 ch) const {
+ return !(ch >= curData->variablesBase && ch < variableLimit);
+}
+
+/**
+ * Set the maximum backup to 'backup', in response to a pragma
+ * statement.
+ */
+void TransliteratorParser::pragmaMaximumBackup(int32_t /*backup*/) {
+ //TODO Finish
+}
+
+/**
+ * Begin normalizing all rules using the given mode, in response
+ * to a pragma statement.
+ */
+void TransliteratorParser::pragmaNormalizeRules(UNormalizationMode /*mode*/) {
+ //TODO Finish
+}
+
+static const UChar PRAGMA_USE[] = {0x75,0x73,0x65,0x20,0}; // "use "
+
+static const UChar PRAGMA_VARIABLE_RANGE[] = {0x7E,0x76,0x61,0x72,0x69,0x61,0x62,0x6C,0x65,0x20,0x72,0x61,0x6E,0x67,0x65,0x20,0x23,0x20,0x23,0x7E,0x3B,0}; // "~variable range # #~;"
+
+static const UChar PRAGMA_MAXIMUM_BACKUP[] = {0x7E,0x6D,0x61,0x78,0x69,0x6D,0x75,0x6D,0x20,0x62,0x61,0x63,0x6B,0x75,0x70,0x20,0x23,0x7E,0x3B,0}; // "~maximum backup #~;"
+
+static const UChar PRAGMA_NFD_RULES[] = {0x7E,0x6E,0x66,0x64,0x20,0x72,0x75,0x6C,0x65,0x73,0x7E,0x3B,0}; // "~nfd rules~;"
+
+static const UChar PRAGMA_NFC_RULES[] = {0x7E,0x6E,0x66,0x63,0x20,0x72,0x75,0x6C,0x65,0x73,0x7E,0x3B,0}; // "~nfc rules~;"
+
+/**
+ * Return true if the given rule looks like a pragma.
+ * @param pos offset to the first non-whitespace character
+ * of the rule.
+ * @param limit pointer past the last character of the rule.
+ */
+UBool TransliteratorParser::resemblesPragma(const UnicodeString& rule, int32_t pos, int32_t limit) {
+ // Must start with /use\s/i
+ return ICU_Utility::parsePattern(rule, pos, limit, PRAGMA_USE, NULL) >= 0;
+}
+
+/**
+ * Parse a pragma. This method assumes resemblesPragma() has
+ * already returned true.
+ * @param pos offset to the first non-whitespace character
+ * of the rule.
+ * @param limit pointer past the last character of the rule.
+ * @return the position index after the final ';' of the pragma,
+ * or -1 on failure.
+ */
+int32_t TransliteratorParser::parsePragma(const UnicodeString& rule, int32_t pos, int32_t limit, UErrorCode& status) {
+ int32_t array[2];
+
+ // resemblesPragma() has already returned true, so we
+ // know that pos points to /use\s/i; we can skip 4 characters
+ // immediately
+ pos += 4;
+
+ // Here are the pragmas we recognize:
+ // use variable range 0xE000 0xEFFF;
+ // use maximum backup 16;
+ // use nfd rules;
+ // use nfc rules;
+ int p = ICU_Utility::parsePattern(rule, pos, limit, PRAGMA_VARIABLE_RANGE, array);
+ if (p >= 0) {
+ setVariableRange(array[0], array[1], status);
+ return p;
+ }
+
+ p = ICU_Utility::parsePattern(rule, pos, limit, PRAGMA_MAXIMUM_BACKUP, array);
+ if (p >= 0) {
+ pragmaMaximumBackup(array[0]);
+ return p;
+ }
+
+ p = ICU_Utility::parsePattern(rule, pos, limit, PRAGMA_NFD_RULES, NULL);
+ if (p >= 0) {
+ pragmaNormalizeRules(UNORM_NFD);
+ return p;
+ }
+
+ p = ICU_Utility::parsePattern(rule, pos, limit, PRAGMA_NFC_RULES, NULL);
+ if (p >= 0) {
+ pragmaNormalizeRules(UNORM_NFC);
+ return p;
+ }
+
+ // Syntax error: unable to parse pragma
+ return -1;
+}
+
+/**
+ * MAIN PARSER. Parse the next rule in the given rule string, starting
+ * at pos. Return the index after the last character parsed. Do not
+ * parse characters at or after limit.
+ *
+ * Important: The character at pos must be a non-whitespace character
+ * that is not the comment character.
+ *
+ * This method handles quoting, escaping, and whitespace removal. It
+ * parses the end-of-rule character. It recognizes context and cursor
+ * indicators. Once it does a lexical breakdown of the rule at pos, it
+ * creates a rule object and adds it to our rule list.
+ */
+int32_t TransliteratorParser::parseRule(const UnicodeString& rule, int32_t pos, int32_t limit, UErrorCode& status) {
+ // Locate the left side, operator, and right side
+ int32_t start = pos;
+ UChar op = 0;
+ int32_t i;
+
+ // Set up segments data
+ segmentStandins.truncate(0);
+ segmentObjects.removeAllElements();
+
+ // Use pointers to automatics to make swapping possible.
+ RuleHalf _left(*this), _right(*this);
+ RuleHalf* left = &_left;
+ RuleHalf* right = &_right;
+
+ undefinedVariableName.remove();
+ pos = left->parse(rule, pos, limit, status);
+ if (U_FAILURE(status)) {
+ return start;
+ }
+
+ if (pos == limit || u_strchr(gOPERATORS, (op = rule.charAt(--pos))) == NULL) {
+ return syntaxError(U_MISSING_OPERATOR, rule, start, status);
+ }
+ ++pos;
+
+ // Found an operator char. Check for forward-reverse operator.
+ if (op == REVERSE_RULE_OP &&
+ (pos < limit && rule.charAt(pos) == FORWARD_RULE_OP)) {
+ ++pos;
+ op = FWDREV_RULE_OP;
+ }
+
+ // Translate alternate op characters.
+ switch (op) {
+ case ALT_FORWARD_RULE_OP:
+ op = FORWARD_RULE_OP;
+ break;
+ case ALT_REVERSE_RULE_OP:
+ op = REVERSE_RULE_OP;
+ break;
+ case ALT_FWDREV_RULE_OP:
+ op = FWDREV_RULE_OP;
+ break;
+ }
+
+ pos = right->parse(rule, pos, limit, status);
+ if (U_FAILURE(status)) {
+ return start;
+ }
+
+ if (pos < limit) {
+ if (rule.charAt(--pos) == END_OF_RULE) {
+ ++pos;
+ } else {
+ // RuleHalf parser must have terminated at an operator
+ return syntaxError(U_UNQUOTED_SPECIAL, rule, start, status);
+ }
+ }
+
+ if (op == VARIABLE_DEF_OP) {
+ // LHS is the name. RHS is a single character, either a literal
+ // or a set (already parsed). If RHS is longer than one
+ // character, it is either a multi-character string, or multiple
+ // sets, or a mixture of chars and sets -- syntax error.
+
+ // We expect to see a single undefined variable (the one being
+ // defined).
+ if (undefinedVariableName.length() == 0) {
+ // "Missing '$' or duplicate definition"
+ return syntaxError(U_BAD_VARIABLE_DEFINITION, rule, start, status);
+ }
+ if (left->text.length() != 1 || left->text.charAt(0) != variableLimit) {
+ // "Malformed LHS"
+ return syntaxError(U_MALFORMED_VARIABLE_DEFINITION, rule, start, status);
+ }
+ if (left->anchorStart || left->anchorEnd ||
+ right->anchorStart || right->anchorEnd) {
+ return syntaxError(U_MALFORMED_VARIABLE_DEFINITION, rule, start, status);
+ }
+ // We allow anything on the right, including an empty string.
+ UnicodeString* value = new UnicodeString(right->text);
+ variableNames.put(undefinedVariableName, value, status);
+ ++variableLimit;
+ return pos;
+ }
+
+ // If this is not a variable definition rule, we shouldn't have
+ // any undefined variable names.
+ if (undefinedVariableName.length() != 0) {
+ return syntaxError(// "Undefined variable $" + undefinedVariableName,
+ U_UNDEFINED_VARIABLE,
+ rule, start, status);
+ }
+
+ // Verify segments
+ if (segmentStandins.length() > segmentObjects.size()) {
+ syntaxError(U_UNDEFINED_SEGMENT_REFERENCE, rule, start, status);
+ }
+ for (i=0; i<segmentStandins.length(); ++i) {
+ if (segmentStandins.charAt(i) == 0) {
+ syntaxError(U_INTERNAL_TRANSLITERATOR_ERROR, rule, start, status); // will never happen
+ }
+ }
+ for (i=0; i<segmentObjects.size(); ++i) {
+ if (segmentObjects.elementAt(i) == NULL) {
+ syntaxError(U_INTERNAL_TRANSLITERATOR_ERROR, rule, start, status); // will never happen
+ }
+ }
+
+ // If the direction we want doesn't match the rule
+ // direction, do nothing.
+ if (op != FWDREV_RULE_OP &&
+ ((direction == UTRANS_FORWARD) != (op == FORWARD_RULE_OP))) {
+ return pos;
+ }
+
+ // Transform the rule into a forward rule by swapping the
+ // sides if necessary.
+ if (direction == UTRANS_REVERSE) {
+ left = &_right;
+ right = &_left;
+ }
+
+ // Remove non-applicable elements in forward-reverse
+ // rules. Bidirectional rules ignore elements that do not
+ // apply.
+ if (op == FWDREV_RULE_OP) {
+ right->removeContext();
+ left->cursor = -1;
+ left->cursorOffset = 0;
+ }
+
+ // Normalize context
+ if (left->ante < 0) {
+ left->ante = 0;
+ }
+ if (left->post < 0) {
+ left->post = left->text.length();
+ }
+
+ // Context is only allowed on the input side. Cursors are only
+ // allowed on the output side. Segment delimiters can only appear
+ // on the left, and references on the right. Cursor offset
+ // cannot appear without an explicit cursor. Cursor offset
+ // cannot place the cursor outside the limits of the context.
+ // Anchors are only allowed on the input side.
+ if (right->ante >= 0 || right->post >= 0 || left->cursor >= 0 ||
+ (right->cursorOffset != 0 && right->cursor < 0) ||
+ // - The following two checks were used to ensure that the
+ // - the cursor offset stayed within the ante- or postcontext.
+ // - However, with the addition of quantifiers, we have to
+ // - allow arbitrary cursor offsets and do runtime checking.
+ //(right->cursorOffset > (left->text.length() - left->post)) ||
+ //(-right->cursorOffset > left->ante) ||
+ right->anchorStart || right->anchorEnd ||
+ !left->isValidInput(*this) || !right->isValidOutput(*this) ||
+ left->ante > left->post) {
+
+ return syntaxError(U_MALFORMED_RULE, rule, start, status);
+ }
+
+ // Flatten segment objects vector to an array
+ UnicodeFunctor** segmentsArray = NULL;
+ if (segmentObjects.size() > 0) {
+ segmentsArray = (UnicodeFunctor **)uprv_malloc(segmentObjects.size() * sizeof(UnicodeFunctor *));
+ segmentObjects.toArray((void**) segmentsArray);
+ }
+
+ curData->ruleSet.addRule(new TransliterationRule(
+ left->text, left->ante, left->post,
+ right->text, right->cursor, right->cursorOffset,
+ segmentsArray,
+ segmentObjects.size(),
+ left->anchorStart, left->anchorEnd,
+ curData,
+ status), status);
+
+ return pos;
+}
+
+/**
+ * Called by main parser upon syntax error. Search the rule string
+ * for the probable end of the rule. Of course, if the error is that
+ * the end of rule marker is missing, then the rule end will not be found.
+ * In any case the rule start will be correctly reported.
+ * @param msg error description
+ * @param rule pattern string
+ * @param start position of first character of current rule
+ */
+int32_t TransliteratorParser::syntaxError(UErrorCode parseErrorCode,
+ const UnicodeString& rule,
+ int32_t pos,
+ UErrorCode& status)
+{
+ parseError.offset = pos;
+ parseError.line = 0 ; /* we are not using line numbers */
+
+ // for pre-context
+ const int32_t LEN = U_PARSE_CONTEXT_LEN - 1;
+ int32_t start = uprv_max(pos - LEN, 0);
+ int32_t stop = pos;
+
+ rule.extract(start,stop-start,parseError.preContext);
+ //null terminate the buffer
+ parseError.preContext[stop-start] = 0;
+
+ //for post-context
+ start = pos;
+ stop = uprv_min(pos + LEN, rule.length());
+
+ rule.extract(start,stop-start,parseError.postContext);
+ //null terminate the buffer
+ parseError.postContext[stop-start]= 0;
+
+ status = (UErrorCode)parseErrorCode;
+ return pos;
+
+}
+
+/**
+ * Parse a UnicodeSet out, store it, and return the stand-in character
+ * used to represent it.
+ */
+UChar TransliteratorParser::parseSet(const UnicodeString& rule,
+ ParsePosition& pos,
+ UErrorCode& status) {
+ UnicodeSet* set = new UnicodeSet(rule, pos, USET_IGNORE_SPACE, parseData, status);
+ set->compact();
+ return generateStandInFor(set, status);
+}
+
+/**
+ * Generate and return a stand-in for a new UnicodeFunctor. Store
+ * the matcher (adopt it).
+ */
+UChar TransliteratorParser::generateStandInFor(UnicodeFunctor* adopted, UErrorCode& status) {
+ // assert(obj != null);
+
+ // Look up previous stand-in, if any. This is a short list
+ // (typical n is 0, 1, or 2); linear search is optimal.
+ for (int32_t i=0; i<variablesVector.size(); ++i) {
+ if (variablesVector.elementAt(i) == adopted) { // [sic] pointer comparison
+ return (UChar) (curData->variablesBase + i);
+ }
+ }
+
+ if (variableNext >= variableLimit) {
+ delete adopted;
+ status = U_VARIABLE_RANGE_EXHAUSTED;
+ return 0;
+ }
+ variablesVector.addElement(adopted, status);
+ return variableNext++;
+}
+
+/**
+ * Return the standin for segment seg (1-based).
+ */
+UChar TransliteratorParser::getSegmentStandin(int32_t seg, UErrorCode& status) {
+ // Special character used to indicate an empty spot
+ UChar empty = curData->variablesBase - 1;
+ while (segmentStandins.length() < seg) {
+ segmentStandins.append(empty);
+ }
+ UChar c = segmentStandins.charAt(seg-1);
+ if (c == empty) {
+ if (variableNext >= variableLimit) {
+ status = U_VARIABLE_RANGE_EXHAUSTED;
+ return 0;
+ }
+ c = variableNext++;
+ // Set a placeholder in the master variables vector that will be
+ // filled in later by setSegmentObject(). We know that we will get
+ // called first because setSegmentObject() will call us.
+ variablesVector.addElement((void*) NULL, status);
+ segmentStandins.setCharAt(seg-1, c);
+ }
+ return c;
+}
+
+/**
+ * Set the object for segment seg (1-based).
+ */
+void TransliteratorParser::setSegmentObject(int32_t seg, StringMatcher* adopted, UErrorCode& status) {
+ // Since we call parseSection() recursively, nested
+ // segments will result in segment i+1 getting parsed
+ // and stored before segment i; be careful with the
+ // vector handling here.
+ if (segmentObjects.size() < seg) {
+ segmentObjects.setSize(seg);
+ }
+ int32_t index = getSegmentStandin(seg, status) - curData->variablesBase;
+ if (segmentObjects.elementAt(seg-1) != NULL ||
+ variablesVector.elementAt(index) != NULL) {
+ // should never happen
+ status = U_INTERNAL_TRANSLITERATOR_ERROR;
+ return;
+ }
+ segmentObjects.setElementAt(adopted, seg-1);
+ variablesVector.setElementAt(adopted, index);
+}
+
+/**
+ * Return the stand-in for the dot set. It is allocated the first
+ * time and reused thereafter.
+ */
+UChar TransliteratorParser::getDotStandIn(UErrorCode& status) {
+ if (dotStandIn == (UChar) -1) {
+ dotStandIn = generateStandInFor(new UnicodeSet(DOT_SET, status), status);
+ }
+ return dotStandIn;
+}
+
+/**
+ * Append the value of the given variable name to the given
+ * UnicodeString.
+ */
+void TransliteratorParser::appendVariableDef(const UnicodeString& name,
+ UnicodeString& buf,
+ UErrorCode& status) {
+ const UnicodeString* s = (const UnicodeString*) variableNames.get(name);
+ if (s == NULL) {
+ // We allow one undefined variable so that variable definition
+ // statements work. For the first undefined variable we return
+ // the special placeholder variableLimit-1, and save the variable
+ // name.
+ if (undefinedVariableName.length() == 0) {
+ undefinedVariableName = name;
+ if (variableNext >= variableLimit) {
+ // throw new RuntimeException("Private use variables exhausted");
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ buf.append((UChar) --variableLimit);
+ } else {
+ //throw new IllegalArgumentException("Undefined variable $"
+ // + name);
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ } else {
+ buf.append(*s);
+ }
+}
+
+/**
+ * Glue method to get around access restrictions in C++.
+ */
+/*Transliterator* TransliteratorParser::createBasicInstance(const UnicodeString& id, const UnicodeString* canonID) {
+ return Transliterator::createBasicInstance(id, canonID);
+}*/
+
+U_NAMESPACE_END
+
+U_CAPI int32_t
+utrans_stripRules(const UChar *source, int32_t sourceLen, UChar *target, UErrorCode *status) {
+ U_NAMESPACE_USE
+
+ //const UChar *sourceStart = source;
+ const UChar *targetStart = target;
+ const UChar *sourceLimit = source+sourceLen;
+ UChar *targetLimit = target+sourceLen;
+ UChar32 c = 0;
+ UBool quoted = FALSE;
+ int32_t index;
+
+ uprv_memset(target, 0, sourceLen*U_SIZEOF_UCHAR);
+
+ /* read the rules into the buffer */
+ while (source < sourceLimit)
+ {
+ index=0;
+ U16_NEXT_UNSAFE(source, index, c);
+ source+=index;
+ if(c == QUOTE) {
+ quoted = (UBool)!quoted;
+ }
+ else if (!quoted) {
+ if (c == RULE_COMMENT_CHAR) {
+ /* skip comments and all preceding spaces */
+ while (targetStart < target && *(target - 1) == 0x0020) {
+ target--;
+ }
+ do {
+ c = *(source++);
+ }
+ while (c != CR && c != LF);
+ }
+ else if (c == ESCAPE) {
+ UChar32 c2 = *source;
+ if (c2 == CR || c2 == LF) {
+ /* A backslash at the end of a line. */
+ /* Since we're stripping lines, ignore the backslash. */
+ source++;
+ continue;
+ }
+ if (c2 == 0x0075 && source+5 < sourceLimit) { /* \u seen. \U isn't unescaped. */
+ int32_t escapeOffset = 0;
+ UnicodeString escapedStr(source, 5);
+ c2 = escapedStr.unescapeAt(escapeOffset);
+
+ if (c2 == (UChar32)0xFFFFFFFF || escapeOffset == 0)
+ {
+ *status = U_PARSE_ERROR;
+ return 0;
+ }
+ if (!uprv_isRuleWhiteSpace(c2) && !u_iscntrl(c2) && !u_ispunct(c2)) {
+ /* It was escaped for a reason. Write what it was suppose to be. */
+ source+=5;
+ c = c2;
+ }
+ }
+ else if (c2 == QUOTE) {
+ /* \' seen. Make sure we don't do anything when we see it again. */
+ quoted = (UBool)!quoted;
+ }
+ }
+ }
+ if (c == CR || c == LF)
+ {
+ /* ignore spaces carriage returns, and all leading spaces on the next line.
+ * and line feed unless in the form \uXXXX
+ */
+ quoted = FALSE;
+ while (source < sourceLimit) {
+ c = *(source);
+ if (c != CR && c != LF && c != 0x0020) {
+ break;
+ }
+ source++;
+ }
+ continue;
+ }
+
+ /* Append UChar * after dissembling if c > 0xffff*/
+ index=0;
+ U16_APPEND_UNSAFE(target, index, c);
+ target+=index;
+ }
+ if (target < targetLimit) {
+ *target = 0;
+ }
+ return (int32_t)(target-targetStart);
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt_pars.h b/Build/source/libs/icu/icu-xetex/i18n/rbt_pars.h
new file mode 100644
index 00000000000..96bdac06479
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt_pars.h
@@ -0,0 +1,355 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2007, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+#ifndef RBT_PARS_H
+#define RBT_PARS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+#ifdef XP_CPLUSPLUS
+
+#include "unicode/uobject.h"
+#include "unicode/parseerr.h"
+#include "unicode/unorm.h"
+#include "rbt.h"
+#include "hash.h"
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+class TransliterationRuleData;
+class UnicodeFunctor;
+class ParseData;
+class RuleHalf;
+class ParsePosition;
+class StringMatcher;
+
+class TransliteratorParser : public UMemory {
+
+ public:
+
+ /**
+ * A Vector of TransliterationRuleData objects, one for each discrete group
+ * of rules in the rule set
+ */
+ UVector dataVector;
+
+ /**
+ * PUBLIC data member.
+ * A Vector of UnicodeStrings containing all of the ID blocks in the rule set
+ */
+ UVector idBlockVector;
+
+ /**
+ * PUBLIC data member containing the parsed compound filter, if any.
+ */
+ UnicodeSet* compoundFilter;
+
+ private:
+
+ /**
+ * The current data object for which we are parsing rules
+ */
+ TransliterationRuleData* curData;
+
+ UTransDirection direction;
+
+ /**
+ * Parse error information.
+ */
+ UParseError parseError;
+
+ /**
+ * Temporary symbol table used during parsing.
+ */
+ ParseData* parseData;
+
+ /**
+ * Temporary vector of matcher variables. When parsing is complete, this
+ * is copied into the array data.variables. As with data.variables,
+ * element 0 corresponds to character data.variablesBase.
+ */
+ UVector variablesVector;
+
+ /**
+ * Temporary table of variable names. When parsing is complete, this is
+ * copied into data.variableNames.
+ */
+ Hashtable variableNames;
+
+ /**
+ * String of standins for segments. Used during the parsing of a single
+ * rule. segmentStandins.charAt(0) is the standin for "$1" and corresponds
+ * to StringMatcher object segmentObjects.elementAt(0), etc.
+ */
+ UnicodeString segmentStandins;
+
+ /**
+ * Vector of StringMatcher objects for segments. Used during the
+ * parsing of a single rule.
+ * segmentStandins.charAt(0) is the standin for "$1" and corresponds
+ * to StringMatcher object segmentObjects.elementAt(0), etc.
+ */
+ UVector segmentObjects;
+
+ /**
+ * The next available stand-in for variables. This starts at some point in
+ * the private use area (discovered dynamically) and increments up toward
+ * <code>variableLimit</code>. At any point during parsing, available
+ * variables are <code>variableNext..variableLimit-1</code>.
+ */
+ UChar variableNext;
+
+ /**
+ * The last available stand-in for variables. This is discovered
+ * dynamically. At any point during parsing, available variables are
+ * <code>variableNext..variableLimit-1</code>.
+ */
+ UChar variableLimit;
+
+ /**
+ * When we encounter an undefined variable, we do not immediately signal
+ * an error, in case we are defining this variable, e.g., "$a = [a-z];".
+ * Instead, we save the name of the undefined variable, and substitute
+ * in the placeholder char variableLimit - 1, and decrement
+ * variableLimit.
+ */
+ UnicodeString undefinedVariableName;
+
+ /**
+ * The stand-in character for the 'dot' set, represented by '.' in
+ * patterns. This is allocated the first time it is needed, and
+ * reused thereafter.
+ */
+ UChar dotStandIn;
+
+public:
+
+ /**
+ * Constructor.
+ */
+ TransliteratorParser(UErrorCode &statusReturn);
+
+ /**
+ * Destructor.
+ */
+ ~TransliteratorParser();
+
+ /**
+ * Parse the given string as a sequence of rules, separated by newline
+ * characters ('\n'), and cause this object to implement those rules. Any
+ * previous rules are discarded. Typically this method is called exactly
+ * once after construction.
+ *
+ * Parse the given rules, in the given direction. After this call
+ * returns, query the public data members for results. The caller
+ * owns the 'data' and 'compoundFilter' data members after this
+ * call returns.
+ * @param rules rules, separated by ';'
+ * @param direction either FORWARD or REVERSE.
+ * @param pe Struct to recieve information on position
+ * of error if an error is encountered
+ * @param ec Output param set to success/failure code.
+ */
+ void parse(const UnicodeString& rules,
+ UTransDirection direction,
+ UParseError& pe,
+ UErrorCode& ec);
+
+ /**
+ * Return the compound filter parsed by parse(). Caller owns result.
+ * @return the compound filter parsed by parse().
+ */
+ UnicodeSet* orphanCompoundFilter();
+
+private:
+
+ /**
+ * Return a representation of this transliterator as source rules.
+ * @param rules Output param to receive the rules.
+ * @param direction either FORWARD or REVERSE.
+ */
+ void parseRules(const UnicodeString& rules,
+ UTransDirection direction,
+ UErrorCode& status);
+
+ /**
+ * MAIN PARSER. Parse the next rule in the given rule string, starting
+ * at pos. Return the index after the last character parsed. Do not
+ * parse characters at or after limit.
+ *
+ * Important: The character at pos must be a non-whitespace character
+ * that is not the comment character.
+ *
+ * This method handles quoting, escaping, and whitespace removal. It
+ * parses the end-of-rule character. It recognizes context and cursor
+ * indicators. Once it does a lexical breakdown of the rule at pos, it
+ * creates a rule object and adds it to our rule list.
+ * @param rules Output param to receive the rules.
+ * @param pos the starting position.
+ * @param limit pointer past the last character of the rule.
+ * @return the index after the last character parsed.
+ */
+ int32_t parseRule(const UnicodeString& rule, int32_t pos, int32_t limit, UErrorCode& status);
+
+ /**
+ * Set the variable range to [start, end] (inclusive).
+ * @param start the start value of the range.
+ * @param end the end value of the range.
+ */
+ void setVariableRange(int32_t start, int32_t end, UErrorCode& status);
+
+ /**
+ * Assert that the given character is NOT within the variable range.
+ * If it is, return FALSE. This is neccesary to ensure that the
+ * variable range does not overlap characters used in a rule.
+ * @param ch the given character.
+ * @return True, if the given character is NOT within the variable range.
+ */
+ UBool checkVariableRange(UChar32 ch) const;
+
+ /**
+ * Set the maximum backup to 'backup', in response to a pragma
+ * statement.
+ * @param backup the new value to be set.
+ */
+ void pragmaMaximumBackup(int32_t backup);
+
+ /**
+ * Begin normalizing all rules using the given mode, in response
+ * to a pragma statement.
+ * @param mode the given mode.
+ */
+ void pragmaNormalizeRules(UNormalizationMode mode);
+
+ /**
+ * Return true if the given rule looks like a pragma.
+ * @param pos offset to the first non-whitespace character
+ * of the rule.
+ * @param limit pointer past the last character of the rule.
+ * @return true if the given rule looks like a pragma.
+ */
+ static UBool resemblesPragma(const UnicodeString& rule, int32_t pos, int32_t limit);
+
+ /**
+ * Parse a pragma. This method assumes resemblesPragma() has
+ * already returned true.
+ * @param pos offset to the first non-whitespace character
+ * of the rule.
+ * @param limit pointer past the last character of the rule.
+ * @return the position index after the final ';' of the pragma,
+ * or -1 on failure.
+ */
+ int32_t parsePragma(const UnicodeString& rule, int32_t pos, int32_t limit, UErrorCode& status);
+
+ /**
+ * Called by main parser upon syntax error. Search the rule string
+ * for the probable end of the rule. Of course, if the error is that
+ * the end of rule marker is missing, then the rule end will not be found.
+ * In any case the rule start will be correctly reported.
+ * @param parseErrorCode error code.
+ * @param msg error description.
+ * @param start position of first character of current rule.
+ * @return start position of first character of current rule.
+ */
+ int32_t syntaxError(UErrorCode parseErrorCode, const UnicodeString&, int32_t start,
+ UErrorCode& status);
+
+ /**
+ * Parse a UnicodeSet out, store it, and return the stand-in character
+ * used to represent it.
+ *
+ * @param rule the rule for UnicodeSet.
+ * @param pos the position in pattern at which to start parsing.
+ * @return the stand-in character used to represent it.
+ */
+ UChar parseSet(const UnicodeString& rule,
+ ParsePosition& pos,
+ UErrorCode& status);
+
+ /**
+ * Generate and return a stand-in for a new UnicodeFunctor. Store
+ * the matcher (adopt it).
+ * @param adopted the UnicodeFunctor to be adopted.
+ * @return a stand-in for a new UnicodeFunctor.
+ */
+ UChar generateStandInFor(UnicodeFunctor* adopted, UErrorCode& status);
+
+ /**
+ * Return the standin for segment seg (1-based).
+ * @param seg the given segment.
+ * @return the standIn character for the given segment.
+ */
+ UChar getSegmentStandin(int32_t seg, UErrorCode& status);
+
+ /**
+ * Set the object for segment seg (1-based).
+ * @param seg the given segment.
+ * @param adopted the StringMatcher to be adopted.
+ */
+ void setSegmentObject(int32_t seg, StringMatcher* adopted, UErrorCode& status);
+
+ /**
+ * Return the stand-in for the dot set. It is allocated the first
+ * time and reused thereafter.
+ * @return the stand-in for the dot set.
+ */
+ UChar getDotStandIn(UErrorCode& status);
+
+ /**
+ * Append the value of the given variable name to the given
+ * UnicodeString.
+ * @param name the variable name to be appended.
+ * @param buf the given UnicodeString to append to.
+ */
+ void appendVariableDef(const UnicodeString& name,
+ UnicodeString& buf,
+ UErrorCode& status);
+
+ /**
+ * Glue method to get around access restrictions in C++.
+ */
+ /*static Transliterator* createBasicInstance(const UnicodeString& id,
+ const UnicodeString* canonID);*/
+
+ friend class RuleHalf;
+
+ // Disallowed methods; no impl.
+ /**
+ * Copy constructor
+ */
+ TransliteratorParser(const TransliteratorParser&);
+
+ /**
+ * Assignment operator
+ */
+ TransliteratorParser& operator=(const TransliteratorParser&);
+};
+
+U_NAMESPACE_END
+
+#endif /* #ifdef XP_CPLUSPLUS */
+
+/**
+ * Strip/convert the following from the transliterator rules:
+ * comments
+ * newlines
+ * white space at the beginning and end of a line
+ * unescape \u notation
+ *
+ * The target must be equal in size as the source.
+ * @internal
+ */
+U_CAPI int32_t
+utrans_stripRules(const UChar *source, int32_t sourceLen, UChar *target, UErrorCode *status);
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt_rule.cpp b/Build/source/libs/icu/icu-xetex/i18n/rbt_rule.cpp
new file mode 100644
index 00000000000..65ba78c2f8d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt_rule.cpp
@@ -0,0 +1,556 @@
+/*
+ **********************************************************************
+ * Copyright (C) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 11/17/99 aliu Creation.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/rep.h"
+#include "unicode/unifilt.h"
+#include "unicode/uniset.h"
+#include "rbt_rule.h"
+#include "rbt_data.h"
+#include "cmemory.h"
+#include "strmatch.h"
+#include "strrepl.h"
+#include "util.h"
+#include "putilimp.h"
+
+static const UChar FORWARD_OP[] = {32,62,32,0}; // " > "
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Construct a new rule with the given input, output text, and other
+ * attributes. A cursor position may be specified for the output text.
+ * @param input input string, including key and optional ante and
+ * post context
+ * @param anteContextPos offset into input to end of ante context, or -1 if
+ * none. Must be <= input.length() if not -1.
+ * @param postContextPos offset into input to start of post context, or -1
+ * if none. Must be <= input.length() if not -1, and must be >=
+ * anteContextPos.
+ * @param output output string
+ * @param cursorPosition offset into output at which cursor is located, or -1 if
+ * none. If less than zero, then the cursor is placed after the
+ * <code>output</code>; that is, -1 is equivalent to
+ * <code>output.length()</code>. If greater than
+ * <code>output.length()</code> then an exception is thrown.
+ * @param segs array of UnicodeFunctors corresponding to input pattern
+ * segments, or null if there are none. The array itself is adopted,
+ * but the pointers within it are not.
+ * @param segsCount number of elements in segs[]
+ * @param anchorStart TRUE if the the rule is anchored on the left to
+ * the context start
+ * @param anchorEnd TRUE if the rule is anchored on the right to the
+ * context limit
+ */
+TransliterationRule::TransliterationRule(const UnicodeString& input,
+ int32_t anteContextPos, int32_t postContextPos,
+ const UnicodeString& outputStr,
+ int32_t cursorPosition, int32_t cursorOffset,
+ UnicodeFunctor** segs,
+ int32_t segsCount,
+ UBool anchorStart, UBool anchorEnd,
+ const TransliterationRuleData* theData,
+ UErrorCode& status) :
+ UMemory(),
+ segments(0),
+ data(theData) {
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // Do range checks only when warranted to save time
+ if (anteContextPos < 0) {
+ anteContextLength = 0;
+ } else {
+ if (anteContextPos > input.length()) {
+ // throw new IllegalArgumentException("Invalid ante context");
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ anteContextLength = anteContextPos;
+ }
+ if (postContextPos < 0) {
+ keyLength = input.length() - anteContextLength;
+ } else {
+ if (postContextPos < anteContextLength ||
+ postContextPos > input.length()) {
+ // throw new IllegalArgumentException("Invalid post context");
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ keyLength = postContextPos - anteContextLength;
+ }
+ if (cursorPosition < 0) {
+ cursorPosition = outputStr.length();
+ } else if (cursorPosition > outputStr.length()) {
+ // throw new IllegalArgumentException("Invalid cursor position");
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ // We don't validate the segments array. The caller must
+ // guarantee that the segments are well-formed (that is, that
+ // all $n references in the output refer to indices of this
+ // array, and that no array elements are null).
+ this->segments = segs;
+ this->segmentsCount = segsCount;
+
+ pattern = input;
+ flags = 0;
+ if (anchorStart) {
+ flags |= ANCHOR_START;
+ }
+ if (anchorEnd) {
+ flags |= ANCHOR_END;
+ }
+
+ anteContext = NULL;
+ if (anteContextLength > 0) {
+ anteContext = new StringMatcher(pattern, 0, anteContextLength,
+ FALSE, *data);
+ /* test for NULL */
+ if (anteContext == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ key = NULL;
+ if (keyLength > 0) {
+ key = new StringMatcher(pattern, anteContextLength, anteContextLength + keyLength,
+ FALSE, *data);
+ /* test for NULL */
+ if (key == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ int32_t postContextLength = pattern.length() - keyLength - anteContextLength;
+ postContext = NULL;
+ if (postContextLength > 0) {
+ postContext = new StringMatcher(pattern, anteContextLength + keyLength, pattern.length(),
+ FALSE, *data);
+ /* test for NULL */
+ if (postContext == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ this->output = new StringReplacer(outputStr, cursorPosition + cursorOffset, data);
+ /* test for NULL */
+ if (this->output == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+}
+
+/**
+ * Copy constructor.
+ */
+TransliterationRule::TransliterationRule(TransliterationRule& other) :
+ UMemory(other),
+ anteContext(NULL),
+ key(NULL),
+ postContext(NULL),
+ pattern(other.pattern),
+ anteContextLength(other.anteContextLength),
+ keyLength(other.keyLength),
+ flags(other.flags),
+ data(other.data) {
+
+ segments = NULL;
+ segmentsCount = 0;
+ if (other.segmentsCount > 0) {
+ segments = (UnicodeFunctor **)uprv_malloc(other.segmentsCount * sizeof(UnicodeFunctor *));
+ uprv_memcpy(segments, other.segments, other.segmentsCount*sizeof(segments[0]));
+ }
+
+ if (other.anteContext != NULL) {
+ anteContext = (StringMatcher*) other.anteContext->clone();
+ }
+ if (other.key != NULL) {
+ key = (StringMatcher*) other.key->clone();
+ }
+ if (other.postContext != NULL) {
+ postContext = (StringMatcher*) other.postContext->clone();
+ }
+ output = other.output->clone();
+}
+
+TransliterationRule::~TransliterationRule() {
+ uprv_free(segments);
+ delete anteContext;
+ delete key;
+ delete postContext;
+ delete output;
+}
+
+/**
+ * Return the preceding context length. This method is needed to
+ * support the <code>Transliterator</code> method
+ * <code>getMaximumContextLength()</code>. Internally, this is
+ * implemented as the anteContextLength, optionally plus one if
+ * there is a start anchor. The one character anchor gap is
+ * needed to make repeated incremental transliteration with
+ * anchors work.
+ */
+int32_t TransliterationRule::getContextLength(void) const {
+ return anteContextLength + ((flags & ANCHOR_START) ? 1 : 0);
+}
+
+/**
+ * Internal method. Returns 8-bit index value for this rule.
+ * This is the low byte of the first character of the key,
+ * unless the first character of the key is a set. If it's a
+ * set, or otherwise can match multiple keys, the index value is -1.
+ */
+int16_t TransliterationRule::getIndexValue() const {
+ if (anteContextLength == pattern.length()) {
+ // A pattern with just ante context {such as foo)>bar} can
+ // match any key.
+ return -1;
+ }
+ UChar32 c = pattern.char32At(anteContextLength);
+ return (int16_t)(data->lookupMatcher(c) == NULL ? (c & 0xFF) : -1);
+}
+
+/**
+ * Internal method. Returns true if this rule matches the given
+ * index value. The index value is an 8-bit integer, 0..255,
+ * representing the low byte of the first character of the key.
+ * It matches this rule if it matches the first character of the
+ * key, or if the first character of the key is a set, and the set
+ * contains any character with a low byte equal to the index
+ * value. If the rule contains only ante context, as in foo)>bar,
+ * then it will match any key.
+ */
+UBool TransliterationRule::matchesIndexValue(uint8_t v) const {
+ // Delegate to the key, or if there is none, to the postContext.
+ // If there is neither then we match any key; return true.
+ UnicodeMatcher *m = (key != NULL) ? key : postContext;
+ return (m != NULL) ? m->matchesIndexValue(v) : TRUE;
+}
+
+/**
+ * Return true if this rule masks another rule. If r1 masks r2 then
+ * r1 matches any input string that r2 matches. If r1 masks r2 and r2 masks
+ * r1 then r1 == r2. Examples: "a>x" masks "ab>y". "a>x" masks "a[b]>y".
+ * "[c]a>x" masks "[dc]a>y".
+ */
+UBool TransliterationRule::masks(const TransliterationRule& r2) const {
+ /* Rule r1 masks rule r2 if the string formed of the
+ * antecontext, key, and postcontext overlaps in the following
+ * way:
+ *
+ * r1: aakkkpppp
+ * r2: aaakkkkkpppp
+ * ^
+ *
+ * The strings must be aligned at the first character of the
+ * key. The length of r1 to the left of the alignment point
+ * must be <= the length of r2 to the left; ditto for the
+ * right. The characters of r1 must equal (or be a superset
+ * of) the corresponding characters of r2. The superset
+ * operation should be performed to check for UnicodeSet
+ * masking.
+ *
+ * Anchors: Two patterns that differ only in anchors only
+ * mask one another if they are exactly equal, and r2 has
+ * all the anchors r1 has (optionally, plus some). Here Y
+ * means the row masks the column, N means it doesn't.
+ *
+ * ab ^ab ab$ ^ab$
+ * ab Y Y Y Y
+ * ^ab N Y N Y
+ * ab$ N N Y Y
+ * ^ab$ N N N Y
+ *
+ * Post context: {a}b masks ab, but not vice versa, since {a}b
+ * matches everything ab matches, and {a}b matches {|a|}b but ab
+ * does not. Pre context is different (a{b} does not align with
+ * ab).
+ */
+
+ /* LIMITATION of the current mask algorithm: Some rule
+ * maskings are currently not detected. For example,
+ * "{Lu}]a>x" masks "A]a>y". This can be added later. TODO
+ */
+
+ int32_t len = pattern.length();
+ int32_t left = anteContextLength;
+ int32_t left2 = r2.anteContextLength;
+ int32_t right = len - left;
+ int32_t right2 = r2.pattern.length() - left2;
+ int32_t cachedCompare = r2.pattern.compare(left2 - left, len, pattern);
+
+ // TODO Clean this up -- some logic might be combinable with the
+ // next statement.
+
+ // Test for anchor masking
+ if (left == left2 && right == right2 &&
+ keyLength <= r2.keyLength &&
+ 0 == cachedCompare) {
+ // The following boolean logic implements the table above
+ return (flags == r2.flags) ||
+ (!(flags & ANCHOR_START) && !(flags & ANCHOR_END)) ||
+ ((r2.flags & ANCHOR_START) && (r2.flags & ANCHOR_END));
+ }
+
+ return left <= left2 &&
+ (right < right2 ||
+ (right == right2 && keyLength <= r2.keyLength)) &&
+ (0 == cachedCompare);
+}
+
+static inline int32_t posBefore(const Replaceable& str, int32_t pos) {
+ return (pos > 0) ?
+ pos - UTF_CHAR_LENGTH(str.char32At(pos-1)) :
+ pos - 1;
+}
+
+static inline int32_t posAfter(const Replaceable& str, int32_t pos) {
+ return (pos >= 0 && pos < str.length()) ?
+ pos + UTF_CHAR_LENGTH(str.char32At(pos)) :
+ pos + 1;
+}
+
+/**
+ * Attempt a match and replacement at the given position. Return
+ * the degree of match between this rule and the given text. The
+ * degree of match may be mismatch, a partial match, or a full
+ * match. A mismatch means at least one character of the text
+ * does not match the context or key. A partial match means some
+ * context and key characters match, but the text is not long
+ * enough to match all of them. A full match means all context
+ * and key characters match.
+ *
+ * If a full match is obtained, perform a replacement, update pos,
+ * and return U_MATCH. Otherwise both text and pos are unchanged.
+ *
+ * @param text the text
+ * @param pos the position indices
+ * @param incremental if TRUE, test for partial matches that may
+ * be completed by additional text inserted at pos.limit.
+ * @return one of <code>U_MISMATCH</code>,
+ * <code>U_PARTIAL_MATCH</code>, or <code>U_MATCH</code>. If
+ * incremental is FALSE then U_PARTIAL_MATCH will not be returned.
+ */
+UMatchDegree TransliterationRule::matchAndReplace(Replaceable& text,
+ UTransPosition& pos,
+ UBool incremental) const {
+ // Matching and replacing are done in one method because the
+ // replacement operation needs information obtained during the
+ // match. Another way to do this is to have the match method
+ // create a match result struct with relevant offsets, and to pass
+ // this into the replace method.
+
+ // ============================ MATCH ===========================
+
+ // Reset segment match data
+ if (segments != NULL) {
+ for (int32_t i=0; i<segmentsCount; ++i) {
+ ((StringMatcher*) segments[i])->resetMatch();
+ }
+ }
+
+// int32_t lenDelta, keyLimit;
+ int32_t keyLimit;
+
+ // ------------------------ Ante Context ------------------------
+
+ // A mismatch in the ante context, or with the start anchor,
+ // is an outright U_MISMATCH regardless of whether we are
+ // incremental or not.
+ int32_t oText; // offset into 'text'
+// int32_t newStart = 0;
+ int32_t minOText;
+
+ // Note (1): We process text in 16-bit code units, rather than
+ // 32-bit code points. This works because stand-ins are
+ // always in the BMP and because we are doing a literal match
+ // operation, which can be done 16-bits at a time.
+
+ int32_t anteLimit = posBefore(text, pos.contextStart);
+
+ UMatchDegree match;
+
+ // Start reverse match at char before pos.start
+ oText = posBefore(text, pos.start);
+
+ if (anteContext != NULL) {
+ match = anteContext->matches(text, oText, anteLimit, FALSE);
+ if (match != U_MATCH) {
+ return U_MISMATCH;
+ }
+ }
+
+ minOText = posAfter(text, oText);
+
+ // ------------------------ Start Anchor ------------------------
+
+ if (((flags & ANCHOR_START) != 0) && oText != anteLimit) {
+ return U_MISMATCH;
+ }
+
+ // -------------------- Key and Post Context --------------------
+
+ oText = pos.start;
+
+ if (key != NULL) {
+ match = key->matches(text, oText, pos.limit, incremental);
+ if (match != U_MATCH) {
+ return match;
+ }
+ }
+
+ keyLimit = oText;
+
+ if (postContext != NULL) {
+ if (incremental && keyLimit == pos.limit) {
+ // The key matches just before pos.limit, and there is
+ // a postContext. Since we are in incremental mode,
+ // we must assume more characters may be inserted at
+ // pos.limit -- this is a partial match.
+ return U_PARTIAL_MATCH;
+ }
+
+ match = postContext->matches(text, oText, pos.contextLimit, incremental);
+ if (match != U_MATCH) {
+ return match;
+ }
+ }
+
+ // ------------------------- Stop Anchor ------------------------
+
+ if (((flags & ANCHOR_END)) != 0) {
+ if (oText != pos.contextLimit) {
+ return U_MISMATCH;
+ }
+ if (incremental) {
+ return U_PARTIAL_MATCH;
+ }
+ }
+
+ // =========================== REPLACE ==========================
+
+ // We have a full match. The key is between pos.start and
+ // keyLimit.
+
+ int32_t newStart;
+ int32_t newLength = output->toReplacer()->replace(text, pos.start, keyLimit, newStart);
+ int32_t lenDelta = newLength - (keyLimit - pos.start);
+
+ oText += lenDelta;
+ pos.limit += lenDelta;
+ pos.contextLimit += lenDelta;
+ // Restrict new value of start to [minOText, min(oText, pos.limit)].
+ pos.start = uprv_max(minOText, uprv_min(uprv_min(oText, pos.limit), newStart));
+ return U_MATCH;
+}
+
+/**
+ * Create a source string that represents this rule. Append it to the
+ * given string.
+ */
+UnicodeString& TransliterationRule::toRule(UnicodeString& rule,
+ UBool escapeUnprintable) const {
+
+ // Accumulate special characters (and non-specials following them)
+ // into quoteBuf. Append quoteBuf, within single quotes, when
+ // a non-quoted element must be inserted.
+ UnicodeString str, quoteBuf;
+
+ // Do not emit the braces '{' '}' around the pattern if there
+ // is neither anteContext nor postContext.
+ UBool emitBraces =
+ (anteContext != NULL) || (postContext != NULL);
+
+ // Emit start anchor
+ if ((flags & ANCHOR_START) != 0) {
+ rule.append((UChar)94/*^*/);
+ }
+
+ // Emit the input pattern
+ ICU_Utility::appendToRule(rule, anteContext, escapeUnprintable, quoteBuf);
+
+ if (emitBraces) {
+ ICU_Utility::appendToRule(rule, (UChar) 0x007B /*{*/, TRUE, escapeUnprintable, quoteBuf);
+ }
+
+ ICU_Utility::appendToRule(rule, key, escapeUnprintable, quoteBuf);
+
+ if (emitBraces) {
+ ICU_Utility::appendToRule(rule, (UChar) 0x007D /*}*/, TRUE, escapeUnprintable, quoteBuf);
+ }
+
+ ICU_Utility::appendToRule(rule, postContext, escapeUnprintable, quoteBuf);
+
+ // Emit end anchor
+ if ((flags & ANCHOR_END) != 0) {
+ rule.append((UChar)36/*$*/);
+ }
+
+ ICU_Utility::appendToRule(rule, FORWARD_OP, TRUE, escapeUnprintable, quoteBuf);
+
+ // Emit the output pattern
+
+ ICU_Utility::appendToRule(rule, output->toReplacer()->toReplacerPattern(str, escapeUnprintable),
+ TRUE, escapeUnprintable, quoteBuf);
+
+ ICU_Utility::appendToRule(rule, (UChar) 0x003B /*;*/, TRUE, escapeUnprintable, quoteBuf);
+
+ return rule;
+}
+
+void TransliterationRule::setData(const TransliterationRuleData* d) {
+ data = d;
+ if (anteContext != NULL) anteContext->setData(d);
+ if (postContext != NULL) postContext->setData(d);
+ if (key != NULL) key->setData(d);
+ // assert(output != NULL);
+ output->setData(d);
+ // Don't have to do segments since they are in the context or key
+}
+
+/**
+ * Union the set of all characters that may be modified by this rule
+ * into the given set.
+ */
+void TransliterationRule::addSourceSetTo(UnicodeSet& toUnionTo) const {
+ int32_t limit = anteContextLength + keyLength;
+ for (int32_t i=anteContextLength; i<limit; ) {
+ UChar32 ch = pattern.char32At(i);
+ i += UTF_CHAR_LENGTH(ch);
+ const UnicodeMatcher* matcher = data->lookupMatcher(ch);
+ if (matcher == NULL) {
+ toUnionTo.add(ch);
+ } else {
+ matcher->addMatchSetTo(toUnionTo);
+ }
+ }
+}
+
+/**
+ * Union the set of all characters that may be emitted by this rule
+ * into the given set.
+ */
+void TransliterationRule::addTargetSetTo(UnicodeSet& toUnionTo) const {
+ output->toReplacer()->addReplacementSetTo(toUnionTo);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt_rule.h b/Build/source/libs/icu/icu-xetex/i18n/rbt_rule.h
new file mode 100644
index 00000000000..0816956ce81
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt_rule.h
@@ -0,0 +1,308 @@
+/*
+* Copyright (C) {1999-2001}, International Business Machines Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+#ifndef RBT_RULE_H
+#define RBT_RULE_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/utrans.h"
+#include "unicode/unimatch.h"
+
+U_NAMESPACE_BEGIN
+
+class Replaceable;
+class TransliterationRuleData;
+class StringMatcher;
+class UnicodeFunctor;
+
+/**
+ * A transliteration rule used by
+ * <code>RuleBasedTransliterator</code>.
+ * <code>TransliterationRule</code> is an immutable object.
+ *
+ * <p>A rule consists of an input pattern and an output string. When
+ * the input pattern is matched, the output string is emitted. The
+ * input pattern consists of zero or more characters which are matched
+ * exactly (the key) and optional context. Context must match if it
+ * is specified. Context may be specified before the key, after the
+ * key, or both. The key, preceding context, and following context
+ * may contain variables. Variables represent a set of Unicode
+ * characters, such as the letters <i>a</i> through <i>z</i>.
+ * Variables are detected by looking up each character in a supplied
+ * variable list to see if it has been so defined.
+ *
+ * <p>A rule may contain segments in its input string and segment
+ * references in its output string. A segment is a substring of the
+ * input pattern, indicated by an offset and limit. The segment may
+ * be in the preceding or following context. It may not span a
+ * context boundary. A segment reference is a special character in
+ * the output string that causes a segment of the input string (not
+ * the input pattern) to be copied to the output string. The range of
+ * special characters that represent segment references is defined by
+ * RuleBasedTransliterator.Data.
+ *
+ * @author Alan Liu
+ */
+class TransliterationRule : public UMemory {
+
+private:
+
+ // TODO Eliminate the pattern and keyLength data members. They
+ // are used only by masks() and getIndexValue() which are called
+ // only during build time, not during run-time. Perhaps these
+ // methods and pattern/keyLength can be isolated into a separate
+ // object.
+
+ /**
+ * The match that must occur before the key, or null if there is no
+ * preceding context.
+ */
+ StringMatcher *anteContext;
+
+ /**
+ * The matcher object for the key. If null, then the key is empty.
+ */
+ StringMatcher *key;
+
+ /**
+ * The match that must occur after the key, or null if there is no
+ * following context.
+ */
+ StringMatcher *postContext;
+
+ /**
+ * The object that performs the replacement if the key,
+ * anteContext, and postContext are matched. Never null.
+ */
+ UnicodeFunctor* output;
+
+ /**
+ * The string that must be matched, consisting of the anteContext, key,
+ * and postContext, concatenated together, in that order. Some components
+ * may be empty (zero length).
+ * @see anteContextLength
+ * @see keyLength
+ */
+ UnicodeString pattern;
+
+ /**
+ * An array of matcher objects corresponding to the input pattern
+ * segments. If there are no segments this is null. N.B. This is
+ * a UnicodeMatcher for generality, but in practice it is always a
+ * StringMatcher. In the future we may generalize this, but for
+ * now we sometimes cast down to StringMatcher.
+ *
+ * The array is owned, but the pointers within it are not.
+ */
+ UnicodeFunctor** segments;
+
+ /**
+ * The number of elements in segments[] or zero if segments is NULL.
+ */
+ int32_t segmentsCount;
+
+ /**
+ * The length of the string that must match before the key. If
+ * zero, then there is no matching requirement before the key.
+ * Substring [0,anteContextLength) of pattern is the anteContext.
+ */
+ int32_t anteContextLength;
+
+ /**
+ * The length of the key. Substring [anteContextLength,
+ * anteContextLength + keyLength) is the key.
+
+ */
+ int32_t keyLength;
+
+ /**
+ * Miscellaneous attributes.
+ */
+ int8_t flags;
+
+ /**
+ * Flag attributes.
+ */
+ enum {
+ ANCHOR_START = 1,
+ ANCHOR_END = 2
+ };
+
+ /**
+ * An alias pointer to the data for this rule. The data provides
+ * lookup services for matchers and segments.
+ */
+ const TransliterationRuleData* data;
+
+public:
+
+ /**
+ * Construct a new rule with the given input, output text, and other
+ * attributes. A cursor position may be specified for the output text.
+ * @param input input string, including key and optional ante and
+ * post context.
+ * @param anteContextPos offset into input to end of ante context, or -1 if
+ * none. Must be <= input.length() if not -1.
+ * @param postContextPos offset into input to start of post context, or -1
+ * if none. Must be <= input.length() if not -1, and must be >=
+ * anteContextPos.
+ * @param outputStr output string.
+ * @param cursorPosition offset into output at which cursor is located, or -1 if
+ * none. If less than zero, then the cursor is placed after the
+ * <code>output</code>; that is, -1 is equivalent to
+ * <code>output.length()</code>. If greater than
+ * <code>output.length()</code> then an exception is thrown.
+ * @param cursorOffset an offset to be added to cursorPos to position the
+ * cursor either in the ante context, if < 0, or in the post context, if >
+ * 0. For example, the rule "abc{def} > | @@@ xyz;" changes "def" to
+ * "xyz" and moves the cursor to before "a". It would have a cursorOffset
+ * of -3.
+ * @param segs array of UnicodeMatcher corresponding to input pattern
+ * segments, or null if there are none. The array itself is adopted,
+ * but the pointers within it are not.
+ * @param segsCount number of elements in segs[].
+ * @param anchorStart TRUE if the the rule is anchored on the left to
+ * the context start.
+ * @param anchorEnd TRUE if the rule is anchored on the right to the
+ * context limit.
+ * @param data the rule data.
+ * @param status Output parameter filled in with success or failure status.
+ */
+ TransliterationRule(const UnicodeString& input,
+ int32_t anteContextPos, int32_t postContextPos,
+ const UnicodeString& outputStr,
+ int32_t cursorPosition, int32_t cursorOffset,
+ UnicodeFunctor** segs,
+ int32_t segsCount,
+ UBool anchorStart, UBool anchorEnd,
+ const TransliterationRuleData* data,
+ UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ * @param other the object to be copied.
+ */
+ TransliterationRule(TransliterationRule& other);
+
+ /**
+ * Destructor.
+ */
+ virtual ~TransliterationRule();
+
+ /**
+ * Change the data object that this rule belongs to. Used
+ * internally by the TransliterationRuleData copy constructor.
+ * @param data the new data value to be set.
+ */
+ void setData(const TransliterationRuleData* data);
+
+ /**
+ * Return the preceding context length. This method is needed to
+ * support the <code>Transliterator</code> method
+ * <code>getMaximumContextLength()</code>. Internally, this is
+ * implemented as the anteContextLength, optionally plus one if
+ * there is a start anchor. The one character anchor gap is
+ * needed to make repeated incremental transliteration with
+ * anchors work.
+ * @return the preceding context length.
+ */
+ virtual int32_t getContextLength(void) const;
+
+ /**
+ * Internal method. Returns 8-bit index value for this rule.
+ * This is the low byte of the first character of the key,
+ * unless the first character of the key is a set. If it's a
+ * set, or otherwise can match multiple keys, the index value is -1.
+ * @return 8-bit index value for this rule.
+ */
+ int16_t getIndexValue() const;
+
+ /**
+ * Internal method. Returns true if this rule matches the given
+ * index value. The index value is an 8-bit integer, 0..255,
+ * representing the low byte of the first character of the key.
+ * It matches this rule if it matches the first character of the
+ * key, or if the first character of the key is a set, and the set
+ * contains any character with a low byte equal to the index
+ * value. If the rule contains only ante context, as in foo)>bar,
+ * then it will match any key.
+ * @param v the given index value.
+ * @return true if this rule matches the given index value.
+ */
+ UBool matchesIndexValue(uint8_t v) const;
+
+ /**
+ * Return true if this rule masks another rule. If r1 masks r2 then
+ * r1 matches any input string that r2 matches. If r1 masks r2 and r2 masks
+ * r1 then r1 == r2. Examples: "a>x" masks "ab>y". "a>x" masks "a[b]>y".
+ * "[c]a>x" masks "[dc]a>y".
+ * @param r2 the given rule to be compared with.
+ * @return true if this rule masks 'r2'
+ */
+ virtual UBool masks(const TransliterationRule& r2) const;
+
+ /**
+ * Attempt a match and replacement at the given position. Return
+ * the degree of match between this rule and the given text. The
+ * degree of match may be mismatch, a partial match, or a full
+ * match. A mismatch means at least one character of the text
+ * does not match the context or key. A partial match means some
+ * context and key characters match, but the text is not long
+ * enough to match all of them. A full match means all context
+ * and key characters match.
+ *
+ * If a full match is obtained, perform a replacement, update pos,
+ * and return U_MATCH. Otherwise both text and pos are unchanged.
+ *
+ * @param text the text
+ * @param pos the position indices
+ * @param incremental if TRUE, test for partial matches that may
+ * be completed by additional text inserted at pos.limit.
+ * @return one of <code>U_MISMATCH</code>,
+ * <code>U_PARTIAL_MATCH</code>, or <code>U_MATCH</code>. If
+ * incremental is FALSE then U_PARTIAL_MATCH will not be returned.
+ */
+ UMatchDegree matchAndReplace(Replaceable& text,
+ UTransPosition& pos,
+ UBool incremental) const;
+
+ /**
+ * Create a rule string that represents this rule object. Append
+ * it to the given string.
+ */
+ virtual UnicodeString& toRule(UnicodeString& pat,
+ UBool escapeUnprintable) const;
+
+ /**
+ * Union the set of all characters that may be modified by this rule
+ * into the given set.
+ */
+ void addSourceSetTo(UnicodeSet& toUnionTo) const;
+
+ /**
+ * Union the set of all characters that may be emitted by this rule
+ * into the given set.
+ */
+ void addTargetSetTo(UnicodeSet& toUnionTo) const;
+
+ private:
+
+ friend class StringMatcher;
+
+ TransliterationRule &operator=(const TransliterationRule &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt_set.cpp b/Build/source/libs/icu/icu-xetex/i18n/rbt_set.cpp
new file mode 100644
index 00000000000..21f85eef743
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt_set.cpp
@@ -0,0 +1,455 @@
+/*
+ **********************************************************************
+ * Copyright (C) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 11/17/99 aliu Creation.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#include "rbt_set.h"
+#include "rbt_rule.h"
+#include "cmemory.h"
+#include "putilimp.h"
+
+U_CDECL_BEGIN
+static void U_CALLCONV _deleteRule(void *rule) {
+ delete (U_NAMESPACE_QUALIFIER TransliterationRule *)rule;
+}
+U_CDECL_END
+
+//----------------------------------------------------------------------
+// BEGIN Debugging support
+//----------------------------------------------------------------------
+
+// #define DEBUG_RBT
+
+#ifdef DEBUG_RBT
+#include <stdio.h>
+#include "charstr.h"
+
+/**
+ * @param appendTo result is appended to this param.
+ * @param input the string being transliterated
+ * @param pos the index struct
+ */
+static UnicodeString& _formatInput(UnicodeString &appendTo,
+ const UnicodeString& input,
+ const UTransPosition& pos) {
+ // Output a string of the form aaa{bbb|ccc|ddd}eee, where
+ // the {} indicate the context start and limit, and the ||
+ // indicate the start and limit.
+ if (0 <= pos.contextStart &&
+ pos.contextStart <= pos.start &&
+ pos.start <= pos.limit &&
+ pos.limit <= pos.contextLimit &&
+ pos.contextLimit <= input.length()) {
+
+ UnicodeString a, b, c, d, e;
+ input.extractBetween(0, pos.contextStart, a);
+ input.extractBetween(pos.contextStart, pos.start, b);
+ input.extractBetween(pos.start, pos.limit, c);
+ input.extractBetween(pos.limit, pos.contextLimit, d);
+ input.extractBetween(pos.contextLimit, input.length(), e);
+ appendTo.append(a).append((UChar)123/*{*/).append(b).
+ append((UChar)124/*|*/).append(c).append((UChar)124/*|*/).append(d).
+ append((UChar)125/*}*/).append(e);
+ } else {
+ appendTo.append("INVALID UTransPosition");
+ //appendTo.append((UnicodeString)"INVALID UTransPosition {cs=" +
+ // pos.contextStart + ", s=" + pos.start + ", l=" +
+ // pos.limit + ", cl=" + pos.contextLimit + "} on " +
+ // input);
+ }
+ return appendTo;
+}
+
+// Append a hex string to the target
+UnicodeString& _appendHex(uint32_t number,
+ int32_t digits,
+ UnicodeString& target) {
+ static const UChar digitString[] = {
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0
+ };
+ while (digits--) {
+ target += digitString[(number >> (digits*4)) & 0xF];
+ }
+ return target;
+}
+
+// Replace nonprintable characters with unicode escapes
+UnicodeString& _escape(const UnicodeString &source,
+ UnicodeString &target) {
+ for (int32_t i = 0; i < source.length(); ) {
+ UChar32 ch = source.char32At(i);
+ i += UTF_CHAR_LENGTH(ch);
+ if (ch < 0x09 || (ch > 0x0A && ch < 0x20)|| ch > 0x7E) {
+ if (ch <= 0xFFFF) {
+ target += "\\u";
+ _appendHex(ch, 4, target);
+ } else {
+ target += "\\U";
+ _appendHex(ch, 8, target);
+ }
+ } else {
+ target += ch;
+ }
+ }
+ return target;
+}
+
+inline void _debugOut(const char* msg, TransliterationRule* rule,
+ const Replaceable& theText, UTransPosition& pos) {
+ UnicodeString buf(msg, "");
+ if (rule) {
+ UnicodeString r;
+ rule->toRule(r, TRUE);
+ buf.append((UChar)32).append(r);
+ }
+ buf.append(UnicodeString(" => ", ""));
+ UnicodeString* text = (UnicodeString*)&theText;
+ _formatInput(buf, *text, pos);
+ UnicodeString esc;
+ _escape(buf, esc);
+ CharString cbuf(esc);
+ printf("%s\n", (const char*) cbuf);
+}
+
+#else
+#define _debugOut(msg, rule, theText, pos)
+#endif
+
+//----------------------------------------------------------------------
+// END Debugging support
+//----------------------------------------------------------------------
+
+// Fill the precontext and postcontext with the patterns of the rules
+// that are masking one another.
+static void maskingError(const U_NAMESPACE_QUALIFIER TransliterationRule& rule1,
+ const U_NAMESPACE_QUALIFIER TransliterationRule& rule2,
+ UParseError& parseError) {
+ U_NAMESPACE_QUALIFIER UnicodeString r;
+ int32_t len;
+
+ parseError.line = parseError.offset = -1;
+
+ // for pre-context
+ rule1.toRule(r, FALSE);
+ len = uprv_min(r.length(), U_PARSE_CONTEXT_LEN-1);
+ r.extract(0, len, parseError.preContext);
+ parseError.preContext[len] = 0;
+
+ //for post-context
+ r.truncate(0);
+ rule2.toRule(r, FALSE);
+ len = uprv_min(r.length(), U_PARSE_CONTEXT_LEN-1);
+ r.extract(0, len, parseError.postContext);
+ parseError.postContext[len] = 0;
+}
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Construct a new empty rule set.
+ */
+TransliterationRuleSet::TransliterationRuleSet(UErrorCode& status) : UMemory() {
+ ruleVector = new UVector(&_deleteRule, NULL, status);
+ rules = NULL;
+ maxContextLength = 0;
+ if (ruleVector == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+}
+
+/**
+ * Copy constructor.
+ */
+TransliterationRuleSet::TransliterationRuleSet(const TransliterationRuleSet& other) :
+ UMemory(other),
+ ruleVector(0),
+ rules(0),
+ maxContextLength(other.maxContextLength) {
+
+ int32_t i, len;
+ uprv_memcpy(index, other.index, sizeof(index));
+ UErrorCode status = U_ZERO_ERROR;
+ ruleVector = new UVector(&_deleteRule, NULL, status);
+ if (other.ruleVector != 0 && ruleVector != 0 && U_SUCCESS(status)) {
+ len = other.ruleVector->size();
+ for (i=0; i<len && U_SUCCESS(status); ++i) {
+ ruleVector->addElement(new TransliterationRule(
+ *(TransliterationRule*)other.ruleVector->elementAt(i)), status);
+ }
+ }
+ if (other.rules != 0) {
+ UParseError p;
+ freeze(p, status);
+ }
+}
+
+/**
+ * Destructor.
+ */
+TransliterationRuleSet::~TransliterationRuleSet() {
+ delete ruleVector; // This deletes the contained rules
+ uprv_free(rules);
+}
+
+void TransliterationRuleSet::setData(const TransliterationRuleData* d) {
+ /**
+ * We assume that the ruleset has already been frozen.
+ */
+ int32_t len = index[256]; // see freeze()
+ for (int32_t i=0; i<len; ++i) {
+ rules[i]->setData(d);
+ }
+}
+
+/**
+ * Return the maximum context length.
+ * @return the length of the longest preceding context.
+ */
+int32_t TransliterationRuleSet::getMaximumContextLength(void) const {
+ return maxContextLength;
+}
+
+/**
+ * Add a rule to this set. Rules are added in order, and order is
+ * significant. The last call to this method must be followed by
+ * a call to <code>freeze()</code> before the rule set is used.
+ *
+ * <p>If freeze() has already been called, calling addRule()
+ * unfreezes the rules, and freeze() must be called again.
+ *
+ * @param adoptedRule the rule to add
+ */
+void TransliterationRuleSet::addRule(TransliterationRule* adoptedRule,
+ UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ delete adoptedRule;
+ return;
+ }
+ ruleVector->addElement(adoptedRule, status);
+
+ int32_t len;
+ if ((len = adoptedRule->getContextLength()) > maxContextLength) {
+ maxContextLength = len;
+ }
+
+ uprv_free(rules);
+ rules = 0;
+}
+
+/**
+ * Check this for masked rules and index it to optimize performance.
+ * The sequence of operations is: (1) add rules to a set using
+ * <code>addRule()</code>; (2) freeze the set using
+ * <code>freeze()</code>; (3) use the rule set. If
+ * <code>addRule()</code> is called after calling this method, it
+ * invalidates this object, and this method must be called again.
+ * That is, <code>freeze()</code> may be called multiple times,
+ * although for optimal performance it shouldn't be.
+ */
+void TransliterationRuleSet::freeze(UParseError& parseError,UErrorCode& status) {
+ /* Construct the rule array and index table. We reorder the
+ * rules by sorting them into 256 bins. Each bin contains all
+ * rules matching the index value for that bin. A rule
+ * matches an index value if string whose first key character
+ * has a low byte equal to the index value can match the rule.
+ *
+ * Each bin contains zero or more rules, in the same order
+ * they were found originally. However, the total rules in
+ * the bins may exceed the number in the original vector,
+ * since rules that have a variable as their first key
+ * character will generally fall into more than one bin.
+ *
+ * That is, each bin contains all rules that either have that
+ * first index value as their first key character, or have
+ * a set containing the index value as their first character.
+ */
+ int32_t n = ruleVector->size();
+ int32_t j;
+ int16_t x;
+ UVector v(2*n, status); // heuristic; adjust as needed
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ /* Precompute the index values. This saves a LOT of time.
+ * Be careful not to call malloc(0).
+ */
+ int16_t* indexValue = (int16_t*) uprv_malloc( sizeof(int16_t) * (n > 0 ? n : 1) );
+ /* test for NULL */
+ if (indexValue == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (j=0; j<n; ++j) {
+ TransliterationRule* r = (TransliterationRule*) ruleVector->elementAt(j);
+ indexValue[j] = r->getIndexValue();
+ }
+ for (x=0; x<256; ++x) {
+ index[x] = v.size();
+ for (j=0; j<n; ++j) {
+ if (indexValue[j] >= 0) {
+ if (indexValue[j] == x) {
+ v.addElement(ruleVector->elementAt(j), status);
+ }
+ } else {
+ // If the indexValue is < 0, then the first key character is
+ // a set, and we must use the more time-consuming
+ // matchesIndexValue check. In practice this happens
+ // rarely, so we seldom tread this code path.
+ TransliterationRule* r = (TransliterationRule*) ruleVector->elementAt(j);
+ if (r->matchesIndexValue((uint8_t)x)) {
+ v.addElement(r, status);
+ }
+ }
+ }
+ }
+ uprv_free(indexValue);
+ index[256] = v.size();
+
+ /* Freeze things into an array.
+ */
+ uprv_free(rules); // Contains alias pointers
+
+ /* You can't do malloc(0)! */
+ if (v.size() == 0) {
+ rules = NULL;
+ return;
+ }
+ rules = (TransliterationRule **)uprv_malloc(v.size() * sizeof(TransliterationRule *));
+ /* test for NULL */
+ if (rules == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ for (j=0; j<v.size(); ++j) {
+ rules[j] = (TransliterationRule*) v.elementAt(j);
+ }
+
+ // TODO Add error reporting that indicates the rules that
+ // are being masked.
+ //UnicodeString errors;
+
+ /* Check for masking. This is MUCH faster than our old check,
+ * which was each rule against each following rule, since we
+ * only have to check for masking within each bin now. It's
+ * 256*O(n2^2) instead of O(n1^2), where n1 is the total rule
+ * count, and n2 is the per-bin rule count. But n2<<n1, so
+ * it's a big win.
+ */
+ for (x=0; x<256; ++x) {
+ for (j=index[x]; j<index[x+1]-1; ++j) {
+ TransliterationRule* r1 = rules[j];
+ for (int32_t k=j+1; k<index[x+1]; ++k) {
+ TransliterationRule* r2 = rules[k];
+ if (r1->masks(*r2)) {
+//| if (errors == null) {
+//| errors = new StringBuffer();
+//| } else {
+//| errors.append("\n");
+//| }
+//| errors.append("Rule " + r1 + " masks " + r2);
+ status = U_RULE_MASK_ERROR;
+ maskingError(*r1, *r2, parseError);
+ return;
+ }
+ }
+ }
+ }
+
+ //if (errors != null) {
+ // throw new IllegalArgumentException(errors.toString());
+ //}
+}
+
+/**
+ * Transliterate the given text with the given UTransPosition
+ * indices. Return TRUE if the transliteration should continue
+ * or FALSE if it should halt (because of a U_PARTIAL_MATCH match).
+ * Note that FALSE is only ever returned if isIncremental is TRUE.
+ * @param text the text to be transliterated
+ * @param pos the position indices, which will be updated
+ * @param incremental if TRUE, assume new text may be inserted
+ * at index.limit, and return FALSE if thre is a partial match.
+ * @return TRUE unless a U_PARTIAL_MATCH has been obtained,
+ * indicating that transliteration should stop until more text
+ * arrives.
+ */
+UBool TransliterationRuleSet::transliterate(Replaceable& text,
+ UTransPosition& pos,
+ UBool incremental) {
+ int16_t indexByte = (int16_t) (text.char32At(pos.start) & 0xFF);
+ for (int32_t i=index[indexByte]; i<index[indexByte+1]; ++i) {
+ UMatchDegree m = rules[i]->matchAndReplace(text, pos, incremental);
+ switch (m) {
+ case U_MATCH:
+ _debugOut("match", rules[i], text, pos);
+ return TRUE;
+ case U_PARTIAL_MATCH:
+ _debugOut("partial match", rules[i], text, pos);
+ return FALSE;
+ default: /* Ram: added default to make GCC happy */
+ break;
+ }
+ }
+ // No match or partial match from any rule
+ pos.start += UTF_CHAR_LENGTH(text.char32At(pos.start));
+ _debugOut("no match", NULL, text, pos);
+ return TRUE;
+}
+
+/**
+ * Create rule strings that represents this rule set.
+ */
+UnicodeString& TransliterationRuleSet::toRules(UnicodeString& ruleSource,
+ UBool escapeUnprintable) const {
+ int32_t i;
+ int32_t count = ruleVector->size();
+ ruleSource.truncate(0);
+ for (i=0; i<count; ++i) {
+ if (i != 0) {
+ ruleSource.append((UChar) 0x000A /*\n*/);
+ }
+ TransliterationRule *r =
+ (TransliterationRule*) ruleVector->elementAt(i);
+ r->toRule(ruleSource, escapeUnprintable);
+ }
+ return ruleSource;
+}
+
+/**
+ * Return the set of all characters that may be modified
+ * (getTarget=false) or emitted (getTarget=true) by this set.
+ */
+UnicodeSet& TransliterationRuleSet::getSourceTargetSet(UnicodeSet& result,
+ UBool getTarget) const
+{
+ result.clear();
+ int32_t count = ruleVector->size();
+ for (int32_t i=0; i<count; ++i) {
+ TransliterationRule* r =
+ (TransliterationRule*) ruleVector->elementAt(i);
+ if (getTarget) {
+ r->addTargetSetTo(result);
+ } else {
+ r->addSourceSetTo(result);
+ }
+ }
+ return result;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbt_set.h b/Build/source/libs/icu/icu-xetex/i18n/rbt_set.h
new file mode 100644
index 00000000000..f92e13002c2
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbt_set.h
@@ -0,0 +1,165 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2007, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+#ifndef RBT_SET_H
+#define RBT_SET_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uobject.h"
+#include "unicode/utrans.h"
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+class Replaceable;
+class TransliterationRule;
+class TransliterationRuleData;
+class UnicodeFilter;
+class UnicodeString;
+class UnicodeSet;
+
+/**
+ * A set of rules for a <code>RuleBasedTransliterator</code>.
+ * @author Alan Liu
+ */
+class TransliterationRuleSet : public UMemory {
+ /**
+ * Vector of rules, in the order added. This is used while the
+ * rule set is getting built. After that, freeze() reorders and
+ * indexes the rules into rules[]. Any given rule is stored once
+ * in ruleVector, and one or more times in rules[]. ruleVector
+ * owns and deletes the rules.
+ */
+ UVector* ruleVector;
+
+ /**
+ * Sorted and indexed table of rules. This is created by freeze()
+ * from the rules in ruleVector. It contains alias pointers to
+ * the rules in ruleVector. It is zero before freeze() is called
+ * and non-zero thereafter.
+ */
+ TransliterationRule** rules;
+
+ /**
+ * Index table. For text having a first character c, compute x = c&0xFF.
+ * Now use rules[index[x]..index[x+1]-1]. This index table is created by
+ * freeze(). Before freeze() is called it contains garbage.
+ */
+ int32_t index[257];
+
+ /**
+ * Length of the longest preceding context
+ */
+ int32_t maxContextLength;
+
+public:
+
+ /**
+ * Construct a new empty rule set.
+ * @param status Output parameter filled in with success or failure status.
+ */
+ TransliterationRuleSet(UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ */
+ TransliterationRuleSet(const TransliterationRuleSet&);
+
+ /**
+ * Destructor.
+ */
+ virtual ~TransliterationRuleSet();
+
+ /**
+ * Change the data object that this rule belongs to. Used
+ * internally by the TransliterationRuleData copy constructor.
+ * @param data the new data value to be set.
+ */
+ void setData(const TransliterationRuleData* data);
+
+ /**
+ * Return the maximum context length.
+ * @return the length of the longest preceding context.
+ */
+ virtual int32_t getMaximumContextLength(void) const;
+
+ /**
+ * Add a rule to this set. Rules are added in order, and order is
+ * significant. The last call to this method must be followed by
+ * a call to <code>freeze()</code> before the rule set is used.
+ * This method must <em>not</em> be called after freeze() has been
+ * called.
+ *
+ * @param adoptedRule the rule to add
+ */
+ virtual void addRule(TransliterationRule* adoptedRule,
+ UErrorCode& status);
+
+ /**
+ * Check this for masked rules and index it to optimize performance.
+ * The sequence of operations is: (1) add rules to a set using
+ * <code>addRule()</code>; (2) freeze the set using
+ * <code>freeze()</code>; (3) use the rule set. If
+ * <code>addRule()</code> is called after calling this method, it
+ * invalidates this object, and this method must be called again.
+ * That is, <code>freeze()</code> may be called multiple times,
+ * although for optimal performance it shouldn't be.
+ * @param parseError A pointer to UParseError to receive information about errors
+ * occurred.
+ * @param status Output parameter filled in with success or failure status.
+ */
+ virtual void freeze(UParseError& parseError, UErrorCode& status);
+
+ /**
+ * Transliterate the given text with the given UTransPosition
+ * indices. Return TRUE if the transliteration should continue
+ * or FALSE if it should halt (because of a U_PARTIAL_MATCH match).
+ * Note that FALSE is only ever returned if isIncremental is TRUE.
+ * @param text the text to be transliterated
+ * @param index the position indices, which will be updated
+ * @param isIncremental if TRUE, assume new text may be inserted
+ * at index.limit, and return FALSE if thre is a partial match.
+ * @return TRUE unless a U_PARTIAL_MATCH has been obtained,
+ * indicating that transliteration should stop until more text
+ * arrives.
+ */
+ UBool transliterate(Replaceable& text,
+ UTransPosition& index,
+ UBool isIncremental);
+
+ /**
+ * Create rule strings that represents this rule set.
+ * @param result string to receive the rule strings. Current
+ * contents will be deleted.
+ * @param escapeUnprintable True, will escape the unprintable characters
+ * @return A reference to 'result'.
+ */
+ virtual UnicodeString& toRules(UnicodeString& result,
+ UBool escapeUnprintable) const;
+
+ /**
+ * Return the set of all characters that may be modified
+ * (getTarget=false) or emitted (getTarget=true) by this set.
+ */
+ UnicodeSet& getSourceTargetSet(UnicodeSet& result,
+ UBool getTarget) const;
+
+private:
+
+ TransliterationRuleSet &operator=(const TransliterationRuleSet &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rbtz.cpp b/Build/source/libs/icu/icu-xetex/i18n/rbtz.cpp
new file mode 100644
index 00000000000..f810d70b841
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rbtz.cpp
@@ -0,0 +1,931 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/rbtz.h"
+#include "unicode/gregocal.h"
+#include "uvector.h"
+#include "gregoimp.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A struct representing a time zone transition
+ */
+struct Transition {
+ UDate time;
+ TimeZoneRule* from;
+ TimeZoneRule* to;
+};
+
+static UBool compareRules(UVector* rules1, UVector* rules2) {
+ if (rules1 == NULL && rules2 == NULL) {
+ return TRUE;
+ } else if (rules1 == NULL || rules2 == NULL) {
+ return FALSE;
+ }
+ int32_t size = rules1->size();
+ if (size != rules2->size()) {
+ return FALSE;
+ }
+ for (int32_t i = 0; i < size; i++) {
+ TimeZoneRule *r1 = (TimeZoneRule*)rules1->elementAt(i);
+ TimeZoneRule *r2 = (TimeZoneRule*)rules2->elementAt(i);
+ if (*r1 != *r2) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone)
+
+RuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString& id, InitialTimeZoneRule* initialRule)
+: BasicTimeZone(id), fInitialRule(initialRule), fHistoricRules(NULL), fFinalRules(NULL),
+ fHistoricTransitions(NULL), fUpToDate(FALSE) {
+}
+
+RuleBasedTimeZone::RuleBasedTimeZone(const RuleBasedTimeZone& source)
+: BasicTimeZone(source), fInitialRule(source.fInitialRule->clone()),
+ fHistoricTransitions(NULL), fUpToDate(FALSE) {
+ fHistoricRules = copyRules(source.fHistoricRules);
+ fFinalRules = copyRules(source.fFinalRules);
+ if (source.fUpToDate) {
+ UErrorCode status = U_ZERO_ERROR;
+ complete(status);
+ }
+}
+
+RuleBasedTimeZone::~RuleBasedTimeZone() {
+ deleteTransitions();
+ deleteRules();
+}
+
+RuleBasedTimeZone&
+RuleBasedTimeZone::operator=(const RuleBasedTimeZone& right) {
+ if (*this != right) {
+ BasicTimeZone::operator=(right);
+ deleteRules();
+ fInitialRule = right.fInitialRule->clone();
+ fHistoricRules = copyRules(right.fHistoricRules);
+ fFinalRules = copyRules(right.fFinalRules);
+ deleteTransitions();
+ fUpToDate = FALSE;
+ }
+ return *this;
+}
+
+UBool
+RuleBasedTimeZone::operator==(const TimeZone& that) const {
+ if (this == &that) {
+ return TRUE;
+ }
+ if (getDynamicClassID() != that.getDynamicClassID()
+ || BasicTimeZone::operator==(that) == FALSE) {
+ return FALSE;
+ }
+ RuleBasedTimeZone *rbtz = (RuleBasedTimeZone*)&that;
+ if (*fInitialRule != *(rbtz->fInitialRule)) {
+ return FALSE;
+ }
+ if (compareRules(fHistoricRules, rbtz->fHistoricRules)
+ && compareRules(fFinalRules, rbtz->fFinalRules)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+RuleBasedTimeZone::operator!=(const TimeZone& that) const {
+ return !operator==(that);
+}
+
+void
+RuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (rule->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()
+ && ((AnnualTimeZoneRule*)rule)->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
+ // A final rule
+ if (fFinalRules == NULL) {
+ fFinalRules = new UVector(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ } else if (fFinalRules->size() >= 2) {
+ // Cannot handle more than two final rules
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ fFinalRules->addElement((void*)rule, status);
+ } else {
+ // Non-final rule
+ if (fHistoricRules == NULL) {
+ fHistoricRules = new UVector(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ fHistoricRules->addElement((void*)rule, status);
+ }
+ // Mark dirty, so transitions are recalculated at next complete() call
+ fUpToDate = FALSE;
+}
+
+void
+RuleBasedTimeZone::complete(UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fUpToDate) {
+ return;
+ }
+ // Make sure either no final rules or a pair of AnnualTimeZoneRules
+ // are available.
+ if (fFinalRules != NULL && fFinalRules->size() != 2) {
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+
+ UBool *done = NULL;
+ // Create a TimezoneTransition and add to the list
+ if (fHistoricRules != NULL || fFinalRules != NULL) {
+ TimeZoneRule *curRule = fInitialRule;
+ UDate lastTransitionTime = MIN_MILLIS;
+
+ // Build the transition array which represents historical time zone
+ // transitions.
+ if (fHistoricRules != NULL && fHistoricRules->size() > 0) {
+ int32_t i;
+ int32_t historicCount = fHistoricRules->size();
+ done = (UBool*)uprv_malloc(sizeof(UBool) * historicCount);
+ if (done == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ for (i = 0; i < historicCount; i++) {
+ done[i] = FALSE;
+ }
+ while (TRUE) {
+ int32_t curStdOffset = curRule->getRawOffset();
+ int32_t curDstSavings = curRule->getDSTSavings();
+ UDate nextTransitionTime = MAX_MILLIS;
+ TimeZoneRule *nextRule = NULL;
+ TimeZoneRule *r = NULL;
+ UBool avail;
+ UDate tt;
+ UnicodeString curName, name;
+ curRule->getName(curName);
+
+ for (i = 0; i < historicCount; i++) {
+ if (done[i]) {
+ continue;
+ }
+ r = (TimeZoneRule*)fHistoricRules->elementAt(i);
+ avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt);
+ if (!avail) {
+ // No more transitions from this rule - skip this rule next time
+ done[i] = TRUE;
+ } else {
+ r->getName(name);
+ if (*r == *curRule ||
+ (name == curName && r->getRawOffset() == curRule->getRawOffset()
+ && r->getDSTSavings() == curRule->getDSTSavings())) {
+ continue;
+ }
+ if (tt < nextTransitionTime) {
+ nextTransitionTime = tt;
+ nextRule = r;
+ }
+ }
+ }
+
+ if (nextRule == NULL) {
+ // Check if all historic rules are done
+ UBool bDoneAll = TRUE;
+ for (int32_t j = 0; j < historicCount; j++) {
+ if (!done[j]) {
+ bDoneAll = FALSE;
+ break;
+ }
+ }
+ if (bDoneAll) {
+ break;
+ }
+ }
+
+ if (fFinalRules != NULL) {
+ // Check if one of final rules has earlier transition date
+ for (i = 0; i < 2 /* fFinalRules->size() */; i++) {
+ TimeZoneRule *fr = (TimeZoneRule*)fFinalRules->elementAt(i);
+ if (*fr == *curRule) {
+ continue;
+ }
+ r = (TimeZoneRule*)fFinalRules->elementAt(i);
+ avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt);
+ if (avail) {
+ if (tt < nextTransitionTime) {
+ nextTransitionTime = tt;
+ nextRule = r;
+ }
+ }
+ }
+ }
+
+ if (nextRule == NULL) {
+ // Nothing more
+ break;
+ }
+
+ if (fHistoricTransitions == NULL) {
+ fHistoricTransitions = new UVector(status);
+ if (U_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
+ Transition *trst = (Transition*)uprv_malloc(sizeof(Transition));
+ if (trst == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ trst->time = nextTransitionTime;
+ trst->from = curRule;
+ trst->to = nextRule;
+ fHistoricTransitions->addElement(trst, status);
+ if (U_FAILURE(status)) {
+ goto cleanup;
+ }
+ lastTransitionTime = nextTransitionTime;
+ curRule = nextRule;
+ }
+ }
+ if (fFinalRules != NULL) {
+ if (fHistoricTransitions == NULL) {
+ fHistoricTransitions = new UVector(status);
+ if (U_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
+ // Append the first transition for each
+ TimeZoneRule *rule0 = (TimeZoneRule*)fFinalRules->elementAt(0);
+ TimeZoneRule *rule1 = (TimeZoneRule*)fFinalRules->elementAt(1);
+ UDate tt0, tt1;
+ UBool avail0 = rule0->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt0);
+ UBool avail1 = rule1->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt1);
+ if (!avail0 || !avail1) {
+ // Should not happen, because both rules are permanent
+ status = U_INVALID_STATE_ERROR;
+ goto cleanup;
+ }
+ Transition *final0 = (Transition*)uprv_malloc(sizeof(Transition));
+ if (final0 == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ Transition *final1 = (Transition*)uprv_malloc(sizeof(Transition));
+ if (final1 == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ if (tt0 < tt1) {
+ final0->time = tt0;
+ final0->from = curRule;
+ final0->to = rule0;
+ rule1->getNextStart(tt0, rule0->getRawOffset(), rule0->getDSTSavings(), false, final1->time);
+ final1->from = rule0;
+ final1->to = rule1;
+ } else {
+ final0->time = tt1;
+ final0->from = curRule;
+ final0->to = rule1;
+ rule0->getNextStart(tt1, rule1->getRawOffset(), rule1->getDSTSavings(), false, final1->time);
+ final1->from = rule1;
+ final1->to = rule0;
+ }
+ fHistoricTransitions->addElement(final0, status);
+ if (U_FAILURE(status)) {
+ goto cleanup;
+ }
+ fHistoricTransitions->addElement(final1, status);
+ if (U_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
+ }
+ fUpToDate = TRUE;
+ if (done != NULL) {
+ uprv_free(done);
+ }
+ return;
+
+cleanup:
+ deleteTransitions();
+ if (done != NULL) {
+ uprv_free(done);
+ }
+ fUpToDate = FALSE;
+}
+
+TimeZone*
+RuleBasedTimeZone::clone(void) const {
+ return new RuleBasedTimeZone(*this);
+}
+
+int32_t
+RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ if (month < UCAL_JANUARY || month > UCAL_DECEMBER) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ } else {
+ return getOffset(era, year, month, day, dayOfWeek, millis,
+ Grego::monthLength(year, month), status);
+ }
+}
+
+int32_t
+RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t /*dayOfWeek*/, int32_t millis,
+ int32_t /*monthLength*/, UErrorCode& status) const {
+ // dayOfWeek and monthLength are unused
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ if (era == GregorianCalendar::BC) {
+ // Convert to extended year
+ year = 1 - year;
+ }
+ int32_t rawOffset, dstOffset;
+ UDate time = (UDate)Grego::fieldsToDay(year, month, day) * U_MILLIS_PER_DAY + millis;
+ getOffsetInternal(time, TRUE, kDaylight, kStandard, rawOffset, dstOffset, status);
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ return (rawOffset + dstOffset);
+}
+
+void
+RuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& status) const {
+ getOffsetInternal(date, local, kFormer, kLatter, rawOffset, dstOffset, status);
+}
+
+void
+RuleBasedTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/ {
+ getOffsetInternal(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, status);
+}
+
+
+/*
+ * The internal getOffset implementation
+ */
+void
+RuleBasedTimeZone::getOffsetInternal(UDate date, UBool local,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
+ int32_t& rawOffset, int32_t& dstOffset,
+ UErrorCode& status) const {
+ rawOffset = 0;
+ dstOffset = 0;
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (!fUpToDate) {
+ // Transitions are not yet resolved. We cannot do it here
+ // because this method is const. Thus, do nothing and return
+ // error status.
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ const TimeZoneRule *rule = NULL;
+ if (fHistoricTransitions == NULL) {
+ rule = fInitialRule;
+ } else {
+ UDate tstart = getTransitionTime((Transition*)fHistoricTransitions->elementAt(0),
+ local, NonExistingTimeOpt, DuplicatedTimeOpt);
+ if (date < tstart) {
+ rule = fInitialRule;
+ } else {
+ int32_t idx = fHistoricTransitions->size() - 1;
+ UDate tend = getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
+ local, NonExistingTimeOpt, DuplicatedTimeOpt);
+ if (date > tend) {
+ if (fFinalRules != NULL) {
+ rule = findRuleInFinal(date, local, NonExistingTimeOpt, DuplicatedTimeOpt);
+ } else {
+ // no final rule, use the last rule
+ rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
+ }
+ } else {
+ // Find a historical transition
+ while (idx >= 0) {
+ if (date >= getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
+ local, NonExistingTimeOpt, DuplicatedTimeOpt)) {
+ break;
+ }
+ idx--;
+ }
+ rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
+ }
+ }
+ }
+ if (rule != NULL) {
+ rawOffset = rule->getRawOffset();
+ dstOffset = rule->getDSTSavings();
+ }
+}
+
+void
+RuleBasedTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
+ // We don't support this operation at this moment.
+ // Nothing to do!
+}
+
+int32_t
+RuleBasedTimeZone::getRawOffset(void) const {
+ // Note: This implementation returns standard GMT offset
+ // as of current time.
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t raw, dst;
+ getOffset(uprv_getUTCtime() * U_MILLIS_PER_SECOND,
+ FALSE, raw, dst, status);
+ return raw;
+}
+
+UBool
+RuleBasedTimeZone::useDaylightTime(void) const {
+ // Note: This implementation returns true when
+ // daylight saving time is used as of now or
+ // after the next transition.
+ UErrorCode status = U_ZERO_ERROR;
+ UDate now = uprv_getUTCtime() * U_MILLIS_PER_SECOND;
+ int32_t raw, dst;
+ getOffset(now, FALSE, raw, dst, status);
+ if (dst != 0) {
+ return TRUE;
+ }
+ // If DST is not used now, check if DST is used after the next transition
+ UDate time;
+ TimeZoneRule *from, *to;
+ UBool avail = findNext(now, FALSE, time, from, to);
+ if (avail && to->getDSTSavings() != 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+RuleBasedTimeZone::inDaylightTime(UDate date, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ int32_t raw, dst;
+ getOffset(date, FALSE, raw, dst, status);
+ if (dst != 0) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+RuleBasedTimeZone::hasSameRules(const TimeZone& other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ if (getDynamicClassID() != other.getDynamicClassID()) {
+ return FALSE;
+ }
+ const RuleBasedTimeZone& that = (const RuleBasedTimeZone&)other;
+ if (*fInitialRule != *(that.fInitialRule)) {
+ return FALSE;
+ }
+ if (compareRules(fHistoricRules, that.fHistoricRules)
+ && compareRules(fFinalRules, that.fFinalRules)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+RuleBasedTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+ UErrorCode status = U_ZERO_ERROR;
+ complete(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ UDate transitionTime;
+ TimeZoneRule *fromRule, *toRule;
+ UBool found = findNext(base, inclusive, transitionTime, fromRule, toRule);
+ if (found) {
+ result.setTime(transitionTime);
+ result.setFrom((const TimeZoneRule&)*fromRule);
+ result.setTo((const TimeZoneRule&)*toRule);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+RuleBasedTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+ UErrorCode status = U_ZERO_ERROR;
+ complete(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ UDate transitionTime;
+ TimeZoneRule *fromRule, *toRule;
+ UBool found = findPrev(base, inclusive, transitionTime, fromRule, toRule);
+ if (found) {
+ result.setTime(transitionTime);
+ result.setFrom((const TimeZoneRule&)*fromRule);
+ result.setTo((const TimeZoneRule&)*toRule);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int32_t
+RuleBasedTimeZone::countTransitionRules(UErrorCode& /*status*/) /*const*/ {
+ int32_t count = 0;
+ if (fHistoricRules != NULL) {
+ count += fHistoricRules->size();
+ }
+ if (fFinalRules != NULL) {
+ count += fFinalRules->size();
+ }
+ return count;
+}
+
+void
+RuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[],
+ int32_t& trscount,
+ UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // Initial rule
+ initial = fInitialRule;
+
+ // Transition rules
+ int32_t cnt = 0;
+ int32_t idx;
+ if (fHistoricRules != NULL && cnt < trscount) {
+ int32_t historicCount = fHistoricRules->size();
+ idx = 0;
+ while (cnt < trscount && idx < historicCount) {
+ trsrules[cnt++] = (const TimeZoneRule*)fHistoricRules->elementAt(idx++);
+ }
+ }
+ if (fFinalRules != NULL && cnt < trscount) {
+ int32_t finalCount = fFinalRules->size();
+ idx = 0;
+ while (cnt < trscount && idx < finalCount) {
+ trsrules[cnt++] = (const TimeZoneRule*)fFinalRules->elementAt(idx++);
+ }
+ }
+ // Set the result length
+ trscount = cnt;
+}
+
+void
+RuleBasedTimeZone::deleteRules(void) {
+ delete fInitialRule;
+ fInitialRule = NULL;
+ if (fHistoricRules != NULL) {
+ while (!fHistoricRules->isEmpty()) {
+ delete (TimeZoneRule*)(fHistoricRules->orphanElementAt(0));
+ }
+ delete fHistoricRules;
+ fHistoricRules = NULL;
+ }
+ if (fFinalRules != NULL) {
+ while (!fFinalRules->isEmpty()) {
+ delete (AnnualTimeZoneRule*)(fFinalRules->orphanElementAt(0));
+ }
+ delete fFinalRules;
+ fFinalRules = NULL;
+ }
+}
+
+void
+RuleBasedTimeZone::deleteTransitions(void) {
+ if (fHistoricTransitions != NULL) {
+ while (!fHistoricTransitions->isEmpty()) {
+ Transition *trs = (Transition*)fHistoricTransitions->orphanElementAt(0);
+ uprv_free(trs);
+ }
+ delete fHistoricTransitions;
+ }
+ fHistoricTransitions = NULL;
+}
+
+UVector*
+RuleBasedTimeZone::copyRules(UVector* source) {
+ if (source == NULL) {
+ return NULL;
+ }
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t size = source->size();
+ UVector *rules = new UVector(size, ec);
+ if (U_FAILURE(ec)) {
+ return NULL;
+ }
+ int32_t i;
+ for (i = 0; i < size; i++) {
+ rules->addElement(((TimeZoneRule*)source->elementAt(i))->clone(), ec);
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ }
+ if (U_FAILURE(ec)) {
+ // In case of error, clean up
+ for (i = 0; i < rules->size(); i++) {
+ TimeZoneRule *rule = (TimeZoneRule*)rules->orphanElementAt(i);
+ delete rule;
+ }
+ delete rules;
+ return NULL;
+ }
+ return rules;
+}
+
+TimeZoneRule*
+RuleBasedTimeZone::findRuleInFinal(UDate date, UBool local,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
+ if (fFinalRules == NULL) {
+ return NULL;
+ }
+
+ AnnualTimeZoneRule* fr0 = (AnnualTimeZoneRule*)fFinalRules->elementAt(0);
+ AnnualTimeZoneRule* fr1 = (AnnualTimeZoneRule*)fFinalRules->elementAt(1);
+ if (fr0 == NULL || fr1 == NULL) {
+ return NULL;
+ }
+
+ UDate start0, start1;
+ UDate base;
+ int32_t localDelta;
+
+ base = date;
+ if (local) {
+ localDelta = getLocalDelta(fr1->getRawOffset(), fr1->getDSTSavings(),
+ fr0->getRawOffset(), fr0->getDSTSavings(),
+ NonExistingTimeOpt, DuplicatedTimeOpt);
+ base -= localDelta;
+ }
+ UBool avail0 = fr0->getPreviousStart(base, fr1->getRawOffset(), fr1->getDSTSavings(), TRUE, start0);
+
+ base = date;
+ if (local) {
+ localDelta = getLocalDelta(fr0->getRawOffset(), fr0->getDSTSavings(),
+ fr1->getRawOffset(), fr1->getDSTSavings(),
+ NonExistingTimeOpt, DuplicatedTimeOpt);
+ base -= localDelta;
+ }
+ UBool avail1 = fr1->getPreviousStart(base, fr0->getRawOffset(), fr0->getDSTSavings(), TRUE, start1);
+
+ if (avail0 && (!avail1 || start0 > start1)) {
+ return fr0;
+ } else if (avail1) {
+ return fr1;
+ }
+ return NULL;
+}
+
+UBool
+RuleBasedTimeZone::findNext(UDate base, UBool inclusive, UDate& transitionTime,
+ TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const {
+ if (fHistoricTransitions == NULL) {
+ return FALSE;
+ }
+ UBool isFinal = FALSE;
+ UBool found = FALSE;
+ Transition result;
+ Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
+ UDate tt = tzt->time;
+ if (tt > base || (inclusive && tt == base)) {
+ result = *tzt;
+ found = TRUE;
+ } else {
+ int32_t idx = fHistoricTransitions->size() - 1;
+ tzt = (Transition*)fHistoricTransitions->elementAt(idx);
+ tt = tzt->time;
+ if (inclusive && tt == base) {
+ result = *tzt;
+ found = TRUE;
+ } else if (tt <= base) {
+ if (fFinalRules != NULL) {
+ // Find a transion time with finalRules
+ TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0);
+ TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1);
+ UDate start0, start1;
+ UBool avail0 = r0->getNextStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0);
+ UBool avail1 = r1->getNextStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1);
+ // avail0/avail1 should be always TRUE
+ if (!avail0 && !avail1) {
+ return FALSE;
+ }
+ if (!avail1 || start0 < start1) {
+ result.time = start0;
+ result.from = r1;
+ result.to = r0;
+ } else {
+ result.time = start1;
+ result.from = r0;
+ result.to = r1;
+ }
+ isFinal = TRUE;
+ found = TRUE;
+ }
+ } else {
+ // Find a transition within the historic transitions
+ idx--;
+ Transition *prev = tzt;
+ while (idx > 0) {
+ tzt = (Transition*)fHistoricTransitions->elementAt(idx);
+ tt = tzt->time;
+ if (tt < base || (!inclusive && tt == base)) {
+ break;
+ }
+ idx--;
+ prev = tzt;
+ }
+ result.time = prev->time;
+ result.from = prev->from;
+ result.to = prev->to;
+ found = TRUE;
+ }
+ }
+ if (found) {
+ // For now, this implementation ignore transitions with only zone name changes.
+ if (result.from->getRawOffset() == result.to->getRawOffset()
+ && result.from->getDSTSavings() == result.to->getDSTSavings()) {
+ if (isFinal) {
+ return FALSE;
+ } else {
+ // No offset changes. Try next one if not final
+ return findNext(result.time, FALSE /* always exclusive */,
+ transitionTime, fromRule, toRule);
+ }
+ }
+ transitionTime = result.time;
+ fromRule = result.from;
+ toRule = result.to;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+RuleBasedTimeZone::findPrev(UDate base, UBool inclusive, UDate& transitionTime,
+ TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const {
+ if (fHistoricTransitions == NULL) {
+ return FALSE;
+ }
+ UBool found = FALSE;
+ Transition result;
+ Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
+ UDate tt = tzt->time;
+ if (inclusive && tt == base) {
+ result = *tzt;
+ found = TRUE;
+ } else if (tt < base) {
+ int32_t idx = fHistoricTransitions->size() - 1;
+ tzt = (Transition*)fHistoricTransitions->elementAt(idx);
+ tt = tzt->time;
+ if (inclusive && tt == base) {
+ result = *tzt;
+ found = TRUE;
+ } else if (tt < base) {
+ if (fFinalRules != NULL) {
+ // Find a transion time with finalRules
+ TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0);
+ TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1);
+ UDate start0, start1;
+ UBool avail0 = r0->getPreviousStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0);
+ UBool avail1 = r1->getPreviousStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1);
+ // avail0/avail1 should be always TRUE
+ if (!avail0 && !avail1) {
+ return FALSE;
+ }
+ if (!avail1 || start0 > start1) {
+ result.time = start0;
+ result.from = r1;
+ result.to = r0;
+ } else {
+ result.time = start1;
+ result.from = r0;
+ result.to = r1;
+ }
+ } else {
+ result = *tzt;
+ }
+ found = TRUE;
+ } else {
+ // Find a transition within the historic transitions
+ idx--;
+ while (idx >= 0) {
+ tzt = (Transition*)fHistoricTransitions->elementAt(idx);
+ tt = tzt->time;
+ if (tt < base || (inclusive && tt == base)) {
+ break;
+ }
+ idx--;
+ }
+ result = *tzt;
+ found = TRUE;
+ }
+ }
+ if (found) {
+ // For now, this implementation ignore transitions with only zone name changes.
+ if (result.from->getRawOffset() == result.to->getRawOffset()
+ && result.from->getDSTSavings() == result.to->getDSTSavings()) {
+ // No offset changes. Try next one if not final
+ return findPrev(result.time, FALSE /* always exclusive */,
+ transitionTime, fromRule, toRule);
+ }
+ transitionTime = result.time;
+ fromRule = result.from;
+ toRule = result.to;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UDate
+RuleBasedTimeZone::getTransitionTime(Transition* transition, UBool local,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
+ UDate time = transition->time;
+ if (local) {
+ time += getLocalDelta(transition->from->getRawOffset(), transition->from->getDSTSavings(),
+ transition->to->getRawOffset(), transition->to->getDSTSavings(),
+ NonExistingTimeOpt, DuplicatedTimeOpt);
+ }
+ return time;
+}
+
+int32_t
+RuleBasedTimeZone::getLocalDelta(int32_t rawBefore, int32_t dstBefore, int32_t rawAfter, int32_t dstAfter,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
+ int32_t delta = 0;
+
+ int32_t offsetBefore = rawBefore + dstBefore;
+ int32_t offsetAfter = rawAfter + dstAfter;
+
+ UBool dstToStd = (dstBefore != 0) && (dstAfter == 0);
+ UBool stdToDst = (dstBefore == 0) && (dstAfter != 0);
+
+ if (offsetAfter - offsetBefore >= 0) {
+ // Positive transition, which makes a non-existing local time range
+ if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
+ || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
+ delta = offsetBefore;
+ } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
+ || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
+ delta = offsetAfter;
+ } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
+ delta = offsetBefore;
+ } else {
+ // Interprets the time with rule before the transition,
+ // default for non-existing time range
+ delta = offsetAfter;
+ }
+ } else {
+ // Negative transition, which makes a duplicated local time range
+ if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
+ || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
+ delta = offsetAfter;
+ } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
+ || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
+ delta = offsetBefore;
+ } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
+ delta = offsetBefore;
+ } else {
+ // Interprets the time with rule after the transition,
+ // default for duplicated local time range
+ delta = offsetAfter;
+ }
+ }
+ return delta;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/regexcmp.cpp b/Build/source/libs/icu/icu-xetex/i18n/regexcmp.cpp
new file mode 100644
index 00000000000..558f80b6c48
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/regexcmp.cpp
@@ -0,0 +1,3529 @@
+
+//
+// file: regexcmp.cpp
+//
+// Copyright (C) 2002-2007 International Business Machines Corporation and others.
+// All Rights Reserved.
+//
+// This file contains the ICU regular expression compiler, which is responsible
+// for processing a regular expression pattern into the compiled form that
+// is used by the match finding engine.
+//
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#include "unicode/uchar.h"
+#include "unicode/uchriter.h"
+#include "unicode/parsepos.h"
+#include "unicode/parseerr.h"
+#include "unicode/regex.h"
+#include "util.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uvectr32.h"
+#include "uassert.h"
+#include "ucln_in.h"
+
+#include "regeximp.h"
+#include "regexcst.h" // Contains state table for the regex pattern parser.
+ // generated by a Perl script.
+#include "regexcmp.h"
+#include "regexst.h"
+
+
+
+U_NAMESPACE_BEGIN
+
+
+
+
+
+//------------------------------------------------------------------------------
+//
+// Constructor.
+//
+//------------------------------------------------------------------------------
+RegexCompile::RegexCompile(RegexPattern *rxp, UErrorCode &status) : fParenStack(status)
+{
+ fStatus = &status;
+
+ fRXPat = rxp;
+ fScanIndex = 0;
+ fNextIndex = 0;
+ fPeekChar = -1;
+ fLineNum = 1;
+ fCharNum = 0;
+ fQuoteMode = FALSE;
+ fInBackslashQuote = FALSE;
+ fModeFlags = fRXPat->fFlags | 0x80000000;
+ fEOLComments = TRUE;
+
+ fMatchOpenParen = -1;
+ fMatchCloseParen = -1;
+ fStringOpStart = -1;
+
+ if (U_SUCCESS(status) && U_FAILURE(rxp->fDeferredStatus)) {
+ status = rxp->fDeferredStatus;
+ }
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// Destructor
+//
+//------------------------------------------------------------------------------
+RegexCompile::~RegexCompile() {
+}
+
+//------------------------------------------------------------------------------
+//
+// Compile regex pattern. The state machine for rexexp pattern parsing is here.
+// The state tables are hand-written in the file regexcst.txt,
+// and converted to the form used here by a perl
+// script regexcst.pl
+//
+//------------------------------------------------------------------------------
+void RegexCompile::compile(
+ const UnicodeString &pat, // Source pat to be compiled.
+ UParseError &pp, // Error position info
+ UErrorCode &e) // Error Code
+{
+ fStatus = &e;
+ fParseErr = &pp;
+ fStackPtr = 0;
+ fStack[fStackPtr] = 0;
+
+ if (U_FAILURE(*fStatus)) {
+ return;
+ }
+
+ // There should be no pattern stuff in the RegexPattern object. They can not be reused.
+ U_ASSERT(fRXPat->fPattern.length() == 0);
+
+ // Prepare the RegexPattern object to receive the compiled pattern.
+ // TODO: remove per-instance field, and just use globals directly. (But check perf)
+ fRXPat->fPattern = pat;
+ fRXPat->fStaticSets = RegexStaticSets::gStaticSets->fPropSets;
+ fRXPat->fStaticSets8 = RegexStaticSets::gStaticSets->fPropSets8;
+
+
+ // Initialize the pattern scanning state machine
+ fPatternLength = pat.length();
+ uint16_t state = 1;
+ const RegexTableEl *tableEl;
+ nextChar(fC); // Fetch the first char from the pattern string.
+
+ //
+ // Main loop for the regex pattern parsing state machine.
+ // Runs once per state transition.
+ // Each time through optionally performs, depending on the state table,
+ // - an advance to the the next pattern char
+ // - an action to be performed.
+ // - pushing or popping a state to/from the local state return stack.
+ // file regexcst.txt is the source for the state table. The logic behind
+ // recongizing the pattern syntax is there, not here.
+ //
+ for (;;) {
+ // Bail out if anything has gone wrong.
+ // Regex pattern parsing stops on the first error encountered.
+ if (U_FAILURE(*fStatus)) {
+ break;
+ }
+
+ U_ASSERT(state != 0);
+
+ // Find the state table element that matches the input char from the pattern, or the
+ // class of the input character. Start with the first table row for this
+ // state, then linearly scan forward until we find a row that matches the
+ // character. The last row for each state always matches all characters, so
+ // the search will stop there, if not before.
+ //
+ tableEl = &gRuleParseStateTable[state];
+ REGEX_SCAN_DEBUG_PRINTF(("char, line, col = (\'%c\', %d, %d) state=%s ",
+ fC.fChar, fLineNum, fCharNum, RegexStateNames[state]));
+
+ for (;;) { // loop through table rows belonging to this state, looking for one
+ // that matches the current input char.
+ REGEX_SCAN_DEBUG_PRINTF(("."));
+ if (tableEl->fCharClass < 127 && fC.fQuoted == FALSE && tableEl->fCharClass == fC.fChar) {
+ // Table row specified an individual character, not a set, and
+ // the input character is not quoted, and
+ // the input character matched it.
+ break;
+ }
+ if (tableEl->fCharClass == 255) {
+ // Table row specified default, match anything character class.
+ break;
+ }
+ if (tableEl->fCharClass == 254 && fC.fQuoted) {
+ // Table row specified "quoted" and the char was quoted.
+ break;
+ }
+ if (tableEl->fCharClass == 253 && fC.fChar == (UChar32)-1) {
+ // Table row specified eof and we hit eof on the input.
+ break;
+ }
+
+ if (tableEl->fCharClass >= 128 && tableEl->fCharClass < 240 && // Table specs a char class &&
+ fC.fQuoted == FALSE && // char is not escaped &&
+ fC.fChar != (UChar32)-1) { // char is not EOF
+ UnicodeSet *uniset = RegexStaticSets::gStaticSets->fRuleSets[tableEl->fCharClass-128];
+ if (uniset->contains(fC.fChar)) {
+ // Table row specified a character class, or set of characters,
+ // and the current char matches it.
+ break;
+ }
+ }
+
+ // No match on this row, advance to the next row for this state,
+ tableEl++;
+ }
+ REGEX_SCAN_DEBUG_PRINTF(("\n"));
+
+ //
+ // We've found the row of the state table that matches the current input
+ // character from the rules string.
+ // Perform any action specified by this row in the state table.
+ if (doParseActions(tableEl->fAction) == FALSE) {
+ // Break out of the state machine loop if the
+ // the action signalled some kind of error, or
+ // the action was to exit, occurs on normal end-of-rules-input.
+ break;
+ }
+
+ if (tableEl->fPushState != 0) {
+ fStackPtr++;
+ if (fStackPtr >= kStackSize) {
+ error(U_REGEX_INTERNAL_ERROR);
+ REGEX_SCAN_DEBUG_PRINTF(("RegexCompile::parse() - state stack overflow.\n"));
+ fStackPtr--;
+ }
+ fStack[fStackPtr] = tableEl->fPushState;
+ }
+
+ //
+ // NextChar. This is where characters are actually fetched from the pattern.
+ // Happens under control of the 'n' tag in the state table.
+ //
+ if (tableEl->fNextChar) {
+ nextChar(fC);
+ }
+
+ // Get the next state from the table entry, or from the
+ // state stack if the next state was specified as "pop".
+ if (tableEl->fNextState != 255) {
+ state = tableEl->fNextState;
+ } else {
+ state = fStack[fStackPtr];
+ fStackPtr--;
+ if (fStackPtr < 0) {
+ // state stack underflow
+ // This will occur if the user pattern has mis-matched parentheses,
+ // with extra close parens.
+ //
+ fStackPtr++;
+ error(U_REGEX_MISMATCHED_PAREN);
+ }
+ }
+
+ }
+
+ //
+ // The pattern has now been read and processed, and the compiled code generated.
+ //
+
+ // Back-reference fixup
+ //
+ int32_t loc;
+ for (loc=0; loc<fRXPat->fCompiledPat->size(); loc++) {
+ int32_t op = fRXPat->fCompiledPat->elementAti(loc);
+ int32_t opType = URX_TYPE(op);
+ if (opType == URX_BACKREF || opType == URX_BACKREF_I) {
+ int32_t where = URX_VAL(op);
+ if (where > fRXPat->fGroupMap->size()) {
+ error(U_REGEX_INVALID_BACK_REF);
+ break;
+ }
+ where = fRXPat->fGroupMap->elementAti(where-1);
+ op = URX_BUILD(opType, where);
+ fRXPat->fCompiledPat->setElementAt(op, loc);
+ }
+ }
+
+
+ //
+ // Compute the number of digits requried for the largest capture group number.
+ //
+ fRXPat->fMaxCaptureDigits = 1;
+ int32_t n = 10;
+ for (;;) {
+ if (n > fRXPat->fGroupMap->size()) {
+ break;
+ }
+ fRXPat->fMaxCaptureDigits++;
+ n *= 10;
+ }
+
+ //
+ // The pattern's fFrameSize so far has accumulated the requirements for
+ // storage for capture parentheses, counters, etc. that are encountered
+ // in the pattern. Add space for the two variables that are always
+ // present in the saved state: the input string position and the
+ // position in the compiled pattern.
+ //
+ fRXPat->fFrameSize+=2;
+
+ //
+ // Get bounds for the minimum and maximum length of a string that this
+ // pattern can match. Used to avoid looking for matches in strings that
+ // are too short.
+ //
+ fRXPat->fMinMatchLen = minMatchLength(3, fRXPat->fCompiledPat->size()-1);
+
+ //
+ // Optimization passes
+ //
+ matchStartType();
+ OptDotStar();
+ stripNOPs();
+
+ //
+ // Set up fast latin-1 range sets
+ //
+ int32_t numSets = fRXPat->fSets->size();
+ fRXPat->fSets8 = new Regex8BitSet[numSets];
+ int32_t i;
+ for (i=0; i<numSets; i++) {
+ UnicodeSet *s = (UnicodeSet *)fRXPat->fSets->elementAt(i);
+ fRXPat->fSets8[i].init(s);
+ }
+
+}
+
+
+
+
+
+//------------------------------------------------------------------------------
+//
+// doParseAction Do some action during regex pattern parsing.
+// Called by the parse state machine.
+//
+// Generation of the match engine PCode happens here, or
+// in functions called from the parse actions defined here.
+//
+//
+//------------------------------------------------------------------------------
+UBool RegexCompile::doParseActions(int32_t action)
+{
+ UBool returnVal = TRUE;
+
+ switch ((Regex_PatternParseAction)action) {
+
+ case doPatStart:
+ // Start of pattern compiles to:
+ //0 SAVE 2 Fall back to position of FAIL
+ //1 jmp 3
+ //2 FAIL Stop if we ever reach here.
+ //3 NOP Dummy, so start of pattern looks the same as
+ // the start of an ( grouping.
+ //4 NOP Resreved, will be replaced by a save if there are
+ // OR | operators at the top level
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_STATE_SAVE, 2), *fStatus);
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_JMP, 3), *fStatus);
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_FAIL, 0), *fStatus);
+
+ // Standard open nonCapture paren action emits the two NOPs and
+ // sets up the paren stack frame.
+ doParseActions(doOpenNonCaptureParen);
+ break;
+
+ case doPatFinish:
+ // We've scanned to the end of the pattern
+ // The end of pattern compiles to:
+ // URX_END
+ // which will stop the runtime match engine.
+ // Encountering end of pattern also behaves like a close paren,
+ // and forces fixups of the State Save at the beginning of the compiled pattern
+ // and of any OR operations at the top level.
+ //
+ handleCloseParen();
+ if (fParenStack.size() > 0) {
+ // Missing close paren in pattern.
+ error(U_REGEX_MISMATCHED_PAREN);
+ }
+
+ // add the END operation to the compiled pattern.
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_END, 0), *fStatus);
+
+ // Terminate the pattern compilation state machine.
+ returnVal = FALSE;
+ break;
+
+
+
+ case doOrOperator:
+ // Scanning a '|', as in (A|B)
+ {
+ // Insert a SAVE operation at the start of the pattern section preceding
+ // this OR at this level. This SAVE will branch the match forward
+ // to the right hand side of the OR in the event that the left hand
+ // side fails to match and backtracks. Locate the position for the
+ // save from the location on the top of the parentheses stack.
+ int32_t savePosition = fParenStack.popi();
+ int32_t op = fRXPat->fCompiledPat->elementAti(savePosition);
+ U_ASSERT(URX_TYPE(op) == URX_NOP); // original contents of reserved location
+ op = URX_BUILD(URX_STATE_SAVE, fRXPat->fCompiledPat->size()+1);
+ fRXPat->fCompiledPat->setElementAt(op, savePosition);
+
+ // Append an JMP operation into the compiled pattern. The operand for
+ // the JMP will eventually be the location following the ')' for the
+ // group. This will be patched in later, when the ')' is encountered.
+ op = URX_BUILD(URX_JMP, 0);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Push the position of the newly added JMP op onto the parentheses stack.
+ // This registers if for fixup when this block's close paren is encountered.
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);
+
+ // Append a NOP to the compiled pattern. This is the slot reserved
+ // for a SAVE in the event that there is yet another '|' following
+ // this one.
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);
+ }
+ break;
+
+
+ case doOpenCaptureParen:
+ // Open Paren.
+ // Compile to a
+ // - NOP, which later may be replaced by a save-state if the
+ // parenthesized group gets a * quantifier, followed by
+ // - START_CAPTURE n where n is stack frame offset to the capture group variables.
+ // - NOP, which may later be replaced by a save-state if there
+ // is an '|' alternation within the parens.
+ //
+ // Each capture group gets three slots in the save stack frame:
+ // 0: Capture Group start position (in input string being matched.)
+ // 1: Capture Group end positino.
+ // 2: Start of Match-in-progress.
+ // The first two locations are for a completed capture group, and are
+ // referred to by back references and the like.
+ // The third location stores the capture start position when an START_CAPTURE is
+ // encountered. This will be promoted to a completed capture when (and if) the corresponding
+ // END_CAPure is encountered.
+ {
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
+ int32_t varsLoc = fRXPat->fFrameSize; // Reserve three slots in match stack frame.
+ fRXPat->fFrameSize += 3;
+ int32_t cop = URX_BUILD(URX_START_CAPTURE, varsLoc);
+ fRXPat->fCompiledPat->addElement(cop, *fStatus);
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
+
+ // On the Parentheses stack, start a new frame and add the postions
+ // of the two NOPs. Depending on what follows in the pattern, the
+ // NOPs may be changed to SAVE_STATE or JMP ops, with a target
+ // address of the end of the parenthesized group.
+ fParenStack.push(fModeFlags, *fStatus); // Match mode state
+ fParenStack.push(capturing, *fStatus); // Frame type.
+ fParenStack.push(fRXPat->fCompiledPat->size()-3, *fStatus); // The first NOP location
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus); // The second NOP loc
+
+ // Save the mapping from group number to stack frame variable position.
+ fRXPat->fGroupMap->addElement(varsLoc, *fStatus);
+ }
+ break;
+
+ case doOpenNonCaptureParen:
+ // Open non-caputuring (grouping only) Paren.
+ // Compile to a
+ // - NOP, which later may be replaced by a save-state if the
+ // parenthesized group gets a * quantifier, followed by
+ // - NOP, which may later be replaced by a save-state if there
+ // is an '|' alternation within the parens.
+ {
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
+
+ // On the Parentheses stack, start a new frame and add the postions
+ // of the two NOPs.
+ fParenStack.push(fModeFlags, *fStatus); // Match mode state
+ fParenStack.push(plain, *fStatus); // Begin a new frame.
+ fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus); // The first NOP location
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus); // The second NOP loc
+ }
+ break;
+
+
+ case doOpenAtomicParen:
+ // Open Atomic Paren. (?>
+ // Compile to a
+ // - NOP, which later may be replaced if the parenthesized group
+ // has a quantifier, followed by
+ // - STO_SP save state stack position, so it can be restored at the ")"
+ // - NOP, which may later be replaced by a save-state if there
+ // is an '|' alternation within the parens.
+ {
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
+ int32_t varLoc = fRXPat->fDataSize; // Reserve a data location for saving the
+ fRXPat->fDataSize += 1; // state stack ptr.
+ int32_t stoOp = URX_BUILD(URX_STO_SP, varLoc);
+ fRXPat->fCompiledPat->addElement(stoOp, *fStatus);
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
+
+ // On the Parentheses stack, start a new frame and add the postions
+ // of the two NOPs. Depending on what follows in the pattern, the
+ // NOPs may be changed to SAVE_STATE or JMP ops, with a target
+ // address of the end of the parenthesized group.
+ fParenStack.push(fModeFlags, *fStatus); // Match mode state
+ fParenStack.push(atomic, *fStatus); // Frame type.
+ fParenStack.push(fRXPat->fCompiledPat->size()-3, *fStatus); // The first NOP
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus); // The second NOP
+ }
+ break;
+
+
+ case doOpenLookAhead:
+ // Positive Look-ahead (?= stuff )
+ // Compiles to
+ // 1 START_LA dataLoc
+ // 2. NOP reserved for use by quantifiers on the block.
+ // Look-ahead can't have quantifiers, but paren stack
+ // compile time conventions require the slot anyhow.
+ // 3. NOP may be replaced if there is are '|' ops in the block.
+ // 4. code for parenthesized stuff.
+ // 5. ENDLA
+ //
+ // Two data slots are reserved, for saving the stack ptr and the input position.
+ {
+ int32_t dataLoc = fRXPat->fDataSize;
+ fRXPat->fDataSize += 2;
+ int32_t op = URX_BUILD(URX_LA_START, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ op = URX_BUILD(URX_NOP, 0);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // On the Parentheses stack, start a new frame and add the postions
+ // of the NOPs.
+ fParenStack.push(fModeFlags, *fStatus); // Match mode state
+ fParenStack.push(lookAhead, *fStatus); // Frame type.
+ fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus); // The first NOP location
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus); // The second NOP location
+ }
+ break;
+
+ case doOpenLookAheadNeg:
+ // Negated Lookahead. (?! stuff )
+ // Compiles to
+ // 1. START_LA dataloc
+ // 2. SAVE_STATE 7 // Fail within look-ahead block restores to this state,
+ // // which continues with the match.
+ // 3. NOP // Std. Open Paren sequence, for possible '|'
+ // 4. code for parenthesized stuff.
+ // 5. END_LA // Cut back stack, remove saved state from step 2.
+ // 6. FAIL // code in block succeeded, so neg. lookahead fails.
+ // 7. ...
+ {
+ int32_t dataLoc = fRXPat->fDataSize;
+ fRXPat->fDataSize += 2;
+ int32_t op = URX_BUILD(URX_LA_START, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ op = URX_BUILD(URX_STATE_SAVE, 0); // dest address will be patched later.
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ op = URX_BUILD(URX_NOP, 0);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // On the Parentheses stack, start a new frame and add the postions
+ // of the StateSave and NOP.
+ fParenStack.push(fModeFlags, *fStatus); // Match mode state
+ fParenStack.push( negLookAhead, *fStatus); // Frame type
+ fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus); // The STATE_SAVE location
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus); // The second NOP location
+
+ // Instructions #5 and #6 will be added when the ')' is encountered.
+ }
+ break;
+
+ case doOpenLookBehind:
+ {
+ // Compile a (?<= look-behind open paren.
+ //
+ // Compiles to
+ // 0 URX_LB_START dataLoc
+ // 1 URX_LB_CONT dataLoc
+ // 2 MinMatchLen
+ // 3 MaxMatchLen
+ // 4 URX_NOP Standard '(' boilerplate.
+ // 5 URX_NOP Reserved slot for use with '|' ops within (block).
+ // 6 <code for LookBehind expression>
+ // 7 URX_LB_END dataLoc # Check match len, restore input len
+ // 8 URX_LA_END dataLoc # Restore stack, input pos
+ //
+ // Allocate a block of matcher data, to contain (when running a match)
+ // 0: Stack ptr on entry
+ // 1: Input Index on entry
+ // 2: Start index of match current match attempt.
+ // 3: Original Input String len.
+
+ // Allocate data space
+ int32_t dataLoc = fRXPat->fDataSize;
+ fRXPat->fDataSize += 4;
+
+ // Emit URX_LB_START
+ int32_t op = URX_BUILD(URX_LB_START, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Emit URX_LB_CONT
+ op = URX_BUILD(URX_LB_CONT, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ fRXPat->fCompiledPat->addElement(0, *fStatus); // MinMatchLength. To be filled later.
+ fRXPat->fCompiledPat->addElement(0, *fStatus); // MaxMatchLength. To be filled later.
+
+ // Emit the NOP
+ op = URX_BUILD(URX_NOP, 0);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // On the Parentheses stack, start a new frame and add the postions
+ // of the URX_LB_CONT and the NOP.
+ fParenStack.push(fModeFlags, *fStatus); // Match mode state
+ fParenStack.push(lookBehind, *fStatus); // Frame type
+ fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus); // The first NOP location
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus); // The 2nd NOP location
+
+ // The final two instructions will be added when the ')' is encountered.
+ }
+
+ break;
+
+ case doOpenLookBehindNeg:
+ {
+ // Compile a (?<! negated look-behind open paren.
+ //
+ // Compiles to
+ // 0 URX_LB_START dataLoc # Save entry stack, input len
+ // 1 URX_LBN_CONT dataLoc # Iterate possible match positions
+ // 2 MinMatchLen
+ // 3 MaxMatchLen
+ // 4 continueLoc (9)
+ // 5 URX_NOP Standard '(' boilerplate.
+ // 6 URX_NOP Reserved slot for use with '|' ops within (block).
+ // 7 <code for LookBehind expression>
+ // 8 URX_LBN_END dataLoc # Check match len, cause a FAIL
+ // 9 ...
+ //
+ // Allocate a block of matcher data, to contain (when running a match)
+ // 0: Stack ptr on entry
+ // 1: Input Index on entry
+ // 2: Start index of match current match attempt.
+ // 3: Original Input String len.
+
+ // Allocate data space
+ int32_t dataLoc = fRXPat->fDataSize;
+ fRXPat->fDataSize += 4;
+
+ // Emit URX_LB_START
+ int32_t op = URX_BUILD(URX_LB_START, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Emit URX_LBN_CONT
+ op = URX_BUILD(URX_LBN_CONT, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ fRXPat->fCompiledPat->addElement(0, *fStatus); // MinMatchLength. To be filled later.
+ fRXPat->fCompiledPat->addElement(0, *fStatus); // MaxMatchLength. To be filled later.
+ fRXPat->fCompiledPat->addElement(0, *fStatus); // Continue Loc. To be filled later.
+
+ // Emit the NOP
+ op = URX_BUILD(URX_NOP, 0);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // On the Parentheses stack, start a new frame and add the postions
+ // of the URX_LB_CONT and the NOP.
+ fParenStack.push(fModeFlags, *fStatus); // Match mode state
+ fParenStack.push(lookBehindN, *fStatus); // Frame type
+ fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus); // The first NOP location
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus); // The 2nd NOP location
+
+ // The final two instructions will be added when the ')' is encountered.
+ }
+ break;
+
+ case doConditionalExpr:
+ // Conditionals such as (?(1)a:b)
+ case doPerlInline:
+ // Perl inline-condtionals. (?{perl code}a|b) We're not perl, no way to do them.
+ error(U_REGEX_UNIMPLEMENTED);
+ break;
+
+
+ case doCloseParen:
+ handleCloseParen();
+ if (fParenStack.size() <= 0) {
+ // Extra close paren, or missing open paren.
+ error(U_REGEX_MISMATCHED_PAREN);
+ }
+ break;
+
+ case doNOP:
+ break;
+
+
+ case doBadOpenParenType:
+ case doRuleError:
+ error(U_REGEX_RULE_SYNTAX);
+ break;
+
+
+ case doMismatchedParenErr:
+ error(U_REGEX_MISMATCHED_PAREN);
+ break;
+
+ case doPlus:
+ // Normal '+' compiles to
+ // 1. stuff to be repeated (already built)
+ // 2. jmp-sav 1
+ // 3. ...
+ //
+ // Or, if the item to be repeated can match a zero length string,
+ // 1. STO_INP_LOC data-loc
+ // 2. body of stuff to be repeated
+ // 3. JMP_SAV_X 2
+ // 4. ...
+
+ //
+ // Or, if the item to be repeated is simple
+ // 1. Item to be repeated.
+ // 2. LOOP_SR_I set number (assuming repeated item is a set ref)
+ // 3. LOOP_C stack location
+ {
+ int32_t topLoc = blockTopLoc(FALSE); // location of item #1
+ int32_t frameLoc;
+
+ // Check for simple constructs, which may get special optimized code.
+ if (topLoc == fRXPat->fCompiledPat->size() - 1) {
+ int32_t repeatedOp = fRXPat->fCompiledPat->elementAti(topLoc);
+
+ if (URX_TYPE(repeatedOp) == URX_SETREF) {
+ // Emit optimized code for [char set]+
+ int32_t loopOpI = URX_BUILD(URX_LOOP_SR_I, URX_VAL(repeatedOp));
+ fRXPat->fCompiledPat->addElement(loopOpI, *fStatus);
+ frameLoc = fRXPat->fFrameSize;
+ fRXPat->fFrameSize++;
+ int32_t loopOpC = URX_BUILD(URX_LOOP_C, frameLoc);
+ fRXPat->fCompiledPat->addElement(loopOpC, *fStatus);
+ break;
+ }
+
+ if (URX_TYPE(repeatedOp) == URX_DOTANY ||
+ URX_TYPE(repeatedOp) == URX_DOTANY_ALL) {
+ // Emit Optimized code for .+ operations.
+ int32_t loopOpI = URX_BUILD(URX_LOOP_DOT_I, 0);
+ if (URX_TYPE(repeatedOp) == URX_DOTANY_ALL) {
+ // URX_LOOP_DOT_I operand is a flag indicating . matches any mode.
+ loopOpI |= 1;
+ }
+ fRXPat->fCompiledPat->addElement(loopOpI, *fStatus);
+ frameLoc = fRXPat->fFrameSize;
+ fRXPat->fFrameSize++;
+ int32_t loopOpC = URX_BUILD(URX_LOOP_C, frameLoc);
+ fRXPat->fCompiledPat->addElement(loopOpC, *fStatus);
+ break;
+ }
+
+ }
+
+ // General case.
+
+ // Check for minimum match length of zero, which requires
+ // extra loop-breaking code.
+ if (minMatchLength(topLoc, fRXPat->fCompiledPat->size()-1) == 0) {
+ // Zero length match is possible.
+ // Emit the code sequence that can handle it.
+ insertOp(topLoc);
+ frameLoc = fRXPat->fFrameSize;
+ fRXPat->fFrameSize++;
+
+ int32_t op = URX_BUILD(URX_STO_INP_LOC, frameLoc);
+ fRXPat->fCompiledPat->setElementAt(op, topLoc);
+
+ op = URX_BUILD(URX_JMP_SAV_X, topLoc+1);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ } else {
+ // Simpler code when the repeated body must match something non-empty
+ int32_t jmpOp = URX_BUILD(URX_JMP_SAV, topLoc);
+ fRXPat->fCompiledPat->addElement(jmpOp, *fStatus);
+ }
+ }
+ break;
+
+ case doNGPlus:
+ // Non-greedy '+?' compiles to
+ // 1. stuff to be repeated (already built)
+ // 2. state-save 1
+ // 3. ...
+ {
+ int32_t topLoc = blockTopLoc(FALSE);
+ int32_t saveStateOp = URX_BUILD(URX_STATE_SAVE, topLoc);
+ fRXPat->fCompiledPat->addElement(saveStateOp, *fStatus);
+ }
+ break;
+
+
+ case doOpt:
+ // Normal (greedy) ? quantifier.
+ // Compiles to
+ // 1. state save 3
+ // 2. body of optional block
+ // 3. ...
+ // Insert the state save into the compiled pattern, and we're done.
+ {
+ int32_t saveStateLoc = blockTopLoc(TRUE);
+ int32_t saveStateOp = URX_BUILD(URX_STATE_SAVE, fRXPat->fCompiledPat->size());
+ fRXPat->fCompiledPat->setElementAt(saveStateOp, saveStateLoc);
+ }
+ break;
+
+ case doNGOpt:
+ // Non-greedy ?? quantifier
+ // compiles to
+ // 1. jmp 4
+ // 2. body of optional block
+ // 3 jmp 5
+ // 4. state save 2
+ // 5 ...
+ // This code is less than ideal, with two jmps instead of one, because we can only
+ // insert one instruction at the top of the block being iterated.
+ {
+ int32_t jmp1_loc = blockTopLoc(TRUE);
+ int32_t jmp2_loc = fRXPat->fCompiledPat->size();
+
+ int32_t jmp1_op = URX_BUILD(URX_JMP, jmp2_loc+1);
+ fRXPat->fCompiledPat->setElementAt(jmp1_op, jmp1_loc);
+
+ int32_t jmp2_op = URX_BUILD(URX_JMP, jmp2_loc+2);
+ fRXPat->fCompiledPat->addElement(jmp2_op, *fStatus);
+
+ int32_t save_op = URX_BUILD(URX_STATE_SAVE, jmp1_loc+1);
+ fRXPat->fCompiledPat->addElement(save_op, *fStatus);
+ }
+ break;
+
+
+ case doStar:
+ // Normal (greedy) * quantifier.
+ // Compiles to
+ // 1. STATE_SAVE 4
+ // 2. body of stuff being iterated over
+ // 3. JMP_SAV 2
+ // 4. ...
+ //
+ // Or, if the body is a simple [Set],
+ // 1. LOOP_SR_I set number
+ // 2. LOOP_C stack location
+ // ...
+ //
+ // Or if this is a .*
+ // 1. LOOP_DOT_I (. matches all mode flag)
+ // 2. LOOP_C stack location
+ //
+ // Or, if the body can match a zero-length string, to inhibit infinite loops,
+ // 1. STATE_SAVE 5
+ // 2. STO_INP_LOC data-loc
+ // 3. body of stuff
+ // 4. JMP_SAV_X 2
+ // 5. ...
+ {
+ // location of item #1, the STATE_SAVE
+ int32_t topLoc = blockTopLoc(FALSE);
+ int32_t dataLoc = -1;
+
+ // Check for simple *, where the construct being repeated
+ // compiled to single opcode, and might be optimizable.
+ if (topLoc == fRXPat->fCompiledPat->size() - 1) {
+ int32_t repeatedOp = fRXPat->fCompiledPat->elementAti(topLoc);
+
+ if (URX_TYPE(repeatedOp) == URX_SETREF) {
+ // Emit optimized code for a [char set]*
+ int32_t loopOpI = URX_BUILD(URX_LOOP_SR_I, URX_VAL(repeatedOp));
+ fRXPat->fCompiledPat->setElementAt(loopOpI, topLoc);
+ dataLoc = fRXPat->fFrameSize;
+ fRXPat->fFrameSize++;
+ int32_t loopOpC = URX_BUILD(URX_LOOP_C, dataLoc);
+ fRXPat->fCompiledPat->addElement(loopOpC, *fStatus);
+ break;
+ }
+
+ if (URX_TYPE(repeatedOp) == URX_DOTANY ||
+ URX_TYPE(repeatedOp) == URX_DOTANY_ALL) {
+ // Emit Optimized code for .* operations.
+ int32_t loopOpI = URX_BUILD(URX_LOOP_DOT_I, 0);
+ if (URX_TYPE(repeatedOp) == URX_DOTANY_ALL) {
+ // URX_LOOP_DOT_I operand is a flag indicating . matches any mode.
+ loopOpI |= 1;
+ }
+ fRXPat->fCompiledPat->setElementAt(loopOpI, topLoc);
+ dataLoc = fRXPat->fFrameSize;
+ fRXPat->fFrameSize++;
+ int32_t loopOpC = URX_BUILD(URX_LOOP_C, dataLoc);
+ fRXPat->fCompiledPat->addElement(loopOpC, *fStatus);
+ break;
+ }
+ }
+
+ // Emit general case code for this *
+ // The optimizations did not apply.
+
+ int32_t saveStateLoc = blockTopLoc(TRUE);
+ int32_t jmpOp = URX_BUILD(URX_JMP_SAV, saveStateLoc+1);
+
+ // Check for minimum match length of zero, which requires
+ // extra loop-breaking code.
+ if (minMatchLength(saveStateLoc, fRXPat->fCompiledPat->size()-1) == 0) {
+ insertOp(saveStateLoc);
+ dataLoc = fRXPat->fFrameSize;
+ fRXPat->fFrameSize++;
+
+ int32_t op = URX_BUILD(URX_STO_INP_LOC, dataLoc);
+ fRXPat->fCompiledPat->setElementAt(op, saveStateLoc+1);
+ jmpOp = URX_BUILD(URX_JMP_SAV_X, saveStateLoc+2);
+ }
+
+ // Locate the position in the compiled pattern where the match will continue
+ // after completing the *. (4 or 5 in the comment above)
+ int32_t continueLoc = fRXPat->fCompiledPat->size()+1;
+
+ // Put together the save state op store it into the compiled code.
+ int32_t saveStateOp = URX_BUILD(URX_STATE_SAVE, continueLoc);
+ fRXPat->fCompiledPat->setElementAt(saveStateOp, saveStateLoc);
+
+ // Append the URX_JMP_SAV or URX_JMPX operation to the compiled pattern.
+ fRXPat->fCompiledPat->addElement(jmpOp, *fStatus);
+ }
+ break;
+
+ case doNGStar:
+ // Non-greedy *? quantifier
+ // compiles to
+ // 1. JMP 3
+ // 2. body of stuff being iterated over
+ // 3. STATE_SAVE 2
+ // 4 ...
+ {
+ int32_t jmpLoc = blockTopLoc(TRUE); // loc 1.
+ int32_t saveLoc = fRXPat->fCompiledPat->size(); // loc 3.
+ int32_t jmpOp = URX_BUILD(URX_JMP, saveLoc);
+ int32_t stateSaveOp = URX_BUILD(URX_STATE_SAVE, jmpLoc+1);
+ fRXPat->fCompiledPat->setElementAt(jmpOp, jmpLoc);
+ fRXPat->fCompiledPat->addElement(stateSaveOp, *fStatus);
+ }
+ break;
+
+
+ case doIntervalInit:
+ // The '{' opening an interval quantifier was just scanned.
+ // Init the counter varaiables that will accumulate the values as the digits
+ // are scanned.
+ fIntervalLow = 0;
+ fIntervalUpper = -1;
+ break;
+
+ case doIntevalLowerDigit:
+ // Scanned a digit from the lower value of an {lower,upper} interval
+ {
+ int32_t digitValue = u_charDigitValue(fC.fChar);
+ U_ASSERT(digitValue >= 0);
+ fIntervalLow = fIntervalLow*10 + digitValue;
+ if (fIntervalLow < 0) {
+ error(U_REGEX_NUMBER_TOO_BIG);
+ }
+ }
+ break;
+
+ case doIntervalUpperDigit:
+ // Scanned a digit from the upper value of an {lower,upper} interval
+ {
+ if (fIntervalUpper < 0) {
+ fIntervalUpper = 0;
+ }
+ int32_t digitValue = u_charDigitValue(fC.fChar);
+ U_ASSERT(digitValue >= 0);
+ fIntervalUpper = fIntervalUpper*10 + digitValue;
+ if (fIntervalUpper < 0) {
+ error(U_REGEX_NUMBER_TOO_BIG);
+ }
+ }
+ break;
+
+ case doIntervalSame:
+ // Scanned a single value interval like {27}. Upper = Lower.
+ fIntervalUpper = fIntervalLow;
+ break;
+
+ case doInterval:
+ // Finished scanning a normal {lower,upper} interval. Generate the code for it.
+ if (compileInlineInterval() == FALSE) {
+ compileInterval(URX_CTR_INIT, URX_CTR_LOOP);
+ }
+ break;
+
+ case doPossessiveInterval:
+ // Finished scanning a Possessive {lower,upper}+ interval. Generate the code for it.
+ {
+ // Remember the loc for the top of the block being looped over.
+ // (Can not reserve a slot in the compiled pattern at this time, becuase
+ // compileInterval needs to reserve also, and blockTopLoc can only reserve
+ // once per block.)
+ int32_t topLoc = blockTopLoc(FALSE);
+
+ // Produce normal looping code.
+ compileInterval(URX_CTR_INIT, URX_CTR_LOOP);
+
+ // Surround the just-emitted normal looping code with a STO_SP ... LD_SP
+ // just as if the loop was inclosed in atomic parentheses.
+
+ // First the STO_SP before the start of the loop
+ insertOp(topLoc);
+ int32_t varLoc = fRXPat->fDataSize; // Reserve a data location for saving the
+ fRXPat->fDataSize += 1; // state stack ptr.
+ int32_t op = URX_BUILD(URX_STO_SP, varLoc);
+ fRXPat->fCompiledPat->setElementAt(op, topLoc);
+
+ int32_t loopOp = fRXPat->fCompiledPat->popi();
+ U_ASSERT(URX_TYPE(loopOp) == URX_CTR_LOOP && URX_VAL(loopOp) == topLoc);
+ loopOp++; // point LoopOp after the just-inserted STO_SP
+ fRXPat->fCompiledPat->push(loopOp, *fStatus);
+
+ // Then the LD_SP after the end of the loop
+ op = URX_BUILD(URX_LD_SP, varLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+
+ break;
+
+ case doNGInterval:
+ // Finished scanning a non-greedy {lower,upper}? interval. Generate the code for it.
+ compileInterval(URX_CTR_INIT_NG, URX_CTR_LOOP_NG);
+ break;
+
+ case doIntervalError:
+ error(U_REGEX_BAD_INTERVAL);
+ break;
+
+ case doLiteralChar:
+ // We've just scanned a "normal" character from the pattern,
+ literalChar(fC.fChar);
+ break;
+
+
+
+ case doDotAny:
+ // scanned a ".", match any single character.
+ {
+ int32_t op;
+ if (fModeFlags & UREGEX_DOTALL) {
+ op = URX_BUILD(URX_DOTANY_ALL, 0);
+ } else {
+ op = URX_BUILD(URX_DOTANY, 0);
+ }
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+ break;
+
+ case doCaret:
+ {
+ int32_t op = (fModeFlags & UREGEX_MULTILINE)? URX_CARET_M : URX_CARET;
+ fRXPat->fCompiledPat->addElement(URX_BUILD(op, 0), *fStatus);
+ }
+ break;
+
+
+ case doDollar:
+ {
+ int32_t op = (fModeFlags & UREGEX_MULTILINE)? URX_DOLLAR_M : URX_DOLLAR;
+ fRXPat->fCompiledPat->addElement(URX_BUILD(op, 0), *fStatus);
+ }
+ break;
+
+ case doBackslashA:
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_CARET, 0), *fStatus);
+ break;
+
+ case doBackslashB:
+ {
+ #if UCONFIG_NO_BREAK_ITERATION==1
+ if (fModeFlags & UREGEX_UWORD) {
+ error(U_UNSUPPORTED_ERROR);
+ }
+ #endif
+ int32_t op = (fModeFlags & UREGEX_UWORD)? URX_BACKSLASH_BU : URX_BACKSLASH_B;
+ fRXPat->fCompiledPat->addElement(URX_BUILD(op, 1), *fStatus);
+ }
+ break;
+
+ case doBackslashb:
+ {
+ #if UCONFIG_NO_BREAK_ITERATION==1
+ if (fModeFlags & UREGEX_UWORD) {
+ error(U_UNSUPPORTED_ERROR);
+ }
+ #endif
+ int32_t op = (fModeFlags & UREGEX_UWORD)? URX_BACKSLASH_BU : URX_BACKSLASH_B;
+ fRXPat->fCompiledPat->addElement(URX_BUILD(op, 0), *fStatus);
+ }
+ break;
+
+ case doBackslashD:
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_D, 1), *fStatus);
+ break;
+
+ case doBackslashd:
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_D, 0), *fStatus);
+ break;
+
+ case doBackslashG:
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_G, 0), *fStatus);
+ break;
+
+ case doBackslashS:
+ fRXPat->fCompiledPat->addElement(
+ URX_BUILD(URX_STAT_SETREF_N, URX_ISSPACE_SET), *fStatus);
+ break;
+
+ case doBackslashs:
+ fRXPat->fCompiledPat->addElement(
+ URX_BUILD(URX_STATIC_SETREF, URX_ISSPACE_SET), *fStatus);
+ break;
+
+ case doBackslashW:
+ fRXPat->fCompiledPat->addElement(
+ URX_BUILD(URX_STAT_SETREF_N, URX_ISWORD_SET), *fStatus);
+ break;
+
+ case doBackslashw:
+ fRXPat->fCompiledPat->addElement(
+ URX_BUILD(URX_STATIC_SETREF, URX_ISWORD_SET), *fStatus);
+ break;
+
+ case doBackslashX:
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_X, 0), *fStatus);
+ break;
+
+
+ case doBackslashZ:
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_DOLLAR, 0), *fStatus);
+ break;
+
+ case doBackslashz:
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_Z, 0), *fStatus);
+ break;
+
+ case doEscapeError:
+ error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+ break;
+
+ case doExit:
+ returnVal = FALSE;
+ break;
+
+ case doProperty:
+ {
+ UnicodeSet *theSet = scanProp();
+ compileSet(theSet);
+ }
+ break;
+
+
+ case doScanUnicodeSet:
+ {
+ UnicodeSet *theSet = scanSet();
+ compileSet(theSet);
+ }
+ break;
+
+ case doEnterQuoteMode:
+ // Just scanned a \Q. Put character scanner into quote mode.
+ fQuoteMode = TRUE;
+ break;
+
+ case doBackRef:
+ // BackReference. Somewhat unusual in that the front-end can not completely parse
+ // the regular expression, because the number of digits to be consumed
+ // depends on the number of capture groups that have been defined. So
+ // we have to do it here instead.
+ {
+ int32_t numCaptureGroups = fRXPat->fGroupMap->size();
+ int32_t groupNum = 0;
+ UChar32 c = fC.fChar;
+
+ for (;;) {
+ // Loop once per digit, for max allowed number of digits in a back reference.
+ int32_t digit = u_charDigitValue(c);
+ groupNum = groupNum * 10 + digit;
+ if (groupNum >= numCaptureGroups) {
+ break;
+ }
+ c = peekCharLL();
+ if (RegexStaticSets::gStaticSets->fRuleDigitsAlias->contains(c) == FALSE) {
+ break;
+ }
+ nextCharLL();
+ }
+
+ // Scan of the back reference in the source regexp is complete. Now generate
+ // the compiled code for it.
+ // Because capture groups can be forward-referenced by back-references,
+ // we fill the operand with the capture group number. At the end
+ // of compilation, it will be changed to the variable's location.
+ U_ASSERT(groupNum > 0);
+ int32_t op;
+ if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
+ op = URX_BUILD(URX_BACKREF_I, groupNum);
+ } else {
+ op = URX_BUILD(URX_BACKREF, groupNum);
+ }
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+ break;
+
+
+ case doPossessivePlus:
+ // Possessive ++ quantifier.
+ // Compiles to
+ // 1. STO_SP
+ // 2. body of stuff being iterated over
+ // 3. STATE_SAVE 5
+ // 4. JMP 2
+ // 5. LD_SP
+ // 6. ...
+ //
+ // Note: TODO: This is pretty inefficient. A mass of saved state is built up
+ // then unconditionally discarded. Perhaps introduce a new opcode
+ //
+ {
+ // Emit the STO_SP
+ int32_t topLoc = blockTopLoc(TRUE);
+ int32_t stoLoc = fRXPat->fDataSize;
+ fRXPat->fDataSize++; // Reserve the data location for storing save stack ptr.
+ int32_t op = URX_BUILD(URX_STO_SP, stoLoc);
+ fRXPat->fCompiledPat->setElementAt(op, topLoc);
+
+ // Emit the STATE_SAVE
+ op = URX_BUILD(URX_STATE_SAVE, fRXPat->fCompiledPat->size()+2);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Emit the JMP
+ op = URX_BUILD(URX_JMP, topLoc+1);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Emit the LD_SP
+ op = URX_BUILD(URX_LD_SP, stoLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+ break;
+
+ case doPossessiveStar:
+ // Possessive *+ quantifier.
+ // Compiles to
+ // 1. STO_SP loc
+ // 2. STATE_SAVE 5
+ // 3. body of stuff being iterated over
+ // 4. JMP 2
+ // 5. LD_SP loc
+ // 6 ...
+ // TODO: do something to cut back the state stack each time through the loop.
+ {
+ // Reserve two slots at the top of the block.
+ int32_t topLoc = blockTopLoc(TRUE);
+ insertOp(topLoc);
+
+ // emit STO_SP loc
+ int32_t stoLoc = fRXPat->fDataSize;
+ fRXPat->fDataSize++; // Reserve the data location for storing save stack ptr.
+ int32_t op = URX_BUILD(URX_STO_SP, stoLoc);
+ fRXPat->fCompiledPat->setElementAt(op, topLoc);
+
+ // Emit the SAVE_STATE 5
+ int32_t L7 = fRXPat->fCompiledPat->size()+1;
+ op = URX_BUILD(URX_STATE_SAVE, L7);
+ fRXPat->fCompiledPat->setElementAt(op, topLoc+1);
+
+ // Append the JMP operation.
+ op = URX_BUILD(URX_JMP, topLoc+1);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Emit the LD_SP loc
+ op = URX_BUILD(URX_LD_SP, stoLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+ break;
+
+ case doPossessiveOpt:
+ // Possessive ?+ quantifier.
+ // Compiles to
+ // 1. STO_SP loc
+ // 2. SAVE_STATE 5
+ // 3. body of optional block
+ // 4. LD_SP loc
+ // 5. ...
+ //
+ {
+ // Reserve two slots at the top of the block.
+ int32_t topLoc = blockTopLoc(TRUE);
+ insertOp(topLoc);
+
+ // Emit the STO_SP
+ int32_t stoLoc = fRXPat->fDataSize;
+ fRXPat->fDataSize++; // Reserve the data location for storing save stack ptr.
+ int32_t op = URX_BUILD(URX_STO_SP, stoLoc);
+ fRXPat->fCompiledPat->setElementAt(op, topLoc);
+
+ // Emit the SAVE_STATE
+ int32_t continueLoc = fRXPat->fCompiledPat->size()+1;
+ op = URX_BUILD(URX_STATE_SAVE, continueLoc);
+ fRXPat->fCompiledPat->setElementAt(op, topLoc+1);
+
+ // Emit the LD_SP
+ op = URX_BUILD(URX_LD_SP, stoLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+ break;
+
+
+ case doBeginMatchMode:
+ fNewModeFlags = fModeFlags;
+ fSetModeFlag = TRUE;
+ break;
+
+ case doMatchMode: // (?i) and similar
+ {
+ int32_t bit = 0;
+ switch (fC.fChar) {
+ case 0x69: /* 'i' */ bit = UREGEX_CASE_INSENSITIVE; break;
+ case 0x6d: /* 'm' */ bit = UREGEX_MULTILINE; break;
+ case 0x73: /* 's' */ bit = UREGEX_DOTALL; break;
+ case 0x77: /* 'w' */ bit = UREGEX_UWORD; break;
+ case 0x78: /* 'x' */ bit = UREGEX_COMMENTS; break;
+ case 0x2d: /* '-' */ fSetModeFlag = FALSE; break;
+ default:
+ U_ASSERT(FALSE); // Should never happen. Other chars are filtered out
+ // by the scanner.
+ }
+ if (fSetModeFlag) {
+ fNewModeFlags |= bit;
+ } else {
+ fNewModeFlags &= ~bit;
+ }
+ }
+ break;
+
+ case doSetMatchMode:
+ // We've got a (?i) or similar. The match mode is being changed, but
+ // the change is not scoped to a parenthesized block.
+ U_ASSERT(fNewModeFlags < 0);
+ fModeFlags = fNewModeFlags;
+
+ // Prevent any string from spanning across the change of match mode.
+ // Otherwise the pattern "abc(?i)def" would make a single string of "abcdef"
+ fixLiterals();
+ break;
+
+
+ case doMatchModeParen:
+ // We've got a (?i: or similar. Begin a parenthesized block, save old
+ // mode flags so they can be restored at the close of the block.
+ //
+ // Compile to a
+ // - NOP, which later may be replaced by a save-state if the
+ // parenthesized group gets a * quantifier, followed by
+ // - NOP, which may later be replaced by a save-state if there
+ // is an '|' alternation within the parens.
+ {
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
+
+ // On the Parentheses stack, start a new frame and add the postions
+ // of the two NOPs (a normal non-capturing () frame, except for the
+ // saving of the orignal mode flags.)
+ fParenStack.push(fModeFlags, *fStatus);
+ fParenStack.push(flags, *fStatus); // Frame Marker
+ fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus); // The first NOP
+ fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus); // The second NOP
+
+ // Set the current mode flags to the new values.
+ U_ASSERT(fNewModeFlags < 0);
+ fModeFlags = fNewModeFlags;
+ }
+ break;
+
+ case doBadModeFlag:
+ error(U_REGEX_INVALID_FLAG);
+ break;
+
+ case doSuppressComments:
+ // We have just scanned a '(?'. We now need to prevent the character scanner from
+ // treating a '#' as a to-the-end-of-line comment.
+ // (This Perl compatibility just gets uglier and uglier to do...)
+ fEOLComments = FALSE;
+ break;
+
+
+
+ default:
+ U_ASSERT(FALSE);
+ error(U_REGEX_INTERNAL_ERROR);
+ break;
+ }
+
+ if (U_FAILURE(*fStatus)) {
+ returnVal = FALSE;
+ }
+
+ return returnVal;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// literalChar We've encountered a literal character from the pattern,
+// or an escape sequence that reduces to a character.
+// Add it to the string containing all literal chars/strings from
+// the pattern.
+// If we are in a pattern string already, add the new char to it.
+// If we aren't in a pattern string, begin one now.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::literalChar(UChar32 c) {
+ int32_t op; // An operation in the compiled pattern.
+ int32_t opType;
+ int32_t patternLoc; // A position in the compiled pattern.
+ int32_t stringLen;
+
+
+ // If the last thing compiled into the pattern was not a literal char,
+ // force this new literal char to begin a new string, and not append to the previous.
+ op = fRXPat->fCompiledPat->lastElementi();
+ opType = URX_TYPE(op);
+ if (!(opType == URX_STRING_LEN || opType == URX_ONECHAR || opType == URX_ONECHAR_I)) {
+ fixLiterals();
+ }
+
+ if (fStringOpStart == -1) {
+ // First char of a string in the pattern.
+ // Emit a OneChar op into the compiled pattern.
+ emitONE_CHAR(c);
+
+ // Also add it to the string pool, in case we get a second adjacent literal
+ // and want to change form ONE_CHAR to STRING
+ fStringOpStart = fRXPat->fLiteralText.length();
+ fRXPat->fLiteralText.append(c);
+ return;
+ }
+
+ // We are adding onto an existing string
+ fRXPat->fLiteralText.append(c);
+
+ op = fRXPat->fCompiledPat->lastElementi();
+ opType = URX_TYPE(op);
+ U_ASSERT(opType == URX_ONECHAR || opType == URX_ONECHAR_I || opType == URX_STRING_LEN);
+
+ // If the most recently emitted op is a URX_ONECHAR,
+ if (opType == URX_ONECHAR || opType == URX_ONECHAR_I) {
+ if (U16_IS_TRAIL(c) && U16_IS_LEAD(URX_VAL(op))) {
+ // The most recently emitted op is a ONECHAR that was the first half
+ // of a surrogate pair. Update the ONECHAR's operand to be the
+ // supplementary code point resulting from both halves of the pair.
+ c = U16_GET_SUPPLEMENTARY(URX_VAL(op), c);
+ op = URX_BUILD(opType, c);
+ patternLoc = fRXPat->fCompiledPat->size() - 1;
+ fRXPat->fCompiledPat->setElementAt(op, patternLoc);
+ return;
+ }
+
+ // The most recently emitted op is a ONECHAR.
+ // We've now received another adjacent char. Change the ONECHAR op
+ // to a string op.
+ if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
+ op = URX_BUILD(URX_STRING_I, fStringOpStart);
+ } else {
+ op = URX_BUILD(URX_STRING, fStringOpStart);
+ }
+ patternLoc = fRXPat->fCompiledPat->size() - 1;
+ fRXPat->fCompiledPat->setElementAt(op, patternLoc);
+ op = URX_BUILD(URX_STRING_LEN, 0);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+
+ // The pattern contains a URX_SRING / URX_STRING_LEN. Update the
+ // string length to reflect the new char we just added to the string.
+ stringLen = fRXPat->fLiteralText.length() - fStringOpStart;
+ op = URX_BUILD(URX_STRING_LEN, stringLen);
+ patternLoc = fRXPat->fCompiledPat->size() - 1;
+ fRXPat->fCompiledPat->setElementAt(op, patternLoc);
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// emitONE_CHAR emit a ONE_CHAR op into the generated code.
+// Choose cased or uncased version, depending on the
+// match mode and whether the character itself is cased.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::emitONE_CHAR(UChar32 c) {
+ int32_t op;
+ if ((fModeFlags & UREGEX_CASE_INSENSITIVE) &&
+ u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
+ // We have a cased character, and are in case insensitive matching mode.
+ c = u_foldCase(c, U_FOLD_CASE_DEFAULT);
+ op = URX_BUILD(URX_ONECHAR_I, c);
+ } else {
+ // Uncased char, or case sensitive match mode.
+ // Either way, just generate a literal compare of the char.
+ op = URX_BUILD(URX_ONECHAR, c);
+ }
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// fixLiterals When compiling something that can follow a literal
+// string in a pattern, we need to "fix" any preceding
+// string, which will cause any subsequent literals to
+// begin a new string, rather than appending to the
+// old one.
+//
+// Optionally, split the last char of the string off into
+// a single "ONE_CHAR" operation, so that quantifiers can
+// apply to that char alone. Example: abc*
+// The * must apply to the 'c' only.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::fixLiterals(UBool split) {
+ int32_t stringStart = fStringOpStart; // start index of the current literal string
+ int32_t op; // An op from/for the compiled pattern.
+ int32_t opType; // An opcode type from the compiled pattern.
+ int32_t stringLastCharIdx;
+ UChar32 lastChar;
+ int32_t stringNextToLastCharIdx;
+ UChar32 nextToLastChar;
+ int32_t stringLen;
+
+ fStringOpStart = -1;
+ if (!split) {
+ return;
+ }
+
+ // Split: We need to ensure that the last item in the compiled pattern does
+ // not refer to a literal string of more than one char. If it does,
+ // separate the last char from the rest of the string.
+
+ // If the last operation from the compiled pattern is not a string,
+ // nothing needs to be done
+ op = fRXPat->fCompiledPat->lastElementi();
+ opType = URX_TYPE(op);
+ if (opType != URX_STRING_LEN) {
+ return;
+ }
+ stringLen = URX_VAL(op);
+
+ //
+ // Find the position of the last code point in the string (might be a surrogate pair)
+ //
+ stringLastCharIdx = fRXPat->fLiteralText.length();
+ stringLastCharIdx = fRXPat->fLiteralText.moveIndex32(stringLastCharIdx, -1);
+ lastChar = fRXPat->fLiteralText.char32At(stringLastCharIdx);
+
+ // The string should always be at least two code points long, meaning that there
+ // should be something before the last char position that we just found.
+ U_ASSERT(stringLastCharIdx > stringStart);
+ stringNextToLastCharIdx = fRXPat->fLiteralText.moveIndex32(stringLastCharIdx, -1);
+ U_ASSERT(stringNextToLastCharIdx >= stringStart);
+ nextToLastChar = fRXPat->fLiteralText.char32At(stringNextToLastCharIdx);
+
+ if (stringNextToLastCharIdx > stringStart) {
+ // The length of string remaining after removing one char is two or more.
+ // Leave the string in the compiled pattern, shorten it by one char,
+ // and append a URX_ONECHAR op for the last char.
+ stringLen -= (fRXPat->fLiteralText.length() - stringLastCharIdx);
+ op = URX_BUILD(URX_STRING_LEN, stringLen);
+ fRXPat->fCompiledPat->setElementAt(op, fRXPat->fCompiledPat->size() -1);
+ emitONE_CHAR(lastChar);
+ } else {
+ // The original string consisted of exactly two characters. Replace
+ // the existing compiled URX_STRING/URX_STRING_LEN ops with a pair
+ // of URX_ONECHARs.
+ fRXPat->fCompiledPat->setSize(fRXPat->fCompiledPat->size() -2);
+ emitONE_CHAR(nextToLastChar);
+ emitONE_CHAR(lastChar);
+ }
+}
+
+
+
+
+
+
+//------------------------------------------------------------------------------
+//
+// insertOp() Insert a slot for a new opcode into the already
+// compiled pattern code.
+//
+// Fill the slot with a NOP. Our caller will replace it
+// with what they really wanted.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::insertOp(int32_t where) {
+ UVector32 *code = fRXPat->fCompiledPat;
+ U_ASSERT(where>0 && where < code->size());
+
+ int32_t nop = URX_BUILD(URX_NOP, 0);
+ code->insertElementAt(nop, where, *fStatus);
+
+ // Walk through the pattern, looking for any ops with targets that
+ // were moved down by the insert. Fix them.
+ int32_t loc;
+ for (loc=0; loc<code->size(); loc++) {
+ int32_t op = code->elementAti(loc);
+ int32_t opType = URX_TYPE(op);
+ int32_t opValue = URX_VAL(op);
+ if ((opType == URX_JMP ||
+ opType == URX_JMPX ||
+ opType == URX_STATE_SAVE ||
+ opType == URX_CTR_LOOP ||
+ opType == URX_CTR_LOOP_NG ||
+ opType == URX_JMP_SAV ||
+ opType == URX_RELOC_OPRND) && opValue > where) {
+ // Target location for this opcode is after the insertion point and
+ // needs to be incremented to adjust for the insertion.
+ opValue++;
+ op = URX_BUILD(opType, opValue);
+ code->setElementAt(op, loc);
+ }
+ }
+
+ // Now fix up the parentheses stack. All positive values in it are locations in
+ // the compiled pattern. (Negative values are frame boundaries, and don't need fixing.)
+ for (loc=0; loc<fParenStack.size(); loc++) {
+ int32_t x = fParenStack.elementAti(loc);
+ U_ASSERT(x < code->size());
+ if (x>where) {
+ x++;
+ fParenStack.setElementAt(x, loc);
+ }
+ }
+
+ if (fMatchCloseParen > where) {
+ fMatchCloseParen++;
+ }
+ if (fMatchOpenParen > where) {
+ fMatchOpenParen++;
+ }
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// blockTopLoc() Find or create a location in the compiled pattern
+// at the start of the operation or block that has
+// just been compiled. Needed when a quantifier (* or
+// whatever) appears, and we need to add an operation
+// at the start of the thing being quantified.
+//
+// (Parenthesized Blocks) have a slot with a NOP that
+// is reserved for this purpose. .* or similar don't
+// and a slot needs to be added.
+//
+// parameter reserveLoc : TRUE - ensure that there is space to add an opcode
+// at the returned location.
+// FALSE - just return the address,
+// do not reserve a location there.
+//
+//------------------------------------------------------------------------------
+int32_t RegexCompile::blockTopLoc(UBool reserveLoc) {
+ int32_t theLoc;
+ if (fRXPat->fCompiledPat->size() == fMatchCloseParen)
+ {
+ // The item just processed is a parenthesized block.
+ theLoc = fMatchOpenParen; // A slot is already reserved for us.
+ U_ASSERT(theLoc > 0);
+ U_ASSERT(URX_TYPE(((uint32_t)fRXPat->fCompiledPat->elementAti(theLoc))) == URX_NOP);
+ }
+ else {
+ // Item just compiled is a single thing, a ".", or a single char, or a set reference.
+ // No slot for STATE_SAVE was pre-reserved in the compiled code.
+ // We need to make space now.
+ fixLiterals(TRUE); // If last item was a string, separate the last char.
+ theLoc = fRXPat->fCompiledPat->size()-1;
+ if (reserveLoc) {
+ /*int32_t opAtTheLoc = fRXPat->fCompiledPat->elementAti(theLoc);*/
+ int32_t nop = URX_BUILD(URX_NOP, 0);
+ fRXPat->fCompiledPat->insertElementAt(nop, theLoc, *fStatus);
+ }
+ }
+ return theLoc;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// handleCloseParen When compiling a close paren, we need to go back
+// and fix up any JMP or SAVE operations within the
+// parenthesized block that need to target the end
+// of the block. The locations of these are kept on
+// the paretheses stack.
+//
+// This function is called both when encountering a
+// real ) and at the end of the pattern.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::handleCloseParen() {
+ int32_t patIdx;
+ int32_t patOp;
+ if (fParenStack.size() <= 0) {
+ error(U_REGEX_MISMATCHED_PAREN);
+ return;
+ }
+
+ // Force any literal chars that may follow the close paren to start a new string,
+ // and not attach to any preceding it.
+ fixLiterals(FALSE);
+
+ // Fixup any operations within the just-closed parenthesized group
+ // that need to reference the end of the (block).
+ // (The first one popped from the stack is an unused slot for
+ // alternation (OR) state save, but applying the fixup to it does no harm.)
+ for (;;) {
+ patIdx = fParenStack.popi();
+ if (patIdx < 0) {
+ // value < 0 flags the start of the frame on the paren stack.
+ break;
+ }
+ U_ASSERT(patIdx>0 && patIdx <= fRXPat->fCompiledPat->size());
+ patOp = fRXPat->fCompiledPat->elementAti(patIdx);
+ U_ASSERT(URX_VAL(patOp) == 0); // Branch target for JMP should not be set.
+ patOp |= fRXPat->fCompiledPat->size(); // Set it now.
+ fRXPat->fCompiledPat->setElementAt(patOp, patIdx);
+ fMatchOpenParen = patIdx;
+ }
+
+ // At the close of any parenthesized block, restore the match mode flags to
+ // the value they had at the open paren. Saved value is
+ // at the top of the paren stack.
+ fModeFlags = fParenStack.popi();
+ U_ASSERT(fModeFlags < 0);
+
+ // DO any additional fixups, depending on the specific kind of
+ // parentesized grouping this is
+
+ switch (patIdx) {
+ case plain:
+ case flags:
+ // No additional fixups required.
+ // (Grouping-only parentheses)
+ break;
+ case capturing:
+ // Capturing Parentheses.
+ // Insert a End Capture op into the pattern.
+ // The frame offset of the variables for this cg is obtained from the
+ // start capture op and put it into the end-capture op.
+ {
+ int32_t captureOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
+ U_ASSERT(URX_TYPE(captureOp) == URX_START_CAPTURE);
+
+ int32_t frameVarLocation = URX_VAL(captureOp);
+ int32_t endCaptureOp = URX_BUILD(URX_END_CAPTURE, frameVarLocation);
+ fRXPat->fCompiledPat->addElement(endCaptureOp, *fStatus);
+ }
+ break;
+ case atomic:
+ // Atomic Parenthesis.
+ // Insert a LD_SP operation to restore the state stack to the position
+ // it was when the atomic parens were entered.
+ {
+ int32_t stoOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
+ U_ASSERT(URX_TYPE(stoOp) == URX_STO_SP);
+ int32_t stoLoc = URX_VAL(stoOp);
+ int32_t ldOp = URX_BUILD(URX_LD_SP, stoLoc);
+ fRXPat->fCompiledPat->addElement(ldOp, *fStatus);
+ }
+ break;
+
+ case lookAhead:
+ {
+ int32_t startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-1);
+ U_ASSERT(URX_TYPE(startOp) == URX_LA_START);
+ int32_t dataLoc = URX_VAL(startOp);
+ int32_t op = URX_BUILD(URX_LA_END, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+ break;
+
+ case negLookAhead:
+ {
+ // See comment at doOpenLookAheadNeg
+ int32_t startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-1);
+ U_ASSERT(URX_TYPE(startOp) == URX_LA_START);
+ int32_t dataLoc = URX_VAL(startOp);
+ int32_t op = URX_BUILD(URX_LA_END, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ op = URX_BUILD(URX_FAIL, 0);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Patch the URX_SAVE near the top of the block.
+ int32_t saveOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen);
+ U_ASSERT(URX_TYPE(saveOp) == URX_STATE_SAVE);
+ int32_t dest = fRXPat->fCompiledPat->size();
+ saveOp = URX_BUILD(URX_STATE_SAVE, dest);
+ fRXPat->fCompiledPat->setElementAt(saveOp, fMatchOpenParen);
+ }
+ break;
+
+ case lookBehind:
+ {
+ // See comment at doOpenLookBehind.
+
+ // Append the URX_LB_END and URX_LA_END to the compiled pattern.
+ int32_t startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-4);
+ U_ASSERT(URX_TYPE(startOp) == URX_LB_START);
+ int32_t dataLoc = URX_VAL(startOp);
+ int32_t op = URX_BUILD(URX_LB_END, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ op = URX_BUILD(URX_LA_END, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Determine the min and max bounds for the length of the
+ // string that the pattern can match.
+ // An unbounded upper limit is an error.
+ int32_t patEnd = fRXPat->fCompiledPat->size() - 1;
+ int32_t minML = minMatchLength(fMatchOpenParen, patEnd);
+ int32_t maxML = maxMatchLength(fMatchOpenParen, patEnd);
+ if (maxML == INT32_MAX) {
+ error(U_REGEX_LOOK_BEHIND_LIMIT);
+ break;
+ }
+ U_ASSERT(minML <= maxML);
+
+ // Insert the min and max match len bounds into the URX_LB_CONT op that
+ // appears at the top of the look-behind block, at location fMatchOpenParen+1
+ fRXPat->fCompiledPat->setElementAt(minML, fMatchOpenParen-2);
+ fRXPat->fCompiledPat->setElementAt(maxML, fMatchOpenParen-1);
+
+ }
+ break;
+
+
+
+ case lookBehindN:
+ {
+ // See comment at doOpenLookBehindNeg.
+
+ // Append the URX_LBN_END to the compiled pattern.
+ int32_t startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
+ U_ASSERT(URX_TYPE(startOp) == URX_LB_START);
+ int32_t dataLoc = URX_VAL(startOp);
+ int32_t op = URX_BUILD(URX_LBN_END, dataLoc);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ // Determine the min and max bounds for the length of the
+ // string that the pattern can match.
+ // An unbounded upper limit is an error.
+ int32_t patEnd = fRXPat->fCompiledPat->size() - 1;
+ int32_t minML = minMatchLength(fMatchOpenParen, patEnd);
+ int32_t maxML = maxMatchLength(fMatchOpenParen, patEnd);
+ if (maxML == INT32_MAX) {
+ error(U_REGEX_LOOK_BEHIND_LIMIT);
+ break;
+ }
+ U_ASSERT(minML <= maxML);
+
+ // Insert the min and max match len bounds into the URX_LB_CONT op that
+ // appears at the top of the look-behind block, at location fMatchOpenParen+1
+ fRXPat->fCompiledPat->setElementAt(minML, fMatchOpenParen-3);
+ fRXPat->fCompiledPat->setElementAt(maxML, fMatchOpenParen-2);
+
+ // Insert the pattern location to continue at after a successful match
+ // as the last operand of the URX_LBN_CONT
+ op = URX_BUILD(URX_RELOC_OPRND, fRXPat->fCompiledPat->size());
+ fRXPat->fCompiledPat->setElementAt(op, fMatchOpenParen-1);
+ }
+ break;
+
+
+
+ default:
+ U_ASSERT(FALSE);
+ }
+
+ // remember the next location in the compiled pattern.
+ // The compilation of Quantifiers will look at this to see whether its looping
+ // over a parenthesized block or a single item
+ fMatchCloseParen = fRXPat->fCompiledPat->size();
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// compileSet Compile the pattern operations for a reference to a
+// UnicodeSet.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::compileSet(UnicodeSet *theSet)
+{
+ if (theSet == NULL) {
+ return;
+ }
+ int32_t setSize = theSet->size();
+ UChar32 firstSetChar = theSet->charAt(0);
+ if (firstSetChar == -1) {
+ // Sets that contain only strings, but no individual chars,
+ // will end up here.
+ error(U_REGEX_SET_CONTAINS_STRING);
+ setSize = 0;
+ }
+
+ switch (setSize) {
+ case 0:
+ {
+ // Set of no elements. Always fails to match.
+ fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKTRACK, 0), *fStatus);
+ delete theSet;
+ }
+ break;
+
+ case 1:
+ {
+ // The set contains only a single code point. Put it into
+ // the compiled pattern as a single char operation rather
+ // than a set, and discard the set itself.
+ literalChar(firstSetChar);
+ delete theSet;
+ }
+ break;
+
+ default:
+ {
+ // The set contains two or more chars. (the normal case)
+ // Put it into the compiled pattern as a set.
+ int32_t setNumber = fRXPat->fSets->size();
+ fRXPat->fSets->addElement(theSet, *fStatus);
+ int32_t setOp = URX_BUILD(URX_SETREF, setNumber);
+ fRXPat->fCompiledPat->addElement(setOp, *fStatus);
+ }
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//
+// compileInterval Generate the code for a {min, max} style interval quantifier.
+// Except for the specific opcodes used, the code is the same
+// for all three types (greedy, non-greedy, possessive) of
+// intervals. The opcodes are supplied as parameters.
+//
+// The code for interval loops has this form:
+// 0 CTR_INIT counter loc (in stack frame)
+// 1 5 patt address of CTR_LOOP at bottom of block
+// 2 min count
+// 3 max count (-1 for unbounded)
+// 4 ... block to be iterated over
+// 5 CTR_LOOP
+//
+// In
+//------------------------------------------------------------------------------
+void RegexCompile::compileInterval(int32_t InitOp, int32_t LoopOp)
+{
+ // The CTR_INIT op at the top of the block with the {n,m} quantifier takes
+ // four slots in the compiled code. Reserve them.
+ int32_t topOfBlock = blockTopLoc(TRUE);
+ insertOp(topOfBlock);
+ insertOp(topOfBlock);
+ insertOp(topOfBlock);
+
+ // The operands for the CTR_INIT opcode include the index in the matcher data
+ // of the counter. Allocate it now.
+ int32_t counterLoc = fRXPat->fFrameSize;
+ fRXPat->fFrameSize++;
+
+ int32_t op = URX_BUILD(InitOp, counterLoc);
+ fRXPat->fCompiledPat->setElementAt(op, topOfBlock);
+
+ // The second operand of CTR_INIT is the location following the end of the loop.
+ // Must put in as a URX_RELOC_OPRND so that the value will be adjusted if the
+ // compilation of something later on causes the code to grow and the target
+ // position to move.
+ int32_t loopEnd = fRXPat->fCompiledPat->size();
+ op = URX_BUILD(URX_RELOC_OPRND, loopEnd);
+ fRXPat->fCompiledPat->setElementAt(op, topOfBlock+1);
+
+ // Followed by the min and max counts.
+ fRXPat->fCompiledPat->setElementAt(fIntervalLow, topOfBlock+2);
+ fRXPat->fCompiledPat->setElementAt(fIntervalUpper, topOfBlock+3);
+
+ // Apend the CTR_LOOP op. The operand is the location of the CTR_INIT op.
+ // Goes at end of the block being looped over, so just append to the code so far.
+ op = URX_BUILD(LoopOp, topOfBlock);
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+
+ if ((fIntervalLow & 0xff000000) != 0 ||
+ fIntervalUpper > 0 && (fIntervalUpper & 0xff000000) != 0) {
+ error(U_REGEX_NUMBER_TOO_BIG);
+ }
+
+ if (fIntervalLow > fIntervalUpper && fIntervalUpper != -1) {
+ error(U_REGEX_MAX_LT_MIN);
+ }
+}
+
+
+
+UBool RegexCompile::compileInlineInterval() {
+ if (fIntervalUpper > 10 || fIntervalUpper < fIntervalLow) {
+ // Too big to inline. Fail, which will cause looping code to be generated.
+ // (Upper < Lower picks up unbounded upper and errors, both.)
+ return FALSE;
+ }
+
+ int32_t topOfBlock = blockTopLoc(FALSE);
+ if (fIntervalUpper == 0) {
+ // Pathological case. Attempt no matches, as if the block doesn't exist.
+ fRXPat->fCompiledPat->setSize(topOfBlock);
+ return TRUE;
+ }
+
+ if (topOfBlock != fRXPat->fCompiledPat->size()-1 && fIntervalUpper != 1) {
+ // The thing being repeated is not a single op, but some
+ // more complex block. Do it as a loop, not inlines.
+ // Note that things "repeated" a max of once are handled as inline, because
+ // the one copy of the code already generated is just fine.
+ return FALSE;
+ }
+
+ // Pick up the opcode that is to be repeated
+ //
+ int32_t op = fRXPat->fCompiledPat->elementAti(topOfBlock);
+
+ // Compute the pattern location where the inline sequence
+ // will end, and set up the state save op that will be needed.
+ //
+ int32_t endOfSequenceLoc = fRXPat->fCompiledPat->size()-1
+ + fIntervalUpper + (fIntervalUpper-fIntervalLow);
+ int32_t saveOp = URX_BUILD(URX_STATE_SAVE, endOfSequenceLoc);
+ if (fIntervalLow == 0) {
+ insertOp(topOfBlock);
+ fRXPat->fCompiledPat->setElementAt(saveOp, topOfBlock);
+ }
+
+
+
+ // Loop, emitting the op for the thing being repeated each time.
+ // Loop starts at 1 because one instance of the op already exists in the pattern,
+ // it was put there when it was originally encountered.
+ int32_t i;
+ for (i=1; i<fIntervalUpper; i++ ) {
+ if (i == fIntervalLow) {
+ fRXPat->fCompiledPat->addElement(saveOp, *fStatus);
+ }
+ if (i > fIntervalLow) {
+ fRXPat->fCompiledPat->addElement(saveOp, *fStatus);
+ }
+ fRXPat->fCompiledPat->addElement(op, *fStatus);
+ }
+ return TRUE;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// matchStartType Determine how a match can start.
+// Used to optimize find() operations.
+//
+// Operation is very similar to minMatchLength(). Walk the compiled
+// pattern, keeping an on-going minimum-match-length. For any
+// op where the min match coming in is zero, add that ops possible
+// starting matches to the possible starts for the overall pattern.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::matchStartType() {
+ if (U_FAILURE(*fStatus)) {
+ return;
+ }
+
+
+ int32_t loc; // Location in the pattern of the current op being processed.
+ int32_t op; // The op being processed
+ int32_t opType; // The opcode type of the op
+ int32_t currentLen = 0; // Minimum length of a match to this point (loc) in the pattern
+ int32_t numInitialStrings = 0; // Number of strings encountered that could match at start.
+
+ UBool atStart = TRUE; // True if no part of the pattern yet encountered
+ // could have advanced the position in a match.
+ // (Maximum match length so far == 0)
+
+ // forwardedLength is a vector holding minimum-match-length values that
+ // are propagated forward in the pattern by JMP or STATE_SAVE operations.
+ // It must be one longer than the pattern being checked because some ops
+ // will jmp to a end-of-block+1 location from within a block, and we must
+ // count those when checking the block.
+ int32_t end = fRXPat->fCompiledPat->size();
+ UVector32 forwardedLength(end+1, *fStatus);
+ forwardedLength.setSize(end+1);
+ for (loc=3; loc<end; loc++) {
+ forwardedLength.setElementAt(INT32_MAX, loc);
+ }
+
+ for (loc = 3; loc<end; loc++) {
+ op = fRXPat->fCompiledPat->elementAti(loc);
+ opType = URX_TYPE(op);
+
+ // The loop is advancing linearly through the pattern.
+ // If the op we are now at was the destination of a branch in the pattern,
+ // and that path has a shorter minimum length than the current accumulated value,
+ // replace the current accumulated value.
+ U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);
+ if (forwardedLength.elementAti(loc) < currentLen) {
+ currentLen = forwardedLength.elementAti(loc);
+ U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);
+ }
+
+ switch (opType) {
+ // Ops that don't change the total length matched
+ case URX_RESERVED_OP:
+ case URX_END:
+ case URX_STRING_LEN:
+ case URX_NOP:
+ case URX_START_CAPTURE:
+ case URX_END_CAPTURE:
+ case URX_BACKSLASH_B:
+ case URX_BACKSLASH_BU:
+ case URX_BACKSLASH_G:
+ case URX_BACKSLASH_Z:
+ case URX_DOLLAR:
+ case URX_RELOC_OPRND:
+ case URX_STO_INP_LOC:
+ case URX_DOLLAR_M:
+ case URX_BACKTRACK:
+ case URX_BACKREF: // BackRef. Must assume that it might be a zero length match
+ case URX_BACKREF_I:
+
+ case URX_STO_SP: // Setup for atomic or possessive blocks. Doesn't change what can match.
+ case URX_LD_SP:
+ break;
+
+ case URX_CARET:
+ if (atStart) {
+ fRXPat->fStartType = START_START;
+ }
+ break;
+
+ case URX_CARET_M:
+ if (atStart) {
+ fRXPat->fStartType = START_LINE;
+ }
+ break;
+
+ case URX_ONECHAR:
+ if (currentLen == 0) {
+ // This character could appear at the start of a match.
+ // Add it to the set of possible starting characters.
+ fRXPat->fInitialChars->add(URX_VAL(op));
+ numInitialStrings += 2;
+ }
+ currentLen++;
+ atStart = FALSE;
+ break;
+
+
+ case URX_SETREF:
+ if (currentLen == 0) {
+ int32_t sn = URX_VAL(op);
+ U_ASSERT(sn > 0 && sn < fRXPat->fSets->size());
+ const UnicodeSet *s = (UnicodeSet *)fRXPat->fSets->elementAt(sn);
+ fRXPat->fInitialChars->addAll(*s);
+ numInitialStrings += 2;
+ }
+ currentLen++;
+ atStart = FALSE;
+ break;
+
+ case URX_LOOP_SR_I:
+ // [Set]*, like a SETREF, above, in what it can match,
+ // but may not match at all, so currentLen is not incremented.
+ if (currentLen == 0) {
+ int32_t sn = URX_VAL(op);
+ U_ASSERT(sn > 0 && sn < fRXPat->fSets->size());
+ const UnicodeSet *s = (UnicodeSet *)fRXPat->fSets->elementAt(sn);
+ fRXPat->fInitialChars->addAll(*s);
+ numInitialStrings += 2;
+ }
+ atStart = FALSE;
+ break;
+
+ case URX_LOOP_DOT_I:
+ if (currentLen == 0) {
+ // .* at the start of a pattern.
+ // Any character can begin the match.
+ fRXPat->fInitialChars->clear();
+ fRXPat->fInitialChars->complement();
+ numInitialStrings += 2;
+ }
+ atStart = FALSE;
+ break;
+
+
+ case URX_STATIC_SETREF:
+ if (currentLen == 0) {
+ int32_t sn = URX_VAL(op);
+ U_ASSERT(sn>0 && sn<URX_LAST_SET);
+ const UnicodeSet *s = fRXPat->fStaticSets[sn];
+ fRXPat->fInitialChars->addAll(*s);
+ numInitialStrings += 2;
+ }
+ currentLen++;
+ atStart = FALSE;
+ break;
+
+
+
+ case URX_STAT_SETREF_N:
+ if (currentLen == 0) {
+ int32_t sn = URX_VAL(op);
+ const UnicodeSet *s = fRXPat->fStaticSets[sn];
+ UnicodeSet sc(*s);
+ sc.complement();
+ fRXPat->fInitialChars->addAll(sc);
+ numInitialStrings += 2;
+ }
+ currentLen++;
+ atStart = FALSE;
+ break;
+
+
+
+ case URX_BACKSLASH_D:
+ // Digit Char
+ if (currentLen == 0) {
+ UnicodeSet s;
+ s.applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, U_GC_ND_MASK, *fStatus);
+ if (URX_VAL(op) != 0) {
+ s.complement();
+ }
+ fRXPat->fInitialChars->addAll(s);
+ numInitialStrings += 2;
+ }
+ currentLen++;
+ atStart = FALSE;
+ break;
+
+
+ case URX_ONECHAR_I:
+ // Case Insensitive Single Character.
+ if (currentLen == 0) {
+ UChar32 c = URX_VAL(op);
+ if (u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
+ // character may have distinct cased forms. Add all of them
+ // to the set of possible starting match chars.
+ UnicodeSet s(c, c);
+ s.closeOver(USET_CASE_INSENSITIVE);
+ fRXPat->fInitialChars->addAll(s);
+ } else {
+ // Char has no case variants. Just add it as-is to the
+ // set of possible starting chars.
+ fRXPat->fInitialChars->add(c);
+ }
+ numInitialStrings += 2;
+ }
+ currentLen++;
+ atStart = FALSE;
+ break;
+
+
+ case URX_BACKSLASH_X: // Grahpeme Cluster. Minimum is 1, max unbounded.
+ case URX_DOTANY_ALL: // . matches one or two.
+ case URX_DOTANY:
+ case URX_DOTANY_ALL_PL:
+ case URX_DOTANY_PL:
+ if (currentLen == 0) {
+ // These constructs are all bad news when they appear at the start
+ // of a match. Any character can begin the match.
+ fRXPat->fInitialChars->clear();
+ fRXPat->fInitialChars->complement();
+ numInitialStrings += 2;
+ }
+ currentLen++;
+ atStart = FALSE;
+ break;
+
+
+ case URX_JMPX:
+ loc++; // Except for extra operand on URX_JMPX, same as URX_JMP.
+ case URX_JMP:
+ {
+ int32_t jmpDest = URX_VAL(op);
+ if (jmpDest < loc) {
+ // Loop of some kind. Can safely ignore, the worst that will happen
+ // is that we understate the true minimum length
+ currentLen = forwardedLength.elementAti(loc+1);
+
+ } else {
+ // Forward jump. Propagate the current min length to the target loc of the jump.
+ U_ASSERT(jmpDest <= end+1);
+ if (forwardedLength.elementAti(jmpDest) > currentLen) {
+ forwardedLength.setElementAt(currentLen, jmpDest);
+ }
+ }
+ }
+ atStart = FALSE;
+ break;
+
+ case URX_JMP_SAV:
+ case URX_JMP_SAV_X:
+ // Combo of state save to the next loc, + jmp backwards.
+ // Net effect on min. length computation is nothing.
+ atStart = FALSE;
+ break;
+
+ case URX_FAIL:
+ // Fails are kind of like a branch, except that the min length was
+ // propagated already, by the state save.
+ currentLen = forwardedLength.elementAti(loc+1);
+ atStart = FALSE;
+ break;
+
+
+ case URX_STATE_SAVE:
+ {
+ // State Save, for forward jumps, propagate the current minimum.
+ // of the state save.
+ int32_t jmpDest = URX_VAL(op);
+ if (jmpDest > loc) {
+ if (currentLen < forwardedLength.elementAti(jmpDest)) {
+ forwardedLength.setElementAt(currentLen, jmpDest);
+ }
+ }
+ }
+ atStart = FALSE;
+ break;
+
+
+
+
+ case URX_STRING:
+ {
+ loc++;
+ int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+ int32_t stringLen = URX_VAL(stringLenOp);
+ U_ASSERT(URX_TYPE(stringLenOp) == URX_STRING_LEN);
+ U_ASSERT(stringLenOp >= 2);
+ if (currentLen == 0) {
+ // Add the starting character of this string to the set of possible starting
+ // characters for this pattern.
+ int32_t stringStartIdx = URX_VAL(op);
+ UChar32 c = fRXPat->fLiteralText.char32At(stringStartIdx);
+ fRXPat->fInitialChars->add(c);
+
+ // Remember this string. After the entire pattern has been checked,
+ // if nothing else is identified that can start a match, we'll use it.
+ numInitialStrings++;
+ fRXPat->fInitialStringIdx = stringStartIdx;
+ fRXPat->fInitialStringLen = stringLen;
+ }
+
+ currentLen += stringLen;
+ atStart = FALSE;
+ }
+ break;
+
+ case URX_STRING_I:
+ {
+ // Case-insensitive string. Unlike exact-match strings, we won't
+ // attempt a string search for possible match positions. But we
+ // do update the set of possible starting characters.
+ loc++;
+ int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+ int32_t stringLen = URX_VAL(stringLenOp);
+ U_ASSERT(URX_TYPE(stringLenOp) == URX_STRING_LEN);
+ U_ASSERT(stringLenOp >= 2);
+ if (currentLen == 0) {
+ // Add the starting character of this string to the set of possible starting
+ // characters for this pattern.
+ int32_t stringStartIdx = URX_VAL(op);
+ UChar32 c = fRXPat->fLiteralText.char32At(stringStartIdx);
+ UnicodeSet s(c, c);
+ s.closeOver(USET_CASE_INSENSITIVE);
+ fRXPat->fInitialChars->addAll(s);
+ numInitialStrings += 2; // Matching on an initial string not possible.
+ }
+ currentLen += stringLen;
+ atStart = FALSE;
+ }
+ break;
+
+ case URX_CTR_INIT:
+ case URX_CTR_INIT_NG:
+ {
+ // Loop Init Ops. These don't change the min length, but they are 4 word ops
+ // so location must be updated accordingly.
+ // Loop Init Ops.
+ // If the min loop count == 0
+ // move loc forwards to the end of the loop, skipping over the body.
+ // If the min count is > 0,
+ // continue normal processing of the body of the loop.
+ int32_t loopEndLoc = fRXPat->fCompiledPat->elementAti(loc+1);
+ loopEndLoc = URX_VAL(loopEndLoc);
+ int32_t minLoopCount = fRXPat->fCompiledPat->elementAti(loc+2);
+ if (minLoopCount == 0) {
+ // Min Loop Count of 0, treat like a forward branch and
+ // move the current minimum length up to the target
+ // (end of loop) location.
+ U_ASSERT(loopEndLoc <= end+1);
+ if (forwardedLength.elementAti(loopEndLoc) > currentLen) {
+ forwardedLength.setElementAt(currentLen, loopEndLoc);
+ }
+ }
+ loc+=3; // Skips over operands of CTR_INIT
+ }
+ atStart = FALSE;
+ break;
+
+
+ case URX_CTR_LOOP:
+ case URX_CTR_LOOP_NG:
+ // Loop ops.
+ // The jump is conditional, backwards only.
+ atStart = FALSE;
+ break;
+
+ case URX_LOOP_C:
+ // More loop ops. These state-save to themselves.
+ // don't change the minimum match
+ atStart = FALSE;
+ break;
+
+
+ case URX_LA_START:
+ case URX_LB_START:
+ {
+ // Look-around. Scan forward until the matching look-ahead end,
+ // without processing the look-around block. This is overly pessimistic.
+ int32_t depth = 0;
+ for (;;) {
+ loc++;
+ op = fRXPat->fCompiledPat->elementAti(loc);
+ if (URX_TYPE(op) == URX_LA_START || URX_TYPE(op) == URX_LB_START) {
+ depth++;
+ }
+ if (URX_TYPE(op) == URX_LA_END || URX_TYPE(op)==URX_LBN_END) {
+ if (depth == 0) {
+ break;
+ }
+ depth--;
+ }
+ if (URX_TYPE(op) == URX_STATE_SAVE) {
+ // Need this because neg lookahead blocks will FAIL to outside
+ // of the block.
+ int32_t jmpDest = URX_VAL(op);
+ if (jmpDest > loc) {
+ if (currentLen < forwardedLength.elementAti(jmpDest)) {
+ forwardedLength.setElementAt(currentLen, jmpDest);
+ }
+ }
+ }
+ U_ASSERT(loc <= end);
+ }
+ }
+ break;
+
+ case URX_LA_END:
+ case URX_LB_CONT:
+ case URX_LB_END:
+ case URX_LBN_CONT:
+ case URX_LBN_END:
+ U_ASSERT(FALSE); // Shouldn't get here. These ops should be
+ // consumed by the scan in URX_LA_START and LB_START
+
+ break;
+
+ default:
+ U_ASSERT(FALSE);
+ }
+
+ }
+
+
+ // We have finished walking through the ops. Check whether some forward jump
+ // propagated a shorter length to location end+1.
+ if (forwardedLength.elementAti(end+1) < currentLen) {
+ currentLen = forwardedLength.elementAti(end+1);
+ }
+
+
+ fRXPat->fInitialChars8->init(fRXPat->fInitialChars);
+
+
+ // Sort out what we should check for when looking for candidate match start positions.
+ // In order of preference,
+ // 1. Start of input text buffer.
+ // 2. A literal string.
+ // 3. Start of line in multi-line mode.
+ // 4. A single literal character.
+ // 5. A character from a set of characters.
+ //
+ if (fRXPat->fStartType == START_START) {
+ // Match only at the start of an input text string.
+ // start type is already set. We're done.
+ } else if (numInitialStrings == 1 && fRXPat->fMinMatchLen > 0) {
+ // Match beginning only with a literal string.
+ UChar32 c = fRXPat->fLiteralText.char32At(fRXPat->fInitialStringIdx);
+ U_ASSERT(fRXPat->fInitialChars->contains(c));
+ fRXPat->fStartType = START_STRING;
+ fRXPat->fInitialChar = c;
+ } else if (fRXPat->fStartType == START_LINE) {
+ // Match at start of line in Multi-Line mode.
+ // Nothing to do here; everything is already set.
+ } else if (fRXPat->fMinMatchLen == 0) {
+ // Zero length match possible. We could start anywhere.
+ fRXPat->fStartType = START_NO_INFO;
+ } else if (fRXPat->fInitialChars->size() == 1) {
+ // All matches begin with the same char.
+ fRXPat->fStartType = START_CHAR;
+ fRXPat->fInitialChar = fRXPat->fInitialChars->charAt(0);
+ U_ASSERT(fRXPat->fInitialChar != (UChar32)-1);
+ } else if (fRXPat->fInitialChars->contains((UChar32)0, (UChar32)0x10ffff) == FALSE &&
+ fRXPat->fMinMatchLen > 0) {
+ // Matches start with a set of character smaller than the set of all chars.
+ fRXPat->fStartType = START_SET;
+ } else {
+ // Matches can start with anything
+ fRXPat->fStartType = START_NO_INFO;
+ }
+
+ return;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// minMatchLength Calculate the length of the shortest string that could
+// match the specified pattern.
+// Length is in 16 bit code units, not code points.
+//
+// The calculated length may not be exact. The returned
+// value may be shorter than the actual minimum; it must
+// never be longer.
+//
+// start and end are the range of p-code operations to be
+// examined. The endpoints are included in the range.
+//
+//------------------------------------------------------------------------------
+int32_t RegexCompile::minMatchLength(int32_t start, int32_t end) {
+ if (U_FAILURE(*fStatus)) {
+ return 0;
+ }
+
+ U_ASSERT(start <= end);
+ U_ASSERT(end < fRXPat->fCompiledPat->size());
+
+
+ int32_t loc;
+ int32_t op;
+ int32_t opType;
+ int32_t currentLen = 0;
+
+
+ // forwardedLength is a vector holding minimum-match-length values that
+ // are propagated forward in the pattern by JMP or STATE_SAVE operations.
+ // It must be one longer than the pattern being checked because some ops
+ // will jmp to a end-of-block+1 location from within a block, and we must
+ // count those when checking the block.
+ UVector32 forwardedLength(end+2, *fStatus);
+ forwardedLength.setSize(end+2);
+ for (loc=start; loc<=end+1; loc++) {
+ forwardedLength.setElementAt(INT32_MAX, loc);
+ }
+
+ for (loc = start; loc<=end; loc++) {
+ op = fRXPat->fCompiledPat->elementAti(loc);
+ opType = URX_TYPE(op);
+
+ // The loop is advancing linearly through the pattern.
+ // If the op we are now at was the destination of a branch in the pattern,
+ // and that path has a shorter minimum length than the current accumulated value,
+ // replace the current accumulated value.
+ U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);
+ if (forwardedLength.elementAti(loc) < currentLen) {
+ currentLen = forwardedLength.elementAti(loc);
+ U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);
+ }
+
+ switch (opType) {
+ // Ops that don't change the total length matched
+ case URX_RESERVED_OP:
+ case URX_END:
+ case URX_STRING_LEN:
+ case URX_NOP:
+ case URX_START_CAPTURE:
+ case URX_END_CAPTURE:
+ case URX_BACKSLASH_B:
+ case URX_BACKSLASH_BU:
+ case URX_BACKSLASH_G:
+ case URX_BACKSLASH_Z:
+ case URX_CARET:
+ case URX_DOLLAR:
+ case URX_RELOC_OPRND:
+ case URX_STO_INP_LOC:
+ case URX_DOLLAR_M:
+ case URX_CARET_M:
+ case URX_BACKTRACK:
+ case URX_BACKREF: // BackRef. Must assume that it might be a zero length match
+ case URX_BACKREF_I:
+
+ case URX_STO_SP: // Setup for atomic or possessive blocks. Doesn't change what can match.
+ case URX_LD_SP:
+
+ case URX_JMP_SAV:
+ case URX_JMP_SAV_X:
+ break;
+
+
+ // Ops that match a minimum of one character (one or two 16 bit code units.)
+ //
+ case URX_ONECHAR:
+ case URX_STATIC_SETREF:
+ case URX_STAT_SETREF_N:
+ case URX_SETREF:
+ case URX_BACKSLASH_D:
+ case URX_ONECHAR_I:
+ case URX_BACKSLASH_X: // Grahpeme Cluster. Minimum is 1, max unbounded.
+ case URX_DOTANY_ALL: // . matches one or two.
+ case URX_DOTANY:
+ case URX_DOTANY_PL:
+ case URX_DOTANY_ALL_PL:
+ currentLen++;
+ break;
+
+
+ case URX_JMPX:
+ loc++; // URX_JMPX has an extra operand, ignored here,
+ // otherwise processed identically to URX_JMP.
+ case URX_JMP:
+ {
+ int32_t jmpDest = URX_VAL(op);
+ if (jmpDest < loc) {
+ // Loop of some kind. Can safely ignore, the worst that will happen
+ // is that we understate the true minimum length
+ currentLen = forwardedLength.elementAti(loc+1);
+ } else {
+ // Forward jump. Propagate the current min length to the target loc of the jump.
+ U_ASSERT(jmpDest <= end+1);
+ if (forwardedLength.elementAti(jmpDest) > currentLen) {
+ forwardedLength.setElementAt(currentLen, jmpDest);
+ }
+ }
+ }
+ break;
+
+ case URX_FAIL:
+ {
+ // Fails are kind of like a branch, except that the min length was
+ // propagated already, by the state save.
+ currentLen = forwardedLength.elementAti(loc+1);
+ U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);
+ }
+ break;
+
+
+ case URX_STATE_SAVE:
+ {
+ // State Save, for forward jumps, propagate the current minimum.
+ // of the state save.
+ int32_t jmpDest = URX_VAL(op);
+ if (jmpDest > loc) {
+ if (currentLen < forwardedLength.elementAti(jmpDest)) {
+ forwardedLength.setElementAt(currentLen, jmpDest);
+ }
+ }
+ }
+ break;
+
+
+ case URX_STRING:
+ case URX_STRING_I:
+ {
+ loc++;
+ int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+ currentLen += URX_VAL(stringLenOp);
+ }
+ break;
+
+
+ case URX_CTR_INIT:
+ case URX_CTR_INIT_NG:
+ {
+ // Loop Init Ops.
+ // If the min loop count == 0
+ // move loc forwards to the end of the loop, skipping over the body.
+ // If the min count is > 0,
+ // continue normal processing of the body of the loop.
+ int32_t loopEndLoc = fRXPat->fCompiledPat->elementAti(loc+1);
+ loopEndLoc = URX_VAL(loopEndLoc);
+ int32_t minLoopCount = fRXPat->fCompiledPat->elementAti(loc+2);
+ if (minLoopCount == 0) {
+ loc = loopEndLoc;
+ } else {
+ loc+=3; // Skips over operands of CTR_INIT
+ }
+ }
+ break;
+
+
+ case URX_CTR_LOOP:
+ case URX_CTR_LOOP_NG:
+ // Loop ops.
+ // The jump is conditional, backwards only.
+ break;
+
+ case URX_LOOP_SR_I:
+ case URX_LOOP_DOT_I:
+ case URX_LOOP_C:
+ // More loop ops. These state-save to themselves.
+ // don't change the minimum match - could match nothing at all.
+ break;
+
+
+ case URX_LA_START:
+ case URX_LB_START:
+ {
+ // Look-around. Scan forward until the matching look-ahead end,
+ // without processing the look-around block. This is overly pessimistic.
+ // TODO: Positive lookahead could recursively do the block, then continue
+ // with the longer of the block or the value coming in.
+ int32_t depth = 0;
+ for (;;) {
+ loc++;
+ op = fRXPat->fCompiledPat->elementAti(loc);
+ if (URX_TYPE(op) == URX_LA_START || URX_TYPE(op) == URX_LB_START) {
+ depth++;
+ }
+ if (URX_TYPE(op) == URX_LA_END || URX_TYPE(op)==URX_LBN_END) {
+ if (depth == 0) {
+ break;
+ }
+ depth--;
+ }
+ if (URX_TYPE(op) == URX_STATE_SAVE) {
+ // Need this because neg lookahead blocks will FAIL to outside
+ // of the block.
+ int32_t jmpDest = URX_VAL(op);
+ if (jmpDest > loc) {
+ if (currentLen < forwardedLength.elementAti(jmpDest)) {
+ forwardedLength.setElementAt(currentLen, jmpDest);
+ }
+ }
+ }
+
+ U_ASSERT(loc <= end);
+ }
+ }
+ break;
+
+ case URX_LA_END:
+ case URX_LB_CONT:
+ case URX_LB_END:
+ case URX_LBN_CONT:
+ case URX_LBN_END:
+ // Only come here if the matching URX_LA_START or URX_LB_START was not in the
+ // range being sized, which happens when measuring size of look-behind blocks.
+ break;
+
+ default:
+ U_ASSERT(FALSE);
+ }
+
+ }
+
+ // We have finished walking through the ops. Check whether some forward jump
+ // propagated a shorter length to location end+1.
+ if (forwardedLength.elementAti(end+1) < currentLen) {
+ currentLen = forwardedLength.elementAti(end+1);
+ U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);
+ }
+
+ return currentLen;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// maxMatchLength Calculate the length of the longest string that could
+// match the specified pattern.
+// Length is in 16 bit code units, not code points.
+//
+// The calculated length may not be exact. The returned
+// value may be longer than the actual maximum; it must
+// never be shorter.
+//
+//------------------------------------------------------------------------------
+int32_t RegexCompile::maxMatchLength(int32_t start, int32_t end) {
+ if (U_FAILURE(*fStatus)) {
+ return 0;
+ }
+ U_ASSERT(start <= end);
+ U_ASSERT(end < fRXPat->fCompiledPat->size());
+
+
+ int32_t loc;
+ int32_t op;
+ int32_t opType;
+ int32_t currentLen = 0;
+ UVector32 forwardedLength(end+1, *fStatus);
+ forwardedLength.setSize(end+1);
+
+ for (loc=start; loc<=end; loc++) {
+ forwardedLength.setElementAt(0, loc);
+ }
+
+ for (loc = start; loc<=end; loc++) {
+ op = fRXPat->fCompiledPat->elementAti(loc);
+ opType = URX_TYPE(op);
+
+ // The loop is advancing linearly through the pattern.
+ // If the op we are now at was the destination of a branch in the pattern,
+ // and that path has a longer maximum length than the current accumulated value,
+ // replace the current accumulated value.
+ if (forwardedLength.elementAti(loc) > currentLen) {
+ currentLen = forwardedLength.elementAti(loc);
+ }
+
+ switch (opType) {
+ // Ops that don't change the total length matched
+ case URX_RESERVED_OP:
+ case URX_END:
+ case URX_STRING_LEN:
+ case URX_NOP:
+ case URX_START_CAPTURE:
+ case URX_END_CAPTURE:
+ case URX_BACKSLASH_B:
+ case URX_BACKSLASH_BU:
+ case URX_BACKSLASH_G:
+ case URX_BACKSLASH_Z:
+ case URX_CARET:
+ case URX_DOLLAR:
+ case URX_RELOC_OPRND:
+ case URX_STO_INP_LOC:
+ case URX_DOLLAR_M:
+ case URX_CARET_M:
+ case URX_BACKTRACK:
+
+ case URX_STO_SP: // Setup for atomic or possessive blocks. Doesn't change what can match.
+ case URX_LD_SP:
+
+ case URX_LB_END:
+ case URX_LB_CONT:
+ case URX_LBN_CONT:
+ case URX_LBN_END:
+ break;
+
+
+ // Ops that increase that cause an unbounded increase in the length
+ // of a matched string, or that increase it a hard to characterize way.
+ // Call the max length unbounded, and stop further checking.
+ case URX_BACKREF: // BackRef. Must assume that it might be a zero length match
+ case URX_BACKREF_I:
+ case URX_BACKSLASH_X: // Grahpeme Cluster. Minimum is 1, max unbounded.
+ case URX_DOTANY_PL:
+ case URX_DOTANY_ALL_PL:
+ currentLen = INT32_MAX;
+ break;
+
+
+ // Ops that match a max of one character (possibly two 16 bit code units.)
+ //
+ case URX_STATIC_SETREF:
+ case URX_STAT_SETREF_N:
+ case URX_SETREF:
+ case URX_BACKSLASH_D:
+ case URX_ONECHAR_I:
+ case URX_DOTANY_ALL:
+ case URX_DOTANY:
+ currentLen+=2;
+ break;
+
+ // Single literal character. Increase current max length by one or two,
+ // depending on whether the char is in the supplementary range.
+ case URX_ONECHAR:
+ currentLen++;
+ if (URX_VAL(op) > 0x10000) {
+ currentLen++;
+ }
+ break;
+
+ // Jumps.
+ //
+ case URX_JMP:
+ case URX_JMPX:
+ case URX_JMP_SAV:
+ case URX_JMP_SAV_X:
+ {
+ int32_t jmpDest = URX_VAL(op);
+ if (jmpDest < loc) {
+ // Loop of some kind. Max match length is unbounded.
+ currentLen = INT32_MAX;
+ } else {
+ // Forward jump. Propagate the current min length to the target loc of the jump.
+ if (forwardedLength.elementAti(jmpDest) < currentLen) {
+ forwardedLength.setElementAt(currentLen, jmpDest);
+ }
+ currentLen = 0;
+ }
+ }
+ break;
+
+ case URX_FAIL:
+ // Fails are kind of like a branch, except that the max length was
+ // propagated already, by the state save.
+ currentLen = forwardedLength.elementAti(loc+1);
+ break;
+
+
+ case URX_STATE_SAVE:
+ {
+ // State Save, for forward jumps, propagate the current minimum.
+ // of the state save.
+ // For backwards jumps, they create a loop, maximum
+ // match length is unbounded.
+ int32_t jmpDest = URX_VAL(op);
+ if (jmpDest > loc) {
+ if (currentLen > forwardedLength.elementAti(jmpDest)) {
+ forwardedLength.setElementAt(currentLen, jmpDest);
+ }
+ } else {
+ currentLen = INT32_MAX;
+ }
+ }
+ break;
+
+
+
+
+ case URX_STRING:
+ case URX_STRING_I:
+ {
+ loc++;
+ int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+ currentLen += URX_VAL(stringLenOp);
+ }
+ break;
+
+
+ case URX_CTR_INIT:
+ case URX_CTR_INIT_NG:
+ case URX_CTR_LOOP:
+ case URX_CTR_LOOP_NG:
+ case URX_LOOP_SR_I:
+ case URX_LOOP_DOT_I:
+ case URX_LOOP_C:
+ // For anything to do with loops, make the match length unbounded.
+ // Note: INIT instructions are multi-word. Can ignore because
+ // INT32_MAX length will stop the per-instruction loop.
+ currentLen = INT32_MAX;
+ break;
+
+
+
+ case URX_LA_START:
+ case URX_LA_END:
+ // Look-ahead. Just ignore, treat the look-ahead block as if
+ // it were normal pattern. Gives a too-long match length,
+ // but good enough for now.
+ break;
+
+ // End of look-ahead ops should always be consumed by the processing at
+ // the URX_LA_START op.
+ // U_ASSERT(FALSE);
+ // break;
+
+ case URX_LB_START:
+ {
+ // Look-behind. Scan forward until the matching look-around end,
+ // without processing the look-behind block.
+ int32_t depth = 0;
+ for (;;) {
+ loc++;
+ op = fRXPat->fCompiledPat->elementAti(loc);
+ if (URX_TYPE(op) == URX_LA_START || URX_TYPE(op) == URX_LB_START) {
+ depth++;
+ }
+ if (URX_TYPE(op) == URX_LA_END || URX_TYPE(op)==URX_LBN_END) {
+ if (depth == 0) {
+ break;
+ }
+ depth--;
+ }
+ U_ASSERT(loc < end);
+ }
+ }
+ break;
+
+ default:
+ U_ASSERT(FALSE);
+ }
+
+
+ if (currentLen == INT32_MAX) {
+ // The maximum length is unbounded.
+ // Stop further processing of the pattern.
+ break;
+ }
+
+ }
+ return currentLen;
+
+}
+
+
+//------------------------------------------------------------------------------
+//
+// stripNOPs Remove any NOP operations from the compiled pattern code.
+// Extra NOPs are inserted for some constructs during the initial
+// code generation to provide locations that may be patched later.
+// Many end up unneeded, and are removed by this function.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::stripNOPs() {
+
+ if (U_FAILURE(*fStatus)) {
+ return;
+ }
+
+ int32_t end = fRXPat->fCompiledPat->size();
+ UVector32 deltas(end, *fStatus);
+
+ // Make a first pass over the code, computing the amount that things
+ // will be offset at each location in the original code.
+ int32_t loc;
+ int32_t d = 0;
+ for (loc=0; loc<end; loc++) {
+ deltas.addElement(d, *fStatus);
+ int32_t op = fRXPat->fCompiledPat->elementAti(loc);
+ if (URX_TYPE(op) == URX_NOP) {
+ d++;
+ }
+ }
+
+ // Make a second pass over the code, removing the NOPs by moving following
+ // code up, and patching operands that refer to code locations that
+ // are being moved. The array of offsets from the first step is used
+ // to compute the new operand values.
+ int32_t src;
+ int32_t dst = 0;
+ for (src=0; src<end; src++) {
+ int32_t op = fRXPat->fCompiledPat->elementAti(src);
+ int32_t opType = URX_TYPE(op);
+ switch (opType) {
+ case URX_NOP:
+ break;
+
+ case URX_STATE_SAVE:
+ case URX_JMP:
+ case URX_CTR_LOOP:
+ case URX_CTR_LOOP_NG:
+ case URX_RELOC_OPRND:
+ case URX_JMPX:
+ case URX_JMP_SAV:
+ case URX_JMP_SAV_X:
+ // These are instructions with operands that refer to code locations.
+ {
+ int32_t operandAddress = URX_VAL(op);
+ U_ASSERT(operandAddress>=0 && operandAddress<deltas.size());
+ int32_t fixedOperandAddress = operandAddress - deltas.elementAti(operandAddress);
+ op = URX_BUILD(opType, fixedOperandAddress);
+ fRXPat->fCompiledPat->setElementAt(op, dst);
+ dst++;
+ break;
+ }
+
+ case URX_RESERVED_OP:
+ case URX_RESERVED_OP_N:
+ case URX_BACKTRACK:
+ case URX_END:
+ case URX_ONECHAR:
+ case URX_STRING:
+ case URX_STRING_LEN:
+ case URX_START_CAPTURE:
+ case URX_END_CAPTURE:
+ case URX_STATIC_SETREF:
+ case URX_STAT_SETREF_N:
+ case URX_SETREF:
+ case URX_DOTANY:
+ case URX_FAIL:
+ case URX_BACKSLASH_B:
+ case URX_BACKSLASH_BU:
+ case URX_BACKSLASH_G:
+ case URX_BACKSLASH_X:
+ case URX_BACKSLASH_Z:
+ case URX_DOTANY_ALL:
+ case URX_DOTANY_ALL_PL:
+ case URX_DOTANY_PL:
+ case URX_BACKSLASH_D:
+ case URX_CARET:
+ case URX_DOLLAR:
+ case URX_CTR_INIT:
+ case URX_CTR_INIT_NG:
+ case URX_STO_SP:
+ case URX_LD_SP:
+ case URX_BACKREF:
+ case URX_STO_INP_LOC:
+ case URX_LA_START:
+ case URX_LA_END:
+ case URX_ONECHAR_I:
+ case URX_STRING_I:
+ case URX_BACKREF_I:
+ case URX_DOLLAR_M:
+ case URX_CARET_M:
+ case URX_LB_START:
+ case URX_LB_CONT:
+ case URX_LB_END:
+ case URX_LBN_CONT:
+ case URX_LBN_END:
+ case URX_LOOP_SR_I:
+ case URX_LOOP_DOT_I:
+ case URX_LOOP_C:
+ // These instructions are unaltered by the relocation.
+ fRXPat->fCompiledPat->setElementAt(op, dst);
+ dst++;
+ break;
+
+ default:
+ // Some op is unaccounted for.
+ U_ASSERT(FALSE);
+ error(U_REGEX_INTERNAL_ERROR);
+ }
+ }
+
+ fRXPat->fCompiledPat->setSize(dst);
+}
+
+
+
+
+//------------------------------------------------------------------------------
+//
+// OptDotStar Optimize patterns that end with a '.*' or '.+' to
+// just advance the input to the end.
+//
+// Transform this compiled sequence
+// [DOT_ANY | DOT_ANY_ALL]
+// JMP_SAV to previous instruction
+// [NOP | END_CAPTURE | DOLLAR | BACKSLASH_Z]*
+// END
+//
+// To
+// NOP
+// [DOT_ANY_PL | DOT_ANY_ALL_PL]
+// [NOP | END_CAPTURE | DOLLAR | BACKSLASH_Z]*
+// END
+//
+//------------------------------------------------------------------------------
+void RegexCompile::OptDotStar() {
+ // Scan backwards in the pattern, looking for a JMP_SAV near the end.
+ int32_t jmpLoc;
+ int32_t op = 0;
+ int32_t opType;
+ for (jmpLoc=fRXPat->fCompiledPat->size(); jmpLoc--;) {
+ U_ASSERT(jmpLoc>0);
+ op = fRXPat->fCompiledPat->elementAti(jmpLoc);
+ opType = URX_TYPE(op);
+ switch(opType) {
+
+
+ case URX_END:
+ case URX_NOP:
+ case URX_END_CAPTURE:
+ case URX_DOLLAR_M:
+ case URX_DOLLAR:
+ case URX_BACKSLASH_Z:
+ // These ops may follow the JMP_SAV without preventing us from
+ // doing this optimization.
+ continue;
+
+ case URX_JMP_SAV:
+ // Got a trailing JMP_SAV that's a candidate for optimization.
+ break;
+
+ default:
+ // This optimization not possible.
+ return;
+ }
+ break; // from the for loop.
+ }
+
+ // We found in URX_JMP_SAV near the end that is a candidate for optimizing.
+ // Is the target address the previous instruction?
+ // Is the previous instruction a flavor of URX_DOTANY
+ int32_t loopTopLoc = URX_VAL(op);
+ if (loopTopLoc != jmpLoc-1) {
+ return;
+ }
+ int32_t newOp;
+ int32_t oldOp = fRXPat->fCompiledPat->elementAti(loopTopLoc);
+ int32_t oldOpType = opType = URX_TYPE(oldOp);
+ if (oldOpType == URX_DOTANY) {
+ newOp = URX_BUILD(URX_DOTANY_PL, 0);
+ }
+ else if (oldOpType == URX_DOTANY_ALL) {
+ newOp = URX_BUILD(URX_DOTANY_ALL_PL, 0);
+ } else {
+ return; // Sequence we were looking for isn't there.
+ }
+
+ // Substitute the new instructions into the pattern.
+ // The NOP will be removed in a later optimization step.
+ fRXPat->fCompiledPat->setElementAt(URX_BUILD(URX_NOP, 0), loopTopLoc);
+ fRXPat->fCompiledPat->setElementAt(newOp, jmpLoc);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// Error Report a rule parse error.
+// Only report it if no previous error has been recorded.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::error(UErrorCode e) {
+ if (U_SUCCESS(*fStatus)) {
+ *fStatus = e;
+ fParseErr->line = fLineNum;
+ fParseErr->offset = fCharNum;
+
+ // Fill in the context.
+ // Note: extractBetween() pins supplied indicies to the string bounds.
+ uprv_memset(fParseErr->preContext, 0, sizeof(fParseErr->preContext));
+ uprv_memset(fParseErr->postContext, 0, sizeof(fParseErr->postContext));
+ fRXPat->fPattern.extractBetween(fScanIndex-U_PARSE_CONTEXT_LEN+1, fScanIndex,
+ fParseErr->preContext, 0);
+ fRXPat->fPattern.extractBetween(fScanIndex, fScanIndex+U_PARSE_CONTEXT_LEN-1,
+ fParseErr->postContext, 0);
+ }
+}
+
+
+//
+// Assorted Unicode character constants.
+// Numeric because there is no portable way to enter them as literals.
+// (Think EBCDIC).
+//
+static const UChar chCR = 0x0d; // New lines, for terminating comments.
+static const UChar chLF = 0x0a;
+static const UChar chNEL = 0x85; // NEL newline variant
+static const UChar chLS = 0x2028; // Unicode Line Separator
+static const UChar chPound = 0x23; // '#', introduces a comment.
+static const UChar chE = 0x45; // 'E'
+static const UChar chUpperN = 0x4E;
+static const UChar chLowerP = 0x70;
+static const UChar chUpperP = 0x50;
+static const UChar chBackSlash = 0x5c; // '\' introduces a char escape
+static const UChar chLBracket = 0x5b;
+static const UChar chRBracket = 0x5d;
+static const UChar chRBrace = 0x7d;
+
+
+//------------------------------------------------------------------------------
+//
+// nextCharLL Low Level Next Char from the regex pattern.
+// Get a char from the string, keep track of input position
+// for error reporting.
+//
+//------------------------------------------------------------------------------
+UChar32 RegexCompile::nextCharLL() {
+ UChar32 ch;
+ UnicodeString &pattern = fRXPat->fPattern;
+
+ if (fPeekChar != -1) {
+ ch = fPeekChar;
+ fPeekChar = -1;
+ return ch;
+ }
+ if (fPatternLength==0 || fNextIndex >= fPatternLength) {
+ return (UChar32)-1;
+ }
+ ch = pattern.char32At(fNextIndex);
+ fNextIndex = pattern.moveIndex32(fNextIndex, 1);
+
+ if (ch == chCR ||
+ ch == chNEL ||
+ ch == chLS ||
+ ch == chLF && fLastChar != chCR) {
+ // Character is starting a new line. Bump up the line number, and
+ // reset the column to 0.
+ fLineNum++;
+ fCharNum=0;
+ if (fQuoteMode) {
+ error(U_REGEX_RULE_SYNTAX);
+ fQuoteMode = FALSE;
+ }
+ }
+ else {
+ // Character is not starting a new line. Except in the case of a
+ // LF following a CR, increment the column position.
+ if (ch != chLF) {
+ fCharNum++;
+ }
+ }
+ fLastChar = ch;
+ return ch;
+}
+
+//------------------------------------------------------------------------------
+//
+// peekCharLL Low Level Character Scanning, sneak a peek at the next
+// character without actually getting it.
+//
+//------------------------------------------------------------------------------
+UChar32 RegexCompile::peekCharLL() {
+ if (fPeekChar == -1) {
+ fPeekChar = nextCharLL();
+ }
+ return fPeekChar;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// nextChar for pattern scanning. At this level, we handle stripping
+// out comments and processing some backslash character escapes.
+// The rest of the pattern grammar is handled at the next level up.
+//
+//------------------------------------------------------------------------------
+void RegexCompile::nextChar(RegexPatternChar &c) {
+
+ fScanIndex = fNextIndex;
+ c.fChar = nextCharLL();
+ c.fQuoted = FALSE;
+
+ if (fQuoteMode) {
+ c.fQuoted = TRUE;
+ if ((c.fChar==chBackSlash && peekCharLL()==chE) || c.fChar == (UChar32)-1) {
+ fQuoteMode = FALSE; // Exit quote mode,
+ nextCharLL(); // discard the E
+ nextChar(c); // recurse to get the real next char
+ }
+ }
+ else if (fInBackslashQuote) {
+ // The current character immediately follows a '\'
+ // Don't check for any further escapes, just return it as-is.
+ // Don't set c.fQuoted, because that would prevent the state machine from
+ // dispatching on the character.
+ fInBackslashQuote = FALSE;
+ }
+ else
+ {
+ // We are not in a \Q quoted region \E of the source.
+ //
+ if (fModeFlags & UREGEX_COMMENTS) {
+ //
+ // We are in free-spacing and comments mode.
+ // Scan through any white space and comments, until we
+ // reach a significant character or the end of inut.
+ for (;;) {
+ if (c.fChar == (UChar32)-1) {
+ break; // End of Input
+ }
+ if (c.fChar == chPound && fEOLComments == TRUE) {
+ // Start of a comment. Consume the rest of it, until EOF or a new line
+ for (;;) {
+ c.fChar = nextCharLL();
+ if (c.fChar == (UChar32)-1 || // EOF
+ c.fChar == chCR ||
+ c.fChar == chLF ||
+ c.fChar == chNEL ||
+ c.fChar == chLS) {
+ break;
+ }
+ }
+ }
+ if (uprv_isRuleWhiteSpace(c.fChar) == FALSE) {
+ break;
+ }
+ c.fChar = nextCharLL();
+ }
+ }
+
+ //
+ // check for backslash escaped characters.
+ //
+ int32_t startX = fNextIndex; // start and end positions of the
+ int32_t endX = fNextIndex; // sequence following the '\'
+ if (c.fChar == chBackSlash) {
+ if (RegexStaticSets::gStaticSets->fUnescapeCharSet.contains(peekCharLL())) {
+ //
+ // A '\' sequence that is handled by ICU's standard unescapeAt function.
+ // Includes \uxxxx, \n, \r, many others.
+ // Return the single equivalent character.
+ //
+ nextCharLL(); // get & discard the peeked char.
+ c.fQuoted = TRUE;
+ c.fChar = fRXPat->fPattern.unescapeAt(endX);
+ if (startX == endX) {
+ error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+ }
+ fCharNum += endX - startX;
+ fNextIndex = endX;
+ }
+ else
+ {
+ // We are in a '\' escape that will be handled by the state table scanner.
+ // Just return the backslash, but remember that the following char is to
+ // be taken literally. TODO: this is awkward, think about alternatives.
+ fInBackslashQuote = TRUE;
+ }
+ }
+ }
+
+ // re-enable # to end-of-line comments, in case they were disabled.
+ // They are disabled by the parser upon seeing '(?', but this lasts for
+ // the fetching of the next character only.
+ fEOLComments = TRUE;
+
+ // putc(c.fChar, stdout);
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// scanSet Construct a UnicodeSet from the text at the current scan
+// position. Advance the scan position to the first character
+// after the set.
+//
+// The scan position is normally under the control of the state machine
+// that controls pattern parsing. UnicodeSets, however, are parsed by
+// the UnicodeSet constructor, not by the Regex pattern parser.
+//
+//------------------------------------------------------------------------------
+UnicodeSet *RegexCompile::scanSet() {
+ UnicodeSet *uset = NULL;
+ ParsePosition pos;
+ int i;
+
+ if (U_FAILURE(*fStatus)) {
+ return NULL;
+ }
+
+ pos.setIndex(fScanIndex);
+ UErrorCode localStatus = U_ZERO_ERROR;
+ uint32_t usetFlags = 0;
+ if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
+ usetFlags |= USET_CASE_INSENSITIVE;
+ }
+ if (fModeFlags & UREGEX_COMMENTS) {
+ usetFlags |= USET_IGNORE_SPACE;
+ }
+
+ uset = new UnicodeSet(fRXPat->fPattern, pos,
+ usetFlags, NULL, localStatus);
+ if (U_FAILURE(localStatus)) {
+ // TODO: Get more accurate position of the error from UnicodeSet's return info.
+ // UnicodeSet appears to not be reporting correctly at this time.
+ REGEX_SCAN_DEBUG_PRINTF(("UnicodeSet parse postion.ErrorIndex = %d\n", pos.getIndex()));
+ error(localStatus);
+ delete uset;
+ return NULL;
+ }
+
+ // Advance the current scan postion over the UnicodeSet.
+ // Don't just set fScanIndex because the line/char positions maintained
+ // for error reporting would be thrown off.
+ i = pos.getIndex();
+ for (;;) {
+ if (fNextIndex >= i) {
+ break;
+ }
+ nextCharLL();
+ }
+
+ return uset;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// scanProp Construct a UnicodeSet from the text at the current scan
+// position, which will be of the form \p{whaterver}
+//
+// The scan position will be at the 'p' or 'P'. On return
+// the scan position should be just after the '}'
+//
+// Return a UnicodeSet, constructed from the \P pattern,
+// or NULL if the pattern is invalid.
+//
+//------------------------------------------------------------------------------
+UnicodeSet *RegexCompile::scanProp() {
+ UnicodeSet *uset = NULL;
+
+ if (U_FAILURE(*fStatus)) {
+ return NULL;
+ }
+
+ U_ASSERT(fC.fChar == chLowerP || fC.fChar == chUpperP || fC.fChar == chUpperN);
+
+ // enclose the \p{property} from the regex pattern source in [brackets]
+ UnicodeString setPattern;
+ setPattern.append(chLBracket);
+ setPattern.append(chBackSlash);
+ for (;;) {
+ setPattern.append(fC.fChar);
+ if (fC.fChar == chRBrace) {
+ break;
+ }
+ nextChar(fC);
+ if (fC.fChar == -1) {
+ // Hit the end of the input string without finding the closing '}'
+ error(U_REGEX_PROPERTY_SYNTAX);
+ return NULL;
+ }
+ }
+ setPattern.append(chRBracket);
+
+ uint32_t usetFlags = 0;
+ if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
+ usetFlags |= USET_CASE_INSENSITIVE;
+ }
+ if (fModeFlags & UREGEX_COMMENTS) {
+ usetFlags |= USET_IGNORE_SPACE;
+ }
+
+ // Build the UnicodeSet from the set pattern we just built up in a string.
+ uset = new UnicodeSet(setPattern, usetFlags, NULL, *fStatus);
+ if (U_FAILURE(*fStatus)) {
+ delete uset;
+ uset = NULL;
+ }
+
+ nextChar(fC); // Continue overall regex pattern processing with char after the '}'
+ return uset;
+}
+
+U_NAMESPACE_END
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/regexcmp.h b/Build/source/libs/icu/icu-xetex/i18n/regexcmp.h
new file mode 100644
index 00000000000..ac81684afc3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/regexcmp.h
@@ -0,0 +1,201 @@
+//
+// regexcmp.h
+//
+// Copyright (C) 2002-2007, International Business Machines Corporation and others.
+// All Rights Reserved.
+//
+// This file contains declarations for the class RegexCompile
+//
+// This class is internal to the regular expression implementation.
+// For the public Regular Expression API, see the file "unicode/regex.h"
+//
+
+
+#ifndef RBBISCAN_H
+#define RBBISCAN_H
+
+#include "unicode/utypes.h"
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/uobject.h"
+#include "unicode/uniset.h"
+#include "unicode/parseerr.h"
+#include "uhash.h"
+#include "uvector.h"
+
+
+
+U_NAMESPACE_BEGIN
+
+
+//--------------------------------------------------------------------------------
+//
+// class RegexCompile Contains the regular expression compiler.
+//
+//--------------------------------------------------------------------------------
+static const int kStackSize = 100; // The size of the state stack for
+ // pattern parsing. Corresponds roughly
+ // to the depth of parentheses nesting
+ // that is allowed in the rules.
+
+struct RegexTableEl;
+class RegexPattern;
+
+
+class RegexCompile : public UMemory {
+public:
+
+ struct RegexPatternChar {
+ UChar32 fChar;
+ UBool fQuoted;
+ };
+
+ RegexCompile(RegexPattern *rp, UErrorCode &e);
+
+ void compile(const UnicodeString &pat, UParseError &pp, UErrorCode &e);
+
+
+ virtual ~RegexCompile();
+
+ void nextChar(RegexPatternChar &c); // Get the next char from the input stream.
+
+ static void cleanup(); // Memory cleanup
+
+
+
+ // Categories of parentheses in pattern.
+ // The category is saved in the compile-time parentheses stack frame, and
+ // determines the code to be generated when the matching close ) is encountered.
+ enum EParenClass {
+ plain = -1, // No special handling
+ capturing = -2,
+ atomic = -3,
+ lookAhead = -4,
+ negLookAhead = -5,
+ flags = -6,
+ lookBehind = -7,
+ lookBehindN = -8
+ };
+
+private:
+
+
+ UBool doParseActions(int32_t a);
+ void error(UErrorCode e); // error reporting convenience function.
+
+ UChar32 nextCharLL();
+ UChar32 peekCharLL();
+ UnicodeSet *scanSet();
+ UnicodeSet *scanProp();
+ void handleCloseParen();
+ int32_t blockTopLoc(UBool reserve); // Locate a position in the compiled pattern
+ // at the top of the just completed block
+ // or operation, and optionally ensure that
+ // there is space to add an opcode there.
+ void compileSet(UnicodeSet *theSet); // Generate the compiled pattern for
+ // a reference to a UnicodeSet.
+ void compileInterval(int32_t InitOp, // Generate the code for a {min,max} quantifier.
+ int32_t LoopOp);
+ UBool compileInlineInterval(); // Generate inline code for a {min,max} quantifier
+ void literalChar(UChar32 c); // Compile a literal char
+ void fixLiterals(UBool split=FALSE); // Fix literal strings.
+ void insertOp(int32_t where); // Open up a slot for a new op in the
+ // generated code at the specified location.
+ void emitONE_CHAR(UChar32 c); // EMit a ONE_CHAR op into the compiled code,
+ // taking case mode into account.
+ int32_t minMatchLength(int32_t start,
+ int32_t end);
+ int32_t maxMatchLength(int32_t start,
+ int32_t end);
+ void matchStartType();
+ void stripNOPs();
+ void OptDotStar();
+
+
+ UErrorCode *fStatus;
+ RegexPattern *fRXPat;
+ UParseError *fParseErr;
+
+ //
+ // Data associated with low level character scanning
+ //
+ int32_t fScanIndex; // Index of current character being processed
+ // in the rule input string.
+ int32_t fNextIndex; // Index of the next character, which
+ // is the first character not yet scanned.
+ UBool fQuoteMode; // Scan is in a \Q...\E quoted region
+ UBool fInBackslashQuote; // Scan is between a '\' and the following char.
+ UBool fEOLComments; // When scan is just after '(?', inhibit #... to
+ // end of line comments, in favor of (?#...) comments.
+ int32_t fLineNum; // Line number in input file.
+ int32_t fCharNum; // Char position within the line.
+ UChar32 fLastChar; // Previous char, needed to count CR-LF
+ // as a single line, not two.
+ UChar32 fPeekChar; // Saved char, if we've scanned ahead.
+
+
+ RegexPatternChar fC; // Current char for parse state machine
+ // processing.
+
+ //
+ // Data for the state machine that parses the regular expression.
+ //
+ RegexTableEl **fStateTable; // State Transition Table for regex Rule
+ // parsing. index by p[state][char-class]
+
+ uint16_t fStack[kStackSize]; // State stack, holds state pushes
+ int32_t fStackPtr; // and pops as specified in the state
+ // transition rules.
+
+ //
+ // Data associated with the generation of the pcode for the match engine
+ //
+ int32_t fModeFlags; // Match Flags. (Case Insensitive, etc.)
+ // Always has high bit (31) set so that flag values
+ // on the paren stack are distinguished from relocatable
+ // pcode addresses.
+ int32_t fNewModeFlags; // New flags, while compiling (?i, holds state
+ // until last flag is scanned.
+ UBool fSetModeFlag; // true for (?ismx, false for (?-ismx
+
+
+ int32_t fStringOpStart; // While a literal string is being scanned
+ // holds the start index within RegexPattern.
+ // fLiteralText where the string is being stored.
+
+ int32_t fPatternLength; // Length of the input pattern string.
+
+ UVector32 fParenStack; // parentheses stack. Each frame consists of
+ // the positions of compiled pattern operations
+ // needing fixup, followed by negative value. The
+ // first entry in each frame is the position of the
+ // spot reserved for use when a quantifier
+ // needs to add a SAVE at the start of a (block)
+ // The negative value (-1, -2,...) indicates
+ // the kind of paren that opened the frame. Some
+ // need special handling on close.
+
+
+ int32_t fMatchOpenParen; // The position in the compiled pattern
+ // of the slot reserved for a state save
+ // at the start of the most recently processed
+ // parenthesized block.
+ int32_t fMatchCloseParen; // The position in the pattern of the first
+ // location after the most recently processed
+ // parenthesized block.
+
+ int32_t fIntervalLow; // {lower, upper} interval quantifier values.
+ int32_t fIntervalUpper; // Placed here temporarily, when pattern is
+ // initially scanned. Each new interval
+ // encountered overwrites these values.
+ // -1 for the upper interval value means none
+ // was specified (unlimited occurences.)
+
+ int32_t fNameStartPos; // Starting position of a \N{NAME} name in a
+ // pattern, valid while remainder of name is
+ // scanned.
+};
+
+U_NAMESPACE_END
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+#endif // RBBISCAN_H
diff --git a/Build/source/libs/icu/icu-xetex/i18n/regexcst.h b/Build/source/libs/icu/icu-xetex/i18n/regexcst.h
new file mode 100644
index 00000000000..6cca845310f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/regexcst.h
@@ -0,0 +1,314 @@
+//---------------------------------------------------------------------------------
+//
+// Generated Header File. Do not edit by hand.
+// This file contains the state table for the ICU Regular Expression Pattern Parser
+// It is generated by the Perl script "regexcst.pl" from
+// the rule parser state definitions file "regexcst.txt".
+//
+// Copyright (C) 2002-2003 International Business Machines Corporation
+// and others. All rights reserved.
+//
+//---------------------------------------------------------------------------------
+#ifndef RBBIRPT_H
+#define RBBIRPT_H
+
+U_NAMESPACE_BEGIN
+//
+// Character classes for regex pattern scanning.
+//
+ static const uint8_t kRuleSet_digit_char = 128;
+ static const uint8_t kRuleSet_white_space = 129;
+ static const uint8_t kRuleSet_rule_char = 130;
+
+
+enum Regex_PatternParseAction {
+ doPossessivePlus,
+ doCloseParen,
+ doProperty,
+ doBeginMatchMode,
+ doOrOperator,
+ doOpenCaptureParen,
+ doBadOpenParenType,
+ doRuleError,
+ doIntevalLowerDigit,
+ doBackslashs,
+ doNGOpt,
+ doBackslashw,
+ doMismatchedParenErr,
+ doOpenLookBehind,
+ doBackslashz,
+ doIntervalError,
+ doStar,
+ doCaret,
+ doEnterQuoteMode,
+ doNGStar,
+ doMatchMode,
+ doIntervalUpperDigit,
+ doOpenLookAheadNeg,
+ doPlus,
+ doOpenNonCaptureParen,
+ doBackslashA,
+ doBackslashB,
+ doNGPlus,
+ doSetMatchMode,
+ doPatFinish,
+ doBackslashD,
+ doPossessiveInterval,
+ doEscapeError,
+ doBackslashG,
+ doSuppressComments,
+ doMatchModeParen,
+ doOpt,
+ doInterval,
+ doLiteralChar,
+ doIntervalInit,
+ doOpenAtomicParen,
+ doBackslashS,
+ doOpenLookAhead,
+ doBackRef,
+ doDollar,
+ doDotAny,
+ doBackslashW,
+ doBackslashX,
+ doScanUnicodeSet,
+ doBackslashZ,
+ doPerlInline,
+ doPossessiveOpt,
+ doNOP,
+ doConditionalExpr,
+ doExit,
+ doNGInterval,
+ doPatStart,
+ doBadModeFlag,
+ doBackslashb,
+ doPossessiveStar,
+ doBackslashd,
+ doIntervalSame,
+ doOpenLookBehindNeg,
+ rbbiLastAction};
+
+//-------------------------------------------------------------------------------
+//
+// RegexTableEl represents the structure of a row in the transition table
+// for the pattern parser state machine.
+//-------------------------------------------------------------------------------
+struct RegexTableEl {
+ Regex_PatternParseAction fAction;
+ uint8_t fCharClass; // 0-127: an individual ASCII character
+ // 128-255: character class index
+ uint8_t fNextState; // 0-250: normal next-state numbers
+ // 255: pop next-state from stack.
+ uint8_t fPushState;
+ UBool fNextChar;
+};
+
+static const struct RegexTableEl gRuleParseStateTable[] = {
+ {doNOP, 0, 0, 0, TRUE}
+ , {doPatStart, 255, 2,0, FALSE} // 1 start
+ , {doLiteralChar, 254, 14,0, TRUE} // 2 term
+ , {doLiteralChar, 130, 14,0, TRUE} // 3
+ , {doScanUnicodeSet, 91 /* [ */, 14,0, TRUE} // 4
+ , {doNOP, 40 /* ( */, 27,0, TRUE} // 5
+ , {doDotAny, 46 /* . */, 14,0, TRUE} // 6
+ , {doCaret, 94 /* ^ */, 2,0, TRUE} // 7
+ , {doDollar, 36 /* $ */, 2,0, TRUE} // 8
+ , {doNOP, 92 /* \ */, 81,0, TRUE} // 9
+ , {doOrOperator, 124 /* | */, 2,0, TRUE} // 10
+ , {doCloseParen, 41 /* ) */, 255,0, TRUE} // 11
+ , {doPatFinish, 253, 2,0, FALSE} // 12
+ , {doRuleError, 255, 101,0, FALSE} // 13
+ , {doNOP, 42 /* * */, 59,0, TRUE} // 14 expr-quant
+ , {doNOP, 43 /* + */, 62,0, TRUE} // 15
+ , {doNOP, 63 /* ? */, 65,0, TRUE} // 16
+ , {doIntervalInit, 123 /* { */, 68,0, TRUE} // 17
+ , {doNOP, 40 /* ( */, 23,0, TRUE} // 18
+ , {doNOP, 255, 20,0, FALSE} // 19
+ , {doOrOperator, 124 /* | */, 2,0, TRUE} // 20 expr-cont
+ , {doCloseParen, 41 /* ) */, 255,0, TRUE} // 21
+ , {doNOP, 255, 2,0, FALSE} // 22
+ , {doSuppressComments, 63 /* ? */, 25,0, TRUE} // 23 open-paren-quant
+ , {doNOP, 255, 27,0, FALSE} // 24
+ , {doNOP, 35 /* # */, 47, 14, TRUE} // 25 open-paren-quant2
+ , {doNOP, 255, 29,0, FALSE} // 26
+ , {doSuppressComments, 63 /* ? */, 29,0, TRUE} // 27 open-paren
+ , {doOpenCaptureParen, 255, 2, 14, FALSE} // 28
+ , {doOpenNonCaptureParen, 58 /* : */, 2, 14, TRUE} // 29 open-paren-extended
+ , {doOpenAtomicParen, 62 /* > */, 2, 14, TRUE} // 30
+ , {doOpenLookAhead, 61 /* = */, 2, 20, TRUE} // 31
+ , {doOpenLookAheadNeg, 33 /* ! */, 2, 20, TRUE} // 32
+ , {doNOP, 60 /* < */, 44,0, TRUE} // 33
+ , {doNOP, 35 /* # */, 47, 2, TRUE} // 34
+ , {doBeginMatchMode, 105 /* i */, 50,0, FALSE} // 35
+ , {doBeginMatchMode, 109 /* m */, 50,0, FALSE} // 36
+ , {doBeginMatchMode, 115 /* s */, 50,0, FALSE} // 37
+ , {doBeginMatchMode, 119 /* w */, 50,0, FALSE} // 38
+ , {doBeginMatchMode, 120 /* x */, 50,0, FALSE} // 39
+ , {doBeginMatchMode, 45 /* - */, 50,0, FALSE} // 40
+ , {doConditionalExpr, 40 /* ( */, 101,0, TRUE} // 41
+ , {doPerlInline, 123 /* { */, 101,0, TRUE} // 42
+ , {doBadOpenParenType, 255, 101,0, FALSE} // 43
+ , {doOpenLookBehind, 61 /* = */, 2, 20, TRUE} // 44 open-paren-lookbehind
+ , {doOpenLookBehindNeg, 33 /* ! */, 2, 20, TRUE} // 45
+ , {doBadOpenParenType, 255, 101,0, FALSE} // 46
+ , {doNOP, 41 /* ) */, 255,0, TRUE} // 47 paren-comment
+ , {doMismatchedParenErr, 253, 101,0, FALSE} // 48
+ , {doNOP, 255, 47,0, TRUE} // 49
+ , {doMatchMode, 105 /* i */, 50,0, TRUE} // 50 paren-flag
+ , {doMatchMode, 109 /* m */, 50,0, TRUE} // 51
+ , {doMatchMode, 115 /* s */, 50,0, TRUE} // 52
+ , {doMatchMode, 119 /* w */, 50,0, TRUE} // 53
+ , {doMatchMode, 120 /* x */, 50,0, TRUE} // 54
+ , {doMatchMode, 45 /* - */, 50,0, TRUE} // 55
+ , {doSetMatchMode, 41 /* ) */, 2,0, TRUE} // 56
+ , {doMatchModeParen, 58 /* : */, 2, 14, TRUE} // 57
+ , {doBadModeFlag, 255, 101,0, FALSE} // 58
+ , {doNGStar, 63 /* ? */, 20,0, TRUE} // 59 quant-star
+ , {doPossessiveStar, 43 /* + */, 20,0, TRUE} // 60
+ , {doStar, 255, 20,0, FALSE} // 61
+ , {doNGPlus, 63 /* ? */, 20,0, TRUE} // 62 quant-plus
+ , {doPossessivePlus, 43 /* + */, 20,0, TRUE} // 63
+ , {doPlus, 255, 20,0, FALSE} // 64
+ , {doNGOpt, 63 /* ? */, 20,0, TRUE} // 65 quant-opt
+ , {doPossessiveOpt, 43 /* + */, 20,0, TRUE} // 66
+ , {doOpt, 255, 20,0, FALSE} // 67
+ , {doNOP, 129, 68,0, TRUE} // 68 interval-open
+ , {doNOP, 128, 71,0, FALSE} // 69
+ , {doIntervalError, 255, 101,0, FALSE} // 70
+ , {doIntevalLowerDigit, 128, 71,0, TRUE} // 71 interval-lower
+ , {doNOP, 44 /* , */, 75,0, TRUE} // 72
+ , {doIntervalSame, 125 /* } */, 78,0, TRUE} // 73
+ , {doIntervalError, 255, 101,0, FALSE} // 74
+ , {doIntervalUpperDigit, 128, 75,0, TRUE} // 75 interval-upper
+ , {doNOP, 125 /* } */, 78,0, TRUE} // 76
+ , {doIntervalError, 255, 101,0, FALSE} // 77
+ , {doNGInterval, 63 /* ? */, 20,0, TRUE} // 78 interval-type
+ , {doPossessiveInterval, 43 /* + */, 20,0, TRUE} // 79
+ , {doInterval, 255, 20,0, FALSE} // 80
+ , {doBackslashA, 65 /* A */, 2,0, TRUE} // 81 backslash
+ , {doBackslashB, 66 /* B */, 2,0, TRUE} // 82
+ , {doBackslashb, 98 /* b */, 2,0, TRUE} // 83
+ , {doBackslashd, 100 /* d */, 14,0, TRUE} // 84
+ , {doBackslashD, 68 /* D */, 14,0, TRUE} // 85
+ , {doBackslashG, 71 /* G */, 2,0, TRUE} // 86
+ , {doProperty, 78 /* N */, 14,0, FALSE} // 87
+ , {doProperty, 112 /* p */, 14,0, FALSE} // 88
+ , {doProperty, 80 /* P */, 14,0, FALSE} // 89
+ , {doEnterQuoteMode, 81 /* Q */, 2,0, TRUE} // 90
+ , {doBackslashS, 83 /* S */, 14,0, TRUE} // 91
+ , {doBackslashs, 115 /* s */, 14,0, TRUE} // 92
+ , {doBackslashW, 87 /* W */, 14,0, TRUE} // 93
+ , {doBackslashw, 119 /* w */, 14,0, TRUE} // 94
+ , {doBackslashX, 88 /* X */, 14,0, TRUE} // 95
+ , {doBackslashZ, 90 /* Z */, 2,0, TRUE} // 96
+ , {doBackslashz, 122 /* z */, 2,0, TRUE} // 97
+ , {doBackRef, 128, 14,0, TRUE} // 98
+ , {doEscapeError, 253, 101,0, FALSE} // 99
+ , {doLiteralChar, 255, 14,0, TRUE} // 100
+ , {doExit, 255, 101,0, TRUE} // 101 errorDeath
+ };
+static const char * const RegexStateNames[] = { 0,
+ "start",
+ "term",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "expr-quant",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "expr-cont",
+ 0,
+ 0,
+ "open-paren-quant",
+ 0,
+ "open-paren-quant2",
+ 0,
+ "open-paren",
+ 0,
+ "open-paren-extended",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "open-paren-lookbehind",
+ 0,
+ 0,
+ "paren-comment",
+ 0,
+ 0,
+ "paren-flag",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "quant-star",
+ 0,
+ 0,
+ "quant-plus",
+ 0,
+ 0,
+ "quant-opt",
+ 0,
+ 0,
+ "interval-open",
+ 0,
+ 0,
+ "interval-lower",
+ 0,
+ 0,
+ 0,
+ "interval-upper",
+ 0,
+ 0,
+ "interval-type",
+ 0,
+ 0,
+ "backslash",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "errorDeath",
+ 0};
+
+U_NAMESPACE_END
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/regexcst.pl b/Build/source/libs/icu/icu-xetex/i18n/regexcst.pl
new file mode 100755
index 00000000000..b525cf88b8d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/regexcst.pl
@@ -0,0 +1,332 @@
+#!/usr/bin/perl
+# ********************************************************************
+# * COPYRIGHT:
+# * Copyright (c) 2002-2003, International Business Machines Corporation and
+# * others. All Rights Reserved.
+# ********************************************************************
+#
+# regexcst.pl
+# Compile the regular expression paser state table data into initialized C data.
+# Usage:
+# cd icu/source/i18n
+# perl regexcst.pl < regexcst.txt > regexcst.h
+#
+# The output file, regexcst.h, is included by some of the .cpp regex
+# implementation files. This perl script is NOT run as part
+# of a normal ICU build. It is run by hand when needed, and the
+# regexcst.h generated file is put back into cvs.
+#
+# See regexcst.txt for a description of the input format for this script.
+#
+# This script is derived from rbbicst.pl, which peforms the same function
+# for the Rule Based Break Iterator Rule Parser. Perhaps they could be
+# merged?
+#
+#*********************************************************************
+# Copyright (C) 2002 International Business Machines Corporation *
+# and others. All rights reserved. *
+#*********************************************************************
+
+
+$num_states = 1; # Always the state number for the line being compiled.
+$line_num = 0; # The line number in the input file.
+
+$states{"pop"} = 255; # Add the "pop" to the list of defined state names.
+ # This prevents any state from being labelled with "pop",
+ # and resolves references to "pop" in the next state field.
+
+line_loop: while (<>) {
+ chomp();
+ $line = $_;
+ @fields = split();
+ $line_num++;
+
+ # Remove # comments, which are any fields beginning with a #, plus all
+ # that follow on the line.
+ for ($i=0; $i<@fields; $i++) {
+ if ($fields[$i] =~ /^#/) {
+ @fields = @fields[0 .. $i-1];
+ last;
+ }
+ }
+ # ignore blank lines, and those with no fields left after stripping comments..
+ if (@fields == 0) {
+ next;
+ }
+
+ #
+ # State Label: handling.
+ # Does the first token end with a ":"? If so, it's the name of a state.
+ # Put in a hash, together with the current state number,
+ # so that we can later look up the number from the name.
+ #
+ if (@fields[0] =~ /.*:$/) {
+ $state_name = @fields[0];
+ $state_name =~ s/://; # strip off the colon from the state name.
+
+ if ($states{$state_name} != 0) {
+ print " rbbicst: at line $line-num duplicate definition of state $state_name\n";
+ }
+ $states{$state_name} = $num_states;
+ $stateNames[$num_states] = $state_name;
+
+ # if the label was the only thing on this line, go on to the next line,
+ # otherwise assume that a state definition is on the same line and fall through.
+ if (@fields == 1) {
+ next line_loop;
+ }
+ shift @fields; # shift off label field in preparation
+ # for handling the rest of the line.
+ }
+
+ #
+ # State Transition line.
+ # syntax is this,
+ # character [n] target-state [^push-state] [function-name]
+ # where
+ # [something] is an optional something
+ # character is either a single quoted character e.g. '['
+ # or a name of a character class, e.g. white_space
+ #
+
+ $state_line_num[$num_states] = $line_num; # remember line number with each state
+ # so we can make better error messages later.
+ #
+ # First field, character class or literal character for this transition.
+ #
+ if ($fields[0] =~ /^'.'$/) {
+ # We've got a quoted literal character.
+ $state_literal_chars[$num_states] = $fields[0];
+ $state_literal_chars[$num_states] =~ s/'//g;
+ } else {
+ # We've got the name of a character class.
+ $state_char_class[$num_states] = $fields[0];
+ if ($fields[0] =~ /[\W]/) {
+ print " rbbicsts: at line $line_num, bad character literal or character class name.\n";
+ print " scanning $fields[0]\n";
+ exit(-1);
+ }
+ }
+ shift @fields;
+
+ #
+ # do the 'n' flag
+ #
+ $state_flag[$num_states] = "FALSE";
+ if ($fields[0] eq "n") {
+ $state_flag[$num_states] = "TRUE";
+ shift @fields;
+ }
+
+ #
+ # do the destination state.
+ #
+ $state_dest_state[$num_states] = $fields[0];
+ if ($fields[0] eq "") {
+ print " rbbicsts: at line $line_num, destination state missing.\n";
+ exit(-1);
+ }
+ shift @fields;
+
+ #
+ # do the push state, if present.
+ #
+ if ($fields[0] =~ /^\^/) {
+ $fields[0] =~ s/^\^//;
+ $state_push_state[$num_states] = $fields[0];
+ if ($fields[0] eq "" ) {
+ print " rbbicsts: at line $line_num, expected state after ^ (no spaces).\n";
+ exit(-1);
+ }
+ shift @fields;
+ }
+
+ #
+ # Lastly, do the optional action name.
+ #
+ if ($fields[0] ne "") {
+ $state_func_name[$num_states] = $fields[0];
+ shift @fields;
+ }
+
+ #
+ # There should be no fields left on the line at this point.
+ #
+ if (@fields > 0) {
+ print " rbbicsts: at line $line_num, unexpected extra stuff on input line.\n";
+ print " scanning $fields[0]\n";
+ }
+ $num_states++;
+}
+
+#
+# We've read in the whole file, now go back and output the
+# C source code for the state transition table.
+#
+# We read all states first, before writing anything, so that the state numbers
+# for the destination states are all available to be written.
+#
+
+#
+# Make hashes for the names of the character classes and
+# for the names of the actions that appeared.
+#
+for ($state=1; $state < $num_states; $state++) {
+ if ($state_char_class[$state] ne "") {
+ if ($charClasses{$state_char_class[$state]} == 0) {
+ $charClasses{$state_char_class[$state]} = 1;
+ }
+ }
+ if ($state_func_name[$state] eq "") {
+ $state_func_name[$state] = "doNOP";
+ }
+ if ($actions{$state_action_name[$state]} == 0) {
+ $actions{$state_func_name[$state]} = 1;
+ }
+}
+
+#
+# Check that all of the destination states have been defined
+#
+#
+$states{"exit"} = 0; # Predefined state name, terminates state machine.
+for ($state=1; $state<$num_states; $state++) {
+ if ($states{$state_dest_state[$state]} == 0 && $state_dest_state[$state] ne "exit") {
+ print "Error at line $state_line_num[$state]: target state \"$state_dest_state[$state]\" is not defined.\n";
+ $errors++;
+ }
+ if ($state_push_state[$state] ne "" && $states{$state_push_state[$state]} == 0) {
+ print "Error at line $state_line_num[$state]: target state \"$state_push_state[$state]\" is not defined.\n";
+ $errors++;
+ }
+}
+
+die if ($errors>0);
+
+print "//---------------------------------------------------------------------------------\n";
+print "//\n";
+print "// Generated Header File. Do not edit by hand.\n";
+print "// This file contains the state table for the ICU Regular Expression Pattern Parser\n";
+print "// It is generated by the Perl script \"regexcst.pl\" from\n";
+print "// the rule parser state definitions file \"regexcst.txt\".\n";
+print "//\n";
+print "// Copyright (C) 2002-2003 International Business Machines Corporation \n";
+print "// and others. All rights reserved. \n";
+print "//\n";
+print "//---------------------------------------------------------------------------------\n";
+print "#ifndef RBBIRPT_H\n";
+print "#define RBBIRPT_H\n";
+print "\n";
+print "U_NAMESPACE_BEGIN\n";
+
+#
+# Emit the constants for indicies of Unicode Sets
+# Define one constant for each of the character classes encountered.
+# At the same time, store the index corresponding to the set name back into hash.
+#
+print "//\n";
+print "// Character classes for regex pattern scanning.\n";
+print "//\n";
+$i = 128; # State Table values for Unicode char sets range from 128-250.
+ # Sets "default", "quoted", etc. get special handling.
+ # They have no corresponding UnicodeSet object in the state machine,
+ # but are handled by special case code. So we emit no reference
+ # to a UnicodeSet object to them here.
+foreach $setName (keys %charClasses) {
+ if ($setName eq "default") {
+ $charClasses{$setName} = 255;}
+ elsif ($setName eq "quoted") {
+ $charClasses{$setName} = 254;}
+ elsif ($setName eq "eof") {
+ $charClasses{$setName} = 253;}
+ else {
+ # Normal character class. Fill in array with a ptr to the corresponding UnicodeSet in the state machine.
+ print " static const uint8_t kRuleSet_$setName = $i;\n";
+ $charClasses{$setName} = $i;
+ $i++;
+ }
+}
+print "\n\n";
+
+#
+# Emit the enum for the actions to be performed.
+#
+print "enum Regex_PatternParseAction {\n";
+foreach $act (keys %actions) {
+ print " $act,\n";
+}
+print " rbbiLastAction};\n\n";
+
+#
+# Emit the struct definition for transtion table elements.
+#
+print "//-------------------------------------------------------------------------------\n";
+print "//\n";
+print "// RegexTableEl represents the structure of a row in the transition table\n";
+print "// for the pattern parser state machine.\n";
+print "//-------------------------------------------------------------------------------\n";
+print "struct RegexTableEl {\n";
+print " Regex_PatternParseAction fAction;\n";
+print " uint8_t fCharClass; // 0-127: an individual ASCII character\n";
+print " // 128-255: character class index\n";
+print " uint8_t fNextState; // 0-250: normal next-state numbers\n";
+print " // 255: pop next-state from stack.\n";
+print " uint8_t fPushState;\n";
+print " UBool fNextChar;\n";
+print "};\n\n";
+
+#
+# emit the state transition table
+#
+print "static const struct RegexTableEl gRuleParseStateTable[] = {\n";
+print " {doNOP, 0, 0, 0, TRUE}\n"; # State 0 is a dummy. Real states start with index = 1.
+for ($state=1; $state < $num_states; $state++) {
+ print " , {$state_func_name[$state],";
+ if ($state_literal_chars[$state] ne "") {
+ $c = $state_literal_chars[$state];
+ printf(" %d /* $c */,", ord($c)); # use numeric value, so EBCDIC machines are ok.
+ }else {
+ print " $charClasses{$state_char_class[$state]},";
+ }
+ print " $states{$state_dest_state[$state]},";
+
+ # The push-state field is optional. If omitted, fill field with a zero, which flags
+ # the state machine that there is no push state.
+ if ($state_push_state[$state] eq "") {
+ print "0, ";
+ } else {
+ print " $states{$state_push_state[$state]},";
+ }
+ print " $state_flag[$state]} ";
+
+ # Put out a C++ comment showing the number (index) of this state row,
+ # and, if this is the first row of the table for this state, the state name.
+ print " // $state ";
+ if ($stateNames[$state] ne "") {
+ print " $stateNames[$state]";
+ }
+ print "\n";
+};
+print " };\n";
+
+
+#
+# emit a mapping array from state numbers to state names.
+#
+# This array is used for producing debugging output from the pattern parser.
+#
+print "static const char * const RegexStateNames[] = {";
+for ($state=0; $state<$num_states; $state++) {
+ if ($stateNames[$state] ne "") {
+ print " \"$stateNames[$state]\",\n";
+ } else {
+ print " 0,\n";
+ }
+}
+print " 0};\n\n";
+
+print "U_NAMESPACE_END\n";
+print "#endif\n";
+
+
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/regexcst.txt b/Build/source/libs/icu/icu-xetex/i18n/regexcst.txt
new file mode 100644
index 00000000000..fec788c1417
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/regexcst.txt
@@ -0,0 +1,266 @@
+
+#*****************************************************************************
+#
+# Copyright (C) 2002-2003, International Business Machines Corporation and others.
+# All Rights Reserved.
+#
+#*****************************************************************************
+#
+# file: regexcst.txt
+# ICU Regular Expression Parser State Table
+#
+# This state table is used when reading and parsing a regular expression pattern
+# The pattern parser uses a state machine; the data in this file define the
+# state transitions that occur for each input character.
+#
+# *** This file defines the regex pattern grammar. This is it.
+# *** The determination of what is accepted is here.
+#
+# This file is processed by a perl script "regexcst.pl" to produce initialized C arrays
+# that are then built with the rule parser.
+#
+
+#
+# Here is the syntax of the state definitions in this file:
+#
+#
+#StateName:
+# input-char n next-state ^push-state action
+# input-char n next-state ^push-state action
+# | | | | |
+# | | | | |--- action to be performed by state machine
+# | | | | See function RBBIRuleScanner::doParseActions()
+# | | | |
+# | | | |--- Push this named state onto the state stack.
+# | | | Later, when next state is specified as "pop",
+# | | | the pushed state will become the current state.
+# | | |
+# | | |--- Transition to this state if the current input character matches the input
+# | | character or char class in the left hand column. "pop" causes the next
+# | | state to be popped from the state stack.
+# | |
+# | |--- When making the state transition specified on this line, advance to the next
+# | character from the input only if 'n' appears here.
+# |
+# |--- Character or named character classes to test for. If the current character being scanned
+# matches, peform the actions and go to the state specified on this line.
+# The input character is tested sequentally, in the order written. The characters and
+# character classes tested for do not need to be mutually exclusive. The first match wins.
+#
+
+
+
+
+#
+# start state, scan position is at the beginning of the pattern.
+#
+start:
+ default term doPatStart
+
+
+
+
+#
+# term. At a position where we can accept the start most items in a pattern.
+#
+term:
+ quoted n expr-quant doLiteralChar
+ rule_char n expr-quant doLiteralChar
+ '[' n expr-quant doScanUnicodeSet
+ '(' n open-paren
+ '.' n expr-quant doDotAny
+ '^' n term doCaret
+ '$' n term doDollar
+ '\' n backslash
+ '|' n term doOrOperator
+ ')' n pop doCloseParen
+ eof term doPatFinish
+ default errorDeath doRuleError
+
+
+
+#
+# expr-quant We've just finished scanning a term, now look for the optional
+# trailing quantifier - *, +, ?, *?, etc.
+#
+expr-quant:
+ '*' n quant-star
+ '+' n quant-plus
+ '?' n quant-opt
+ '{' n interval-open doIntervalInit
+ '(' n open-paren-quant
+ default expr-cont
+
+
+#
+# expr-cont Expression, continuation. At a point where additional terms are
+# allowed, but not required. No Quantifiers
+#
+expr-cont:
+ '|' n term doOrOperator
+ ')' n pop doCloseParen
+ default term
+
+
+#
+# open-paren-quant Special case handling for comments appearing before a quantifier,
+# e.g. x(?#comment )*
+# Open parens from expr-quant come here; anything but a (?# comment
+# branches into the normal parenthesis sequence as quickly as possible.
+#
+open-paren-quant:
+ '?' n open-paren-quant2 doSuppressComments
+ default open-paren
+
+open-paren-quant2:
+ '#' n paren-comment ^expr-quant
+ default open-paren-extended
+
+
+#
+# open-paren We've got an open paren. We need to scan further to
+# determine what kind of quantifier it is - plain (, (?:, (?>, or whatever.
+#
+open-paren:
+ '?' n open-paren-extended doSuppressComments
+ default term ^expr-quant doOpenCaptureParen
+
+open-paren-extended:
+ ':' n term ^expr-quant doOpenNonCaptureParen # (?:
+ '>' n term ^expr-quant doOpenAtomicParen # (?>
+ '=' n term ^expr-cont doOpenLookAhead # (?=
+ '!' n term ^expr-cont doOpenLookAheadNeg # (?!
+ '<' n open-paren-lookbehind
+ '#' n paren-comment ^term
+ 'i' paren-flag doBeginMatchMode
+ 'm' paren-flag doBeginMatchMode
+ 's' paren-flag doBeginMatchMode
+ 'w' paren-flag doBeginMatchMode
+ 'x' paren-flag doBeginMatchMode
+ '-' paren-flag doBeginMatchMode
+ '(' n errorDeath doConditionalExpr
+ '{' n errorDeath doPerlInline
+ default errorDeath doBadOpenParenType
+
+open-paren-lookbehind:
+ '=' n term ^expr-cont doOpenLookBehind # (?<=
+ '!' n term ^expr-cont doOpenLookBehindNeg # (?<!
+ default errorDeath doBadOpenParenType
+
+
+#
+# paren-comment We've got a (?# ... ) style comment. Eat pattern text till we get to the ')'
+# TODO: should parens nest here? Check what perl does.
+#
+paren-comment:
+ ')' n pop
+ eof errorDeath doMismatchedParenErr
+ default n paren-comment
+
+#
+# paren-flag Scanned a (?ismx-ismx flag setting
+#
+paren-flag:
+ 'i' n paren-flag doMatchMode
+ 'm' n paren-flag doMatchMode
+ 's' n paren-flag doMatchMode
+ 'w' n paren-flag doMatchMode
+ 'x' n paren-flag doMatchMode
+ '-' n paren-flag doMatchMode
+ ')' n term doSetMatchMode
+ ':' n term ^expr-quant doMatchModeParen
+ default errorDeath doBadModeFlag
+
+
+#
+# quant-star Scanning a '*' quantifier. Need to look ahead to decide
+# between plain '*', '*?', '*+'
+#
+quant-star:
+ '?' n expr-cont doNGStar # *?
+ '+' n expr-cont doPossessiveStar # *+
+ default expr-cont doStar
+
+
+#
+# quant-plus Scanning a '+' quantifier. Need to look ahead to decide
+# between plain '+', '+?', '++'
+#
+quant-plus:
+ '?' n expr-cont doNGPlus # *?
+ '+' n expr-cont doPossessivePlus # *+
+ default expr-cont doPlus
+
+
+#
+# quant-opt Scanning a '?' quantifier. Need to look ahead to decide
+# between plain '?', '??', '?+'
+#
+quant-opt:
+ '?' n expr-cont doNGOpt # ??
+ '+' n expr-cont doPossessiveOpt # ?+
+ default expr-cont doOpt # ?
+
+
+#
+# Interval scanning a '{', the opening delimiter for an interval specification
+# {number} or {min, max} or {min, }
+#
+interval-open:
+ white_space n interval-open # TODO: is white space allowed here in non-free mode?
+ digit_char interval-lower
+ default errorDeath doIntervalError
+
+interval-lower:
+ digit_char n interval-lower doIntevalLowerDigit
+ ',' n interval-upper
+ '}' n interval-type doIntervalSame # {n}
+ default errorDeath doIntervalError
+
+interval-upper:
+ digit_char n interval-upper doIntervalUpperDigit
+ '}' n interval-type
+ default errorDeath doIntervalError
+
+interval-type:
+ '?' n expr-cont doNGInterval # {n,m}?
+ '+' n expr-cont doPossessiveInterval # {n,m}+
+ default expr-cont doInterval # {m,n}
+
+
+#
+# backslash # Backslash. Figure out which of the \thingies we have encountered.
+# The low level next-char function will have preprocessed
+# some of them already; those won't come here.
+backslash:
+ 'A' n term doBackslashA
+ 'B' n term doBackslashB
+ 'b' n term doBackslashb
+ 'd' n expr-quant doBackslashd
+ 'D' n expr-quant doBackslashD
+ 'G' n term doBackslashG
+ 'N' expr-quant doProperty # \N{NAME} named char
+ 'p' expr-quant doProperty # \p{Lu} style property
+ 'P' expr-quant doProperty
+ 'Q' n term doEnterQuoteMode
+ 'S' n expr-quant doBackslashS
+ 's' n expr-quant doBackslashs
+ 'W' n expr-quant doBackslashW
+ 'w' n expr-quant doBackslashw
+ 'X' n expr-quant doBackslashX
+ 'Z' n term doBackslashZ
+ 'z' n term doBackslashz
+ digit_char n expr-quant doBackRef # Will scan multiple digits
+ eof errorDeath doEscapeError
+ default n expr-quant doLiteralChar # Escaped literal char.
+
+
+#
+# errorDeath. This state is specified as the next state whenever a syntax error
+# in the source rules is detected. Barring bugs, the state machine will never
+# actually get here, but will stop because of the action associated with the error.
+# But, just in case, this state asks the state machine to exit.
+errorDeath:
+ default n errorDeath doExit
+
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/regeximp.h b/Build/source/libs/icu/icu-xetex/i18n/regeximp.h
new file mode 100644
index 00000000000..fbf700672ec
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/regeximp.h
@@ -0,0 +1,344 @@
+//
+// Copyright (C) 2002-2005 International Business Machines Corporation
+// and others. All rights reserved.
+//
+// file: regeximp.h
+//
+// ICU Regular Expressions,
+// Definitions of constant values used in the compiled form of
+// a regular expression pattern.
+//
+
+#ifndef _REGEXIMP_H
+#define _REGEXIMP_H
+
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+#ifdef REGEX_DEBUG /* For debugging, define REGEX_DEBUG in regex.h, not here in this file. */
+//
+// debugging options. Enable one or more of the three #defines immediately following
+//
+
+//#define REGEX_SCAN_DEBUG
+#define REGEX_DUMP_DEBUG
+#define REGEX_RUN_DEBUG
+
+// End of #defines inteded to be directly set.
+
+#include <stdio.h>
+#endif
+
+#ifdef REGEX_SCAN_DEBUG
+#define REGEX_SCAN_DEBUG_PRINTF(a) printf a
+#else
+#define REGEX_SCAN_DEBUG_PRINTF(a)
+#endif
+
+#ifdef REGEX_DUMP_DEBUG
+#define REGEX_DUMP_DEBUG_PRINTF(a) printf a
+#else
+#define REGEX_DUMP_DEBUG_PRINTF(a)
+#endif
+
+#ifdef REGEX_RUN_DEBUG
+#define REGEX_RUN_DEBUG_PRINTF(a) printf a
+#define REGEX_DUMP_DEBUG_PRINTF(a) printf a
+#else
+#define REGEX_RUN_DEBUG_PRINTF(a)
+#endif
+
+
+//
+// Opcode types In the compiled form of the regexp, these are the type, or opcodes,
+// of the entries.
+//
+enum {
+ URX_RESERVED_OP = 0, // For multi-operand ops, most non-first words.
+ URX_RESERVED_OP_N = 255, // For multi-operand ops, negative operand values.
+ URX_BACKTRACK = 1,
+ URX_END = 2,
+ URX_ONECHAR = 3, // Value field is the 21 bit unicode char to match
+ URX_STRING = 4, // Value field is index of string start
+ URX_STRING_LEN = 5, // Value field is string length (code units)
+ URX_STATE_SAVE = 6, // Value field is pattern position to push
+ URX_NOP = 7,
+ URX_START_CAPTURE = 8, // Value field is capture group number.
+ URX_END_CAPTURE = 9, // Value field is capture group number
+ URX_STATIC_SETREF = 10, // Value field is index of set in array of sets.
+ URX_SETREF = 11, // Value field is index of set in array of sets.
+ URX_DOTANY = 12,
+ URX_JMP = 13, // Value field is destination position in
+ // the pattern.
+ URX_FAIL = 14, // Stop match operation, No match.
+
+ URX_JMP_SAV = 15, // Operand: JMP destination location
+ URX_BACKSLASH_B = 16, // Value field: 0: \b 1: \B
+ URX_BACKSLASH_G = 17,
+ URX_JMP_SAV_X = 18, // Conditional JMP_SAV,
+ // Used in (x)+, breaks loop on zero length match.
+ // Operand: Jmp destination.
+ URX_BACKSLASH_X = 19,
+ URX_BACKSLASH_Z = 20, // \z Unconditional end of line.
+
+ URX_DOTANY_ALL = 21, // ., in the . matches any mode.
+ URX_BACKSLASH_D = 22, // Value field: 0: \d 1: \D
+ URX_CARET = 23, // Value field: 1: multi-line mode.
+ URX_DOLLAR = 24, // Also for \Z
+
+ URX_CTR_INIT = 25, // Counter Inits for {Interval} loops.
+ URX_CTR_INIT_NG = 26, // 3 kinds, normal, non-greedy, and possessive.
+ // These are 4 word opcodes. See description.
+ // First Operand: Data loc of counter variable
+ // 2nd Operand: Pat loc of the URX_CTR_LOOPx
+ // at the end of the loop.
+ // 3rd Operand: Minimum count.
+ // 4th Operand: Max count, -1 for unbounded.
+
+ URX_DOTANY_PL = 27, // .+, match rest of the line. Fail already at end.
+
+ URX_CTR_LOOP = 28, // Loop Ops for {interval} loops.
+ URX_CTR_LOOP_NG = 29, // Also in three flavors.
+ // Operand is loc of corresponding CTR_INIT.
+
+ URX_DOTANY_ALL_PL = 30, // .+, match rest of the Input. Fail if already at end
+
+ URX_RELOC_OPRND = 31, // Operand value in multi-operand ops that refers
+ // back into compiled pattern code, and thus must
+ // be relocated when inserting/deleting ops in code.
+
+ URX_STO_SP = 32, // Store the stack ptr. Operand is location within
+ // matcher data (not stack data) to store it.
+ URX_LD_SP = 33, // Load the stack pointer. Operand is location
+ // to load from.
+ URX_BACKREF = 34, // Back Reference. Parameter is the index of the
+ // capture group variables in the state stack frame.
+ URX_STO_INP_LOC = 35, // Store the input location. Operand is location
+ // within the matcher stack frame.
+ URX_JMPX = 36, // Conditional JMP.
+ // First Operand: JMP target location.
+ // Second Operand: Data location containing an
+ // input position. If current input position ==
+ // saved input position, FAIL rather than taking
+ // the JMP
+ URX_LA_START = 37, // Starting a LookAround expression.
+ // Save InputPos and SP in static data.
+ // Operand: Static data offset for the save
+ URX_LA_END = 38, // Ending a Lookaround expression.
+ // Restore InputPos and Stack to saved values.
+ // Operand: Static data offset for saved data.
+ URX_ONECHAR_I = 39, // Test for case-insensitive match of a literal character.
+ // Operand: the literal char.
+ URX_STRING_I = 40, // Case insensitive string compare.
+ // First Operand: Index of start of string in string literals
+ // Second Operand (next word in compiled code):
+ // the length of the string.
+ URX_BACKREF_I = 41, // Case insensitive back reference.
+ // Parameter is the index of the
+ // capture group variables in the state stack frame.
+ URX_DOLLAR_M = 42, // $ in multi-line mode.
+ URX_CARET_M = 43, // ^ in multi-line mode.
+ URX_LB_START = 44, // LookBehind Start.
+ // Paramater is data location
+ URX_LB_CONT = 45, // LookBehind Continue.
+ // Param 0: the data location
+ // Param 1: The minimum length of the look-behind match
+ // Param 2: The max length of the look-behind match
+ URX_LB_END = 46, // LookBehind End.
+ // Parameter is the data location.
+ // Check that match ended at the right spot,
+ // Restore original input string len.
+ URX_LBN_CONT = 47, // Negative LookBehind Continue
+ // Param 0: the data location
+ // Param 1: The minimum length of the look-behind match
+ // Param 2: The max length of the look-behind match
+ // Param 3: The pattern loc following the look-behind block.
+ URX_LBN_END = 48, // Negative LookBehind end
+ // Parameter is the data location.
+ // Check that the match ended at the right spot.
+ URX_STAT_SETREF_N = 49, // Reference to a prebuilt set (e.g. \w), negated
+ // Operand is index of set in array of sets.
+ URX_LOOP_SR_I = 50, // Init a [set]* loop.
+ // Operand is the sets index in array of user sets.
+ URX_LOOP_C = 51, // Continue a [set]* or OneChar* loop.
+ // Operand is a matcher static data location.
+ // Must always immediately follow LOOP_x_I instruction.
+ URX_LOOP_DOT_I = 52, // .*, initialization of the optimized loop.
+ // Operand value:
+ // 0: Normal (. doesn't match new-line) mode.
+ // 1: . matches new-line mode.
+ URX_BACKSLASH_BU = 53 // \b or \B in UREGEX_UWORD mode, using Unicode style
+ // word boundaries.
+
+};
+
+// Keep this list of opcode names in sync with the above enum
+// Used for debug printing only.
+#define URX_OPCODE_NAMES \
+ " ", \
+ "BACKTRACK", \
+ "END", \
+ "ONECHAR", \
+ "STRING", \
+ "STRING_LEN", \
+ "STATE_SAVE", \
+ "NOP", \
+ "START_CAPTURE", \
+ "END_CAPTURE", \
+ "URX_STATIC_SETREF", \
+ "SETREF", \
+ "DOTANY", \
+ "JMP", \
+ "FAIL", \
+ "JMP_SAV", \
+ "BACKSLASH_B", \
+ "BACKSLASH_G", \
+ "JMP_SAV_X", \
+ "BACKSLASH_X", \
+ "BACKSLASH_Z", \
+ "DOTANY_ALL", \
+ "BACKSLASH_D", \
+ "CARET", \
+ "DOLLAR", \
+ "CTR_INIT", \
+ "CTR_INIT_NG", \
+ "DOTANY_PL", \
+ "CTR_LOOP", \
+ "CTR_LOOP_NG", \
+ "DOTANY_ALL_PL", \
+ "RELOC_OPRND", \
+ "STO_SP", \
+ "LD_SP", \
+ "BACKREF", \
+ "STO_INP_LOC", \
+ "JMPX", \
+ "LA_START", \
+ "LA_END", \
+ "ONECHAR_I", \
+ "STRING_I", \
+ "BACKREF_I", \
+ "DOLLAR_M", \
+ "CARET_M", \
+ "LB_START", \
+ "LB_CONT", \
+ "LB_END", \
+ "LBN_CONT", \
+ "LBN_END", \
+ "STAT_SETREF_N", \
+ "LOOP_SR_I", \
+ "LOOP_C", \
+ "LOOP_DOT_I", \
+ "BACKSLASH_BU"
+
+
+//
+// Convenience macros for assembling and disassembling a compiled operation.
+//
+#define URX_BUILD(type, val) (int32_t)((type << 24) | (val))
+#define URX_TYPE(x) ((uint32_t)(x) >> 24)
+#define URX_VAL(x) ((x) & 0xffffff)
+
+
+//
+// Access to Unicode Sets composite character properties
+// The sets are accessed by the match engine for things like \w (word boundary)
+//
+enum {
+ URX_ISWORD_SET = 1,
+ URX_ISALNUM_SET = 2,
+ URX_ISALPHA_SET = 3,
+ URX_ISSPACE_SET = 4,
+
+ URX_GC_NORMAL, // Sets for finding grapheme cluster boundaries.
+ URX_GC_EXTEND,
+ URX_GC_CONTROL,
+ URX_GC_L,
+ URX_GC_LV,
+ URX_GC_LVT,
+ URX_GC_V,
+ URX_GC_T,
+
+ URX_LAST_SET,
+
+ URX_NEG_SET = 0x800000 // Flag bit to reverse sense of set
+ // membership test.
+};
+
+
+//
+// Match Engine State Stack Frame Layout.
+//
+struct REStackFrame {
+ int32_t fInputIdx; // Position of next character in the input string
+ int32_t fPatIdx; // Position of next Op in the compiled pattern
+ int32_t fExtra[2]; // Extra state, for capture group start/ends
+ // atomic parentheses, repeat counts, etc.
+ // Locations assigned at pattern compile time.
+};
+
+//
+// Start-Of-Match type. Used by find() to quickly scan to positions where a
+// match might start before firing up the full match engine.
+//
+enum StartOfMatch {
+ START_NO_INFO, // No hint available.
+ START_CHAR, // Match starts with a literal code point.
+ START_SET, // Match starts with something matching a set.
+ START_START, // Match starts at start of buffer only (^ or \A)
+ START_LINE, // Match starts with ^ in multi-line mode.
+ START_STRING // Match starts with a literal string.
+};
+
+#define START_OF_MATCH_STR(v) ((v)==START_NO_INFO? "START_NO_INFO" : \
+ (v)==START_CHAR? "START_CHAR" : \
+ (v)==START_SET? "START_SET" : \
+ (v)==START_START? "START_START" : \
+ (v)==START_LINE? "START_LINE" : \
+ (v)==START_STRING? "START_STRING" : \
+ "ILLEGAL")
+
+
+//
+// 8 bit set, to fast-path latin-1 set membership tests.
+//
+struct Regex8BitSet : public UMemory {
+ inline Regex8BitSet();
+ inline void operator = (const Regex8BitSet &s);
+ inline void init(const UnicodeSet *src);
+ inline UBool contains(UChar32 c);
+ inline void add(UChar32 c);
+ int8_t d[32];
+};
+
+inline Regex8BitSet::Regex8BitSet() {
+ uprv_memset(d, 0, sizeof(d));
+}
+
+inline UBool Regex8BitSet::contains(UChar32 c) {
+ // No bounds checking! This is deliberate.
+ return ((d[c>>3] & 1 <<(c&7)) != 0);
+}
+
+inline void Regex8BitSet::add(UChar32 c) {
+ d[c>>3] |= 1 << (c&7);
+}
+
+inline void Regex8BitSet::init(const UnicodeSet *s) {
+ if (s != NULL) {
+ for (int32_t i=0; i<=255; i++) {
+ if (s->contains(i)) {
+ this->add(i);
+ }
+ }
+ }
+}
+
+inline void Regex8BitSet::operator = (const Regex8BitSet &s) {
+ uprv_memcpy(d, s.d, sizeof(d));
+}
+
+
+U_NAMESPACE_END
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/regexst.cpp b/Build/source/libs/icu/icu-xetex/i18n/regexst.cpp
new file mode 100644
index 00000000000..41014365dff
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/regexst.cpp
@@ -0,0 +1,287 @@
+//
+// regexst.h
+//
+// Copyright (C) 2004-2007, International Business Machines Corporation and others.
+// All Rights Reserved.
+//
+// This file contains class RegexStaticSets
+//
+// This class is internal to the regular expression implementation.
+// For the public Regular Expression API, see the file "unicode/regex.h"
+//
+// RegexStaticSets groups together the common UnicodeSets that are needed
+// for compiling or executing RegularExpressions. This grouping simplifies
+// the thread safe lazy creation and sharing of these sets across
+// all instances of regular expressions.
+//
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#include "unicode/uchar.h"
+#include "unicode/regex.h"
+#include "uprops.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "umutex.h"
+
+#include "regexcst.h" // Contains state table for the regex pattern parser.
+ // generated by a Perl script.
+#include "regexst.h"
+
+
+
+U_NAMESPACE_BEGIN
+
+
+//------------------------------------------------------------------------------
+//
+// Unicode Set pattern strings for all of the required constant sets.
+// Initialized with hex values for portability to EBCDIC based machines.
+// Really ugly, but there's no good way to avoid it.
+//
+//------------------------------------------------------------------------------
+
+// "Rule Char" Characters are those with no special meaning, and therefore do not
+// need to be escaped to appear as literals in a regexp. Expressed
+// as the inverse of those needing escaping -- [^\*\?\+\[\(\)\{\}\^\$\|\\\.]
+static const UChar gRuleSet_rule_char_pattern[] = {
+ // [ ^ \ * \ ? \ + \ [ \ ( / )
+ 0x5b, 0x5e, 0x5c, 0x2a, 0x5c, 0x3f, 0x5c, 0x2b, 0x5c, 0x5b, 0x5c, 0x28, 0x5c, 0x29,
+ // \ { \ } \ ^ \ $ \ | \ \ \ . ]
+ 0x5c, 0x7b,0x5c, 0x7d, 0x5c, 0x5e, 0x5c, 0x24, 0x5c, 0x7c, 0x5c, 0x5c, 0x5c, 0x2e, 0x5d, 0};
+
+
+static const UChar gRuleSet_digit_char_pattern[] = {
+// [ 0 - 9 ]
+ 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0};
+//static const UnicodeSet *gRuleDigits = NULL;
+
+
+
+//
+// Here are the backslash escape characters that ICU's unescape() function
+// will handle.
+//
+static const UChar gUnescapeCharPattern[] = {
+// [ a c e f n r t u U x ]
+ 0x5b, 0x61, 0x63, 0x65, 0x66, 0x6e, 0x72, 0x74, 0x75, 0x55, 0x78, 0x5d, 0};
+
+
+//
+// White space characters that may appear within a pattern in free-form mode
+//
+static const UChar gRuleWhiteSpacePattern[] = {
+ /* "[[:Cf:][:WSpace:]]" */
+ 91, 91, 58, 67, 102, 58, 93, 91, 58, 87,
+ 83, 112, 97, 99, 101, 58, 93, 93, 0 };
+
+
+
+//
+// Unicode Set Definitions for Regular Expression \w
+//
+static const UChar gIsWordPattern[] = {
+// [ \ p { A l p h a b e t i c }
+ 0x5b, 0x5c, 0x70, 0x7b, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, 0x65, 0x74, 0x69, 0x63, 0x7d,
+// \ p { M } Mark
+ 0x5c, 0x70, 0x7b, 0x4d, 0x7d,
+// \ p { N d } Digit_Numeric
+ 0x5c, 0x70, 0x7b, 0x4e, 0x64, 0x7d,
+// \ p { P c } ] Connector_Punctuation
+ 0x5c, 0x70, 0x7b, 0x50, 0x63, 0x7d, 0x5d, 0};
+
+
+//
+// Unicode Set Definitions for Regular Expression \s
+//
+static const UChar gIsSpacePattern[] = {
+// [ \ p { W h i t e S p a c e } ]
+ 0x5b, 0x5c, 0x70, 0x7b, 0x57, 0x68, 0x69, 0x74, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x7d, 0x5d, 0};
+
+
+//
+// UnicodeSets used in implementation of Grapheme Cluster detection, \X
+//
+static const UChar gGC_ControlPattern[] = {
+// [ [ : Z l : ] [ : Z p : ]
+ 0x5b, 0x5b, 0x3a, 0x5A, 0x6c, 0x3a, 0x5d, 0x5b, 0x3a, 0x5A, 0x70, 0x3a, 0x5d,
+// [ : C c : ] [ : C f : ] -
+ 0x5b, 0x3a, 0x43, 0x63, 0x3a, 0x5d, 0x5b, 0x3a, 0x43, 0x66, 0x3a, 0x5d, 0x2d,
+// [ : G r a p h e m e _
+ 0x5b, 0x3a, 0x47, 0x72, 0x61, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x5f,
+// E x t e n d : ] ]
+ 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x3a, 0x5d, 0x5d, 0};
+
+static const UChar gGC_ExtendPattern[] = {
+// [ \ p { G r a p h e m e _
+ 0x5b, 0x5c, 0x70, 0x7b, 0x47, 0x72, 0x61, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x5f,
+// E x t e n d } ]
+ 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x7d, 0x5d, 0};
+
+static const UChar gGC_LPattern[] = {
+// [ \ p { H a n g u l _ S y l
+ 0x5b, 0x5c, 0x70, 0x7b, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x5f, 0x53, 0x79, 0x6c,
+// l a b l e _ T y p e = L } ]
+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x54, 0x79, 0x70, 0x65, 0x3d, 0x4c, 0x7d, 0x5d, 0};
+
+static const UChar gGC_VPattern[] = {
+// [ \ p { H a n g u l _ S y l
+ 0x5b, 0x5c, 0x70, 0x7b, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x5f, 0x53, 0x79, 0x6c,
+// l a b l e _ T y p e = V } ]
+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x54, 0x79, 0x70, 0x65, 0x3d, 0x56, 0x7d, 0x5d, 0};
+
+static const UChar gGC_TPattern[] = {
+// [ \ p { H a n g u l _ S y l
+ 0x5b, 0x5c, 0x70, 0x7b, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x5f, 0x53, 0x79, 0x6c,
+// l a b l e _ T y p e = T } ]
+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x54, 0x79, 0x70, 0x65, 0x3d, 0x54, 0x7d, 0x5d, 0};
+
+static const UChar gGC_LVPattern[] = {
+// [ \ p { H a n g u l _ S y l
+ 0x5b, 0x5c, 0x70, 0x7b, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x5f, 0x53, 0x79, 0x6c,
+// l a b l e _ T y p e = L V } ]
+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x54, 0x79, 0x70, 0x65, 0x3d, 0x4c, 0x56, 0x7d, 0x5d, 0};
+
+static const UChar gGC_LVTPattern[] = {
+// [ \ p { H a n g u l _ S y l
+ 0x5b, 0x5c, 0x70, 0x7b, 0x48, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x5f, 0x53, 0x79, 0x6c,
+// l a b l e _ T y p e = L V T } ]
+ 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x54, 0x79, 0x70, 0x65, 0x3d, 0x4c, 0x56, 0x54, 0x7d, 0x5d, 0};
+
+RegexStaticSets *RegexStaticSets::gStaticSets = NULL;
+
+RegexStaticSets::RegexStaticSets(UErrorCode *status)
+:
+fUnescapeCharSet(UnicodeString(TRUE, gUnescapeCharPattern, -1), *status),
+fRuleDigitsAlias(NULL)
+{
+ // First zero out everything
+ int i;
+ for (i=0; i<URX_LAST_SET; i++) {
+ fPropSets[i] = NULL;
+ }
+ for (i=0; i<(int32_t)(sizeof(fRuleSets)/sizeof(fRuleSets[0])); i++) {
+ fRuleSets[i] = NULL;
+ }
+
+ // Then init the sets to their correct values.
+ fPropSets[URX_ISWORD_SET] = new UnicodeSet(UnicodeString(TRUE, gIsWordPattern, -1), *status);
+ fPropSets[URX_ISSPACE_SET] = new UnicodeSet(UnicodeString(TRUE, gIsSpacePattern, -1), *status);
+ fPropSets[URX_GC_EXTEND] = new UnicodeSet(UnicodeString(TRUE, gGC_ExtendPattern, -1), *status);
+ fPropSets[URX_GC_CONTROL] = new UnicodeSet(UnicodeString(TRUE, gGC_ControlPattern, -1), *status);
+ fPropSets[URX_GC_L] = new UnicodeSet(UnicodeString(TRUE, gGC_LPattern, -1), *status);
+ fPropSets[URX_GC_V] = new UnicodeSet(UnicodeString(TRUE, gGC_VPattern, -1), *status);
+ fPropSets[URX_GC_T] = new UnicodeSet(UnicodeString(TRUE, gGC_TPattern, -1), *status);
+ fPropSets[URX_GC_LV] = new UnicodeSet(UnicodeString(TRUE, gGC_LVPattern, -1), *status);
+ fPropSets[URX_GC_LVT] = new UnicodeSet(UnicodeString(TRUE, gGC_LVTPattern, -1), *status);
+ if (U_FAILURE(*status)) {
+ // Bail out if we were unable to create the above sets.
+ // The rest of the initialization needs them, so we cannot proceed.
+ return;
+ }
+
+
+ //
+ // The following sets are dynamically constructed, because their
+ // initialization strings would be unreasonable.
+ //
+
+
+ //
+ // "Normal" is the set of characters that don't need special handling
+ // when finding grapheme cluster boundaries.
+ //
+ fPropSets[URX_GC_NORMAL] = new UnicodeSet(0, UnicodeSet::MAX_VALUE);
+ fPropSets[URX_GC_NORMAL]->remove(0xac00, 0xd7a4);
+ fPropSets[URX_GC_NORMAL]->removeAll(*fPropSets[URX_GC_CONTROL]);
+ fPropSets[URX_GC_NORMAL]->removeAll(*fPropSets[URX_GC_L]);
+ fPropSets[URX_GC_NORMAL]->removeAll(*fPropSets[URX_GC_V]);
+ fPropSets[URX_GC_NORMAL]->removeAll(*fPropSets[URX_GC_T]);
+
+ // Initialize the 8-bit fast bit sets from the parallel full
+ // UnicodeSets.
+ for (i=0; i<URX_LAST_SET; i++) {
+ if (fPropSets[i]) {
+ fPropSets[i]->compact();
+ fPropSets8[i].init(fPropSets[i]);
+ }
+ }
+
+ // Sets used while parsing rules, but not referenced from the parse state table
+ fRuleSets[kRuleSet_rule_char-128] = new UnicodeSet(UnicodeString(TRUE, gRuleSet_rule_char_pattern, -1), *status);
+ fRuleSets[kRuleSet_white_space-128] = new UnicodeSet(UnicodeString(TRUE, gRuleWhiteSpacePattern, -1), *status);
+ fRuleSets[kRuleSet_digit_char-128] = new UnicodeSet(UnicodeString(TRUE, gRuleSet_digit_char_pattern, -1), *status);
+ fRuleDigitsAlias = fRuleSets[kRuleSet_digit_char-128];
+ for (i=0; i<(int32_t)(sizeof(fRuleSets)/sizeof(fRuleSets[0])); i++) {
+ if (fRuleSets[i]) {
+ fRuleSets[i]->compact();
+ }
+ }
+}
+
+
+RegexStaticSets::~RegexStaticSets() {
+ int32_t i;
+
+ for (i=0; i<URX_LAST_SET; i++) {
+ delete fPropSets[i];
+ fPropSets[i] = NULL;
+ }
+ for (i=0; i<(int32_t)(sizeof(fRuleSets)/sizeof(fRuleSets[0])); i++) {
+ delete fRuleSets[i];
+ fRuleSets[i] = NULL;
+ }
+ fRuleDigitsAlias = NULL;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// regex_cleanup Memory cleanup function, free/delete all
+// cached memory. Called by ICU's u_cleanup() function.
+//
+//------------------------------------------------------------------------------
+UBool
+RegexStaticSets::cleanup(void) {
+ delete RegexStaticSets::gStaticSets;
+ RegexStaticSets::gStaticSets = NULL;
+ return TRUE;
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+regex_cleanup(void) {
+ return RegexStaticSets::cleanup();
+}
+U_CDECL_END
+
+void RegexStaticSets::initGlobals(UErrorCode *status) {
+ RegexStaticSets *p;
+ UMTX_CHECK(NULL, gStaticSets, p);
+ if (p == NULL) {
+ p = new RegexStaticSets(status);
+ if (U_FAILURE(*status)) {
+ delete p;
+ return;
+ }
+ umtx_lock(NULL);
+ if (gStaticSets == NULL) {
+ gStaticSets = p;
+ p = NULL;
+ }
+ umtx_unlock(NULL);
+ if (p) {
+ delete p;
+ }
+ ucln_i18n_registerCleanup(UCLN_I18N_REGEX, regex_cleanup);
+ }
+}
+
+
+U_NAMESPACE_END
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
diff --git a/Build/source/libs/icu/icu-xetex/i18n/regexst.h b/Build/source/libs/icu/icu-xetex/i18n/regexst.h
new file mode 100644
index 00000000000..2fd9c32d773
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/regexst.h
@@ -0,0 +1,57 @@
+//
+// regexst.h
+//
+// Copyright (C) 2003-2007, International Business Machines Corporation and others.
+// All Rights Reserved.
+//
+// This file contains declarations for the class RegexStaticSets
+//
+// This class is internal to the regular expression implementation.
+// For the public Regular Expression API, see the file "unicode/regex.h"
+//
+// RegexStaticSets groups together the common UnicodeSets that are needed
+// for compiling or executing RegularExpressions. This grouping simplifies
+// the thread safe lazy creation and sharing of these sets across
+// all instances of regular expressions.
+//
+
+#ifndef REGEXST_H
+#define REGEXST_H
+
+#include "unicode/utypes.h"
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "regeximp.h"
+
+U_NAMESPACE_BEGIN
+
+class UnicodeSet;
+
+
+class RegexStaticSets : public UMemory {
+public:
+ static RegexStaticSets *gStaticSets; // Ptr to all lazily initialized constant
+ // shared sets.
+
+ RegexStaticSets(UErrorCode *status);
+ ~RegexStaticSets();
+ static void initGlobals(UErrorCode *status);
+ static UBool cleanup();
+
+ UnicodeSet *fPropSets[URX_LAST_SET]; // The sets for common regex items, e.g. \s
+ Regex8BitSet fPropSets8[URX_LAST_SET]; // Fast bitmap sets for latin-1 range for above.
+
+ UnicodeSet *fRuleSets[10]; // Sets used while parsing regexp patterns.
+ UnicodeSet fUnescapeCharSet; // Set of chars handled by unescape when
+ // encountered with a \ in a pattern.
+ UnicodeSet *fRuleDigitsAlias;
+ UnicodeString fEmptyString; // An empty string, to be used when a matcher
+ // is created with no input.
+
+};
+
+
+U_NAMESPACE_END
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+#endif // REGEXST_H
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/reldtfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/reldtfmt.cpp
new file mode 100644
index 00000000000..56d63515d98
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/reldtfmt.cpp
@@ -0,0 +1,317 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+//#define DEBUG_RELDTFMT
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "reldtfmt.h"
+#include "unicode/msgfmt.h"
+
+#include "gregoimp.h" // for CalendarData
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+
+/**
+ * An array of URelativeString structs is used to store the resource data loaded out of the bundle.
+ */
+struct URelativeString {
+ int32_t offset; /** offset of this item, such as, the relative date **/
+ int32_t len; /** length of the string **/
+ const UChar* string; /** string, or NULL if not set **/
+};
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RelativeDateFormat)
+
+RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) :
+DateFormat(other), fDateFormat(NULL), fTimeFormat(NULL), fCombinedFormat(NULL),
+fDateStyle(other.fDateStyle), fTimeStyle(other.fTimeStyle), fLocale(other.fLocale),
+fDayMin(other.fDayMin), fDayMax(other.fDayMax),
+fDatesLen(other.fDatesLen), fDates(NULL)
+{
+ if(other.fDateFormat != NULL) {
+ fDateFormat = (DateFormat*)other.fDateFormat->clone();
+ } else {
+ fDateFormat = NULL;
+ }
+ if (fDatesLen > 0) {
+ fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen);
+ uprv_memcpy(fDates, other.fDates, sizeof(fDates[0])*fDatesLen);
+ }
+ //fCalendar = other.fCalendar->clone();
+/*
+ if(other.fTimeFormat != NULL) {
+ fTimeFormat = (DateFormat*)other.fTimeFormat->clone();
+ } else {
+ fTimeFormat = NULL;
+ }
+*/
+}
+
+RelativeDateFormat::RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const Locale& locale, UErrorCode& status)
+ : DateFormat(), fDateFormat(NULL), fTimeFormat(NULL), fCombinedFormat(NULL),
+fDateStyle(dateStyle), fTimeStyle(timeStyle), fLocale(locale), fDatesLen(0), fDates(NULL)
+ {
+ if(U_FAILURE(status) ) {
+ return;
+ }
+
+ if(fDateStyle != UDAT_NONE) {
+ EStyle newStyle = (EStyle)(fDateStyle & ~UDAT_RELATIVE);
+ // Create a DateFormat in the non-relative style requested.
+ fDateFormat = createDateInstance(newStyle, locale);
+ }
+ if(fTimeStyle != UDAT_NONE) {
+ // don't support time style, for now
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ // Initialize the parent fCalendar, so that parse() works correctly.
+ initializeCalendar(NULL, locale, status);
+ loadDates(status);
+}
+
+RelativeDateFormat::~RelativeDateFormat() {
+ delete fDateFormat;
+ delete fTimeFormat;
+ delete fCombinedFormat;
+ uprv_free(fDates);
+}
+
+
+Format* RelativeDateFormat::clone(void) const {
+ return new RelativeDateFormat(*this);
+}
+
+UBool RelativeDateFormat::operator==(const Format& other) const {
+ if(DateFormat::operator==(other)) {
+ // DateFormat::operator== guarantees following cast is safe
+ RelativeDateFormat* that = (RelativeDateFormat*)&other;
+ return (fDateStyle==that->fDateStyle &&
+ fTimeStyle==that->fTimeStyle &&
+ fLocale==that->fLocale);
+ }
+ return FALSE;
+}
+
+UnicodeString& RelativeDateFormat::format( Calendar& cal,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ // calculate the difference, in days, between 'cal' and now.
+ int dayDiff = dayDifference(cal, status);
+
+ // look up string
+ int32_t len;
+ const UChar *theString = getStringForDay(dayDiff, len, status);
+
+ if(U_FAILURE(status) || (theString==NULL)) {
+ // didn't find it. Fall through to the fDateFormat
+ if(fDateFormat != NULL) {
+ return fDateFormat->format(cal,appendTo,pos);
+ } else {
+ return appendTo; // no op
+ }
+ } else {
+ // found a relative string
+ return appendTo.append(theString, len);
+ }
+}
+
+
+
+UnicodeString&
+RelativeDateFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ // this is just here to get around the hiding problem
+ // (the previous format() override would hide the version of
+ // format() on DateFormat that this function correspond to, so we
+ // have to redefine it here)
+ return DateFormat::format(obj, appendTo, pos, status);
+}
+
+
+void RelativeDateFormat::parse( const UnicodeString& text,
+ Calendar& cal,
+ ParsePosition& pos) const {
+
+ // Can the fDateFormat parse it?
+ if(fDateFormat != NULL) {
+ ParsePosition aPos(pos);
+ fDateFormat->parse(text,cal,aPos);
+ if((aPos.getIndex() != pos.getIndex()) &&
+ (aPos.getErrorIndex()==-1)) {
+ pos=aPos; // copy the sub parse
+ return; // parsed subfmt OK
+ }
+ }
+
+ // Linear search the relative strings
+ for(int n=0;n<fDatesLen;n++) {
+ if(fDates[n].string != NULL &&
+ (0==text.compare(pos.getIndex(),
+ fDates[n].len,
+ fDates[n].string))) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Set the calendar to now+offset
+ cal.setTime(Calendar::getNow(),status);
+ cal.add(UCAL_DATE,fDates[n].offset, status);
+
+ if(U_FAILURE(status)) {
+ // failure in setting calendar fields
+ pos.setErrorIndex(pos.getIndex()+fDates[n].len);
+ } else {
+ pos.setIndex(pos.getIndex()+fDates[n].len);
+ }
+ return;
+ }
+ }
+
+ // parse failed
+}
+
+UDate
+RelativeDateFormat::parse( const UnicodeString& text,
+ ParsePosition& pos) const {
+ // redefined here because the other parse() function hides this function's
+ // cunterpart on DateFormat
+ return DateFormat::parse(text, pos);
+}
+
+UDate
+RelativeDateFormat::parse(const UnicodeString& text, UErrorCode& status) const
+{
+ // redefined here because the other parse() function hides this function's
+ // counterpart on DateFormat
+ return DateFormat::parse(text, status);
+}
+
+
+const UChar *RelativeDateFormat::getStringForDay(int32_t day, int32_t &len, UErrorCode &status) const {
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+
+ // Is it outside the resource bundle's range?
+ if(day < fDayMin || day > fDayMax) {
+ return NULL; // don't have it.
+ }
+
+ // Linear search the held strings
+ for(int n=0;n<fDatesLen;n++) {
+ if(fDates[n].offset == day) {
+ len = fDates[n].len;
+ return fDates[n].string;
+ }
+ }
+
+ return NULL; // not found.
+}
+
+void RelativeDateFormat::loadDates(UErrorCode &status) {
+ CalendarData calData(fLocale, "gregorian", status);
+ UResourceBundle *strings = calData.getByKey3("fields", "day", "relative", status);
+ // set up min/max
+ fDayMin=-1;
+ fDayMax=1;
+
+ if(U_FAILURE(status)) {
+ fDatesLen=0;
+ return;
+ }
+
+ fDatesLen = ures_getSize(strings);
+ fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen);
+
+ // Load in each item into the array...
+ int n = 0;
+
+ UResourceBundle *subString = NULL;
+
+ while(ures_hasNext(strings) && U_SUCCESS(status)) { // iterate over items
+ subString = ures_getNextResource(strings, subString, &status);
+
+ if(U_FAILURE(status) || (subString==NULL)) break;
+
+ // key = offset #
+ const char *key = ures_getKey(subString);
+
+ // load the string and length
+ int32_t aLen;
+ const UChar* aString = ures_getString(subString, &aLen, &status);
+
+ if(U_FAILURE(status) || aString == NULL) break;
+
+ // calculate the offset
+ int32_t offset = atoi(key);
+
+ // set min/max
+ if(offset < fDayMin) {
+ fDayMin = offset;
+ }
+ if(offset > fDayMax) {
+ fDayMax = offset;
+ }
+
+ // copy the string pointer
+ fDates[n].offset = offset;
+ fDates[n].string = aString;
+ fDates[n].len = aLen;
+
+ n++;
+ }
+ ures_close(subString);
+
+ // the fDates[] array could be sorted here, for direct access.
+}
+
+
+// this should to be in DateFormat, instead it was copied from SimpleDateFormat.
+
+Calendar*
+RelativeDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status)
+{
+ if(!U_FAILURE(status)) {
+ fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status);
+ }
+ if (U_SUCCESS(status) && fCalendar == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return fCalendar;
+}
+
+int32_t RelativeDateFormat::dayDifference(Calendar &cal, UErrorCode &status) {
+ if(U_FAILURE(status)) {
+ return 0;
+ }
+ // TODO: Cache the nowCal to avoid heap allocs?
+ Calendar *nowCal = cal.clone();
+ nowCal->setTime(Calendar::getNow(), status);
+ int32_t dayDiff = nowCal->fieldDifference(cal.getTime(status), Calendar::DATE, status);
+ delete nowCal;
+ return dayDiff;
+}
+
+U_NAMESPACE_END
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/reldtfmt.h b/Build/source/libs/icu/icu-xetex/i18n/reldtfmt.h
new file mode 100644
index 00000000000..9957bf833a6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/reldtfmt.h
@@ -0,0 +1,262 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef RELDTFMT_H
+#define RELDTFMT_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Format and parse relative dates and times.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/datefmt.h"
+
+U_NAMESPACE_BEGIN
+
+// forward declarations
+class MessageFormat;
+
+// internal structure used for caching strings
+struct URelativeString;
+
+/**
+ * This class is normally accessed using the kRelative or k...Relative values of EStyle as parameters to DateFormat::createDateInstance.
+ *
+ * Example:
+ * DateFormat *fullrelative = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
+ *
+ * @draft ICU 3.8
+ */
+
+class RelativeDateFormat : public DateFormat {
+public:
+ RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const Locale& locale, UErrorCode& status);
+
+ // overrides
+ /**
+ * Copy constructor.
+ * @draft ICU 3.8
+ */
+ RelativeDateFormat(const RelativeDateFormat&);
+
+ /**
+ * Assignment operator.
+ * @draft ICU 3.8
+ */
+ RelativeDateFormat& operator=(const RelativeDateFormat&);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~RelativeDateFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @draft ICU 3.8
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Return true if the given Format objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Format a date or time, which is the standard millis since 24:00 GMT, Jan
+ * 1, 1970. Overrides DateFormat pure virtual method.
+ * <P>
+ * Example: using the US locale: "yyyy.MM.dd e 'at' HH:mm:ss zzz" ->>
+ * 1996.07.10 AD at 15:08:56 PDT
+ *
+ * @param cal Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos The formatting position. On input: an alignment field,
+ * if desired. On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @draft ICU 3.8
+ */
+ virtual UnicodeString& format( Calendar& cal,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format an object to produce a string. This method handles Formattable
+ * objects with a UDate type. If a the Formattable object type is not a Date,
+ * then it returns a failing UErrorCode.
+ *
+ * @param obj The object to format. Must be a Date.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @draft ICU 3.8
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+
+ /**
+ * Parse a date/time string beginning at the given parse position. For
+ * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
+ * that is equivalent to Date(837039928046).
+ * <P>
+ * By default, parsing is lenient: If the input is not in the form used by
+ * this object's format method but can still be parsed as a date, then the
+ * parse succeeds. Clients may insist on strict adherence to the format by
+ * calling setLenient(false).
+ *
+ * @param text The date/time string to be parsed
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @param pos On input, the position at which to start parsing; on
+ * output, the position at which parsing terminated, or the
+ * start position if the parse failed.
+ * @return A valid UDate if the input could be parsed.
+ * @draft ICU 3.8
+ */
+ virtual void parse( const UnicodeString& text,
+ Calendar& cal,
+ ParsePosition& pos) const;
+
+ /**
+ * Parse a date/time string starting at the given parse position. For
+ * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
+ * that is equivalent to Date(837039928046).
+ * <P>
+ * By default, parsing is lenient: If the input is not in the form used by
+ * this object's format method but can still be parsed as a date, then the
+ * parse succeeds. Clients may insist on strict adherence to the format by
+ * calling setLenient(false).
+ *
+ * @see DateFormat::setLenient(boolean)
+ *
+ * @param text The date/time string to be parsed
+ * @param pos On input, the position at which to start parsing; on
+ * output, the position at which parsing terminated, or the
+ * start position if the parse failed.
+ * @return A valid UDate if the input could be parsed.
+ * @draft ICU 3.8
+ */
+ UDate parse( const UnicodeString& text,
+ ParsePosition& pos) const;
+
+
+ /**
+ * Parse a date/time string. For example, a time text "07/10/96 4:5 PM, PDT"
+ * will be parsed into a UDate that is equivalent to Date(837039928046).
+ * Parsing begins at the beginning of the string and proceeds as far as
+ * possible. Assuming no parse errors were encountered, this function
+ * doesn't return any information about how much of the string was consumed
+ * by the parsing. If you need that information, use the version of
+ * parse() that takes a ParsePosition.
+ *
+ * @param text The date/time string to be parsed
+ * @param status Filled in with U_ZERO_ERROR if the parse was successful, and with
+ * an error value if there was a parse error.
+ * @return A valid UDate if the input could be parsed.
+ * @draft ICU 3.8
+ */
+ virtual UDate parse( const UnicodeString& text,
+ UErrorCode& status) const;
+
+
+
+private:
+ DateFormat *fDateFormat; // the held date format
+ DateFormat *fTimeFormat; // the held time format
+ MessageFormat *fCombinedFormat; // the {0} {1} format.
+
+ UDateFormatStyle fDateStyle;
+ UDateFormatStyle fTimeStyle;
+ Locale fLocale;
+
+ int32_t fDayMin; // day id of lowest #
+ int32_t fDayMax; // day id of highest #
+ int32_t fDatesLen; // Length of array
+ URelativeString *fDates; // array of strings
+
+
+ /**
+ * Get the string at a specific offset.
+ * @param day day offset ( -1, 0, 1, etc.. )
+ * @param len on output, length of string.
+ * @return the string, or NULL if none at that location.
+ */
+ const UChar *getStringForDay(int32_t day, int32_t &len, UErrorCode &status) const;
+
+ /**
+ * Load the Date string array
+ */
+ void loadDates(UErrorCode &status);
+
+ /**
+ * @return the number of days in "until-now"
+ */
+ static int32_t dayDifference(Calendar &until, UErrorCode &status);
+
+ /**
+ * initializes fCalendar from parameters. Returns fCalendar as a convenience.
+ * @param adoptZone Zone to be adopted, or NULL for TimeZone::createDefault().
+ * @param locale Locale of the calendar
+ * @param status Error code
+ * @return the newly constructed fCalendar
+ * @draft ICU 3.8
+ */
+ Calendar* initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status);
+
+public:
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.8
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // RELDTFMT_H
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/rematch.cpp b/Build/source/libs/icu/icu-xetex/i18n/rematch.cpp
new file mode 100644
index 00000000000..503303e7930
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/rematch.cpp
@@ -0,0 +1,2299 @@
+/*
+**************************************************************************
+* Copyright (C) 2002-2007 International Business Machines Corporation *
+* and others. All rights reserved. *
+**************************************************************************
+*/
+//
+// file: rematch.cpp
+//
+// Contains the implementation of class RegexMatcher,
+// which is one of the main API classes for the ICU regular expression package.
+//
+
+#include "unicode/utypes.h"
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/regex.h"
+#include "unicode/uniset.h"
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "unicode/rbbi.h"
+#include "uassert.h"
+#include "cmemory.h"
+#include "uvector.h"
+#include "uvectr32.h"
+#include "regeximp.h"
+#include "regexst.h"
+
+// #include <malloc.h> // Needed for heapcheck testing
+
+U_NAMESPACE_BEGIN
+
+//-----------------------------------------------------------------------------
+//
+// Constructor and Destructor
+//
+//-----------------------------------------------------------------------------
+RegexMatcher::RegexMatcher(const RegexPattern *pat) {
+ fPattern = pat;
+ fPatternOwned = NULL;
+ fInput = NULL;
+ fTraceDebug = FALSE;
+ fDeferredStatus = U_ZERO_ERROR;
+ fStack = new UVector32(fDeferredStatus);
+ fData = fSmallData;
+ fWordBreakItr = NULL;
+ if (pat==NULL) {
+ fDeferredStatus = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (pat->fDataSize > (int32_t)(sizeof(fSmallData)/sizeof(int32_t))) {
+ fData = (int32_t *)uprv_malloc(pat->fDataSize * sizeof(int32_t));
+ }
+ if (fStack == NULL || fData == NULL) {
+ fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ reset(RegexStaticSets::gStaticSets->fEmptyString);
+}
+
+
+
+RegexMatcher::RegexMatcher(const UnicodeString &regexp, const UnicodeString &input,
+ uint32_t flags, UErrorCode &status) {
+ UParseError pe;
+ fPatternOwned = RegexPattern::compile(regexp, flags, pe, status);
+ fPattern = fPatternOwned;
+ fTraceDebug = FALSE;
+ fDeferredStatus = U_ZERO_ERROR;
+ fStack = new UVector32(status);
+ fData = fSmallData;
+ fWordBreakItr = NULL;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fPattern->fDataSize > (int32_t)(sizeof(fSmallData)/sizeof(int32_t))) {
+ fData = (int32_t *)uprv_malloc(fPattern->fDataSize * sizeof(int32_t));
+ }
+ if (fStack == NULL || fData == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ reset(input);
+}
+
+
+RegexMatcher::RegexMatcher(const UnicodeString &regexp,
+ uint32_t flags, UErrorCode &status) {
+ UParseError pe;
+ fTraceDebug = FALSE;
+ fDeferredStatus = U_ZERO_ERROR;
+ fStack = new UVector32(status);
+ fData = fSmallData;
+ fPatternOwned = RegexPattern::compile(regexp, flags, pe, status);
+ fPattern = fPatternOwned;
+ fWordBreakItr = NULL;
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (fPattern->fDataSize > (int32_t)(sizeof(fSmallData)/sizeof(int32_t))) {
+ fData = (int32_t *)uprv_malloc(fPattern->fDataSize * sizeof(int32_t));
+ }
+ if (fStack == NULL || fData == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ reset(RegexStaticSets::gStaticSets->fEmptyString);
+}
+
+
+
+RegexMatcher::~RegexMatcher() {
+ delete fStack;
+ if (fData != fSmallData) {
+ uprv_free(fData);
+ fData = NULL;
+ }
+ if (fPatternOwned) {
+ delete fPatternOwned;
+ fPatternOwned = NULL;
+ fPattern = NULL;
+ }
+ #if UCONFIG_NO_BREAK_ITERATION==0
+ delete fWordBreakItr;
+ #endif
+}
+
+
+
+static const UChar BACKSLASH = 0x5c;
+static const UChar DOLLARSIGN = 0x24;
+//--------------------------------------------------------------------------------
+//
+// appendReplacement
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::appendReplacement(UnicodeString &dest,
+ const UnicodeString &replacement,
+ UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return *this;
+ }
+ if (fMatch == FALSE) {
+ status = U_REGEX_INVALID_STATE;
+ return *this;
+ }
+
+ // Copy input string from the end of previous match to start of current match
+ int32_t len = fMatchStart-fLastReplaceEnd;
+ if (len > 0) {
+ dest.append(*fInput, fLastReplaceEnd, len);
+ }
+ fLastReplaceEnd = fMatchEnd;
+
+
+ // scan the replacement text, looking for substitutions ($n) and \escapes.
+ // TODO: optimize this loop by efficiently scanning for '$' or '\',
+ // move entire ranges not containing substitutions.
+ int32_t replLen = replacement.length();
+ int32_t replIdx = 0;
+ while (replIdx<replLen) {
+ UChar c = replacement.charAt(replIdx);
+ replIdx++;
+ if (c == BACKSLASH) {
+ // Backslash Escape. Copy the following char out without further checks.
+ // Note: Surrogate pairs don't need any special handling
+ // The second half wont be a '$' or a '\', and
+ // will move to the dest normally on the next
+ // loop iteration.
+ if (replIdx >= replLen) {
+ break;
+ }
+ c = replacement.charAt(replIdx);
+
+ if (c==0x55/*U*/ || c==0x75/*u*/) {
+ // We have a \udddd or \Udddddddd escape sequence.
+ UChar32 escapedChar = replacement.unescapeAt(replIdx);
+ if (escapedChar != (UChar32)0xFFFFFFFF) {
+ dest.append(escapedChar);
+ // TODO: Report errors for mal-formed \u escapes?
+ // As this is, the original sequence is output, which may be OK.
+ continue;
+ }
+ }
+
+ // Plain backslash escape. Just put out the escaped character.
+ dest.append(c);
+ replIdx++;
+ continue;
+ }
+
+ if (c != DOLLARSIGN) {
+ // Normal char, not a $. Copy it out without further checks.
+ dest.append(c);
+ continue;
+ }
+
+ // We've got a $. Pick up a capture group number if one follows.
+ // Consume at most the number of digits necessary for the largest capture
+ // number that is valid for this pattern.
+
+ int32_t numDigits = 0;
+ int32_t groupNum = 0;
+ UChar32 digitC;
+ for (;;) {
+ if (replIdx >= replLen) {
+ break;
+ }
+ digitC = replacement.char32At(replIdx);
+ if (u_isdigit(digitC) == FALSE) {
+ break;
+ }
+ replIdx = replacement.moveIndex32(replIdx, 1);
+ groupNum=groupNum*10 + u_charDigitValue(digitC);
+ numDigits++;
+ if (numDigits >= fPattern->fMaxCaptureDigits) {
+ break;
+ }
+ }
+
+
+ if (numDigits == 0) {
+ // The $ didn't introduce a group number at all.
+ // Treat it as just part of the substitution text.
+ dest.append(DOLLARSIGN);
+ continue;
+ }
+
+ // Finally, append the capture group data to the destination.
+ dest.append(group(groupNum, status));
+ if (U_FAILURE(status)) {
+ // Can fail if group number is out of range.
+ break;
+ }
+
+ }
+
+ return *this;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// appendTail Intended to be used in conjunction with appendReplacement()
+// To the destination string, append everything following
+// the last match position from the input string.
+//
+//--------------------------------------------------------------------------------
+UnicodeString &RegexMatcher::appendTail(UnicodeString &dest) {
+ int32_t len = fInput->length()-fMatchEnd;
+ if (len > 0) {
+ dest.append(*fInput, fMatchEnd, len);
+ }
+ return dest;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// end
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::end(UErrorCode &err) const {
+ return end(0, err);
+}
+
+
+
+int32_t RegexMatcher::end(int32_t group, UErrorCode &err) const {
+ if (U_FAILURE(err)) {
+ return -1;
+ }
+ if (fMatch == FALSE) {
+ err = U_REGEX_INVALID_STATE;
+ return -1;
+ }
+ if (group < 0 || group > fPattern->fGroupMap->size()) {
+ err = U_INDEX_OUTOFBOUNDS_ERROR;
+ return -1;
+ }
+ int32_t e = -1;
+ if (group == 0) {
+ e = fMatchEnd;
+ } else {
+ // Get the position within the stack frame of the variables for
+ // this capture group.
+ int32_t groupOffset = fPattern->fGroupMap->elementAti(group-1);
+ U_ASSERT(groupOffset < fPattern->fFrameSize);
+ U_ASSERT(groupOffset >= 0);
+ e = fFrame->fExtra[groupOffset + 1];
+ }
+ return e;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// find()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::find() {
+ // Start at the position of the last match end. (Will be zero if the
+ // matcher has been reset.
+ //
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+
+ int32_t startPos = fMatchEnd;
+
+ if (fMatch) {
+ // Save the position of any previous successful match.
+ fLastMatchEnd = fMatchEnd;
+
+ if (fMatchStart == fMatchEnd) {
+ // Previous match had zero length. Move start position up one position
+ // to avoid sending find() into a loop on zero-length matches.
+ if (startPos == fInput->length()) {
+ fMatch = FALSE;
+ return FALSE;
+ }
+ startPos = fInput->moveIndex32(startPos, 1);
+ }
+ } else {
+ if (fLastMatchEnd >= 0) {
+ // A previous find() failed to match. Don't try again.
+ // (without this test, a pattern with a zero-length match
+ // could match again at the end of an input string.)
+ return FALSE;
+ }
+ }
+
+ int32_t inputLen = fInput->length();
+
+ // Compute the position in the input string beyond which a match can not begin, because
+ // the minimum length match would extend past the end of the input.
+ int32_t testLen = inputLen - fPattern->fMinMatchLen;
+ if (startPos > testLen) {
+ fMatch = FALSE;
+ return FALSE;
+ }
+
+ const UChar *inputBuf = fInput->getBuffer();
+ UChar32 c;
+ U_ASSERT(startPos >= 0);
+
+ switch (fPattern->fStartType) {
+ case START_NO_INFO:
+ // No optimization was found.
+ // Try a match at each input position.
+ for (;;) {
+ MatchAt(startPos, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ if (startPos >= testLen) {
+ return FALSE;
+ }
+ U16_FWD_1(inputBuf, startPos, inputLen);
+ // Note that it's perfectly OK for a pattern to have a zero-length
+ // match at the end of a string, so we must make sure that the loop
+ // runs with startPos == testLen the last time through.
+ }
+ U_ASSERT(FALSE);
+
+ case START_START:
+ // Matches are only possible at the start of the input string
+ // (pattern begins with ^ or \A)
+ if (startPos > 0) {
+ fMatch = FALSE;
+ return FALSE;
+ }
+ MatchAt(startPos, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ return fMatch;
+
+
+ case START_SET:
+ {
+ // Match may start on any char from a pre-computed set.
+ U_ASSERT(fPattern->fMinMatchLen > 0);
+ for (;;) {
+ int32_t pos = startPos;
+ U16_NEXT(inputBuf, startPos, inputLen, c); // like c = inputBuf[startPos++];
+ if (c<256 && fPattern->fInitialChars8->contains(c) ||
+ c>=256 && fPattern->fInitialChars->contains(c)) {
+ MatchAt(pos, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ }
+ if (pos >= testLen) {
+ fMatch = FALSE;
+ return FALSE;
+ }
+ }
+ }
+ U_ASSERT(FALSE);
+
+ case START_STRING:
+ case START_CHAR:
+ {
+ // Match starts on exactly one char.
+ U_ASSERT(fPattern->fMinMatchLen > 0);
+ UChar32 theChar = fPattern->fInitialChar;
+ for (;;) {
+ int32_t pos = startPos;
+ U16_NEXT(inputBuf, startPos, inputLen, c); // like c = inputBuf[startPos++];
+ if (c == theChar) {
+ MatchAt(pos, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ }
+ if (pos >= testLen) {
+ fMatch = FALSE;
+ return FALSE;
+ }
+ }
+ }
+ U_ASSERT(FALSE);
+
+ case START_LINE:
+ {
+ UChar32 c;
+ if (startPos == 0) {
+ MatchAt(startPos, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ U16_NEXT(inputBuf, startPos, inputLen, c); // like c = inputBuf[startPos++];
+ }
+
+ for (;;) {
+ c = inputBuf[startPos-1];
+ if (((c & 0x7f) <= 0x29) && // First quickly bypass as many chars as possible
+ ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029 )) {
+ if (c == 0x0d && startPos < inputLen && inputBuf[startPos] == 0x0a) {
+ startPos++;
+ }
+ MatchAt(startPos, fDeferredStatus);
+ if (U_FAILURE(fDeferredStatus)) {
+ return FALSE;
+ }
+ if (fMatch) {
+ return TRUE;
+ }
+ }
+ if (startPos >= testLen) {
+ fMatch = FALSE;
+ return FALSE;
+ }
+ U16_NEXT(inputBuf, startPos, inputLen, c); // like c = inputBuf[startPos++];
+ // Note that it's perfectly OK for a pattern to have a zero-length
+ // match at the end of a string, so we must make sure that the loop
+ // runs with startPos == testLen the last time through.
+ }
+ }
+
+ default:
+ U_ASSERT(FALSE);
+ }
+
+ U_ASSERT(FALSE);
+ return FALSE;
+}
+
+
+
+UBool RegexMatcher::find(int32_t start, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+ int32_t inputLen = fInput->length();
+ if (start < 0 || start > inputLen) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return FALSE;
+ }
+ this->reset();
+ fMatchEnd = start;
+ return find();
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// group()
+//
+//--------------------------------------------------------------------------------
+UnicodeString RegexMatcher::group(UErrorCode &status) const {
+ return group(0, status);
+}
+
+
+
+UnicodeString RegexMatcher::group(int32_t groupNum, UErrorCode &status) const {
+ int32_t s = start(groupNum, status);
+ int32_t e = end(groupNum, status);
+
+ // Note: calling start() and end() above will do all necessary checking that
+ // the group number is OK and that a match exists. status will be set.
+ if (U_FAILURE(status)) {
+ return UnicodeString();
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return UnicodeString();
+ }
+
+ if (s < 0) {
+ // A capture group wasn't part of the match
+ return UnicodeString();
+ }
+ U_ASSERT(s <= e);
+ return UnicodeString(*fInput, s, e-s);
+}
+
+
+
+
+int32_t RegexMatcher::groupCount() const {
+ return fPattern->fGroupMap->size();
+}
+
+
+
+const UnicodeString &RegexMatcher::input() const {
+ return *fInput;
+}
+
+
+
+
+//--------------------------------------------------------------------------------
+//
+// lookingAt()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::lookingAt(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+ reset();
+ MatchAt(0, status);
+ return fMatch;
+}
+
+
+UBool RegexMatcher::lookingAt(int32_t start, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+ if (start < 0 || start > fInput->length()) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return FALSE;
+ }
+ reset();
+ MatchAt(start, status);
+ return fMatch;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// matches()
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::matches(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+ reset();
+ MatchAt(0, status);
+ UBool success = (fMatch && fMatchEnd==fInput->length());
+ return success;
+}
+
+
+UBool RegexMatcher::matches(int32_t start, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return FALSE;
+ }
+ if (start < 0 || start > fInput->length()) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return FALSE;
+ }
+ reset();
+ MatchAt(start, status);
+ UBool success = (fMatch && fMatchEnd==fInput->length());
+ return success;
+}
+
+
+
+const RegexPattern &RegexMatcher::pattern() const {
+ return *fPattern;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// replaceAll
+//
+//--------------------------------------------------------------------------------
+UnicodeString RegexMatcher::replaceAll(const UnicodeString &replacement, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *fInput;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return *fInput;
+ }
+ UnicodeString destString;
+ for (reset(); find(); ) {
+ appendReplacement(destString, replacement, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ }
+ appendTail(destString);
+ return destString;
+}
+
+
+
+
+//--------------------------------------------------------------------------------
+//
+// replaceFirst
+//
+//--------------------------------------------------------------------------------
+UnicodeString RegexMatcher::replaceFirst(const UnicodeString &replacement, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *fInput;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return *fInput;
+ }
+
+ reset();
+ if (!find()) {
+ return *fInput;
+ }
+
+ UnicodeString destString;
+ appendReplacement(destString, replacement, status);
+ appendTail(destString);
+ return destString;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// reset
+//
+//--------------------------------------------------------------------------------
+RegexMatcher &RegexMatcher::reset() {
+ fMatchStart = 0;
+ fMatchEnd = 0;
+ fLastMatchEnd = -1;
+ fLastReplaceEnd = 0;
+ fMatch = FALSE;
+ resetStack();
+ return *this;
+}
+
+
+
+RegexMatcher &RegexMatcher::reset(const UnicodeString &input) {
+ fInput = &input;
+ reset();
+ if (fWordBreakItr != NULL) {
+ #if UCONFIG_NO_BREAK_ITERATION==0
+ fWordBreakItr->setText(input);
+ #endif
+ }
+ return *this;
+}
+
+/*RegexMatcher &RegexMatcher::reset(const UChar *) {
+ fDeferredStatus = U_INTERNAL_PROGRAM_ERROR;
+ return *this;
+}*/
+
+
+RegexMatcher &RegexMatcher::reset(int32_t position, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ reset();
+ if (position < 0 || position >= fInput->length()) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return *this;
+ }
+ fMatchEnd = position;
+ return *this;
+}
+
+
+
+
+
+//--------------------------------------------------------------------------------
+//
+// setTrace
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::setTrace(UBool state) {
+ fTraceDebug = state;
+}
+
+
+
+//---------------------------------------------------------------------
+//
+// split
+//
+//---------------------------------------------------------------------
+int32_t RegexMatcher::split(const UnicodeString &input,
+ UnicodeString dest[],
+ int32_t destCapacity,
+ UErrorCode &status)
+{
+ //
+ // Check arguements for validity
+ //
+ if (U_FAILURE(status)) {
+ return 0;
+ };
+
+ if (destCapacity < 1) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+
+ //
+ // Reset for the input text
+ //
+ reset(input);
+ int32_t inputLen = input.length();
+ int32_t nextOutputStringStart = 0;
+ if (inputLen == 0) {
+ return 0;
+ }
+
+
+ //
+ // Loop through the input text, searching for the delimiter pattern
+ //
+ int32_t i;
+ int32_t numCaptureGroups = fPattern->fGroupMap->size();
+ for (i=0; ; i++) {
+ if (i>=destCapacity-1) {
+ // There is one or zero output string left.
+ // Fill the last output string with whatever is left from the input, then exit the loop.
+ // ( i will be == destCapicity if we filled the output array while processing
+ // capture groups of the delimiter expression, in which case we will discard the
+ // last capture group saved in favor of the unprocessed remainder of the
+ // input string.)
+ i = destCapacity-1;
+ int32_t remainingLength = inputLen-nextOutputStringStart;
+ if (remainingLength > 0) {
+ dest[i].setTo(input, nextOutputStringStart, remainingLength);
+ }
+ break;
+ }
+ if (find()) {
+ // We found another delimiter. Move everything from where we started looking
+ // up until the start of the delimiter into the next output string.
+ int32_t fieldLen = fMatchStart - nextOutputStringStart;
+ dest[i].setTo(input, nextOutputStringStart, fieldLen);
+ nextOutputStringStart = fMatchEnd;
+
+ // If the delimiter pattern has capturing parentheses, the captured
+ // text goes out into the next n destination strings.
+ int32_t groupNum;
+ for (groupNum=1; groupNum<=numCaptureGroups; groupNum++) {
+ if (i==destCapacity-1) {
+ break;
+ }
+ i++;
+ dest[i] = group(groupNum, status);
+ }
+
+ if (nextOutputStringStart == inputLen) {
+ // The delimiter was at the end of the string. We're done.
+ break;
+ }
+
+ }
+ else
+ {
+ // We ran off the end of the input while looking for the next delimiter.
+ // All the remaining text goes into the current output string.
+ dest[i].setTo(input, nextOutputStringStart, inputLen-nextOutputStringStart);
+ break;
+ }
+ }
+ return i+1;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// start
+//
+//--------------------------------------------------------------------------------
+int32_t RegexMatcher::start(UErrorCode &status) const {
+ return start(0, status);
+}
+
+
+
+
+int32_t RegexMatcher::start(int32_t group, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return -1;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return -1;
+ }
+ if (fMatch == FALSE) {
+ status = U_REGEX_INVALID_STATE;
+ return -1;
+ }
+ if (group < 0 || group > fPattern->fGroupMap->size()) {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return -1;
+ }
+ int32_t s;
+ if (group == 0) {
+ s = fMatchStart;
+ } else {
+ int32_t groupOffset = fPattern->fGroupMap->elementAti(group-1);
+ U_ASSERT(groupOffset < fPattern->fFrameSize);
+ U_ASSERT(groupOffset >= 0);
+ s = fFrame->fExtra[groupOffset];
+ }
+ return s;
+}
+
+
+
+//================================================================================
+//
+// Code following this point in this file is the internal
+// Match Engine Implementation.
+//
+//================================================================================
+
+
+//--------------------------------------------------------------------------------
+//
+// resetStack
+// Discard any previous contents of the state save stack, and initialize a
+// new stack frame to all -1. The -1s are needed for capture group limits,
+// where they indicate that a group has not yet matched anything.
+//--------------------------------------------------------------------------------
+REStackFrame *RegexMatcher::resetStack() {
+ // Discard any previous contents of the state save stack, and initialize a
+ // new stack frame to all -1. The -1s are needed for capture group limits, where
+ // they indicate that a group has not yet matched anything.
+ fStack->removeAllElements();
+
+ int32_t *iFrame = fStack->reserveBlock(fPattern->fFrameSize, fDeferredStatus);
+ int32_t i;
+ for (i=0; i<fPattern->fFrameSize; i++) {
+ iFrame[i] = -1;
+ }
+ return (REStackFrame *)iFrame;
+}
+
+
+
+//--------------------------------------------------------------------------------
+//
+// isWordBoundary
+// in perl, "xab..cd..", \b is true at positions 0,3,5,7
+// For us,
+// If the current char is a combining mark,
+// \b is FALSE.
+// Else Scan backwards to the first non-combining char.
+// We are at a boundary if the this char and the original chars are
+// opposite in membership in \w set
+//
+// parameters: pos - the current position in the input buffer
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::isWordBoundary(int32_t pos) {
+ UBool isBoundary = FALSE;
+ UBool cIsWord = FALSE;
+
+ // Determine whether char c at current position is a member of the word set of chars.
+ // If we're off the end of the string, behave as though we're not at a word char.
+ if (pos < fInput->length()) {
+ UChar32 c = fInput->char32At(pos);
+ if (u_hasBinaryProperty(c, UCHAR_GRAPHEME_EXTEND) || u_charType(c) == U_FORMAT_CHAR) {
+ // Current char is a combining one. Not a boundary.
+ return FALSE;
+ }
+ cIsWord = fPattern->fStaticSets[URX_ISWORD_SET]->contains(c);
+ }
+
+ // Back up until we come to a non-combining char, determine whether
+ // that char is a word char.
+ UBool prevCIsWord = FALSE;
+ int32_t prevPos = pos;
+ for (;;) {
+ if (prevPos == 0) {
+ break;
+ }
+ prevPos = fInput->moveIndex32(prevPos, -1);
+ UChar32 prevChar = fInput->char32At(prevPos);
+ if (!(u_hasBinaryProperty(prevChar, UCHAR_GRAPHEME_EXTEND)
+ || u_charType(prevChar) == U_FORMAT_CHAR)) {
+ prevCIsWord = fPattern->fStaticSets[URX_ISWORD_SET]->contains(prevChar);
+ break;
+ }
+ }
+ isBoundary = cIsWord ^ prevCIsWord;
+ return isBoundary;
+}
+
+//--------------------------------------------------------------------------------
+//
+// isUWordBoundary
+//
+// Test for a word boundary using RBBI word break.
+//
+// parameters: pos - the current position in the input buffer
+//
+//--------------------------------------------------------------------------------
+UBool RegexMatcher::isUWordBoundary(int32_t pos) {
+ UBool returnVal = FALSE;
+#if UCONFIG_NO_BREAK_ITERATION==0
+ UErrorCode status = U_ZERO_ERROR;
+
+ // If we haven't yet created a break iterator for this matcher, do it now.
+ if (fWordBreakItr == NULL) {
+ fWordBreakItr =
+ (RuleBasedBreakIterator *)BreakIterator::createWordInstance(Locale::getEnglish(), status);
+ if (U_FAILURE(status)) {
+ // TODO: reliable error reporting for BI failures.
+ return FALSE;
+ }
+ fWordBreakItr->setText(*fInput);
+ }
+
+ returnVal = fWordBreakItr->isBoundary(pos);
+#endif
+ return returnVal;
+}
+
+//--------------------------------------------------------------------------------
+//
+// StateSave
+// Make a new stack frame, initialized as a copy of the current stack frame.
+// Set the pattern index in the original stack frame from the operand value
+// in the opcode. Execution of the engine continues with the state in
+// the newly created stack frame
+//
+// Note that reserveBlock() may grow the stack, resulting in the
+// whole thing being relocated in memory.
+//
+//--------------------------------------------------------------------------------
+inline REStackFrame *RegexMatcher::StateSave(REStackFrame *fp, int32_t savePatIdx, int32_t frameSize, UErrorCode &status) {
+ // push storage for a new frame.
+ int32_t *newFP = fStack->reserveBlock(frameSize, status);
+ fp = (REStackFrame *)(newFP - frameSize); // in case of realloc of stack.
+
+ // New stack frame = copy of old top frame.
+ int32_t *source = (int32_t *)fp;
+ int32_t *dest = newFP;
+ for (;;) {
+ *dest++ = *source++;
+ if (source == newFP) {
+ break;
+ }
+ }
+
+ fp->fPatIdx = savePatIdx;
+ return (REStackFrame *)newFP;
+}
+
+
+//--------------------------------------------------------------------------------
+//
+// MatchAt This is the actual matching engine.
+//
+//--------------------------------------------------------------------------------
+void RegexMatcher::MatchAt(int32_t startIdx, UErrorCode &status) {
+ UBool isMatch = FALSE; // True if the we have a match.
+
+ int32_t op; // Operation from the compiled pattern, split into
+ int32_t opType; // the opcode
+ int32_t opValue; // and the operand value.
+
+ #ifdef REGEX_RUN_DEBUG
+ if (fTraceDebug)
+ {
+ printf("MatchAt(startIdx=%d)\n", startIdx);
+ printf("Original Pattern: ");
+ int32_t i;
+ for (i=0; i<fPattern->fPattern.length(); i++) {
+ printf("%c", fPattern->fPattern.charAt(i));
+ }
+ printf("\n");
+ printf("Input String: ");
+ for (i=0; i<fInput->length(); i++) {
+ UChar c = fInput->charAt(i);
+ if (c<32 || c>256) {
+ c = '.';
+ }
+ printf("%c", c);
+ }
+ printf("\n");
+ printf("\n");
+ }
+ #endif
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Cache frequently referenced items from the compiled pattern
+ // in local variables.
+ //
+ int32_t *pat = fPattern->fCompiledPat->getBuffer();
+
+ const UChar *litText = fPattern->fLiteralText.getBuffer();
+ UVector *sets = fPattern->fSets;
+ int32_t inputLen = fInput->length();
+ const UChar *inputBuf = fInput->getBuffer();
+
+ REStackFrame *fp = resetStack();
+ int32_t frameSize = fPattern->fFrameSize;
+
+ fp->fPatIdx = 0;
+ fp->fInputIdx = startIdx;
+
+ // Zero out the pattern's static data
+ int32_t i;
+ for (i = 0; i<fPattern->fDataSize; i++) {
+ fData[i] = 0;
+ }
+
+ //
+ // Main loop for interpreting the compiled pattern.
+ // One iteration of the loop per pattern operation performed.
+ //
+ for (;;) {
+#if 0
+ if (_heapchk() != _HEAPOK) {
+ fprintf(stderr, "Heap Trouble\n");
+ }
+#endif
+ op = pat[fp->fPatIdx];
+ opType = URX_TYPE(op);
+ opValue = URX_VAL(op);
+ #ifdef REGEX_RUN_DEBUG
+ if (fTraceDebug) {
+ printf("inputIdx=%d inputChar=%c sp=%3d ", fp->fInputIdx,
+ fInput->char32At(fp->fInputIdx), (int32_t *)fp-fStack->getBuffer());
+ fPattern->dumpOp(fp->fPatIdx);
+ }
+ #endif
+ fp->fPatIdx++;
+
+ switch (opType) {
+
+
+ case URX_NOP:
+ break;
+
+
+ case URX_BACKTRACK:
+ // Force a backtrack. In some circumstances, the pattern compiler
+ // will notice that the pattern can't possibly match anything, and will
+ // emit one of these at that point.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+
+
+ case URX_ONECHAR:
+ if (fp->fInputIdx < inputLen) {
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (c == opValue) {
+ break;
+ }
+ }
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+
+
+ case URX_STRING:
+ {
+ // Test input against a literal string.
+ // Strings require two slots in the compiled pattern, one for the
+ // offset to the string text, and one for the length.
+ int32_t stringStartIdx = opValue;
+ int32_t stringLen;
+
+ op = pat[fp->fPatIdx]; // Fetch the second operand
+ fp->fPatIdx++;
+ opType = URX_TYPE(op);
+ stringLen = URX_VAL(op);
+ U_ASSERT(opType == URX_STRING_LEN);
+ U_ASSERT(stringLen >= 2);
+
+ if (fp->fInputIdx + stringLen > inputLen) {
+ // No match. String is longer than the remaining input text.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+
+ const UChar * pInp = inputBuf + fp->fInputIdx;
+ const UChar * pPat = litText+stringStartIdx;
+ const UChar * pEnd = pInp + stringLen;
+ for(;;) {
+ if (*pInp == *pPat) {
+ pInp++;
+ pPat++;
+ if (pInp == pEnd) {
+ // Successful Match.
+ fp->fInputIdx += stringLen;
+ break;
+ }
+ } else {
+ // Match failed.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+ }
+ }
+ break;
+
+
+
+ case URX_STATE_SAVE:
+ fp = StateSave(fp, opValue, frameSize, status);
+ break;
+
+
+ case URX_END:
+ // The match loop will exit via this path on a successful match,
+ // when we reach the end of the pattern.
+ isMatch = TRUE;
+ goto breakFromLoop;
+
+ // Start and End Capture stack frame variables are layout out like this:
+ // fp->fExtra[opValue] - The start of a completed capture group
+ // opValue+1 - The end of a completed capture group
+ // opValue+2 - the start of a capture group whose end
+ // has not yet been reached (and might not ever be).
+ case URX_START_CAPTURE:
+ U_ASSERT(opValue >= 0 && opValue < frameSize-3);
+ fp->fExtra[opValue+2] = fp->fInputIdx;
+ break;
+
+
+ case URX_END_CAPTURE:
+ U_ASSERT(opValue >= 0 && opValue < frameSize-3);
+ U_ASSERT(fp->fExtra[opValue+2] >= 0); // Start pos for this group must be set.
+ fp->fExtra[opValue] = fp->fExtra[opValue+2]; // Tentative start becomes real.
+ fp->fExtra[opValue+1] = fp->fInputIdx; // End position
+ U_ASSERT(fp->fExtra[opValue] <= fp->fExtra[opValue+1]);
+ break;
+
+
+ case URX_DOLLAR: // $, test for End of line
+ // or for position before new line at end of input
+ if (fp->fInputIdx < inputLen-2) {
+ // We are no where near the end of input. Fail.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+ if (fp->fInputIdx >= inputLen) {
+ // We really are at the end of input. Success.
+ break;
+ }
+ // If we are positioned just before a new-line that is located at the
+ // end of input, succeed.
+ if (fp->fInputIdx == inputLen-1) {
+ UChar32 c = fInput->char32At(fp->fInputIdx);
+ if ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029) {
+ // If not in the middle of a CR/LF sequence
+ if ( !(c==0x0a && fp->fInputIdx>0 && inputBuf[fp->fInputIdx-1]==0x0d)) {
+ break;
+ // At new-line at end of input. Success
+ }
+ }
+ }
+
+ if (fp->fInputIdx == inputLen-2) {
+ if (fInput->char32At(fp->fInputIdx) == 0x0d && fInput->char32At(fp->fInputIdx+1) == 0x0a) {
+ break; // At CR/LF at end of input. Success
+ }
+ }
+
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+
+ break;
+
+
+ case URX_DOLLAR_M: // $, test for End of line in multi-line mode
+ {
+ if (fp->fInputIdx >= inputLen) {
+ // We really are at the end of input. Success.
+ break;
+ }
+ // If we are positioned just before a new-line, succeed.
+ // It makes no difference where the new-line is within the input.
+ UChar32 c = inputBuf[fp->fInputIdx];
+ if ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029) {
+ // At a line end, except for the odd chance of being in the middle of a CR/LF sequence
+ if ( !(c==0x0a && fp->fInputIdx>0 && inputBuf[fp->fInputIdx-1]==0x0d)) {
+ break; // At new-line at end of input. Success
+ }
+ }
+
+ // not at a new line. Fail.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ break;
+
+
+ case URX_CARET: // ^, test for start of line
+ if (fp->fInputIdx != 0) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ break;
+
+
+ case URX_CARET_M: // ^, test for start of line in mulit-line mode
+ {
+ if (fp->fInputIdx == 0) {
+ // We are at the start input. Success.
+ break;
+ }
+ // Check whether character just before the current pos is a new-line
+ // unless we are at the end of input
+ UChar c = inputBuf[fp->fInputIdx - 1];
+ if ((fp->fInputIdx < inputLen) &&
+ ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
+ // It's a new-line. ^ is true. Success.
+ break;
+ }
+ // Not at the start of a line. Fail.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ break;
+
+
+ case URX_BACKSLASH_B: // Test for word boundaries
+ {
+ UBool success = isWordBoundary(fp->fInputIdx);
+ success ^= (opValue != 0); // flip sense for \B
+ if (!success) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ }
+ break;
+
+
+ case URX_BACKSLASH_BU: // Test for word boundaries, Unicode-style
+ {
+ UBool success = isUWordBoundary(fp->fInputIdx);
+ success ^= (opValue != 0); // flip sense for \B
+ if (!success) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ }
+ break;
+
+
+ case URX_BACKSLASH_D: // Test for decimal digit
+ {
+ if (fp->fInputIdx >= inputLen) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+
+ UChar32 c = fInput->char32At(fp->fInputIdx);
+ int8_t ctype = u_charType(c);
+ UBool success = (ctype == U_DECIMAL_DIGIT_NUMBER);
+ success ^= (opValue != 0); // flip sense for \D
+ if (success) {
+ fp->fInputIdx = fInput->moveIndex32(fp->fInputIdx, 1);
+ } else {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ }
+ break;
+
+
+
+
+ case URX_BACKSLASH_G: // Test for position at end of previous match
+ if (!((fMatch && fp->fInputIdx==fMatchEnd) || fMatch==FALSE && fp->fInputIdx==0)) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ break;
+
+
+ case URX_BACKSLASH_X:
+ // Match a Grapheme, as defined by Unicode TR 29.
+ // Differs slightly from Perl, which consumes combining marks independently
+ // of context.
+ {
+
+ // Fail if at end of input
+ if (fp->fInputIdx >= inputLen) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+
+ // Examine (and consume) the current char.
+ // Dispatch into a little state machine, based on the char.
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ UnicodeSet **sets = fPattern->fStaticSets;
+ if (sets[URX_GC_NORMAL]->contains(c)) goto GC_Extend;
+ if (sets[URX_GC_CONTROL]->contains(c)) goto GC_Control;
+ if (sets[URX_GC_L]->contains(c)) goto GC_L;
+ if (sets[URX_GC_LV]->contains(c)) goto GC_V;
+ if (sets[URX_GC_LVT]->contains(c)) goto GC_T;
+ if (sets[URX_GC_V]->contains(c)) goto GC_V;
+ if (sets[URX_GC_T]->contains(c)) goto GC_T;
+ goto GC_Extend;
+
+
+
+GC_L:
+ if (fp->fInputIdx >= inputLen) goto GC_Done;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (sets[URX_GC_L]->contains(c)) goto GC_L;
+ if (sets[URX_GC_LV]->contains(c)) goto GC_V;
+ if (sets[URX_GC_LVT]->contains(c)) goto GC_T;
+ if (sets[URX_GC_V]->contains(c)) goto GC_V;
+ U16_PREV(inputBuf, 0, fp->fInputIdx, c);
+ goto GC_Extend;
+
+GC_V:
+ if (fp->fInputIdx >= inputLen) goto GC_Done;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (sets[URX_GC_V]->contains(c)) goto GC_V;
+ if (sets[URX_GC_T]->contains(c)) goto GC_T;
+ U16_PREV(inputBuf, 0, fp->fInputIdx, c);
+ goto GC_Extend;
+
+GC_T:
+ if (fp->fInputIdx >= inputLen) goto GC_Done;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (sets[URX_GC_T]->contains(c)) goto GC_T;
+ U16_PREV(inputBuf, 0, fp->fInputIdx, c);
+ goto GC_Extend;
+
+GC_Extend:
+ // Combining characters are consumed here
+ for (;;) {
+ if (fp->fInputIdx >= inputLen) {
+ break;
+ }
+ U16_GET(inputBuf, 0, fp->fInputIdx, inputLen, c);
+ if (sets[URX_GC_EXTEND]->contains(c) == FALSE) {
+ break;
+ }
+ U16_FWD_1(inputBuf, fp->fInputIdx, inputLen);
+ }
+ goto GC_Done;
+
+GC_Control:
+ // Most control chars stand alone (don't combine with combining chars),
+ // except for that CR/LF sequence is a single grapheme cluster.
+ if (c == 0x0d && fp->fInputIdx < inputLen && inputBuf[fp->fInputIdx] == 0x0a) {
+ fp->fInputIdx++;
+ }
+
+GC_Done:
+ break;
+ }
+
+
+
+
+ case URX_BACKSLASH_Z: // Test for end of line
+ if (fp->fInputIdx < inputLen) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ break;
+
+
+
+ case URX_STATIC_SETREF:
+ {
+ // Test input character against one of the predefined sets
+ // (Word Characters, for example)
+ // The high bit of the op value is a flag for the match polarity.
+ // 0: success if input char is in set.
+ // 1: success if input char is not in set.
+ if (fp->fInputIdx >= inputLen) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+
+ UBool success = ((opValue & URX_NEG_SET) == URX_NEG_SET);
+ opValue &= ~URX_NEG_SET;
+ U_ASSERT(opValue > 0 && opValue < URX_LAST_SET);
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (c < 256) {
+ Regex8BitSet *s8 = &fPattern->fStaticSets8[opValue];
+ if (s8->contains(c)) {
+ success = !success;
+ }
+ } else {
+ const UnicodeSet *s = fPattern->fStaticSets[opValue];
+ if (s->contains(c)) {
+ success = !success;
+ }
+ }
+ if (!success) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ }
+ break;
+
+
+ case URX_STAT_SETREF_N:
+ {
+ // Test input character for NOT being a member of one of
+ // the predefined sets (Word Characters, for example)
+ if (fp->fInputIdx >= inputLen) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+
+ U_ASSERT(opValue > 0 && opValue < URX_LAST_SET);
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (c < 256) {
+ Regex8BitSet *s8 = &fPattern->fStaticSets8[opValue];
+ if (s8->contains(c) == FALSE) {
+ break;
+ }
+ } else {
+ const UnicodeSet *s = fPattern->fStaticSets[opValue];
+ if (s->contains(c) == FALSE) {
+ break;
+ }
+ }
+
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ break;
+
+
+ case URX_SETREF:
+ if (fp->fInputIdx < inputLen) {
+ // There is input left. Pick up one char and test it for set membership.
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ U_ASSERT(opValue > 0 && opValue < sets->size());
+ if (c<256) {
+ Regex8BitSet *s8 = &fPattern->fSets8[opValue];
+ if (s8->contains(c)) {
+ break;
+ }
+ } else {
+
+ UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+ if (s->contains(c)) {
+ // The character is in the set. A Match.
+ break;
+ }
+ }
+ }
+ // Either at end of input, or the character wasn't in the set.
+ // Either way, we need to back track out.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+
+
+ case URX_DOTANY:
+ {
+ // . matches anything, but stops at end-of-line.
+ if (fp->fInputIdx >= inputLen) {
+ // At end of input. Match failed. Backtrack out.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+ // There is input left. Advance over one char, unless we've hit end-of-line
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (((c & 0x7f) <= 0x29) && // First quickly bypass as many chars as possible
+ ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
+ // End of line in normal mode. . does not match.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+ }
+ break;
+
+
+ case URX_DOTANY_ALL:
+ {
+ // ., in dot-matches-all (including new lines) mode
+ if (fp->fInputIdx >= inputLen) {
+ // At end of input. Match failed. Backtrack out.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+ // There is input left. Advance over one char, except if we are
+ // at a cr/lf, advance over both of them.
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (c==0x0d) {
+ // In the case of a CR/LF, we need to advance over both.
+ UChar nextc = inputBuf[fp->fInputIdx];
+ if (nextc == 0x0a) {
+ fp->fInputIdx++;
+ }
+ }
+ }
+ break;
+
+ case URX_DOTANY_PL:
+ // Match all up to and end-of-line or end-of-input.
+ {
+ // Fail if input already exhausted.
+ if (fp->fInputIdx >= inputLen) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+
+ // There is input left. Fail if we are at the end of a line.
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (((c & 0x7f) <= 0x29) && // First quickly bypass as many chars as possible
+ ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
+ // End of line in normal mode. . does not match.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+
+ // There was input left. Consume it until we hit the end of a line,
+ // or until it's exhausted.
+ while (fp->fInputIdx < inputLen) {
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (((c & 0x7f) <= 0x29) && // First quickly bypass as many chars as possible
+ ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
+ U16_BACK_1(inputBuf, 0, fp->fInputIdx)
+ // Scan has reached a line-end. We are done.
+ break;
+ }
+ }
+ }
+ break;
+
+ case URX_DOTANY_ALL_PL:
+ {
+ // Match up to end of input. Fail if already at end of input.
+ if (fp->fInputIdx >= inputLen) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ } else {
+ fp->fInputIdx = inputLen;
+ }
+ }
+ break;
+
+
+ case URX_JMP:
+ fp->fPatIdx = opValue;
+ break;
+
+ case URX_FAIL:
+ isMatch = FALSE;
+ goto breakFromLoop;
+
+ case URX_JMP_SAV:
+ U_ASSERT(opValue < fPattern->fCompiledPat->size());
+ fp = StateSave(fp, fp->fPatIdx, frameSize, status); // State save to loc following current
+ fp->fPatIdx = opValue; // Then JMP.
+ break;
+
+ case URX_JMP_SAV_X:
+ // This opcode is used with (x)+, when x can match a zero length string.
+ // Same as JMP_SAV, except conditional on the match having made forward progress.
+ // Destination of the JMP must be a URX_STO_INP_LOC, from which we get the
+ // data address of the input position at the start of the loop.
+ {
+ U_ASSERT(opValue > 0 && opValue < fPattern->fCompiledPat->size());
+ int32_t stoOp = pat[opValue-1];
+ U_ASSERT(URX_TYPE(stoOp) == URX_STO_INP_LOC);
+ int32_t frameLoc = URX_VAL(stoOp);
+ U_ASSERT(frameLoc >= 0 && frameLoc < frameSize);
+ int32_t prevInputIdx = fp->fExtra[frameLoc];
+ U_ASSERT(prevInputIdx <= fp->fInputIdx);
+ if (prevInputIdx < fp->fInputIdx) {
+ // The match did make progress. Repeat the loop.
+ fp = StateSave(fp, fp->fPatIdx, frameSize, status); // State save to loc following current
+ fp->fPatIdx = opValue;
+ fp->fExtra[frameLoc] = fp->fInputIdx;
+ }
+ // If the input position did not advance, we do nothing here,
+ // execution will fall out of the loop.
+ }
+ break;
+
+ case URX_CTR_INIT:
+ {
+ U_ASSERT(opValue >= 0 && opValue < frameSize-2);
+ fp->fExtra[opValue] = 0; // Set the loop counter variable to zero
+
+ // Pick up the three extra operands that CTR_INIT has, and
+ // skip the pattern location counter past
+ int32_t instrOperandLoc = fp->fPatIdx;
+ fp->fPatIdx += 3;
+ int32_t loopLoc = URX_VAL(pat[instrOperandLoc]);
+ int32_t minCount = pat[instrOperandLoc+1];
+ int32_t maxCount = pat[instrOperandLoc+2];
+ U_ASSERT(minCount>=0);
+ U_ASSERT(maxCount>=minCount || maxCount==-1);
+ U_ASSERT(loopLoc>fp->fPatIdx);
+
+ if (minCount == 0) {
+ fp = StateSave(fp, loopLoc+1, frameSize, status);
+ }
+ if (maxCount == 0) {
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ }
+ break;
+
+ case URX_CTR_LOOP:
+ {
+ U_ASSERT(opValue>0 && opValue < fp->fPatIdx-2);
+ int32_t initOp = pat[opValue];
+ U_ASSERT(URX_TYPE(initOp) == URX_CTR_INIT);
+ int32_t *pCounter = &fp->fExtra[URX_VAL(initOp)];
+ int32_t minCount = pat[opValue+2];
+ int32_t maxCount = pat[opValue+3];
+ // Increment the counter. Note: we're not worrying about counter
+ // overflow, since the data comes from UnicodeStrings, which
+ // stores its length in an int32_t.
+ (*pCounter)++;
+ U_ASSERT(*pCounter > 0);
+ if ((uint32_t)*pCounter >= (uint32_t)maxCount) {
+ U_ASSERT(*pCounter == maxCount || maxCount == -1);
+ break;
+ }
+ if (*pCounter >= minCount) {
+ fp = StateSave(fp, fp->fPatIdx, frameSize, status);
+ }
+ fp->fPatIdx = opValue + 4; // Loop back.
+ }
+ break;
+
+ case URX_CTR_INIT_NG:
+ {
+ U_ASSERT(opValue >= 0 && opValue < frameSize-2);
+ fp->fExtra[opValue] = 0; // Set the loop counter variable to zero
+
+ // Pick up the three extra operands that CTR_INIT has, and
+ // skip the pattern location counter past
+ int32_t instrOperandLoc = fp->fPatIdx;
+ fp->fPatIdx += 3;
+ int32_t loopLoc = URX_VAL(pat[instrOperandLoc]);
+ int32_t minCount = pat[instrOperandLoc+1];
+ int32_t maxCount = pat[instrOperandLoc+2];
+ U_ASSERT(minCount>=0);
+ U_ASSERT(maxCount>=minCount || maxCount==-1);
+ U_ASSERT(loopLoc>fp->fPatIdx);
+
+ if (minCount == 0) {
+ if (maxCount != 0) {
+ fp = StateSave(fp, fp->fPatIdx, frameSize, status);
+ }
+ fp->fPatIdx = loopLoc+1; // Continue with stuff after repeated block
+ }
+ }
+ break;
+
+ case URX_CTR_LOOP_NG:
+ {
+ U_ASSERT(opValue>0 && opValue < fp->fPatIdx-2);
+ int32_t initOp = pat[opValue];
+ U_ASSERT(URX_TYPE(initOp) == URX_CTR_INIT_NG);
+ int32_t *pCounter = &fp->fExtra[URX_VAL(initOp)];
+ int32_t minCount = pat[opValue+2];
+ int32_t maxCount = pat[opValue+3];
+ // Increment the counter. Note: we're not worrying about counter
+ // overflow, since the data comes from UnicodeStrings, which
+ // stores its length in an int32_t.
+ (*pCounter)++;
+ U_ASSERT(*pCounter > 0);
+
+ if ((uint32_t)*pCounter >= (uint32_t)maxCount) {
+ // The loop has matched the maximum permitted number of times.
+ // Break out of here with no action. Matching will
+ // continue with the following pattern.
+ U_ASSERT(*pCounter == maxCount || maxCount == -1);
+ break;
+ }
+
+ if (*pCounter < minCount) {
+ // We haven't met the minimum number of matches yet.
+ // Loop back for another one.
+ fp->fPatIdx = opValue + 4; // Loop back.
+ } else {
+ // We do have the minimum number of matches.
+ // Fall into the following pattern, but first do
+ // a state save to the top of the loop, so that a failure
+ // in the following pattern will try another iteration of the loop.
+ fp = StateSave(fp, opValue + 4, frameSize, status);
+ }
+ }
+ break;
+
+ // TODO: Possessive flavor of loop ops, or take them out if no longer needed.
+
+ case URX_STO_SP:
+ U_ASSERT(opValue >= 0 && opValue < fPattern->fDataSize);
+ fData[opValue] = fStack->size();
+ break;
+
+ case URX_LD_SP:
+ {
+ U_ASSERT(opValue >= 0 && opValue < fPattern->fDataSize);
+ int32_t newStackSize = fData[opValue];
+ U_ASSERT(newStackSize <= fStack->size());
+ int32_t *newFP = fStack->getBuffer() + newStackSize - frameSize;
+ if (newFP == (int32_t *)fp) {
+ break;
+ }
+ int32_t i;
+ for (i=0; i<frameSize; i++) {
+ newFP[i] = ((int32_t *)fp)[i];
+ }
+ fp = (REStackFrame *)newFP;
+ fStack->setSize(newStackSize);
+ }
+ break;
+
+ case URX_BACKREF:
+ case URX_BACKREF_I:
+ {
+ U_ASSERT(opValue < frameSize);
+ int32_t groupStartIdx = fp->fExtra[opValue];
+ int32_t groupEndIdx = fp->fExtra[opValue+1];
+ U_ASSERT(groupStartIdx <= groupEndIdx);
+ int32_t len = groupEndIdx-groupStartIdx;
+ if (groupStartIdx < 0) {
+ // This capture group has not participated in the match thus far,
+ fp = (REStackFrame *)fStack->popFrame(frameSize); // FAIL, no match.
+ }
+
+ if (len == 0) {
+ // The capture group match was of an empty string.
+ // Verified by testing: Perl matches succeed in this case, so
+ // we do too.
+ break;
+ }
+
+ UBool haveMatch = FALSE;
+ if (fp->fInputIdx + len <= inputLen) {
+ if (opType == URX_BACKREF) {
+ if (u_strncmp(inputBuf+groupStartIdx, inputBuf+fp->fInputIdx, len) == 0) {
+ haveMatch = TRUE;
+ }
+ } else {
+ if (u_strncasecmp(inputBuf+groupStartIdx, inputBuf+fp->fInputIdx,
+ len, U_FOLD_CASE_DEFAULT) == 0) {
+ haveMatch = TRUE;
+ }
+ }
+ }
+ if (haveMatch) {
+ fp->fInputIdx += len; // Match. Advance current input position.
+ } else {
+ fp = (REStackFrame *)fStack->popFrame(frameSize); // FAIL, no match.
+ }
+ }
+ break;
+
+ case URX_STO_INP_LOC:
+ {
+ U_ASSERT(opValue >= 0 && opValue < frameSize);
+ fp->fExtra[opValue] = fp->fInputIdx;
+ }
+ break;
+
+ case URX_JMPX:
+ {
+ int32_t instrOperandLoc = fp->fPatIdx;
+ fp->fPatIdx += 1;
+ int32_t dataLoc = URX_VAL(pat[instrOperandLoc]);
+ U_ASSERT(dataLoc >= 0 && dataLoc < frameSize);
+ int32_t savedInputIdx = fp->fExtra[dataLoc];
+ U_ASSERT(savedInputIdx <= fp->fInputIdx);
+ if (savedInputIdx < fp->fInputIdx) {
+ fp->fPatIdx = opValue; // JMP
+ } else {
+ fp = (REStackFrame *)fStack->popFrame(frameSize); // FAIL, no progress in loop.
+ }
+ }
+ break;
+
+ case URX_LA_START:
+ {
+ // Entering a lookahead block.
+ // Save Stack Ptr, Input Pos.
+ U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
+ fData[opValue] = fStack->size();
+ fData[opValue+1] = fp->fInputIdx;
+ }
+ break;
+
+ case URX_LA_END:
+ {
+ // Leaving a look-ahead block.
+ // restore Stack Ptr, Input Pos to positions they had on entry to block.
+ U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
+ int32_t stackSize = fStack->size();
+ int32_t newStackSize = fData[opValue];
+ U_ASSERT(stackSize >= newStackSize);
+ if (stackSize > newStackSize) {
+ int32_t *newFP = fStack->getBuffer() + newStackSize - frameSize;
+ int32_t i;
+ for (i=0; i<frameSize; i++) {
+ newFP[i] = ((int32_t *)fp)[i];
+ }
+ fp = (REStackFrame *)newFP;
+ fStack->setSize(newStackSize);
+ }
+ fp->fInputIdx = fData[opValue+1];
+ }
+ break;
+
+ case URX_ONECHAR_I:
+ if (fp->fInputIdx < inputLen) {
+ UChar32 c;
+ U16_NEXT(inputBuf, fp->fInputIdx, inputLen, c);
+ if (u_foldCase(c, U_FOLD_CASE_DEFAULT) == opValue) {
+ break;
+ }
+ }
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+
+ case URX_STRING_I:
+ {
+ // Test input against a literal string.
+ // Strings require two slots in the compiled pattern, one for the
+ // offset to the string text, and one for the length.
+ int32_t stringStartIdx, stringLen;
+ stringStartIdx = opValue;
+
+ op = pat[fp->fPatIdx];
+ fp->fPatIdx++;
+ opType = URX_TYPE(op);
+ opValue = URX_VAL(op);
+ U_ASSERT(opType == URX_STRING_LEN);
+ stringLen = opValue;
+
+ int32_t stringEndIndex = fp->fInputIdx + stringLen;
+ if (stringEndIndex <= inputLen) {
+ if (u_strncasecmp(inputBuf+fp->fInputIdx, litText+stringStartIdx,
+ stringLen, U_FOLD_CASE_DEFAULT) == 0) {
+ // Success. Advance the current input position.
+ fp->fInputIdx = stringEndIndex;
+ break;
+ }
+ }
+ // No match. Back up matching to a saved state
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ break;
+
+ case URX_LB_START:
+ {
+ // Entering a look-behind block.
+ // Save Stack Ptr, Input Pos.
+ U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
+ fData[opValue] = fStack->size();
+ fData[opValue+1] = fp->fInputIdx;
+ // Init the variable containing the start index for attempted matches.
+ fData[opValue+2] = -1;
+ // Save input string length, then reset to pin any matches to end at
+ // the current position.
+ fData[opValue+3] = inputLen;
+ inputLen = fp->fInputIdx;
+ }
+ break;
+
+
+ case URX_LB_CONT:
+ {
+ // Positive Look-Behind, at top of loop checking for matches of LB expression
+ // at all possible input starting positions.
+
+ // Fetch the min and max possible match lengths. They are the operands
+ // of this op in the pattern.
+ int32_t minML = pat[fp->fPatIdx++];
+ int32_t maxML = pat[fp->fPatIdx++];
+ U_ASSERT(minML <= maxML);
+ U_ASSERT(minML >= 0);
+
+ // Fetch (from data) the last input index where a match was attempted.
+ U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
+ int32_t *lbStartIdx = &fData[opValue+2];
+ if (*lbStartIdx < 0) {
+ // First time through loop.
+ *lbStartIdx = fp->fInputIdx - minML;
+ } else {
+ // 2nd through nth time through the loop.
+ // Back up start position for match by one.
+ if (*lbStartIdx == 0) {
+ (*lbStartIdx)--; // Because U16_BACK is unsafe starting at 0.
+ } else {
+ U16_BACK_1(inputBuf, 0, *lbStartIdx);
+ }
+ }
+
+ if (*lbStartIdx < 0 || *lbStartIdx < fp->fInputIdx - maxML) {
+ // We have tried all potential match starting points without
+ // getting a match. Backtrack out, and out of the
+ // Look Behind altogether.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ int32_t restoreInputLen = fData[opValue+3];
+ U_ASSERT(restoreInputLen >= inputLen);
+ U_ASSERT(restoreInputLen <= fInput->length());
+ inputLen = restoreInputLen;
+ break;
+ }
+
+ // Save state to this URX_LB_CONT op, so failure to match will repeat the loop.
+ // (successful match will fall off the end of the loop.)
+ fp = StateSave(fp, fp->fPatIdx-3, frameSize, status);
+ fp->fInputIdx = *lbStartIdx;
+ }
+ break;
+
+ case URX_LB_END:
+ // End of a look-behind block, after a successful match.
+ {
+ U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
+ if (fp->fInputIdx != inputLen) {
+ // The look-behind expression matched, but the match did not
+ // extend all the way to the point that we are looking behind from.
+ // FAIL out of here, which will take us back to the LB_CONT, which
+ // will retry the match starting at another position or fail
+ // the look-behind altogether, whichever is appropriate.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+
+ // Look-behind match is good. Restore the orignal input string length,
+ // which had been truncated to pin the end of the lookbehind match to the
+ // position being looked-behind.
+ int32_t originalInputLen = fData[opValue+3];
+ U_ASSERT(originalInputLen >= inputLen);
+ U_ASSERT(originalInputLen <= fInput->length());
+ inputLen = originalInputLen;
+ }
+ break;
+
+
+ case URX_LBN_CONT:
+ {
+ // Negative Look-Behind, at top of loop checking for matches of LB expression
+ // at all possible input starting positions.
+
+ // Fetch the extra parameters of this op.
+ int32_t minML = pat[fp->fPatIdx++];
+ int32_t maxML = pat[fp->fPatIdx++];
+ int32_t continueLoc = pat[fp->fPatIdx++];
+ continueLoc = URX_VAL(continueLoc);
+ U_ASSERT(minML <= maxML);
+ U_ASSERT(minML >= 0);
+ U_ASSERT(continueLoc > fp->fPatIdx);
+
+ // Fetch (from data) the last input index where a match was attempted.
+ U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
+ int32_t *lbStartIdx = &fData[opValue+2];
+ if (*lbStartIdx < 0) {
+ // First time through loop.
+ *lbStartIdx = fp->fInputIdx - minML;
+ } else {
+ // 2nd through nth time through the loop.
+ // Back up start position for match by one.
+ if (*lbStartIdx == 0) {
+ (*lbStartIdx)--; // Because U16_BACK is unsafe starting at 0.
+ } else {
+ U16_BACK_1(inputBuf, 0, *lbStartIdx);
+ }
+ }
+
+ if (*lbStartIdx < 0 || *lbStartIdx < fp->fInputIdx - maxML) {
+ // We have tried all potential match starting points without
+ // getting a match, which means that the negative lookbehind as
+ // a whole has succeeded. Jump forward to the continue location
+ int32_t restoreInputLen = fData[opValue+3];
+ U_ASSERT(restoreInputLen >= inputLen);
+ U_ASSERT(restoreInputLen <= fInput->length());
+ inputLen = restoreInputLen;
+ fp->fPatIdx = continueLoc;
+ break;
+ }
+
+ // Save state to this URX_LB_CONT op, so failure to match will repeat the loop.
+ // (successful match will cause a FAIL out of the loop altogether.)
+ fp = StateSave(fp, fp->fPatIdx-4, frameSize, status);
+ fp->fInputIdx = *lbStartIdx;
+ }
+ break;
+
+ case URX_LBN_END:
+ // End of a negative look-behind block, after a successful match.
+ {
+ U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
+ if (fp->fInputIdx != inputLen) {
+ // The look-behind expression matched, but the match did not
+ // extend all the way to the point that we are looking behind from.
+ // FAIL out of here, which will take us back to the LB_CONT, which
+ // will retry the match starting at another position or succeed
+ // the look-behind altogether, whichever is appropriate.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ break;
+ }
+
+ // Look-behind expression matched, which means look-behind test as
+ // a whole Fails
+
+ // Restore the orignal input string length, which had been truncated
+ // inorder to pin the end of the lookbehind match
+ // to the position being looked-behind.
+ int32_t originalInputLen = fData[opValue+3];
+ U_ASSERT(originalInputLen >= inputLen);
+ U_ASSERT(originalInputLen <= fInput->length());
+ inputLen = originalInputLen;
+
+ // Restore original stack position, discarding any state saved
+ // by the successful pattern match.
+ U_ASSERT(opValue>=0 && opValue+1<fPattern->fDataSize);
+ int32_t newStackSize = fData[opValue];
+ U_ASSERT(fStack->size() > newStackSize);
+ fStack->setSize(newStackSize);
+
+ // FAIL, which will take control back to someplace
+ // prior to entering the look-behind test.
+ fp = (REStackFrame *)fStack->popFrame(frameSize);
+ }
+ break;
+
+
+ case URX_LOOP_SR_I:
+ // Loop Initialization for the optimized implementation of
+ // [some character set]*
+ // This op scans through all matching input.
+ // The following LOOP_C op emulates stack unwinding if the following pattern fails.
+ {
+ U_ASSERT(opValue > 0 && opValue < sets->size());
+ Regex8BitSet *s8 = &fPattern->fSets8[opValue];
+ UnicodeSet *s = (UnicodeSet *)sets->elementAt(opValue);
+
+ // Loop through input, until either the input is exhausted or
+ // we reach a character that is not a member of the set.
+ int32_t ix = fp->fInputIdx;
+ for (;;) {
+ if (ix >= inputLen) {
+ break;
+ }
+ UChar32 c;
+ U16_NEXT(inputBuf, ix, inputLen, c);
+ if (c<256) {
+ if (s8->contains(c) == FALSE) {
+ U16_BACK_1(inputBuf, 0, ix);
+ break;
+ }
+ } else {
+ if (s->contains(c) == FALSE) {
+ U16_BACK_1(inputBuf, 0, ix);
+ break;
+ }
+ }
+ }
+
+ // If there were no matching characters, skip over the loop altogether.
+ // The loop doesn't run at all, a * op always succeeds.
+ if (ix == fp->fInputIdx) {
+ fp->fPatIdx++; // skip the URX_LOOP_C op.
+ break;
+ }
+
+ // Peek ahead in the compiled pattern, to the URX_LOOP_C that
+ // must follow. It's operand is the stack location
+ // that holds the starting input index for the match of this [set]*
+ int32_t loopcOp = pat[fp->fPatIdx];
+ U_ASSERT(URX_TYPE(loopcOp) == URX_LOOP_C);
+ int32_t stackLoc = URX_VAL(loopcOp);
+ U_ASSERT(stackLoc >= 0 && stackLoc < frameSize);
+ fp->fExtra[stackLoc] = fp->fInputIdx;
+ fp->fInputIdx = ix;
+
+ // Save State to the URX_LOOP_C op that follows this one,
+ // so that match failures in the following code will return to there.
+ // Then bump the pattern idx so the LOOP_C is skipped on the way out of here.
+ fp = StateSave(fp, fp->fPatIdx, frameSize, status);
+ fp->fPatIdx++;
+ }
+ break;
+
+
+ case URX_LOOP_DOT_I:
+ // Loop Initialization for the optimized implementation of .*
+ // This op scans through all remaining input.
+ // The following LOOP_C op emulates stack unwinding if the following pattern fails.
+ {
+ // Loop through input until the input is exhausted (we reach an end-of-line)
+ // In multi-line mode, we can just go straight to the end of the input.
+ int32_t ix;
+ if (opValue == 1) {
+ // Multi-line mode.
+ ix = inputLen;
+ } else {
+ // NOT multi-line mode. Line endings do not match '.'
+ // Scan forward until a line ending or end of input.
+ ix = fp->fInputIdx;
+ for (;;) {
+ if (ix >= inputLen) {
+ ix = inputLen;
+ break;
+ }
+ UChar32 c;
+ U16_NEXT(inputBuf, ix, inputLen, c); // c = inputBuf[ix++]
+ if (((c & 0x7f) <= 0x29) &&
+ ((c<=0x0d && c>=0x0a) || c==0x85 ||c==0x2028 || c==0x2029)) {
+ // char is a line ending. Put the input pos back to the
+ // line ending char, and exit the scanning loop.
+ U16_BACK_1(inputBuf, 0, ix);
+ break;
+ }
+ }
+ }
+
+ // If there were no matching characters, skip over the loop altogether.
+ // The loop doesn't run at all, a * op always succeeds.
+ if (ix == fp->fInputIdx) {
+ fp->fPatIdx++; // skip the URX_LOOP_C op.
+ break;
+ }
+
+ // Peek ahead in the compiled pattern, to the URX_LOOP_C that
+ // must follow. It's operand is the stack location
+ // that holds the starting input index for the match of this [set]*
+ int32_t loopcOp = pat[fp->fPatIdx];
+ U_ASSERT(URX_TYPE(loopcOp) == URX_LOOP_C);
+ int32_t stackLoc = URX_VAL(loopcOp);
+ U_ASSERT(stackLoc >= 0 && stackLoc < frameSize);
+ fp->fExtra[stackLoc] = fp->fInputIdx;
+ fp->fInputIdx = ix;
+
+ // Save State to the URX_LOOP_C op that follows this one,
+ // so that match failures in the following code will return to there.
+ // Then bump the pattern idx so the LOOP_C is skipped on the way out of here.
+ fp = StateSave(fp, fp->fPatIdx, frameSize, status);
+ fp->fPatIdx++;
+ }
+ break;
+
+
+ case URX_LOOP_C:
+ {
+ U_ASSERT(opValue>=0 && opValue<frameSize);
+ int32_t terminalIdx = fp->fExtra[opValue];
+ U_ASSERT(terminalIdx <= fp->fInputIdx);
+ if (terminalIdx == fp->fInputIdx) {
+ // We've backed up the input idx to the point that the loop started.
+ // The loop is done. Leave here without saving state.
+ // Subsequent failures won't come back here.
+ break;
+ }
+ // Set up for the next iteration of the loop, with input index
+ // backed up by one from the last time through,
+ // and a state save to this instruction in case the following code fails again.
+ // (We're going backwards because this loop emulates stack unwinding, not
+ // the initial scan forward.)
+ U_ASSERT(fp->fInputIdx > 0);
+ U16_BACK_1(inputBuf, 0, fp->fInputIdx);
+ if (inputBuf[fp->fInputIdx] == 0x0a &&
+ fp->fInputIdx > terminalIdx &&
+ inputBuf[fp->fInputIdx-1] == 0x0d) {
+ int32_t prevOp = pat[fp->fPatIdx-2];
+ if (URX_TYPE(prevOp) == URX_LOOP_DOT_I) {
+ // .*, stepping back over CRLF pair.
+ fp->fInputIdx--;
+ }
+ }
+
+
+ fp = StateSave(fp, fp->fPatIdx-1, frameSize, status);
+ }
+ break;
+
+
+
+ default:
+ // Trouble. The compiled pattern contains an entry with an
+ // unrecognized type tag.
+ U_ASSERT(FALSE);
+ }
+
+ if (U_FAILURE(status)) {
+ break;
+ }
+ }
+
+breakFromLoop:
+ fMatch = isMatch;
+ if (isMatch) {
+ fLastMatchEnd = fMatchEnd;
+ fMatchStart = startIdx;
+ fMatchEnd = fp->fInputIdx;
+ if (fTraceDebug) {
+ REGEX_RUN_DEBUG_PRINTF(("Match. start=%d end=%d\n\n", fMatchStart, fMatchEnd));
+ }
+ }
+ else
+ {
+ if (fTraceDebug) {
+ REGEX_RUN_DEBUG_PRINTF(("No match\n\n"));
+ }
+ }
+
+ fFrame = fp; // The active stack frame when the engine stopped.
+ // Contains the capture group results that we need to
+ // access later.
+
+ return;
+}
+
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegexMatcher)
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/remtrans.cpp b/Build/source/libs/icu/icu-xetex/i18n/remtrans.cpp
new file mode 100644
index 00000000000..d4e616e1dfc
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/remtrans.cpp
@@ -0,0 +1,68 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 04/02/2001 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "remtrans.h"
+#include "unicode/unifilt.h"
+
+static const UChar CURR_ID[] = {65, 110, 121, 45, 0x52, 0x65, 0x6D, 0x6F, 0x76, 0x65, 0x00}; /* "Any-Remove" */
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RemoveTransliterator)
+
+/**
+ * Factory method
+ */
+static Transliterator* RemoveTransliterator_create(const UnicodeString& /*ID*/,
+ Transliterator::Token /*context*/) {
+ /* We don't need the ID or context. We just remove data */
+ return new RemoveTransliterator();
+}
+
+/**
+ * System registration hook.
+ */
+void RemoveTransliterator::registerIDs() {
+
+ Transliterator::_registerFactory(::CURR_ID, RemoveTransliterator_create, integerToken(0));
+
+ Transliterator::_registerSpecialInverse(UNICODE_STRING_SIMPLE("Remove"),
+ UNICODE_STRING_SIMPLE("Null"), FALSE);
+}
+
+RemoveTransliterator::RemoveTransliterator() : Transliterator(::CURR_ID, 0) {}
+
+RemoveTransliterator::~RemoveTransliterator() {}
+
+Transliterator* RemoveTransliterator::clone(void) const {
+ Transliterator* result = new RemoveTransliterator();
+ if (getFilter() != 0) {
+ result->adoptFilter((UnicodeFilter*)(getFilter()->clone()));
+ }
+ return result;
+}
+
+void RemoveTransliterator::handleTransliterate(Replaceable& text, UTransPosition& index,
+ UBool /*isIncremental*/) const {
+ // Our caller (filteredTransliterate) has already narrowed us
+ // to an unfiltered run. Delete it.
+ UnicodeString empty;
+ text.handleReplaceBetween(index.start, index.limit, empty);
+ int32_t len = index.limit - index.start;
+ index.contextLimit -= len;
+ index.limit -= len;
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/remtrans.h b/Build/source/libs/icu/icu-xetex/i18n/remtrans.h
new file mode 100644
index 00000000000..25a5609dffe
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/remtrans.h
@@ -0,0 +1,78 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 04/02/2001 aliu Creation.
+**********************************************************************
+*/
+#ifndef REMTRANS_H
+#define REMTRANS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that removes text.
+ * @author Alan Liu
+ */
+class RemoveTransliterator : public Transliterator {
+
+public:
+
+ /**
+ * Constructs a transliterator.
+ */
+ RemoveTransliterator();
+
+ /**
+ * Destructor.
+ */
+ virtual ~RemoveTransliterator();
+
+ /**
+ * System registration hook.
+ */
+ static void registerIDs();
+
+ /**
+ * Transliterator API.
+ * @return A copy of the object.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param offset the start and limit of the text, the position
+ * of the cursor, and the start and limit of transliteration.
+ * @param incremental if true, assume more text may be coming after
+ * pos.contextLimit. Otherwise, assume the text is complete.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& offset,
+ UBool isIncremental) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/repattrn.cpp b/Build/source/libs/icu/icu-xetex/i18n/repattrn.cpp
new file mode 100644
index 00000000000..bcd11078c45
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/repattrn.cpp
@@ -0,0 +1,617 @@
+//
+// file: repattrn.cpp
+//
+/*
+***************************************************************************
+* Copyright (C) 2002-2006 International Business Machines Corporation *
+* and others. All rights reserved. *
+***************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/regex.h"
+#include "unicode/uclean.h"
+#include "uassert.h"
+#include "uvector.h"
+#include "uvectr32.h"
+#include "regexcmp.h"
+#include "regeximp.h"
+#include "regexst.h"
+
+U_NAMESPACE_BEGIN
+
+//--------------------------------------------------------------------------
+//
+// RegexPattern Default Constructor
+//
+//--------------------------------------------------------------------------
+RegexPattern::RegexPattern() {
+ UErrorCode status = U_ZERO_ERROR;
+ u_init(&status);
+ // Init all of this instances data.
+ init();
+
+ // Lazy init of all shared global sets.
+ RegexStaticSets::initGlobals(&fDeferredStatus);
+}
+
+
+//--------------------------------------------------------------------------
+//
+// Copy Constructor Note: This is a rather inefficient implementation,
+// but it probably doesn't matter.
+//
+//--------------------------------------------------------------------------
+RegexPattern::RegexPattern(const RegexPattern &other) : UObject(other) {
+ init();
+ *this = other;
+}
+
+
+
+//--------------------------------------------------------------------------
+//
+// Assignmenet Operator
+//
+//--------------------------------------------------------------------------
+RegexPattern &RegexPattern::operator = (const RegexPattern &other) {
+ if (this == &other) {
+ // Source and destination are the same. Don't do anything.
+ return *this;
+ }
+
+ // Clean out any previous contents of object being assigned to.
+ zap();
+
+ // Give target object a default initialization
+ init();
+
+ // Copy simple fields
+ fPattern = other.fPattern;
+ fFlags = other.fFlags;
+ fLiteralText = other.fLiteralText;
+ fDeferredStatus = other.fDeferredStatus;
+ fMinMatchLen = other.fMinMatchLen;
+ fFrameSize = other.fFrameSize;
+ fDataSize = other.fDataSize;
+ fMaxCaptureDigits = other.fMaxCaptureDigits;
+ fStaticSets = other.fStaticSets;
+ fStaticSets8 = other.fStaticSets8;
+
+ fStartType = other.fStartType;
+ fInitialStringIdx = other.fInitialStringIdx;
+ fInitialStringLen = other.fInitialStringLen;
+ *fInitialChars = *other.fInitialChars;
+ fInitialChar = other.fInitialChar;
+ *fInitialChars8 = *other.fInitialChars8;
+
+ // Copy the pattern. It's just values, nothing deep to copy.
+ fCompiledPat->assign(*other.fCompiledPat, fDeferredStatus);
+ fGroupMap->assign(*other.fGroupMap, fDeferredStatus);
+
+ // Copy the Unicode Sets.
+ // Could be made more efficient if the sets were reference counted and shared,
+ // but I doubt that pattern copying will be particularly common.
+ // Note: init() already added an empty element zero to fSets
+ int32_t i;
+ int32_t numSets = other.fSets->size();
+ fSets8 = new Regex8BitSet[numSets];
+ for (i=1; i<numSets; i++) {
+ if (U_FAILURE(fDeferredStatus)) {
+ return *this;
+ }
+ UnicodeSet *sourceSet = (UnicodeSet *)other.fSets->elementAt(i);
+ UnicodeSet *newSet = new UnicodeSet(*sourceSet);
+ if (newSet == NULL) {
+ fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ fSets->addElement(newSet, fDeferredStatus);
+ fSets8[i] = other.fSets8[i];
+ }
+
+ return *this;
+}
+
+
+//--------------------------------------------------------------------------
+//
+// init Shared initialization for use by constructors.
+// Bring an uninitialized RegexPattern up to a default state.
+//
+//--------------------------------------------------------------------------
+void RegexPattern::init() {
+ fPattern.remove();
+ fFlags = 0;
+ fCompiledPat = 0;
+ fLiteralText.remove();
+ fSets = NULL;
+ fSets8 = NULL;
+ fDeferredStatus = U_ZERO_ERROR;
+ fMinMatchLen = 0;
+ fFrameSize = 0;
+ fDataSize = 0;
+ fGroupMap = NULL;
+ fMaxCaptureDigits = 1;
+ fStaticSets = NULL;
+ fStaticSets8 = NULL;
+ fStartType = START_NO_INFO;
+ fInitialStringIdx = 0;
+ fInitialStringLen = 0;
+ fInitialChars = NULL;
+ fInitialChar = 0;
+ fInitialChars8 = NULL;
+
+ fCompiledPat = new UVector32(fDeferredStatus);
+ fGroupMap = new UVector32(fDeferredStatus);
+ fSets = new UVector(fDeferredStatus);
+ fInitialChars = new UnicodeSet;
+ fInitialChars8 = new Regex8BitSet;
+ if (U_FAILURE(fDeferredStatus)) {
+ return;
+ }
+ if (fCompiledPat == NULL || fGroupMap == NULL || fSets == NULL ||
+ fInitialChars == NULL || fInitialChars8 == NULL) {
+ fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ // Slot zero of the vector of sets is reserved. Fill it here.
+ fSets->addElement((int32_t)0, fDeferredStatus);
+}
+
+
+//--------------------------------------------------------------------------
+//
+// zap Delete everything owned by this RegexPattern.
+//
+//--------------------------------------------------------------------------
+void RegexPattern::zap() {
+ delete fCompiledPat;
+ fCompiledPat = NULL;
+ int i;
+ for (i=1; i<fSets->size(); i++) {
+ UnicodeSet *s;
+ s = (UnicodeSet *)fSets->elementAt(i);
+ if (s != NULL) {
+ delete s;
+ }
+ }
+ delete fSets;
+ fSets = NULL;
+ delete[] fSets8;
+ fSets8 = NULL;
+ delete fGroupMap;
+ fGroupMap = NULL;
+ delete fInitialChars;
+ fInitialChars = NULL;
+ delete fInitialChars8;
+ fInitialChars8 = NULL;
+}
+
+
+//--------------------------------------------------------------------------
+//
+// Destructor
+//
+//--------------------------------------------------------------------------
+RegexPattern::~RegexPattern() {
+ zap();
+}
+
+
+//--------------------------------------------------------------------------
+//
+// Clone
+//
+//--------------------------------------------------------------------------
+RegexPattern *RegexPattern::clone() const {
+ RegexPattern *copy = new RegexPattern(*this);
+ return copy;
+}
+
+
+//--------------------------------------------------------------------------
+//
+// operator == (comparison) Consider to patterns to be == if the
+// pattern strings and the flags are the same.
+//
+//--------------------------------------------------------------------------
+UBool RegexPattern::operator ==(const RegexPattern &other) const {
+ UBool r = this->fFlags == other.fFlags &&
+ this->fPattern == other.fPattern &&
+ this->fDeferredStatus == other.fDeferredStatus;
+ return r;
+}
+
+//---------------------------------------------------------------------
+//
+// compile
+//
+//---------------------------------------------------------------------
+RegexPattern * U_EXPORT2
+RegexPattern::compile(const UnicodeString &regex,
+ uint32_t flags,
+ UParseError &pe,
+ UErrorCode &status)
+{
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ const uint32_t allFlags = UREGEX_CANON_EQ | UREGEX_CASE_INSENSITIVE | UREGEX_COMMENTS |
+ UREGEX_DOTALL | UREGEX_MULTILINE | UREGEX_UWORD;
+
+ if ((flags & ~allFlags) != 0) {
+ status = U_REGEX_INVALID_FLAG;
+ return NULL;
+ }
+
+ if ((flags & UREGEX_CANON_EQ) != 0) {
+ status = U_REGEX_UNIMPLEMENTED;
+ return NULL;
+ }
+
+ RegexPattern *This = new RegexPattern;
+ if (This == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if (U_FAILURE(This->fDeferredStatus)) {
+ status = This->fDeferredStatus;
+ return NULL;
+ }
+ This->fFlags = flags;
+
+ RegexCompile compiler(This, status);
+ compiler.compile(regex, pe, status);
+
+ return This;
+}
+
+//
+// compile with default flags.
+//
+RegexPattern * U_EXPORT2
+RegexPattern::compile(const UnicodeString &regex,
+ UParseError &pe,
+ UErrorCode &err)
+{
+ return compile(regex, 0, pe, err);
+}
+
+
+
+//
+// compile with no UParseErr parameter.
+//
+RegexPattern * U_EXPORT2
+RegexPattern::compile( const UnicodeString &regex,
+ uint32_t flags,
+ UErrorCode &err)
+{
+ UParseError pe;
+ return compile(regex, flags, pe, err);
+}
+
+
+
+//---------------------------------------------------------------------
+//
+// flags
+//
+//---------------------------------------------------------------------
+uint32_t RegexPattern::flags() const {
+ return fFlags;
+}
+
+
+//---------------------------------------------------------------------
+//
+// matcher(UnicodeString, err)
+//
+//---------------------------------------------------------------------
+RegexMatcher *RegexPattern::matcher(const UnicodeString &input,
+ UErrorCode &status) const {
+ RegexMatcher *retMatcher = matcher(status);
+ if (retMatcher != NULL) {
+ retMatcher->reset(input);
+ }
+ return retMatcher;
+}
+
+#if 0
+RegexMatcher *RegexPattern::matcher(const UChar * /*input*/,
+ UErrorCode &status) const
+{
+ /* This should never get called. The API with UnicodeString should be called instead. */
+ if (U_SUCCESS(status)) {
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return NULL;
+}
+#endif
+
+//---------------------------------------------------------------------
+//
+// matcher(status)
+//
+//---------------------------------------------------------------------
+RegexMatcher *RegexPattern::matcher(UErrorCode &status) const {
+ RegexMatcher *retMatcher = NULL;
+
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (U_FAILURE(fDeferredStatus)) {
+ status = fDeferredStatus;
+ return NULL;
+ }
+
+ retMatcher = new RegexMatcher(this);
+ if (retMatcher == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ return retMatcher;
+}
+
+
+
+//---------------------------------------------------------------------
+//
+// matches Convenience function to test for a match, starting
+// with a pattern string and a data string.
+//
+//---------------------------------------------------------------------
+UBool U_EXPORT2 RegexPattern::matches(const UnicodeString &regex,
+ const UnicodeString &input,
+ UParseError &pe,
+ UErrorCode &status) {
+
+ if (U_FAILURE(status)) {return FALSE;}
+
+ UBool retVal;
+ RegexPattern *pat = NULL;
+ RegexMatcher *matcher = NULL;
+
+ pat = RegexPattern::compile(regex, 0, pe, status);
+ matcher = pat->matcher(input, status);
+ retVal = matcher->matches(status);
+
+ delete matcher;
+ delete pat;
+ return retVal;
+}
+
+
+
+
+//---------------------------------------------------------------------
+//
+// pattern
+//
+//---------------------------------------------------------------------
+UnicodeString RegexPattern::pattern() const {
+ return fPattern;
+}
+
+
+
+
+//---------------------------------------------------------------------
+//
+// split
+//
+//---------------------------------------------------------------------
+int32_t RegexPattern::split(const UnicodeString &input,
+ UnicodeString dest[],
+ int32_t destCapacity,
+ UErrorCode &status) const
+{
+ if (U_FAILURE(status)) {
+ return 0;
+ };
+
+ RegexMatcher m(this);
+ int32_t r = m.split(input, dest, destCapacity, status);
+ return r;
+}
+
+
+
+//---------------------------------------------------------------------
+//
+// dump Output the compiled form of the pattern.
+// Debugging function only.
+//
+//---------------------------------------------------------------------
+#if defined(REGEX_DEBUG)
+void RegexPattern::dumpOp(int32_t index) const {
+ static const char * const opNames[] = {URX_OPCODE_NAMES};
+ int32_t op = fCompiledPat->elementAti(index);
+ int32_t val = URX_VAL(op);
+ int32_t type = URX_TYPE(op);
+ int32_t pinnedType = type;
+ if (pinnedType >= sizeof(opNames)/sizeof(char *)) {
+ pinnedType = 0;
+ }
+
+ REGEX_DUMP_DEBUG_PRINTF(("%4d %08x %-15s ", index, op, opNames[pinnedType]));
+ switch (type) {
+ case URX_NOP:
+ case URX_DOTANY:
+ case URX_DOTANY_ALL:
+ case URX_DOTANY_PL:
+ case URX_DOTANY_ALL_PL:
+ case URX_FAIL:
+ case URX_CARET:
+ case URX_DOLLAR:
+ case URX_BACKSLASH_G:
+ case URX_BACKSLASH_X:
+ case URX_END:
+ case URX_DOLLAR_M:
+ case URX_CARET_M:
+ // Types with no operand field of interest.
+ break;
+
+ case URX_RESERVED_OP:
+ case URX_START_CAPTURE:
+ case URX_END_CAPTURE:
+ case URX_STATE_SAVE:
+ case URX_JMP:
+ case URX_JMP_SAV:
+ case URX_JMP_SAV_X:
+ case URX_BACKSLASH_B:
+ case URX_BACKSLASH_BU:
+ case URX_BACKSLASH_D:
+ case URX_BACKSLASH_Z:
+ case URX_STRING_LEN:
+ case URX_CTR_INIT:
+ case URX_CTR_INIT_NG:
+ case URX_CTR_LOOP:
+ case URX_CTR_LOOP_NG:
+ case URX_RELOC_OPRND:
+ case URX_STO_SP:
+ case URX_LD_SP:
+ case URX_BACKREF:
+ case URX_STO_INP_LOC:
+ case URX_JMPX:
+ case URX_LA_START:
+ case URX_LA_END:
+ case URX_BACKREF_I:
+ case URX_LB_START:
+ case URX_LB_CONT:
+ case URX_LB_END:
+ case URX_LBN_CONT:
+ case URX_LBN_END:
+ case URX_LOOP_C:
+ case URX_LOOP_DOT_I:
+ // types with an integer operand field.
+ REGEX_DUMP_DEBUG_PRINTF(("%d", val));
+ break;
+
+ case URX_ONECHAR:
+ case URX_ONECHAR_I:
+ REGEX_DUMP_DEBUG_PRINTF(("%c", val<256?val:'?'));
+ break;
+
+ case URX_STRING:
+ case URX_STRING_I:
+ {
+ int32_t lengthOp = fCompiledPat->elementAti(index+1);
+ U_ASSERT(URX_TYPE(lengthOp) == URX_STRING_LEN);
+ int32_t length = URX_VAL(lengthOp);
+ int32_t i;
+ for (i=val; i<val+length; i++) {
+ UChar c = fLiteralText[i];
+ if (c < 32 || c >= 256) {c = '.';}
+ REGEX_DUMP_DEBUG_PRINTF(("%c", c));
+ }
+ }
+ break;
+
+ case URX_SETREF:
+ case URX_LOOP_SR_I:
+ {
+ UnicodeString s;
+ UnicodeSet *set = (UnicodeSet *)fSets->elementAt(val);
+ set->toPattern(s, TRUE);
+ for (int32_t i=0; i<s.length(); i++) {
+ REGEX_DUMP_DEBUG_PRINTF(("%c", s.charAt(i)));
+ }
+ }
+ break;
+
+ case URX_STATIC_SETREF:
+ case URX_STAT_SETREF_N:
+ {
+ UnicodeString s;
+ if (val & URX_NEG_SET) {
+ REGEX_DUMP_DEBUG_PRINTF(("NOT "));
+ val &= ~URX_NEG_SET;
+ }
+ UnicodeSet *set = fStaticSets[val];
+ set->toPattern(s, TRUE);
+ for (int32_t i=0; i<s.length(); i++) {
+ REGEX_DUMP_DEBUG_PRINTF(("%c", s.charAt(i)));
+ }
+ }
+ break;
+
+
+ default:
+ REGEX_DUMP_DEBUG_PRINTF(("??????"));
+ break;
+ }
+ REGEX_DUMP_DEBUG_PRINTF(("\n"));
+}
+#endif
+
+
+#if defined(REGEX_DEBUG)
+U_CAPI void U_EXPORT2
+RegexPatternDump(const RegexPattern *This) {
+ int index;
+ int i;
+
+ REGEX_DUMP_DEBUG_PRINTF(("Original Pattern: "));
+ for (i=0; i<This->fPattern.length(); i++) {
+ REGEX_DUMP_DEBUG_PRINTF(("%c", This->fPattern.charAt(i)));
+ }
+ REGEX_DUMP_DEBUG_PRINTF(("\n"));
+ REGEX_DUMP_DEBUG_PRINTF((" Min Match Length: %d\n", This->fMinMatchLen));
+ REGEX_DUMP_DEBUG_PRINTF((" Match Start Type: %s\n", START_OF_MATCH_STR(This->fStartType)));
+ if (This->fStartType == START_STRING) {
+ REGEX_DUMP_DEBUG_PRINTF((" Initial match sting: \""));
+ for (i=This->fInitialStringIdx; i<This->fInitialStringIdx+This->fInitialStringLen; i++) {
+ REGEX_DUMP_DEBUG_PRINTF(("%c", This->fLiteralText[i])); // TODO: non-printables, surrogates.
+ }
+
+ } else if (This->fStartType == START_SET) {
+ int32_t numSetChars = This->fInitialChars->size();
+ if (numSetChars > 20) {
+ numSetChars = 20;
+ }
+ REGEX_DUMP_DEBUG_PRINTF((" Match First Chars : "));
+ for (i=0; i<numSetChars; i++) {
+ UChar32 c = This->fInitialChars->charAt(i);
+ if (0x20<c && c <0x7e) {
+ REGEX_DUMP_DEBUG_PRINTF(("%c ", c));
+ } else {
+ REGEX_DUMP_DEBUG_PRINTF(("%#x ", c));
+ }
+ }
+ if (numSetChars < This->fInitialChars->size()) {
+ REGEX_DUMP_DEBUG_PRINTF((" ..."));
+ }
+ REGEX_DUMP_DEBUG_PRINTF(("\n"));
+
+ } else if (This->fStartType == START_CHAR) {
+ REGEX_DUMP_DEBUG_PRINTF((" First char of Match : "));
+ if (0x20 < This->fInitialChar && This->fInitialChar<0x7e) {
+ REGEX_DUMP_DEBUG_PRINTF(("%c\n", This->fInitialChar));
+ } else {
+ REGEX_DUMP_DEBUG_PRINTF(("%#x\n", This->fInitialChar));
+ }
+ }
+
+ REGEX_DUMP_DEBUG_PRINTF(("\nIndex Binary Type Operand\n" \
+ "-------------------------------------------\n"));
+ for (index = 0; index<This->fCompiledPat->size(); index++) {
+ This->dumpOp(index);
+ }
+ REGEX_DUMP_DEBUG_PRINTF(("\n\n"));
+};
+#endif
+
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RegexPattern)
+
+U_NAMESPACE_END
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
diff --git a/Build/source/libs/icu/icu-xetex/i18n/search.cpp b/Build/source/libs/icu/icu-xetex/i18n/search.cpp
new file mode 100644
index 00000000000..91ece06b730
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/search.cpp
@@ -0,0 +1,402 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2005 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 03/22/2000 helena Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/brkiter.h"
+#include "unicode/schriter.h"
+#include "unicode/search.h"
+#include "usrchimp.h"
+#include "cmemory.h"
+
+// public constructors and destructors -----------------------------------
+U_NAMESPACE_BEGIN
+
+SearchIterator::SearchIterator(const SearchIterator &other)
+ : UObject(other)
+{
+ m_breakiterator_ = other.m_breakiterator_;
+ m_text_ = other.m_text_;
+ m_search_ = (USearch *)uprv_malloc(sizeof(USearch));
+ m_search_->breakIter = other.m_search_->breakIter;
+ m_search_->isCanonicalMatch = other.m_search_->isCanonicalMatch;
+ m_search_->isOverlap = other.m_search_->isOverlap;
+ m_search_->matchedIndex = other.m_search_->matchedIndex;
+ m_search_->matchedLength = other.m_search_->matchedLength;
+ m_search_->text = other.m_search_->text;
+ m_search_->textLength = other.m_search_->textLength;
+}
+
+SearchIterator::~SearchIterator()
+{
+ if (m_search_ != NULL) {
+ uprv_free(m_search_);
+ }
+}
+
+// public get and set methods ----------------------------------------
+
+void SearchIterator::setAttribute(USearchAttribute attribute,
+ USearchAttributeValue value,
+ UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ switch (attribute)
+ {
+ case USEARCH_OVERLAP :
+ m_search_->isOverlap = (value == USEARCH_ON ? TRUE : FALSE);
+ break;
+ case USEARCH_CANONICAL_MATCH :
+ m_search_->isCanonicalMatch = (value == USEARCH_ON ? TRUE : FALSE);
+ break;
+ default:
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ }
+ if (value == USEARCH_ATTRIBUTE_VALUE_COUNT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+USearchAttributeValue SearchIterator::getAttribute(
+ USearchAttribute attribute) const
+{
+ switch (attribute) {
+ case USEARCH_OVERLAP :
+ return (m_search_->isOverlap == TRUE ? USEARCH_ON : USEARCH_OFF);
+ case USEARCH_CANONICAL_MATCH :
+ return (m_search_->isCanonicalMatch == TRUE ? USEARCH_ON :
+ USEARCH_OFF);
+ default :
+ return USEARCH_DEFAULT;
+ }
+}
+
+int32_t SearchIterator::getMatchedStart() const
+{
+ return m_search_->matchedIndex;
+}
+
+int32_t SearchIterator::getMatchedLength() const
+{
+ return m_search_->matchedLength;
+}
+
+void SearchIterator::getMatchedText(UnicodeString &result) const
+{
+ int32_t matchedindex = m_search_->matchedIndex;
+ int32_t matchedlength = m_search_->matchedLength;
+ if (matchedindex != USEARCH_DONE && matchedlength != 0) {
+ result.setTo(m_search_->text + matchedindex, matchedlength);
+ }
+ else {
+ result.remove();
+ }
+}
+
+void SearchIterator::setBreakIterator(BreakIterator *breakiter,
+ UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ m_search_->breakIter = NULL;
+ // the c++ breakiterator may not make use of ubreakiterator.
+ // so we'll have to keep track of it ourselves.
+ m_breakiterator_ = breakiter;
+ }
+}
+
+const BreakIterator * SearchIterator::getBreakIterator(void) const
+{
+ return m_breakiterator_;
+}
+
+void SearchIterator::setText(const UnicodeString &text, UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ if (text.length() == 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ else {
+ m_text_ = text;
+ m_search_->text = m_text_.getBuffer();
+ m_search_->textLength = m_text_.length();
+ }
+ }
+}
+
+void SearchIterator::setText(CharacterIterator &text, UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ text.getText(m_text_);
+ setText(m_text_, status);
+ }
+}
+
+const UnicodeString & SearchIterator::getText(void) const
+{
+ return m_text_;
+}
+
+// operator overloading ----------------------------------------------
+
+UBool SearchIterator::operator==(const SearchIterator &that) const
+{
+ if (this == &that) {
+ return TRUE;
+ }
+ return (m_breakiterator_ == that.m_breakiterator_ &&
+ m_search_->isCanonicalMatch == that.m_search_->isCanonicalMatch &&
+ m_search_->isOverlap == that.m_search_->isOverlap &&
+ m_search_->matchedIndex == that.m_search_->matchedIndex &&
+ m_search_->matchedLength == that.m_search_->matchedLength &&
+ m_search_->textLength == that.m_search_->textLength &&
+ getOffset() == that.getOffset() &&
+ (uprv_memcmp(m_search_->text, that.m_search_->text,
+ m_search_->textLength * sizeof(UChar)) == 0));
+}
+
+// public methods ----------------------------------------------------
+
+int32_t SearchIterator::first(UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return USEARCH_DONE;
+ }
+ setOffset(0, status);
+ return handleNext(0, status);
+}
+
+int32_t SearchIterator::following(int32_t position,
+ UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return USEARCH_DONE;
+ }
+ setOffset(position, status);
+ return handleNext(position, status);
+}
+
+int32_t SearchIterator::last(UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return USEARCH_DONE;
+ }
+ setOffset(m_search_->textLength, status);
+ return handlePrev(m_search_->textLength, status);
+}
+
+int32_t SearchIterator::preceding(int32_t position,
+ UErrorCode &status)
+{
+ if (U_FAILURE(status)) {
+ return USEARCH_DONE;
+ }
+ setOffset(position, status);
+ return handlePrev(position, status);
+}
+
+int32_t SearchIterator::next(UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ int32_t offset = getOffset();
+ int32_t matchindex = m_search_->matchedIndex;
+ int32_t matchlength = m_search_->matchedLength;
+ m_search_->reset = FALSE;
+ if (m_search_->isForwardSearching == TRUE) {
+ int32_t textlength = m_search_->textLength;
+ if (offset == textlength || matchindex == textlength ||
+ (matchindex != USEARCH_DONE &&
+ matchindex + matchlength >= textlength)) {
+ // not enough characters to match
+ setMatchNotFound();
+ return USEARCH_DONE;
+ }
+ }
+ else {
+ // switching direction.
+ // if matchedIndex == USEARCH_DONE, it means that either a
+ // setOffset has been called or that previous ran off the text
+ // string. the iterator would have been set to offset 0 if a
+ // match is not found.
+ m_search_->isForwardSearching = TRUE;
+ if (m_search_->matchedIndex != USEARCH_DONE) {
+ // there's no need to set the collation element iterator
+ // the next call to next will set the offset.
+ return matchindex;
+ }
+ }
+
+ if (matchlength > 0) {
+ // if matchlength is 0 we are at the start of the iteration
+ if (m_search_->isOverlap) {
+ offset ++;
+ }
+ else {
+ offset += matchlength;
+ }
+ }
+ return handleNext(offset, status);
+ }
+ return USEARCH_DONE;
+}
+
+int32_t SearchIterator::previous(UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ int32_t offset;
+ if (m_search_->reset) {
+ offset = m_search_->textLength;
+ m_search_->isForwardSearching = FALSE;
+ m_search_->reset = FALSE;
+ setOffset(offset, status);
+ }
+ else {
+ offset = getOffset();
+ }
+
+ int32_t matchindex = m_search_->matchedIndex;
+ if (m_search_->isForwardSearching == TRUE) {
+ // switching direction.
+ // if matchedIndex == USEARCH_DONE, it means that either a
+ // setOffset has been called or that next ran off the text
+ // string. the iterator would have been set to offset textLength if
+ // a match is not found.
+ m_search_->isForwardSearching = FALSE;
+ if (matchindex != USEARCH_DONE) {
+ return matchindex;
+ }
+ }
+ else {
+ if (offset == 0 || matchindex == 0) {
+ // not enough characters to match
+ setMatchNotFound();
+ return USEARCH_DONE;
+ }
+ }
+
+ if (matchindex != USEARCH_DONE) {
+ return handlePrev(matchindex, status);
+ }
+ return handlePrev(offset, status);
+ }
+ return USEARCH_DONE;
+}
+
+void SearchIterator::reset()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ setMatchNotFound();
+ setOffset(0, status);
+ m_search_->isOverlap = FALSE;
+ m_search_->isCanonicalMatch = FALSE;
+ m_search_->isForwardSearching = TRUE;
+ m_search_->reset = TRUE;
+}
+
+// protected constructors and destructors -----------------------------
+
+SearchIterator::SearchIterator()
+{
+ m_search_ = (USearch *)uprv_malloc(sizeof(USearch));
+ m_search_->breakIter = NULL;
+ m_search_->isOverlap = FALSE;
+ m_search_->isCanonicalMatch = FALSE;
+ m_search_->isForwardSearching = TRUE;
+ m_search_->reset = TRUE;
+ m_search_->matchedIndex = USEARCH_DONE;
+ m_search_->matchedLength = 0;
+ m_search_->text = NULL;
+ m_search_->textLength = 0;
+ m_breakiterator_ = NULL;
+}
+
+SearchIterator::SearchIterator(const UnicodeString &text,
+ BreakIterator *breakiter) :
+ m_breakiterator_(breakiter),
+ m_text_(text)
+{
+ m_search_ = (USearch *)uprv_malloc(sizeof(USearch));
+ m_search_->breakIter = NULL;
+ m_search_->isOverlap = FALSE;
+ m_search_->isCanonicalMatch = FALSE;
+ m_search_->isForwardSearching = TRUE;
+ m_search_->reset = TRUE;
+ m_search_->matchedIndex = USEARCH_DONE;
+ m_search_->matchedLength = 0;
+ m_search_->text = m_text_.getBuffer();
+ m_search_->textLength = text.length();
+}
+
+SearchIterator::SearchIterator(CharacterIterator &text,
+ BreakIterator *breakiter) :
+ m_breakiterator_(breakiter)
+{
+ m_search_ = (USearch *)uprv_malloc(sizeof(USearch));
+ m_search_->breakIter = NULL;
+ m_search_->isOverlap = FALSE;
+ m_search_->isCanonicalMatch = FALSE;
+ m_search_->isForwardSearching = TRUE;
+ m_search_->reset = TRUE;
+ m_search_->matchedIndex = USEARCH_DONE;
+ m_search_->matchedLength = 0;
+ text.getText(m_text_);
+ m_search_->text = m_text_.getBuffer();
+ m_search_->textLength = m_text_.length();
+ m_breakiterator_ = breakiter;
+}
+
+// protected methods ------------------------------------------------------
+
+SearchIterator & SearchIterator::operator=(const SearchIterator &that)
+{
+ if (this != &that) {
+ m_breakiterator_ = that.m_breakiterator_;
+ m_text_ = that.m_text_;
+ m_search_->breakIter = that.m_search_->breakIter;
+ m_search_->isCanonicalMatch = that.m_search_->isCanonicalMatch;
+ m_search_->isOverlap = that.m_search_->isOverlap;
+ m_search_->matchedIndex = that.m_search_->matchedIndex;
+ m_search_->matchedLength = that.m_search_->matchedLength;
+ m_search_->text = that.m_search_->text;
+ m_search_->textLength = that.m_search_->textLength;
+ }
+ return *this;
+}
+
+void SearchIterator::setMatchLength(int32_t length)
+{
+ m_search_->matchedLength = length;
+}
+
+void SearchIterator::setMatchStart(int32_t position)
+{
+ m_search_->matchedIndex = position;
+}
+
+void SearchIterator::setMatchNotFound()
+{
+ setMatchStart(USEARCH_DONE);
+ setMatchLength(0);
+ UErrorCode status = U_ZERO_ERROR;
+ // by default no errors should be returned here since offsets are within
+ // range.
+ if (m_search_->isForwardSearching) {
+ setOffset(m_search_->textLength, status);
+ }
+ else {
+ setOffset(0, status);
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/simpletz.cpp b/Build/source/libs/icu/icu-xetex/i18n/simpletz.cpp
new file mode 100644
index 00000000000..c9cdade3af6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/simpletz.cpp
@@ -0,0 +1,1180 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ *
+ * File SIMPLETZ.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 12/05/96 clhuang Creation.
+ * 04/21/97 aliu Fixed miscellaneous bugs found by inspection and
+ * testing.
+ * 07/29/97 aliu Ported source bodies back from Java version with
+ * numerous feature enhancements and bug fixes.
+ * 08/10/98 stephen JDK 1.2 sync.
+ * 09/17/98 stephen Fixed getOffset() for last hour of year and DST
+ * 12/02/99 aliu Added TimeMode and constructor and setStart/EndRule
+ * methods that take TimeMode. Whitespace cleanup.
+ ********************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/simpletz.h"
+#include "unicode/gregocal.h"
+#include "unicode/smpdtfmt.h"
+
+#include "gregoimp.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleTimeZone)
+
+// Use only for decodeStartRule() and decodeEndRule() where the year is not
+// available. Set February to 29 days to accomodate rules with that date
+// and day-of-week-on-or-before-that-date mode (DOW_LE_DOM_MODE).
+// The compareToRule() method adjusts to February 28 in non-leap years.
+//
+// For actual getOffset() calculations, use Grego::monthLength() and
+// Grego::previousMonthLength() which take leap years into account.
+// We handle leap years assuming always
+// Gregorian, since we know they didn't have daylight time when
+// Gregorian calendar started.
+const int8_t SimpleTimeZone::STATICMONTHLENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};
+
+static const UChar DST_STR[] = {0x0028,0x0044,0x0053,0x0054,0x0029,0}; // "(DST)"
+static const UChar STD_STR[] = {0x0028,0x0053,0x0054,0x0044,0x0029,0}; // "(STD)"
+
+
+// *****************************************************************************
+// class SimpleTimeZone
+// *****************************************************************************
+
+
+SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID)
+: BasicTimeZone(ID),
+ startMonth(0),
+ startDay(0),
+ startDayOfWeek(0),
+ startTime(0),
+ startTimeMode(WALL_TIME),
+ endTimeMode(WALL_TIME),
+ endMonth(0),
+ endDay(0),
+ endDayOfWeek(0),
+ endTime(0),
+ startYear(0),
+ rawOffset(rawOffsetGMT),
+ useDaylight(FALSE),
+ startMode(DOM_MODE),
+ endMode(DOM_MODE),
+ dstSavings(U_MILLIS_PER_HOUR)
+{
+ clearTransitionRules();
+}
+
+// -------------------------------------
+
+SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
+ int8_t savingsStartMonth, int8_t savingsStartDay,
+ int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
+ int8_t savingsEndMonth, int8_t savingsEndDay,
+ int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
+ UErrorCode& status)
+: BasicTimeZone(ID)
+{
+ clearTransitionRules();
+ construct(rawOffsetGMT,
+ savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
+ savingsStartTime, WALL_TIME,
+ savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
+ savingsEndTime, WALL_TIME,
+ U_MILLIS_PER_HOUR, status);
+}
+
+// -------------------------------------
+
+SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
+ int8_t savingsStartMonth, int8_t savingsStartDay,
+ int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
+ int8_t savingsEndMonth, int8_t savingsEndDay,
+ int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
+ int32_t savingsDST, UErrorCode& status)
+: BasicTimeZone(ID)
+{
+ clearTransitionRules();
+ construct(rawOffsetGMT,
+ savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
+ savingsStartTime, WALL_TIME,
+ savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
+ savingsEndTime, WALL_TIME,
+ savingsDST, status);
+}
+
+// -------------------------------------
+
+SimpleTimeZone::SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
+ int8_t savingsStartMonth, int8_t savingsStartDay,
+ int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
+ TimeMode savingsStartTimeMode,
+ int8_t savingsEndMonth, int8_t savingsEndDay,
+ int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
+ TimeMode savingsEndTimeMode,
+ int32_t savingsDST, UErrorCode& status)
+: BasicTimeZone(ID)
+{
+ clearTransitionRules();
+ construct(rawOffsetGMT,
+ savingsStartMonth, savingsStartDay, savingsStartDayOfWeek,
+ savingsStartTime, savingsStartTimeMode,
+ savingsEndMonth, savingsEndDay, savingsEndDayOfWeek,
+ savingsEndTime, savingsEndTimeMode,
+ savingsDST, status);
+}
+
+/**
+ * Internal construction method.
+ */
+void SimpleTimeZone::construct(int32_t rawOffsetGMT,
+ int8_t savingsStartMonth,
+ int8_t savingsStartDay,
+ int8_t savingsStartDayOfWeek,
+ int32_t savingsStartTime,
+ TimeMode savingsStartTimeMode,
+ int8_t savingsEndMonth,
+ int8_t savingsEndDay,
+ int8_t savingsEndDayOfWeek,
+ int32_t savingsEndTime,
+ TimeMode savingsEndTimeMode,
+ int32_t savingsDST,
+ UErrorCode& status)
+{
+ this->rawOffset = rawOffsetGMT;
+ this->startMonth = savingsStartMonth;
+ this->startDay = savingsStartDay;
+ this->startDayOfWeek = savingsStartDayOfWeek;
+ this->startTime = savingsStartTime;
+ this->startTimeMode = savingsStartTimeMode;
+ this->endMonth = savingsEndMonth;
+ this->endDay = savingsEndDay;
+ this->endDayOfWeek = savingsEndDayOfWeek;
+ this->endTime = savingsEndTime;
+ this->endTimeMode = savingsEndTimeMode;
+ this->dstSavings = savingsDST;
+ this->startYear = 0;
+ this->startMode = DOM_MODE;
+ this->endMode = DOM_MODE;
+
+ decodeRules(status);
+
+ if (savingsDST <= 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+// -------------------------------------
+
+SimpleTimeZone::~SimpleTimeZone()
+{
+ deleteTransitionRules();
+}
+
+// -------------------------------------
+
+// Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful.
+SimpleTimeZone::SimpleTimeZone(const SimpleTimeZone &source)
+: BasicTimeZone(source)
+{
+ *this = source;
+}
+
+// -------------------------------------
+
+// Called by TimeZone::createDefault(), then clone() inside a Mutex - be careful.
+SimpleTimeZone &
+SimpleTimeZone::operator=(const SimpleTimeZone &right)
+{
+ if (this != &right)
+ {
+ TimeZone::operator=(right);
+ rawOffset = right.rawOffset;
+ startMonth = right.startMonth;
+ startDay = right.startDay;
+ startDayOfWeek = right.startDayOfWeek;
+ startTime = right.startTime;
+ startTimeMode = right.startTimeMode;
+ startMode = right.startMode;
+ endMonth = right.endMonth;
+ endDay = right.endDay;
+ endDayOfWeek = right.endDayOfWeek;
+ endTime = right.endTime;
+ endTimeMode = right.endTimeMode;
+ endMode = right.endMode;
+ startYear = right.startYear;
+ dstSavings = right.dstSavings;
+ useDaylight = right.useDaylight;
+ clearTransitionRules();
+ }
+ return *this;
+}
+
+// -------------------------------------
+
+UBool
+SimpleTimeZone::operator==(const TimeZone& that) const
+{
+ return ((this == &that) ||
+ (getDynamicClassID() == that.getDynamicClassID() &&
+ TimeZone::operator==(that) &&
+ hasSameRules(that)));
+}
+
+// -------------------------------------
+
+// Called by TimeZone::createDefault() inside a Mutex - be careful.
+TimeZone*
+SimpleTimeZone::clone() const
+{
+ return new SimpleTimeZone(*this);
+}
+
+// -------------------------------------
+
+/**
+ * Sets the daylight savings starting year, that is, the year this time zone began
+ * observing its specified daylight savings time rules. The time zone is considered
+ * not to observe daylight savings time prior to that year; SimpleTimeZone doesn't
+ * support historical daylight-savings-time rules.
+ * @param year the daylight savings starting year.
+ */
+void
+SimpleTimeZone::setStartYear(int32_t year)
+{
+ startYear = year;
+ transitionRulesInitialized = FALSE;
+}
+
+// -------------------------------------
+
+/**
+ * Sets the daylight savings starting rule. For example, in the U.S., Daylight Savings
+ * Time starts at the first Sunday in April, at 2 AM in standard time.
+ * Therefore, you can set the start rule by calling:
+ * setStartRule(TimeFields.APRIL, 1, TimeFields.SUNDAY, 2*60*60*1000);
+ * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calculate
+ * the exact starting date. Their exact meaning depend on their respective signs,
+ * allowing various types of rules to be constructed, as follows:<ul>
+ * <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the
+ * day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday
+ * of the month).
+ * <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify
+ * the day of week in the month counting backward from the end of the month.
+ * (e.g., (-1, MONDAY) is the last Monday in the month)
+ * <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth
+ * specifies the day of the month, regardless of what day of the week it is.
+ * (e.g., (10, 0) is the tenth day of the month)
+ * <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth
+ * specifies the day of the month counting backward from the end of the
+ * month, regardless of what day of the week it is (e.g., (-2, 0) is the
+ * next-to-last day of the month).
+ * <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the
+ * first specified day of the week on or after the specfied day of the month.
+ * (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month
+ * [or the 15th itself if the 15th is a Sunday].)
+ * <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the
+ * last specified day of the week on or before the specified day of the month.
+ * (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month
+ * [or the 20th itself if the 20th is a Tuesday].)</ul>
+ * @param month the daylight savings starting month. Month is 0-based.
+ * eg, 0 for January.
+ * @param dayOfWeekInMonth the daylight savings starting
+ * day-of-week-in-month. Please see the member description for an example.
+ * @param dayOfWeek the daylight savings starting day-of-week. Please see
+ * the member description for an example.
+ * @param time the daylight savings starting time. Please see the member
+ * description for an example.
+ */
+
+void
+SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
+ int32_t time, TimeMode mode, UErrorCode& status)
+{
+ startMonth = (int8_t)month;
+ startDay = (int8_t)dayOfWeekInMonth;
+ startDayOfWeek = (int8_t)dayOfWeek;
+ startTime = time;
+ startTimeMode = mode;
+ decodeStartRule(status);
+ transitionRulesInitialized = FALSE;
+}
+
+// -------------------------------------
+
+void
+SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth,
+ int32_t time, TimeMode mode, UErrorCode& status)
+{
+ setStartRule(month, dayOfMonth, 0, time, mode, status);
+}
+
+// -------------------------------------
+
+void
+SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ int32_t time, TimeMode mode, UBool after, UErrorCode& status)
+{
+ setStartRule(month, after ? dayOfMonth : -dayOfMonth,
+ -dayOfWeek, time, mode, status);
+}
+
+// -------------------------------------
+
+/**
+ * Sets the daylight savings ending rule. For example, in the U.S., Daylight
+ * Savings Time ends at the last (-1) Sunday in October, at 2 AM in standard time.
+ * Therefore, you can set the end rule by calling:
+ * setEndRule(TimeFields.OCTOBER, -1, TimeFields.SUNDAY, 2*60*60*1000);
+ * Various other types of rules can be specified by manipulating the dayOfWeek
+ * and dayOfWeekInMonth parameters. For complete details, see the documentation
+ * for setStartRule().
+ * @param month the daylight savings ending month. Month is 0-based.
+ * eg, 0 for January.
+ * @param dayOfWeekInMonth the daylight savings ending
+ * day-of-week-in-month. See setStartRule() for a complete explanation.
+ * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule()
+ * for a complete explanation.
+ * @param time the daylight savings ending time. Please see the member
+ * description for an example.
+ */
+
+void
+SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
+ int32_t time, TimeMode mode, UErrorCode& status)
+{
+ endMonth = (int8_t)month;
+ endDay = (int8_t)dayOfWeekInMonth;
+ endDayOfWeek = (int8_t)dayOfWeek;
+ endTime = time;
+ endTimeMode = mode;
+ decodeEndRule(status);
+ transitionRulesInitialized = FALSE;
+}
+
+// -------------------------------------
+
+void
+SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth,
+ int32_t time, TimeMode mode, UErrorCode& status)
+{
+ setEndRule(month, dayOfMonth, 0, time, mode, status);
+}
+
+// -------------------------------------
+
+void
+SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ int32_t time, TimeMode mode, UBool after, UErrorCode& status)
+{
+ setEndRule(month, after ? dayOfMonth : -dayOfMonth,
+ -dayOfWeek, time, mode, status);
+}
+
+// -------------------------------------
+
+int32_t
+SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const
+{
+ // Check the month before calling Grego::monthLength(). This
+ // duplicates the test that occurs in the 7-argument getOffset(),
+ // however, this is unavoidable. We don't mind because this method, in
+ // fact, should not be called; internal code should always call the
+ // 7-argument getOffset(), and outside code should use Calendar.get(int
+ // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
+ // this method because it's public API. - liu 8/10/98
+ if(month < UCAL_JANUARY || month > UCAL_DECEMBER) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ return getOffset(era, year, month, day, dayOfWeek, millis, Grego::monthLength(year, month), status);
+}
+
+int32_t
+SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis,
+ int32_t /*monthLength*/, UErrorCode& status) const
+{
+ // Check the month before calling Grego::monthLength(). This
+ // duplicates a test that occurs in the 9-argument getOffset(),
+ // however, this is unavoidable. We don't mind because this method, in
+ // fact, should not be called; internal code should always call the
+ // 9-argument getOffset(), and outside code should use Calendar.get(int
+ // field) with fields ZONE_OFFSET and DST_OFFSET. We can't get rid of
+ // this method because it's public API. - liu 8/10/98
+ if (month < UCAL_JANUARY
+ || month > UCAL_DECEMBER) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ // We ignore monthLength because it can be derived from year and month.
+ // This is so that February in leap years is calculated correctly.
+ // We keep this argument in this function for backwards compatibility.
+ return getOffset(era, year, month, day, dayOfWeek, millis,
+ Grego::monthLength(year, month),
+ Grego::previousMonthLength(year, month),
+ status);
+}
+
+int32_t
+SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis,
+ int32_t monthLength, int32_t prevMonthLength,
+ UErrorCode& status) const
+{
+ if(U_FAILURE(status)) return 0;
+
+ if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC)
+ || month < UCAL_JANUARY
+ || month > UCAL_DECEMBER
+ || day < 1
+ || day > monthLength
+ || dayOfWeek < UCAL_SUNDAY
+ || dayOfWeek > UCAL_SATURDAY
+ || millis < 0
+ || millis >= U_MILLIS_PER_DAY
+ || monthLength < 28
+ || monthLength > 31
+ || prevMonthLength < 28
+ || prevMonthLength > 31) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ int32_t result = rawOffset;
+
+ // Bail out if we are before the onset of daylight savings time
+ if(!useDaylight || year < startYear || era != GregorianCalendar::AD)
+ return result;
+
+ // Check for southern hemisphere. We assume that the start and end
+ // month are different.
+ UBool southern = (startMonth > endMonth);
+
+ // Compare the date to the starting and ending rules.+1 = date>rule, -1
+ // = date<rule, 0 = date==rule.
+ int32_t startCompare = compareToRule((int8_t)month, (int8_t)monthLength, (int8_t)prevMonthLength,
+ (int8_t)day, (int8_t)dayOfWeek, millis,
+ startTimeMode == UTC_TIME ? -rawOffset : 0,
+ startMode, (int8_t)startMonth, (int8_t)startDayOfWeek,
+ (int8_t)startDay, startTime);
+ int32_t endCompare = 0;
+
+ /* We don't always have to compute endCompare. For many instances,
+ * startCompare is enough to determine if we are in DST or not. In the
+ * northern hemisphere, if we are before the start rule, we can't have
+ * DST. In the southern hemisphere, if we are after the start rule, we
+ * must have DST. This is reflected in the way the next if statement
+ * (not the one immediately following) short circuits. */
+ if(southern != (startCompare >= 0)) {
+ endCompare = compareToRule((int8_t)month, (int8_t)monthLength, (int8_t)prevMonthLength,
+ (int8_t)day, (int8_t)dayOfWeek, millis,
+ endTimeMode == WALL_TIME ? dstSavings :
+ (endTimeMode == UTC_TIME ? -rawOffset : 0),
+ endMode, (int8_t)endMonth, (int8_t)endDayOfWeek,
+ (int8_t)endDay, endTime);
+ }
+
+ // Check for both the northern and southern hemisphere cases. We
+ // assume that in the northern hemisphere, the start rule is before the
+ // end rule within the calendar year, and vice versa for the southern
+ // hemisphere.
+ if ((!southern && (startCompare >= 0 && endCompare < 0)) ||
+ (southern && (startCompare >= 0 || endCompare < 0)))
+ result += dstSavings;
+
+ return result;
+}
+
+void
+SimpleTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ int32_t& rawOffsetGMT, int32_t& savingsDST, UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ rawOffsetGMT = getRawOffset();
+ int32_t year, month, dom, dow;
+ double day = uprv_floor(date / U_MILLIS_PER_DAY);
+ int32_t millis = (int32_t) (date - day * U_MILLIS_PER_DAY);
+
+ Grego::dayToFields(day, year, month, dom, dow);
+
+ savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
+ (uint8_t) dow, millis,
+ Grego::monthLength(year, month),
+ status) - rawOffsetGMT;
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UBool recalc = FALSE;
+
+ // Now we need some adjustment
+ if (savingsDST > 0) {
+ if ((nonExistingTimeOpt & kStdDstMask) == kStandard
+ || (nonExistingTimeOpt & kStdDstMask) != kDaylight && (nonExistingTimeOpt & kFormerLatterMask) != kLatter) {
+ date -= getDSTSavings();
+ recalc = TRUE;
+ }
+ } else {
+ if ((duplicatedTimeOpt & kStdDstMask) == kDaylight
+ || (duplicatedTimeOpt & kStdDstMask) != kStandard && (duplicatedTimeOpt & kFormerLatterMask) == kFormer) {
+ date -= getDSTSavings();
+ recalc = TRUE;
+ }
+ }
+ if (recalc) {
+ day = uprv_floor(date / U_MILLIS_PER_DAY);
+ millis = (int32_t) (date - day * U_MILLIS_PER_DAY);
+ Grego::dayToFields(day, year, month, dom, dow);
+ savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
+ (uint8_t) dow, millis,
+ Grego::monthLength(year, month),
+ status) - rawOffsetGMT;
+ }
+}
+
+// -------------------------------------
+
+/**
+ * Compare a given date in the year to a rule. Return 1, 0, or -1, depending
+ * on whether the date is after, equal to, or before the rule date. The
+ * millis are compared directly against the ruleMillis, so any
+ * standard-daylight adjustments must be handled by the caller.
+ *
+ * @return 1 if the date is after the rule date, -1 if the date is before
+ * the rule date, or 0 if the date is equal to the rule date.
+ */
+int32_t
+SimpleTimeZone::compareToRule(int8_t month, int8_t monthLen, int8_t prevMonthLen,
+ int8_t dayOfMonth,
+ int8_t dayOfWeek, int32_t millis, int32_t millisDelta,
+ EMode ruleMode, int8_t ruleMonth, int8_t ruleDayOfWeek,
+ int8_t ruleDay, int32_t ruleMillis)
+{
+ // Make adjustments for startTimeMode and endTimeMode
+ millis += millisDelta;
+ while (millis >= U_MILLIS_PER_DAY) {
+ millis -= U_MILLIS_PER_DAY;
+ ++dayOfMonth;
+ dayOfWeek = (int8_t)(1 + (dayOfWeek % 7)); // dayOfWeek is one-based
+ if (dayOfMonth > monthLen) {
+ dayOfMonth = 1;
+ /* When incrementing the month, it is desirible to overflow
+ * from DECEMBER to DECEMBER+1, since we use the result to
+ * compare against a real month. Wraparound of the value
+ * leads to bug 4173604. */
+ ++month;
+ }
+ }
+ while (millis < 0) {
+ millis += U_MILLIS_PER_DAY;
+ --dayOfMonth;
+ dayOfWeek = (int8_t)(1 + ((dayOfWeek+5) % 7)); // dayOfWeek is one-based
+ if (dayOfMonth < 1) {
+ dayOfMonth = prevMonthLen;
+ --month;
+ }
+ }
+
+ // first compare months. If they're different, we don't have to worry about days
+ // and times
+ if (month < ruleMonth) return -1;
+ else if (month > ruleMonth) return 1;
+
+ // calculate the actual day of month for the rule
+ int32_t ruleDayOfMonth = 0;
+
+ // Adjust the ruleDay to the monthLen, for non-leap year February 29 rule days.
+ if (ruleDay > monthLen) {
+ ruleDay = monthLen;
+ }
+
+ switch (ruleMode)
+ {
+ // if the mode is day-of-month, the day of month is given
+ case DOM_MODE:
+ ruleDayOfMonth = ruleDay;
+ break;
+
+ // if the mode is day-of-week-in-month, calculate the day-of-month from it
+ case DOW_IN_MONTH_MODE:
+ // In this case ruleDay is the day-of-week-in-month (this code is using
+ // the dayOfWeek and dayOfMonth parameters to figure out the day-of-week
+ // of the first day of the month, so it's trusting that they're really
+ // consistent with each other)
+ if (ruleDay > 0)
+ ruleDayOfMonth = 1 + (ruleDay - 1) * 7 +
+ (7 + ruleDayOfWeek - (dayOfWeek - dayOfMonth + 1)) % 7;
+
+ // if ruleDay is negative (we assume it's not zero here), we have to do
+ // the same calculation figuring backward from the last day of the month.
+ else
+ {
+ // (again, this code is trusting that dayOfWeek and dayOfMonth are
+ // consistent with each other here, since we're using them to figure
+ // the day of week of the first of the month)
+ ruleDayOfMonth = monthLen + (ruleDay + 1) * 7 -
+ (7 + (dayOfWeek + monthLen - dayOfMonth) - ruleDayOfWeek) % 7;
+ }
+ break;
+
+ case DOW_GE_DOM_MODE:
+ ruleDayOfMonth = ruleDay +
+ (49 + ruleDayOfWeek - ruleDay - dayOfWeek + dayOfMonth) % 7;
+ break;
+
+ case DOW_LE_DOM_MODE:
+ ruleDayOfMonth = ruleDay -
+ (49 - ruleDayOfWeek + ruleDay + dayOfWeek - dayOfMonth) % 7;
+ // Note at this point ruleDayOfMonth may be <1, although it will
+ // be >=1 for well-formed rules.
+ break;
+ }
+
+ // now that we have a real day-in-month for the rule, we can compare days...
+ if (dayOfMonth < ruleDayOfMonth) return -1;
+ else if (dayOfMonth > ruleDayOfMonth) return 1;
+
+ // ...and if they're equal, we compare times
+ if (millis < ruleMillis) return -1;
+ else if (millis > ruleMillis) return 1;
+ else return 0;
+}
+
+// -------------------------------------
+
+int32_t
+SimpleTimeZone::getRawOffset() const
+{
+ return rawOffset;
+}
+
+// -------------------------------------
+
+void
+SimpleTimeZone::setRawOffset(int32_t offsetMillis)
+{
+ rawOffset = offsetMillis;
+ transitionRulesInitialized = FALSE;
+}
+
+// -------------------------------------
+
+void
+SimpleTimeZone::setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status)
+{
+ if (millisSavedDuringDST <= 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ else {
+ dstSavings = millisSavedDuringDST;
+ }
+ transitionRulesInitialized = FALSE;
+}
+
+// -------------------------------------
+
+int32_t
+SimpleTimeZone::getDSTSavings() const
+{
+ return dstSavings;
+}
+
+// -------------------------------------
+
+UBool
+SimpleTimeZone::useDaylightTime() const
+{
+ return useDaylight;
+}
+
+// -------------------------------------
+
+/**
+ * Overrides TimeZone
+ * Queries if the given date is in Daylight Savings Time.
+ */
+UBool SimpleTimeZone::inDaylightTime(UDate date, UErrorCode& status) const
+{
+ // This method is wasteful since it creates a new GregorianCalendar and
+ // deletes it each time it is called. However, this is a deprecated method
+ // and provided only for Java compatibility as of 8/6/97 [LIU].
+ if (U_FAILURE(status)) return FALSE;
+ GregorianCalendar *gc = new GregorianCalendar(*this, status);
+ /* test for NULL */
+ if (gc == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return FALSE;
+ }
+ gc->setTime(date, status);
+ UBool result = gc->inDaylightTime(status);
+ delete gc;
+ return result;
+}
+
+// -------------------------------------
+
+/**
+ * Return true if this zone has the same rules and offset as another zone.
+ * @param other the TimeZone object to be compared with
+ * @return true if the given zone has the same rules and offset as this one
+ */
+UBool
+SimpleTimeZone::hasSameRules(const TimeZone& other) const
+{
+ if (this == &other) return TRUE;
+ if (other.getDynamicClassID() != SimpleTimeZone::getStaticClassID()) return FALSE;
+ SimpleTimeZone *that = (SimpleTimeZone*)&other;
+ return rawOffset == that->rawOffset &&
+ useDaylight == that->useDaylight &&
+ (!useDaylight
+ // Only check rules if using DST
+ || (dstSavings == that->dstSavings &&
+ startMode == that->startMode &&
+ startMonth == that->startMonth &&
+ startDay == that->startDay &&
+ startDayOfWeek == that->startDayOfWeek &&
+ startTime == that->startTime &&
+ startTimeMode == that->startTimeMode &&
+ endMode == that->endMode &&
+ endMonth == that->endMonth &&
+ endDay == that->endDay &&
+ endDayOfWeek == that->endDayOfWeek &&
+ endTime == that->endTime &&
+ endTimeMode == that->endTimeMode &&
+ startYear == that->startYear));
+}
+
+// -------------------------------------
+
+//----------------------------------------------------------------------
+// Rule representation
+//
+// We represent the following flavors of rules:
+// 5 the fifth of the month
+// lastSun the last Sunday in the month
+// lastMon the last Monday in the month
+// Sun>=8 first Sunday on or after the eighth
+// Sun<=25 last Sunday on or before the 25th
+// This is further complicated by the fact that we need to remain
+// backward compatible with the 1.1 FCS. Finally, we need to minimize
+// API changes. In order to satisfy these requirements, we support
+// three representation systems, and we translate between them.
+//
+// INTERNAL REPRESENTATION
+// This is the format SimpleTimeZone objects take after construction or
+// streaming in is complete. Rules are represented directly, using an
+// unencoded format. We will discuss the start rule only below; the end
+// rule is analogous.
+// startMode Takes on enumerated values DAY_OF_MONTH,
+// DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
+// startDay The day of the month, or for DOW_IN_MONTH mode, a
+// value indicating which DOW, such as +1 for first,
+// +2 for second, -1 for last, etc.
+// startDayOfWeek The day of the week. Ignored for DAY_OF_MONTH.
+//
+// ENCODED REPRESENTATION
+// This is the format accepted by the constructor and by setStartRule()
+// and setEndRule(). It uses various combinations of positive, negative,
+// and zero values to encode the different rules. This representation
+// allows us to specify all the different rule flavors without altering
+// the API.
+// MODE startMonth startDay startDayOfWeek
+// DOW_IN_MONTH_MODE >=0 !=0 >0
+// DOM_MODE >=0 >0 ==0
+// DOW_GE_DOM_MODE >=0 >0 <0
+// DOW_LE_DOM_MODE >=0 <0 <0
+// (no DST) don't care ==0 don't care
+//
+// STREAMED REPRESENTATION
+// We must retain binary compatibility with the 1.1 FCS. The 1.1 code only
+// handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
+// flag useDaylight. When we stream an object out, we translate into an
+// approximate DOW_IN_MONTH_MODE representation so the object can be parsed
+// and used by 1.1 code. Following that, we write out the full
+// representation separately so that contemporary code can recognize and
+// parse it. The full representation is written in a "packed" format,
+// consisting of a version number, a length, and an array of bytes. Future
+// versions of this class may specify different versions. If they wish to
+// include additional data, they should do so by storing them after the
+// packed representation below.
+//----------------------------------------------------------------------
+
+/**
+ * Given a set of encoded rules in startDay and startDayOfMonth, decode
+ * them and set the startMode appropriately. Do the same for endDay and
+ * endDayOfMonth. Upon entry, the day of week variables may be zero or
+ * negative, in order to indicate special modes. The day of month
+ * variables may also be negative. Upon exit, the mode variables will be
+ * set, and the day of week and day of month variables will be positive.
+ * This method also recognizes a startDay or endDay of zero as indicating
+ * no DST.
+ */
+void
+SimpleTimeZone::decodeRules(UErrorCode& status)
+{
+ decodeStartRule(status);
+ decodeEndRule(status);
+}
+
+/**
+ * Decode the start rule and validate the parameters. The parameters are
+ * expected to be in encoded form, which represents the various rule modes
+ * by negating or zeroing certain values. Representation formats are:
+ * <p>
+ * <pre>
+ * DOW_IN_MONTH DOM DOW>=DOM DOW<=DOM no DST
+ * ------------ ----- -------- -------- ----------
+ * month 0..11 same same same don't care
+ * day -5..5 1..31 1..31 -1..-31 0
+ * dayOfWeek 1..7 0 -1..-7 -1..-7 don't care
+ * time 0..ONEDAY same same same don't care
+ * </pre>
+ * The range for month does not include UNDECIMBER since this class is
+ * really specific to GregorianCalendar, which does not use that month.
+ * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
+ * end rule is an exclusive limit point. That is, the range of times that
+ * are in DST include those >= the start and < the end. For this reason,
+ * it should be possible to specify an end of ONEDAY in order to include the
+ * entire day. Although this is equivalent to time 0 of the following day,
+ * it's not always possible to specify that, for example, on December 31.
+ * While arguably the start range should still be 0..ONEDAY-1, we keep
+ * the start and end ranges the same for consistency.
+ */
+void
+SimpleTimeZone::decodeStartRule(UErrorCode& status)
+{
+ if(U_FAILURE(status)) return;
+
+ useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? TRUE : FALSE);
+ if (useDaylight && dstSavings == 0) {
+ dstSavings = U_MILLIS_PER_HOUR;
+ }
+ if (startDay != 0) {
+ if (startMonth < UCAL_JANUARY || startMonth > UCAL_DECEMBER) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (startTime < 0 || startTime > U_MILLIS_PER_DAY ||
+ startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (startDayOfWeek == 0) {
+ startMode = DOM_MODE;
+ } else {
+ if (startDayOfWeek > 0) {
+ startMode = DOW_IN_MONTH_MODE;
+ } else {
+ startDayOfWeek = (int8_t)-startDayOfWeek;
+ if (startDay > 0) {
+ startMode = DOW_GE_DOM_MODE;
+ } else {
+ startDay = (int8_t)-startDay;
+ startMode = DOW_LE_DOM_MODE;
+ }
+ }
+ if (startDayOfWeek > UCAL_SATURDAY) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ }
+ if (startMode == DOW_IN_MONTH_MODE) {
+ if (startDay < -5 || startDay > 5) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ } else if (startDay<1 || startDay > STATICMONTHLENGTH[startMonth]) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ }
+}
+
+/**
+ * Decode the end rule and validate the parameters. This method is exactly
+ * analogous to decodeStartRule().
+ * @see decodeStartRule
+ */
+void
+SimpleTimeZone::decodeEndRule(UErrorCode& status)
+{
+ if(U_FAILURE(status)) return;
+
+ useDaylight = (UBool)((startDay != 0) && (endDay != 0) ? TRUE : FALSE);
+ if (useDaylight && dstSavings == 0) {
+ dstSavings = U_MILLIS_PER_HOUR;
+ }
+ if (endDay != 0) {
+ if (endMonth < UCAL_JANUARY || endMonth > UCAL_DECEMBER) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (endTime < 0 || endTime > U_MILLIS_PER_DAY ||
+ endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (endDayOfWeek == 0) {
+ endMode = DOM_MODE;
+ } else {
+ if (endDayOfWeek > 0) {
+ endMode = DOW_IN_MONTH_MODE;
+ } else {
+ endDayOfWeek = (int8_t)-endDayOfWeek;
+ if (endDay > 0) {
+ endMode = DOW_GE_DOM_MODE;
+ } else {
+ endDay = (int8_t)-endDay;
+ endMode = DOW_LE_DOM_MODE;
+ }
+ }
+ if (endDayOfWeek > UCAL_SATURDAY) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ }
+ if (endMode == DOW_IN_MONTH_MODE) {
+ if (endDay < -5 || endDay > 5) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ } else if (endDay<1 || endDay > STATICMONTHLENGTH[endMonth]) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ }
+}
+
+UBool
+SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+ if (startMonth == 0) {
+ return FALSE;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ initTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ UDate firstTransitionTime = firstTransition->getTime();
+ if (base < firstTransitionTime || (inclusive && base == firstTransitionTime)) {
+ result = *firstTransition;
+ }
+ UDate stdDate, dstDate;
+ UBool stdAvail = stdRule->getNextStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
+ UBool dstAvail = dstRule->getNextStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
+ if (stdAvail && (!dstAvail || stdDate < dstDate)) {
+ result.setTime(stdDate);
+ result.setFrom((const TimeZoneRule&)*dstRule);
+ result.setTo((const TimeZoneRule&)*stdRule);
+ return TRUE;
+ }
+ if (dstAvail && (!stdAvail || dstDate < stdDate)) {
+ result.setTime(dstDate);
+ result.setFrom((const TimeZoneRule&)*stdRule);
+ result.setTo((const TimeZoneRule&)*dstRule);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+ if (startMonth == 0) {
+ return FALSE;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ initTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ UDate firstTransitionTime = firstTransition->getTime();
+ if (base < firstTransitionTime || (!inclusive && base == firstTransitionTime)) {
+ return FALSE;
+ }
+ UDate stdDate, dstDate;
+ UBool stdAvail = stdRule->getPreviousStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
+ UBool dstAvail = dstRule->getPreviousStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
+ if (stdAvail && (!dstAvail || stdDate > dstDate)) {
+ result.setTime(stdDate);
+ result.setFrom((const TimeZoneRule&)*dstRule);
+ result.setTo((const TimeZoneRule&)*stdRule);
+ return TRUE;
+ }
+ if (dstAvail && (!stdAvail || dstDate > stdDate)) {
+ result.setTime(dstDate);
+ result.setFrom((const TimeZoneRule&)*stdRule);
+ result.setTo((const TimeZoneRule&)*dstRule);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+SimpleTimeZone::clearTransitionRules(void) {
+ initialRule = NULL;
+ firstTransition = NULL;
+ stdRule = NULL;
+ dstRule = NULL;
+ transitionRulesInitialized = FALSE;
+}
+
+void
+SimpleTimeZone::deleteTransitionRules(void) {
+ if (initialRule != NULL) {
+ delete initialRule;
+ }
+ if (firstTransition != NULL) {
+ delete firstTransition;
+ }
+ if (stdRule != NULL) {
+ delete stdRule;
+ }
+ if (dstRule != NULL) {
+ delete dstRule;
+ }
+ clearTransitionRules();
+ }
+
+void
+SimpleTimeZone::initTransitionRules(UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (transitionRulesInitialized) {
+ return;
+ }
+ deleteTransitionRules();
+ UnicodeString tzid;
+ getID(tzid);
+
+ if (startMonth != 0) {
+ DateTimeRule* dtRule;
+ DateTimeRule::TimeRuleType timeRuleType;
+ UDate firstStdStart, firstDstStart;
+
+ // Create a TimeZoneRule for daylight saving time
+ timeRuleType = (startTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
+ ((startTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
+ switch (startMode) {
+ case DOM_MODE:
+ dtRule = new DateTimeRule(startMonth, startDay, startTime, timeRuleType);
+ break;
+ case DOW_IN_MONTH_MODE:
+ dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, startTime, timeRuleType);
+ break;
+ case DOW_GE_DOM_MODE:
+ dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, true, startTime, timeRuleType);
+ break;
+ case DOW_LE_DOM_MODE:
+ dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, false, startTime, timeRuleType);
+ break;
+ default:
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ // For now, use ID + "(DST)" as the name
+ dstRule = new AnnualTimeZoneRule(tzid+DST_STR, getRawOffset(), getDSTSavings(),
+ dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
+
+ // Calculate the first DST start time
+ dstRule->getFirstStart(getRawOffset(), 0, firstDstStart);
+
+ // Create a TimeZoneRule for standard time
+ timeRuleType = (endTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
+ ((endTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
+ switch (endMode) {
+ case DOM_MODE:
+ dtRule = new DateTimeRule(endMonth, endDay, endTime, timeRuleType);
+ break;
+ case DOW_IN_MONTH_MODE:
+ dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, endTime, timeRuleType);
+ break;
+ case DOW_GE_DOM_MODE:
+ dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, true, endTime, timeRuleType);
+ break;
+ case DOW_LE_DOM_MODE:
+ dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, false, endTime, timeRuleType);
+ break;
+ }
+ // For now, use ID + "(STD)" as the name
+ stdRule = new AnnualTimeZoneRule(tzid+STD_STR, getRawOffset(), 0,
+ dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
+
+ // Calculate the first STD start time
+ stdRule->getFirstStart(getRawOffset(), dstRule->getDSTSavings(), firstStdStart);
+
+ // Create a TimeZoneRule for initial time
+ if (firstStdStart < firstDstStart) {
+ initialRule = new InitialTimeZoneRule(tzid+DST_STR, getRawOffset(), dstRule->getDSTSavings());
+ firstTransition = new TimeZoneTransition(firstStdStart, *initialRule, *stdRule);
+ } else {
+ initialRule = new InitialTimeZoneRule(tzid+STD_STR, getRawOffset(), 0);
+ firstTransition = new TimeZoneTransition(firstDstStart, *initialRule, *dstRule);
+ }
+
+ } else {
+ // Create a TimeZoneRule for initial time
+ initialRule = new InitialTimeZoneRule(tzid, getRawOffset(), 0);
+ }
+ transitionRulesInitialized = true;
+}
+
+int32_t
+SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) /*const*/ {
+ return (startMonth == 0) ? 0 : 2;
+}
+
+void
+SimpleTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[],
+ int32_t& trscount,
+ UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ initTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ initial = initialRule;
+ int32_t cnt = 0;
+ if (stdRule != NULL) {
+ if (cnt < trscount) {
+ trsrules[cnt++] = stdRule;
+ }
+ if (cnt < trscount) {
+ trsrules[cnt++] = dstRule;
+ }
+ }
+ trscount = cnt;
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/smpdtfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/smpdtfmt.cpp
new file mode 100644
index 00000000000..b52134dc95e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/smpdtfmt.cpp
@@ -0,0 +1,2401 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File SMPDTFMT.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/31/97 aliu Modified extensively to work with 50 locales.
+* 04/01/97 aliu Added support for centuries.
+* 07/09/97 helena Made ParsePosition into a class.
+* 07/21/98 stephen Added initializeDefaultCentury.
+* Removed getZoneIndex (added in DateFormatSymbols)
+* Removed subParseLong
+* Removed chk
+* 02/22/99 stephen Removed character literals for EBCDIC safety
+* 10/14/99 aliu Updated 2-digit year parsing so that only "00" thru
+* "99" are recognized. {j28 4182066}
+* 11/15/99 weiv Added support for week of year/day of week format
+********************************************************************************
+*/
+
+#define ZID_KEY_MAX 128
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/smpdtfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/ures.h"
+#include "unicode/msgfmt.h"
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "unicode/timezone.h"
+#include "unicode/decimfmt.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "unicode/basictz.h"
+#include "unicode/simpletz.h"
+#include "unicode/rbtz.h"
+#include "unicode/vtzone.h"
+#include "olsontz.h"
+#include "util.h"
+#include "gregoimp.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "zstrfmt.h"
+#include "cmemory.h"
+#include "umutex.h"
+#include <float.h>
+
+#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
+#include <stdio.h>
+#endif
+
+// *****************************************************************************
+// class SimpleDateFormat
+// *****************************************************************************
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Last-resort string to use for "GMT" when constructing time zone strings.
+ */
+// For time zones that have no names, use strings GMT+minutes and
+// GMT-minutes. For instance, in France the time zone is GMT+60.
+// Also accepted are GMT+H:MM or GMT-H:MM.
+static const UChar gGmt[] = {0x0047, 0x004D, 0x0054, 0x0000}; // "GMT"
+static const UChar gGmtPlus[] = {0x0047, 0x004D, 0x0054, 0x002B, 0x0000}; // "GMT+"
+static const UChar gGmtMinus[] = {0x0047, 0x004D, 0x0054, 0x002D, 0x0000}; // "GMT-"
+static const UChar gDefGmtPat[] = {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */
+static const UChar gDefGmtNegHmsPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* -HH:mm:ss */
+static const UChar gDefGmtNegHmPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* -HH:mm */
+static const UChar gDefGmtPosHmsPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* +HH:mm:ss */
+static const UChar gDefGmtPosHmPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* +HH:mm */
+typedef enum GmtPatSize {
+ kGmtLen = 3,
+ kGmtPatLen = 6,
+ kNegHmsLen = 9,
+ kNegHmLen = 6,
+ kPosHmsLen = 9,
+ kPosHmLen = 6
+} GmtPatSize;
+
+// This is a pattern-of-last-resort used when we can't load a usable pattern out
+// of a resource.
+static const UChar gDefaultPattern[] =
+{
+ 0x79, 0x79, 0x79, 0x79, 0x4D, 0x4D, 0x64, 0x64, 0x20, 0x68, 0x68, 0x3A, 0x6D, 0x6D, 0x20, 0x61, 0
+}; /* "yyyyMMdd hh:mm a" */
+
+// This prefix is designed to NEVER MATCH real text, in order to
+// suppress the parsing of negative numbers. Adjust as needed (if
+// this becomes valid Unicode).
+static const UChar SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0};
+
+/**
+ * These are the tags we expect to see in normal resource bundle files associated
+ * with a locale.
+ */
+static const char gDateTimePatternsTag[]="DateTimePatterns";
+
+static const UChar gEtcUTC[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x54, 0x43, 0x00}; // "Etc/UTC"
+static const UChar QUOTE = 0x27; // Single quote
+enum {
+ kGMTNegativeHMS = 0,
+ kGMTNegativeHM,
+ kGMTPositiveHMS,
+ kGMTPositiveHM,
+
+ kNumGMTFormatters
+};
+
+static UMTX LOCK;
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::~SimpleDateFormat()
+{
+ delete fSymbols;
+ if (fGMTFormatters) {
+ for (int32_t i = 0; i < kNumGMTFormatters; i++) {
+ if (fGMTFormatters[i]) {
+ delete fGMTFormatters[i];
+ }
+ }
+ uprv_free(fGMTFormatters);
+ }
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
+ : fLocale(Locale::getDefault()),
+ fSymbols(NULL),
+ fGMTFormatters(NULL)
+{
+ construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
+ initializeDefaultCentury();
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+ UErrorCode &status)
+: fPattern(pattern),
+ fLocale(Locale::getDefault()),
+ fSymbols(NULL),
+ fGMTFormatters(NULL)
+{
+ initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initialize(fLocale, status);
+ initializeDefaultCentury();
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+ const Locale& locale,
+ UErrorCode& status)
+: fPattern(pattern),
+ fLocale(locale),
+ fGMTFormatters(NULL)
+{
+ initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status);
+ initialize(fLocale, status);
+ initializeDefaultCentury();
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+ DateFormatSymbols* symbolsToAdopt,
+ UErrorCode& status)
+: fPattern(pattern),
+ fLocale(Locale::getDefault()),
+ fSymbols(symbolsToAdopt),
+ fGMTFormatters(NULL)
+{
+ initializeCalendar(NULL,fLocale,status);
+ initialize(fLocale, status);
+ initializeDefaultCentury();
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
+ const DateFormatSymbols& symbols,
+ UErrorCode& status)
+: fPattern(pattern),
+ fLocale(Locale::getDefault()),
+ fSymbols(new DateFormatSymbols(symbols)),
+ fGMTFormatters(NULL)
+{
+ initializeCalendar(NULL, fLocale, status);
+ initialize(fLocale, status);
+ initializeDefaultCentury();
+}
+
+//----------------------------------------------------------------------
+
+// Not for public consumption; used by DateFormat
+SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
+ EStyle dateStyle,
+ const Locale& locale,
+ UErrorCode& status)
+: fLocale(locale),
+ fSymbols(NULL),
+ fGMTFormatters(NULL)
+{
+ construct(timeStyle, dateStyle, fLocale, status);
+ if(U_SUCCESS(status)) {
+ initializeDefaultCentury();
+ }
+}
+
+//----------------------------------------------------------------------
+
+/**
+ * Not for public consumption; used by DateFormat. This constructor
+ * never fails. If the resource data is not available, it uses the
+ * the last resort symbols.
+ */
+SimpleDateFormat::SimpleDateFormat(const Locale& locale,
+ UErrorCode& status)
+: fPattern(gDefaultPattern),
+ fLocale(locale),
+ fSymbols(NULL),
+ fGMTFormatters(NULL)
+{
+ if (U_FAILURE(status)) return;
+ initializeSymbols(fLocale, initializeCalendar(NULL, fLocale, status),status);
+ if (U_FAILURE(status))
+ {
+ status = U_ZERO_ERROR;
+ delete fSymbols;
+ // This constructor doesn't fail; it uses last resort data
+ fSymbols = new DateFormatSymbols(status);
+ /* test for NULL */
+ if (fSymbols == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+
+ initialize(fLocale, status);
+ if(U_SUCCESS(status)) {
+ initializeDefaultCentury();
+ }
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
+: DateFormat(other),
+ fSymbols(NULL),
+ fGMTFormatters(NULL)
+{
+ *this = other;
+}
+
+//----------------------------------------------------------------------
+
+SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ DateFormat::operator=(other);
+
+ delete fSymbols;
+ fSymbols = NULL;
+
+ if (other.fSymbols)
+ fSymbols = new DateFormatSymbols(*other.fSymbols);
+
+ fDefaultCenturyStart = other.fDefaultCenturyStart;
+ fDefaultCenturyStartYear = other.fDefaultCenturyStartYear;
+ fHaveDefaultCentury = other.fHaveDefaultCentury;
+
+ fPattern = other.fPattern;
+
+ return *this;
+}
+
+//----------------------------------------------------------------------
+
+Format*
+SimpleDateFormat::clone() const
+{
+ return new SimpleDateFormat(*this);
+}
+
+//----------------------------------------------------------------------
+
+UBool
+SimpleDateFormat::operator==(const Format& other) const
+{
+ if (DateFormat::operator==(other)) {
+ // DateFormat::operator== guarantees following cast is safe
+ SimpleDateFormat* that = (SimpleDateFormat*)&other;
+ return (fPattern == that->fPattern &&
+ fSymbols != NULL && // Check for pathological object
+ that->fSymbols != NULL && // Check for pathological object
+ *fSymbols == *that->fSymbols &&
+ fHaveDefaultCentury == that->fHaveDefaultCentury &&
+ fDefaultCenturyStart == that->fDefaultCenturyStart);
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------
+
+void SimpleDateFormat::construct(EStyle timeStyle,
+ EStyle dateStyle,
+ const Locale& locale,
+ UErrorCode& status)
+{
+ // called by several constructors to load pattern data from the resources
+ if (U_FAILURE(status)) return;
+
+ // We will need the calendar to know what type of symbols to load.
+ initializeCalendar(NULL, locale, status);
+ if (U_FAILURE(status)) return;
+
+ CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
+ UResourceBundle *dateTimePatterns = calData.getByKey(gDateTimePatternsTag, status);
+ if (U_FAILURE(status)) return;
+
+ if (ures_getSize(dateTimePatterns) <= kDateTime)
+ {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+
+ setLocaleIDs(ures_getLocaleByType(dateTimePatterns, ULOC_VALID_LOCALE, &status),
+ ures_getLocaleByType(dateTimePatterns, ULOC_ACTUAL_LOCALE, &status));
+
+ // create a symbols object from the locale
+ initializeSymbols(locale,fCalendar, status);
+ if (U_FAILURE(status)) return;
+ /* test for NULL */
+ if (fSymbols == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ const UChar *resStr;
+ int32_t resStrLen = 0;
+
+ // if the pattern should include both date and time information, use the date/time
+ // pattern string as a guide to tell use how to glue together the appropriate date
+ // and time pattern strings. The actual gluing-together is handled by a convenience
+ // method on MessageFormat.
+ if ((timeStyle != kNone) && (dateStyle != kNone))
+ {
+ Formattable timeDateArray[2];
+
+ // use Formattable::adoptString() so that we can use fastCopyFrom()
+ // instead of Formattable::setString()'s unaware, safe, deep string clone
+ // see Jitterbug 2296
+ resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)timeStyle, &resStrLen, &status);
+ timeDateArray[0].adoptString(new UnicodeString(TRUE, resStr, resStrLen));
+ resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)dateStyle, &resStrLen, &status);
+ timeDateArray[1].adoptString(new UnicodeString(TRUE, resStr, resStrLen));
+
+ resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)kDateTime, &resStrLen, &status);
+ MessageFormat::format(UnicodeString(TRUE, resStr, resStrLen), timeDateArray, 2, fPattern, status);
+ }
+ // if the pattern includes just time data or just date date, load the appropriate
+ // pattern string from the resources
+ // setTo() - see DateFormatSymbols::assignArray comments
+ else if (timeStyle != kNone) {
+ resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)timeStyle, &resStrLen, &status);
+ fPattern.setTo(TRUE, resStr, resStrLen);
+ }
+ else if (dateStyle != kNone) {
+ resStr = ures_getStringByIndex(dateTimePatterns, (int32_t)dateStyle, &resStrLen, &status);
+ fPattern.setTo(TRUE, resStr, resStrLen);
+ }
+
+ // and if it includes _neither_, that's an error
+ else
+ status = U_INVALID_FORMAT_ERROR;
+
+ // finally, finish initializing by creating a Calendar and a NumberFormat
+ initialize(locale, status);
+}
+
+//----------------------------------------------------------------------
+
+Calendar*
+SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status)
+{
+ if(!U_FAILURE(status)) {
+ fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status);
+ }
+ if (U_SUCCESS(status) && fCalendar == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return fCalendar;
+}
+
+void
+SimpleDateFormat::initializeSymbols(const Locale& locale, Calendar* calendar, UErrorCode& status)
+{
+ if(U_FAILURE(status)) {
+ fSymbols = NULL;
+ } else {
+ // pass in calendar type - use NULL (default) if no calendar set (or err).
+ fSymbols = new DateFormatSymbols(locale, calendar?calendar->getType() :NULL , status);
+ }
+}
+
+void
+SimpleDateFormat::initialize(const Locale& locale,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status)) return;
+
+ // We don't need to check that the row count is >= 1, since all 2d arrays have at
+ // least one row
+ fNumberFormat = NumberFormat::createInstance(locale, status);
+ if (fNumberFormat != NULL && U_SUCCESS(status))
+ {
+ // no matter what the locale's default number format looked like, we want
+ // to modify it so that it doesn't use thousands separators, doesn't always
+ // show the decimal point, and recognizes integers only when parsing
+
+ fNumberFormat->setGroupingUsed(FALSE);
+ if (fNumberFormat->getDynamicClassID() == DecimalFormat::getStaticClassID())
+ ((DecimalFormat*)fNumberFormat)->setDecimalSeparatorAlwaysShown(FALSE);
+ fNumberFormat->setParseIntegerOnly(TRUE);
+ fNumberFormat->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
+ }
+ else if (U_SUCCESS(status))
+ {
+ status = U_MISSING_RESOURCE_ERROR;
+ }
+}
+
+/* Initialize the fields we use to disambiguate ambiguous years. Separate
+ * so we can call it from readObject().
+ */
+void SimpleDateFormat::initializeDefaultCentury()
+{
+ if(fCalendar) {
+ fHaveDefaultCentury = fCalendar->haveDefaultCentury();
+ if(fHaveDefaultCentury) {
+ fDefaultCenturyStart = fCalendar->defaultCenturyStart();
+ fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear();
+ } else {
+ fDefaultCenturyStart = DBL_MIN;
+ fDefaultCenturyStartYear = -1;
+ }
+ }
+}
+
+/* Define one-century window into which to disambiguate dates using
+ * two-digit years. Make public in JDK 1.2.
+ */
+void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status)
+{
+ if(U_FAILURE(status)) {
+ return;
+ }
+ if(!fCalendar) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ fCalendar->setTime(startDate, status);
+ if(U_SUCCESS(status)) {
+ fHaveDefaultCentury = TRUE;
+ fDefaultCenturyStart = startDate;
+ fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status);
+ }
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ pos.setBeginIndex(0);
+ pos.setEndIndex(0);
+
+ UBool inQuote = FALSE;
+ UChar prevCh = 0;
+ int32_t count = 0;
+
+ // loop through the pattern string character by character
+ for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
+ UChar ch = fPattern[i];
+
+ // Use subFormat() to format a repeated pattern character
+ // when a different pattern or non-pattern character is seen
+ if (ch != prevCh && count > 0) {
+ subFormat(appendTo, prevCh, count, pos, cal, status);
+ count = 0;
+ }
+ if (ch == QUOTE) {
+ // Consecutive single quotes are a single quote literal,
+ // either outside of quotes or between quotes
+ if ((i+1) < fPattern.length() && fPattern[i+1] == QUOTE) {
+ appendTo += (UChar)QUOTE;
+ ++i;
+ } else {
+ inQuote = ! inQuote;
+ }
+ }
+ else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
+ || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
+ // ch is a date-time pattern character to be interpreted
+ // by subFormat(); count the number of times it is repeated
+ prevCh = ch;
+ ++count;
+ }
+ else {
+ // Append quoted characters and unquoted non-pattern characters
+ appendTo += ch;
+ }
+ }
+
+ // Format the last item in the pattern, if any
+ if (count > 0) {
+ subFormat(appendTo, prevCh, count, pos, cal, status);
+ }
+
+ // and if something failed (e.g., an invalid format character), reset our FieldPosition
+ // to (0, 0) to show that
+ // {sfb} look at this later- are these being set correctly?
+ if (U_FAILURE(status)) {
+ pos.setBeginIndex(0);
+ pos.setEndIndex(0);
+ }
+
+ return appendTo;
+}
+
+UnicodeString&
+SimpleDateFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+{
+ // this is just here to get around the hiding problem
+ // (the previous format() override would hide the version of
+ // format() on DateFormat that this function correspond to, so we
+ // have to redefine it here)
+ return DateFormat::format(obj, appendTo, pos, status);
+}
+
+//----------------------------------------------------------------------
+
+// Map index into pattern character string to Calendar field number.
+const UCalendarDateFields
+SimpleDateFormat::fgPatternIndexToCalendarField[] =
+{
+ /*GyM*/ UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
+ /*dkH*/ UCAL_DATE, UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY,
+ /*msS*/ UCAL_MINUTE, UCAL_SECOND, UCAL_MILLISECOND,
+ /*EDF*/ UCAL_DAY_OF_WEEK, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH,
+ /*wWa*/ UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_AM_PM,
+ /*hKz*/ UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET,
+ /*Yeu*/ UCAL_YEAR_WOY, UCAL_DOW_LOCAL, UCAL_EXTENDED_YEAR,
+ /*gAZ*/ UCAL_JULIAN_DAY, UCAL_MILLISECONDS_IN_DAY, UCAL_ZONE_OFFSET,
+ /*v*/ UCAL_ZONE_OFFSET,
+ /*c*/ UCAL_DAY_OF_WEEK,
+ /*L*/ UCAL_MONTH,
+ /*Q*/ UCAL_MONTH,
+ /*q*/ UCAL_MONTH,
+ /*V*/ UCAL_ZONE_OFFSET,
+};
+
+// Map index into pattern character string to DateFormat field number
+const UDateFormatField
+SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
+ /*GyM*/ UDAT_ERA_FIELD, UDAT_YEAR_FIELD, UDAT_MONTH_FIELD,
+ /*dkH*/ UDAT_DATE_FIELD, UDAT_HOUR_OF_DAY1_FIELD, UDAT_HOUR_OF_DAY0_FIELD,
+ /*msS*/ UDAT_MINUTE_FIELD, UDAT_SECOND_FIELD, UDAT_FRACTIONAL_SECOND_FIELD,
+ /*EDF*/ UDAT_DAY_OF_WEEK_FIELD, UDAT_DAY_OF_YEAR_FIELD, UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
+ /*wWa*/ UDAT_WEEK_OF_YEAR_FIELD, UDAT_WEEK_OF_MONTH_FIELD, UDAT_AM_PM_FIELD,
+ /*hKz*/ UDAT_HOUR1_FIELD, UDAT_HOUR0_FIELD, UDAT_TIMEZONE_FIELD,
+ /*Yeu*/ UDAT_YEAR_WOY_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_EXTENDED_YEAR_FIELD,
+ /*gAZ*/ UDAT_JULIAN_DAY_FIELD, UDAT_MILLISECONDS_IN_DAY_FIELD, UDAT_TIMEZONE_RFC_FIELD,
+ /*v*/ UDAT_TIMEZONE_GENERIC_FIELD,
+ /*c*/ UDAT_STANDALONE_DAY_FIELD,
+ /*L*/ UDAT_STANDALONE_MONTH_FIELD,
+ /*Q*/ UDAT_QUARTER_FIELD,
+ /*q*/ UDAT_STANDALONE_QUARTER_FIELD,
+ /*V*/ UDAT_TIMEZONE_SPECIAL_FIELD,
+};
+
+//----------------------------------------------------------------------
+
+/**
+ * Append symbols[value] to dst. Make sure the array index is not out
+ * of bounds.
+ */
+static inline void
+_appendSymbol(UnicodeString& dst,
+ int32_t value,
+ const UnicodeString* symbols,
+ int32_t symbolsCount) {
+ U_ASSERT(0 <= value && value < symbolsCount);
+ if (0 <= value && value < symbolsCount) {
+ dst += symbols[value];
+ }
+}
+
+//---------------------------------------------------------------------
+void
+SimpleDateFormat::appendGMT(UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const{
+ int32_t offset = cal.get(UCAL_ZONE_OFFSET, status) + cal.get(UCAL_DST_OFFSET, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (isDefaultGMTFormat()) {
+ formatGMTDefault(appendTo, offset);
+ } else {
+ ((SimpleDateFormat*)this)->initGMTFormatters(status);
+ if (U_SUCCESS(status)) {
+ int32_t type;
+ if (offset < 0) {
+ offset = -offset;
+ type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTNegativeHM : kGMTNegativeHMS;
+ } else {
+ type = (offset % U_MILLIS_PER_MINUTE) == 0 ? kGMTPositiveHM : kGMTPositiveHMS;
+ }
+ Formattable param(offset, Formattable::kIsDate);
+ FieldPosition fpos(0);
+ fGMTFormatters[type]->format(&param, 1, appendTo, fpos, status);
+ }
+ }
+}
+
+int32_t
+SimpleDateFormat::parseGMT(const UnicodeString &text, ParsePosition &pos) const {
+ if (!isDefaultGMTFormat()) {
+ int32_t start = pos.getIndex();
+
+ // Quick check
+ UBool prefixMatch = FALSE;
+ int32_t prefixLen = fSymbols->fGmtFormat.indexOf((UChar)0x007B /* '{' */);
+ if (prefixLen > 0 && text.compare(start, prefixLen, fSymbols->fGmtFormat, 0, prefixLen) == 0) {
+ prefixMatch = TRUE;
+ }
+ if (prefixMatch) {
+ // Prefix matched
+ UErrorCode status = U_ZERO_ERROR;
+ ((SimpleDateFormat*)this)->initGMTFormatters(status);
+ if (U_SUCCESS(status)) {
+ Formattable parsed;
+ int32_t parsedCount;
+
+ // Try negative Hms
+ fGMTFormatters[kGMTNegativeHMS]->parseObject(text, parsed, pos);
+ if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
+ parsed.getArray(parsedCount);
+ if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
+ return (int32_t)(-1 * parsed[0].getDate());
+ }
+ }
+
+ // Reset ParsePosition
+ pos.setIndex(start);
+ pos.setErrorIndex(-1);
+
+ // Try positive Hms
+ fGMTFormatters[kGMTPositiveHMS]->parseObject(text, parsed, pos);
+ if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
+ parsed.getArray(parsedCount);
+ if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
+ return (int32_t)parsed[0].getDate();
+ }
+ }
+
+ // Reset ParsePosition
+ pos.setIndex(start);
+ pos.setErrorIndex(-1);
+
+ // Try negative Hm
+ fGMTFormatters[kGMTNegativeHM]->parseObject(text, parsed, pos);
+ if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
+ parsed.getArray(parsedCount);
+ if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
+ return (int32_t)(-1 * parsed[0].getDate());
+ }
+ }
+
+ // Reset ParsePosition
+ pos.setIndex(start);
+ pos.setErrorIndex(-1);
+
+ // Try positive Hm
+ fGMTFormatters[kGMTPositiveHM]->parseObject(text, parsed, pos);
+ if (pos.getErrorIndex() == -1 && pos.getIndex() > start) {
+ parsed.getArray(parsedCount);
+ if (parsedCount == 1 && parsed[0].getType() == Formattable::kDate) {
+ return (int32_t)parsed[0].getDate();
+ }
+ }
+
+ // Reset ParsePosition
+ pos.setIndex(start);
+ pos.setErrorIndex(-1);
+ }
+ // fall through to the default GMT parsing method
+ }
+ }
+ return parseGMTDefault(text, pos);
+}
+
+void
+SimpleDateFormat::formatGMTDefault(UnicodeString &appendTo, int32_t offset) const {
+ if (offset < 0) {
+ appendTo += gGmtMinus;
+ offset = -offset; // suppress the '-' sign for text display.
+ }else{
+ appendTo += gGmtPlus;
+ }
+
+ offset /= U_MILLIS_PER_SECOND; // now in seconds
+ int32_t sec = offset % 60;
+ offset /= 60;
+ int32_t min = offset % 60;
+ int32_t hour = offset / 60;
+
+
+ zeroPaddingNumber(appendTo, hour, 2, 2);
+ appendTo += (UChar)0x003A /*':'*/;
+ zeroPaddingNumber(appendTo, min, 2, 2);
+ if (sec != 0) {
+ appendTo += (UChar)0x003A /*':'*/;
+ zeroPaddingNumber(appendTo, sec, 2, 2);
+ }
+}
+
+int32_t
+SimpleDateFormat::parseGMTDefault(const UnicodeString &text, ParsePosition &pos) const {
+ int32_t start = pos.getIndex();
+
+ if (start + kGmtLen + 1 >= text.length()) {
+ pos.setErrorIndex(start);
+ return 0;
+ }
+
+ int32_t cur = start;
+ // "GMT"
+ if (text.compare(start, kGmtLen, gGmt) != 0) {
+ pos.setErrorIndex(start);
+ return 0;
+ }
+ cur += kGmtLen;
+ // Sign
+ UBool negative = FALSE;
+ if (text.charAt(cur) == (UChar)0x002D /* minus */) {
+ negative = TRUE;
+ } else if (text.charAt(cur) != (UChar)0x002B /* plus */) {
+ pos.setErrorIndex(cur);
+ return 0;
+ }
+ cur++;
+
+ // Numbers
+ int32_t numLen;
+ pos.setIndex(cur);
+
+ Formattable number;
+ parseInt(text, number, 6, pos, FALSE);
+ numLen = pos.getIndex() - cur;
+
+ if (numLen <= 0) {
+ pos.setIndex(start);
+ pos.setErrorIndex(cur);
+ return 0;
+ }
+
+ int32_t numVal = number.getLong();
+
+ int32_t hour = 0;
+ int32_t min = 0;
+ int32_t sec = 0;
+
+ if (numLen <= 2) {
+ // H[H][:mm[:ss]]
+ hour = numVal;
+ cur += numLen;
+ if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
+ cur++;
+ pos.setIndex(cur);
+ parseInt(text, number, 2, pos, FALSE);
+ numLen = pos.getIndex() - cur;
+ if (numLen == 2) {
+ // got minute field
+ min = number.getLong();
+ cur += numLen;
+ if (cur + 2 < text.length() && text.charAt(cur) == (UChar)0x003A /* colon */) {
+ cur++;
+ pos.setIndex(cur);
+ parseInt(text, number, 2, pos, FALSE);
+ numLen = pos.getIndex() - cur;
+ if (numLen == 2) {
+ // got second field
+ sec = number.getLong();
+ } else {
+ // reset position
+ pos.setIndex(cur - 1);
+ pos.setErrorIndex(-1);
+ }
+ }
+ } else {
+ // reset postion
+ pos.setIndex(cur - 1);
+ pos.setErrorIndex(-1);
+ }
+ }
+ } else if (numLen == 3 || numLen == 4) {
+ // Hmm or HHmm
+ hour = numVal / 100;
+ min = numVal % 100;
+ } else if (numLen == 5 || numLen == 6) {
+ // Hmmss or HHmmss
+ hour = numVal / 10000;
+ min = (numVal % 10000) / 100;
+ sec = numVal % 100;
+ } else {
+ // HHmmss followed by bogus numbers
+ pos.setIndex(cur + 6);
+
+ int32_t shift = numLen - 6;
+ while (shift > 0) {
+ numVal /= 10;
+ shift--;
+ }
+ hour = numVal / 10000;
+ min = (numVal % 10000) / 100;
+ sec = numVal % 100;
+ }
+
+ int32_t offset = ((hour*60 + min)*60 + sec)*1000;
+ if (negative) {
+ offset = -offset;
+ }
+ return offset;
+}
+
+UBool
+SimpleDateFormat::isDefaultGMTFormat() const {
+ // GMT pattern
+ if (fSymbols->fGmtFormat.length() == 0) {
+ // No GMT pattern is set
+ return TRUE;
+ } else if (fSymbols->fGmtFormat.compare(gDefGmtPat, kGmtPatLen) != 0) {
+ return FALSE;
+ }
+ // Hour patterns
+ if (fSymbols->fGmtHourFormats == NULL || fSymbols->fGmtHourFormatsCount != DateFormatSymbols::GMT_HOUR_COUNT) {
+ // No Hour pattern is set
+ return TRUE;
+ } else if ((fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HMS].compare(gDefGmtNegHmsPat, kNegHmsLen) != 0)
+ || (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HM].compare(gDefGmtNegHmPat, kNegHmLen) != 0)
+ || (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HMS].compare(gDefGmtPosHmsPat, kPosHmsLen) != 0)
+ || (fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HM].compare(gDefGmtPosHmPat, kPosHmLen) != 0)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void
+SimpleDateFormat::formatRFC822TZ(UnicodeString &appendTo, int32_t offset) const {
+ UChar sign = 0x002B /* '+' */;
+ if (offset < 0) {
+ offset = -offset;
+ sign = 0x002D /* '-' */;
+ }
+ appendTo.append(sign);
+
+ int32_t offsetH = offset / U_MILLIS_PER_HOUR;
+ offset = offset % U_MILLIS_PER_HOUR;
+ int32_t offsetM = offset / U_MILLIS_PER_MINUTE;
+ offset = offset % U_MILLIS_PER_MINUTE;
+ int32_t offsetS = offset / U_MILLIS_PER_SECOND;
+
+ int32_t num = 0, denom = 0;
+ if (offsetS == 0) {
+ offset = offsetH*100 + offsetM; // HHmm
+ num = offset % 10000;
+ denom = 1000;
+ } else {
+ offset = offsetH*10000 + offsetM*100 + offsetS; // HHmmss
+ num = offset % 1000000;
+ denom = 100000;
+ }
+ while (denom >= 1) {
+ UChar digit = (UChar)0x0030 + (num / denom);
+ appendTo.append(digit);
+ num = num % denom;
+ denom /= 10;
+ }
+}
+
+void
+SimpleDateFormat::initGMTFormatters(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ umtx_lock(&LOCK);
+ if (fGMTFormatters == NULL) {
+ fGMTFormatters = (MessageFormat**)uprv_malloc(kNumGMTFormatters * sizeof(MessageFormat*));
+ if (fGMTFormatters) {
+ for (int32_t i = 0; i < kNumGMTFormatters; i++) {
+ const UnicodeString *hourPattern;
+ switch (i) {
+ case kGMTNegativeHMS:
+ hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HMS]);
+ break;
+ case kGMTNegativeHM:
+ hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_NEGATIVE_HM]);
+ break;
+ case kGMTPositiveHMS:
+ hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HMS]);
+ break;
+ case kGMTPositiveHM:
+ hourPattern = &(fSymbols->fGmtHourFormats[DateFormatSymbols::GMT_POSITIVE_HM]);
+ break;
+ }
+ fGMTFormatters[i] = new MessageFormat(fSymbols->fGmtFormat, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ SimpleDateFormat *sdf = (SimpleDateFormat*)this->clone();
+ sdf->adoptTimeZone(TimeZone::createTimeZone(UnicodeString(gEtcUTC)));
+ sdf->applyPattern(*hourPattern);
+ fGMTFormatters[i]->adoptFormat(0, sdf);
+ }
+ } else {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ umtx_unlock(&LOCK);
+}
+
+//---------------------------------------------------------------------
+void
+SimpleDateFormat::subFormat(UnicodeString &appendTo,
+ UChar ch,
+ int32_t count,
+ FieldPosition& pos,
+ Calendar& cal,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // this function gets called by format() to produce the appropriate substitution
+ // text for an individual pattern symbol (e.g., "HH" or "yyyy")
+
+ UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
+ UDateFormatField patternCharIndex;
+ const int32_t maxIntCount = 10;
+ int32_t beginOffset = appendTo.length();
+
+ // if the pattern character is unrecognized, signal an error and dump out
+ if (patternCharPtr == NULL)
+ {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+
+ patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
+ UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
+ int32_t value = cal.get(field, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ switch (patternCharIndex) {
+
+ // for any "G" symbol, write out the appropriate era string
+ // "GGGG" is wide era name, anything else is abbreviated name
+ case UDAT_ERA_FIELD:
+ if (count >= 4)
+ _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
+ else
+ _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
+ break;
+
+ // for "yyyy", write out the whole year; for "yy", write out the last 2 digits
+ case UDAT_YEAR_FIELD:
+ case UDAT_YEAR_WOY_FIELD:
+ if (count >= 4)
+ zeroPaddingNumber(appendTo, value, 4, maxIntCount);
+ else if(count == 1)
+ zeroPaddingNumber(appendTo, value, count, maxIntCount);
+ else
+ zeroPaddingNumber(appendTo, value, 2, 2);
+ break; // TODO: this needs to be synced with Java, with GCL/Shanghai's work
+
+ // for "MMMM", write out the whole month name, for "MMM", write out the month
+ // abbreviation, for "M" or "MM", write out the month as a number with the
+ // appropriate number of digits
+ // for "MMMMM", use the narrow form
+ case UDAT_MONTH_FIELD:
+ if (count == 5)
+ _appendSymbol(appendTo, value, fSymbols->fNarrowMonths,
+ fSymbols->fNarrowMonthsCount);
+ else if (count == 4)
+ _appendSymbol(appendTo, value, fSymbols->fMonths,
+ fSymbols->fMonthsCount);
+ else if (count == 3)
+ _appendSymbol(appendTo, value, fSymbols->fShortMonths,
+ fSymbols->fShortMonthsCount);
+ else
+ zeroPaddingNumber(appendTo, value + 1, count, maxIntCount);
+ break;
+
+ // for "LLLL", write out the whole month name, for "LLL", write out the month
+ // abbreviation, for "L" or "LL", write out the month as a number with the
+ // appropriate number of digits
+ // for "LLLLL", use the narrow form
+ case UDAT_STANDALONE_MONTH_FIELD:
+ if (count == 5)
+ _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowMonths,
+ fSymbols->fStandaloneNarrowMonthsCount);
+ else if (count == 4)
+ _appendSymbol(appendTo, value, fSymbols->fStandaloneMonths,
+ fSymbols->fStandaloneMonthsCount);
+ else if (count == 3)
+ _appendSymbol(appendTo, value, fSymbols->fStandaloneShortMonths,
+ fSymbols->fStandaloneShortMonthsCount);
+ else
+ zeroPaddingNumber(appendTo, value + 1, count, maxIntCount);
+ break;
+
+ // for "k" and "kk", write out the hour, adjusting midnight to appear as "24"
+ case UDAT_HOUR_OF_DAY1_FIELD:
+ if (value == 0)
+ zeroPaddingNumber(appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
+ else
+ zeroPaddingNumber(appendTo, value, count, maxIntCount);
+ break;
+
+ case UDAT_FRACTIONAL_SECOND_FIELD:
+ // Fractional seconds left-justify
+ {
+ fNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count);
+ fNumberFormat->setMaximumIntegerDigits(maxIntCount);
+ if (count == 1) {
+ value = (value + 50) / 100;
+ } else if (count == 2) {
+ value = (value + 5) / 10;
+ }
+ FieldPosition p(0);
+ fNumberFormat->format(value, appendTo, p);
+ if (count > 3) {
+ fNumberFormat->setMinimumIntegerDigits(count - 3);
+ fNumberFormat->format((int32_t)0, appendTo, p);
+ }
+ }
+ break;
+
+ // for "EEE", write out the abbreviated day-of-the-week name
+ // for "EEEE", write out the wide day-of-the-week name
+ // for "EEEEE", use the narrow day-of-the-week name
+ case UDAT_DAY_OF_WEEK_FIELD:
+ if (count == 5)
+ _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,
+ fSymbols->fNarrowWeekdaysCount);
+ else if (count == 4)
+ _appendSymbol(appendTo, value, fSymbols->fWeekdays,
+ fSymbols->fWeekdaysCount);
+ else
+ _appendSymbol(appendTo, value, fSymbols->fShortWeekdays,
+ fSymbols->fShortWeekdaysCount);
+ break;
+
+ // for "ccc", write out the abbreviated day-of-the-week name
+ // for "cccc", write out the wide day-of-the-week name
+ // for "ccccc", use the narrow day-of-the-week name
+ case UDAT_STANDALONE_DAY_FIELD:
+ if (count == 5)
+ _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays,
+ fSymbols->fStandaloneNarrowWeekdaysCount);
+ else if (count == 4)
+ _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,
+ fSymbols->fStandaloneWeekdaysCount);
+ else if (count == 3)
+ _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays,
+ fSymbols->fStandaloneShortWeekdaysCount);
+ else
+ zeroPaddingNumber(appendTo, value, 1, maxIntCount);
+ break;
+
+ // for and "a" symbol, write out the whole AM/PM string
+ case UDAT_AM_PM_FIELD:
+ _appendSymbol(appendTo, value, fSymbols->fAmPms,
+ fSymbols->fAmPmsCount);
+ break;
+
+ // for "h" and "hh", write out the hour, adjusting noon and midnight to show up
+ // as "12"
+ case UDAT_HOUR1_FIELD:
+ if (value == 0)
+ zeroPaddingNumber(appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
+ else
+ zeroPaddingNumber(appendTo, value, count, maxIntCount);
+ break;
+
+ // for the "z" symbols, we have to check our time zone data first. If we have a
+ // localized name for the time zone, then "zzzz" / "zzz" indicate whether
+ // daylight time is in effect (long/short) and "zz" / "z" do not (long/short).
+ // If we don't have a localized time zone name,
+ // then the time zone shows up as "GMT+hh:mm" or "GMT-hh:mm" (where "hh:mm" is the
+ // offset from GMT) regardless of how many z's were in the pattern symbol
+ case UDAT_TIMEZONE_FIELD:
+ case UDAT_TIMEZONE_GENERIC_FIELD:
+ case UDAT_TIMEZONE_SPECIAL_FIELD:
+ {
+ UnicodeString zoneString;
+ const ZoneStringFormat *zsf = fSymbols->getZoneStringFormat();
+ if (zsf) {
+ if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
+ if (count < 4) {
+ // "z", "zz", "zzz"
+ zsf->getSpecificShortString(cal, TRUE /*commonly used only*/,
+ zoneString, status);
+ } else {
+ // "zzzz"
+ zsf->getSpecificLongString(cal, zoneString, status);
+ }
+ } else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
+ if (count == 1) {
+ // "v"
+ zsf->getGenericShortString(cal, TRUE /*commonly used only*/,
+ zoneString, status);
+ } else if (count == 4) {
+ // "vvvv"
+ zsf->getGenericLongString(cal, zoneString, status);
+ }
+ } else { // patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD
+ if (count == 1) {
+ // "V"
+ zsf->getSpecificShortString(cal, FALSE /*ignore commonly used*/,
+ zoneString, status);
+ } else if (count == 4) {
+ // "VVVV"
+ zsf->getGenericLocationString(cal, zoneString, status);
+ }
+ }
+ }
+ if (zoneString.isEmpty()) {
+ appendGMT(appendTo, cal, status);
+ } else {
+ appendTo += zoneString;
+ }
+ }
+ break;
+
+ case UDAT_TIMEZONE_RFC_FIELD: // 'Z' - TIMEZONE_RFC
+ if (count < 4) {
+ // RFC822 format, must use ASCII digits
+ value = (cal.get(UCAL_ZONE_OFFSET, status) + cal.get(UCAL_DST_OFFSET, status));
+ formatRFC822TZ(appendTo, value);
+ } else {
+ // long form, localized GMT pattern
+ appendGMT(appendTo, cal, status);
+ }
+ break;
+
+ case UDAT_QUARTER_FIELD:
+ if (count >= 4)
+ _appendSymbol(appendTo, value/3, fSymbols->fQuarters,
+ fSymbols->fQuartersCount);
+ else if (count == 3)
+ _appendSymbol(appendTo, value/3, fSymbols->fShortQuarters,
+ fSymbols->fShortQuartersCount);
+ else
+ zeroPaddingNumber(appendTo, (value/3) + 1, count, maxIntCount);
+ break;
+
+ case UDAT_STANDALONE_QUARTER_FIELD:
+ if (count >= 4)
+ _appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters,
+ fSymbols->fStandaloneQuartersCount);
+ else if (count == 3)
+ _appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters,
+ fSymbols->fStandaloneShortQuartersCount);
+ else
+ zeroPaddingNumber(appendTo, (value/3) + 1, count, maxIntCount);
+ break;
+
+
+ // all of the other pattern symbols can be formatted as simple numbers with
+ // appropriate zero padding
+ default:
+ zeroPaddingNumber(appendTo, value, count, maxIntCount);
+ break;
+ }
+
+ // if the field we're formatting is the one the FieldPosition says it's interested
+ // in, fill in the FieldPosition with this field's positions
+ if (pos.getBeginIndex() == pos.getEndIndex() &&
+ pos.getField() == fgPatternIndexToDateFormatField[patternCharIndex]) {
+ pos.setBeginIndex(beginOffset);
+ pos.setEndIndex(appendTo.length());
+ }
+}
+
+//----------------------------------------------------------------------
+void
+SimpleDateFormat::zeroPaddingNumber(UnicodeString &appendTo, int32_t value, int32_t minDigits, int32_t maxDigits) const
+{
+ FieldPosition pos(0);
+
+ fNumberFormat->setMinimumIntegerDigits(minDigits);
+ fNumberFormat->setMaximumIntegerDigits(maxDigits);
+ fNumberFormat->format(value, appendTo, pos); // 3rd arg is there to speed up processing
+}
+
+//----------------------------------------------------------------------
+
+/**
+ * Format characters that indicate numeric fields. The character
+ * at index 0 is treated specially.
+ */
+static const UChar NUMERIC_FORMAT_CHARS[] = {0x4D, 0x79, 0x75, 0x64, 0x68, 0x48, 0x6D, 0x73, 0x53, 0x44, 0x46, 0x77, 0x57, 0x6B, 0x4B, 0x00}; /* "MyudhHmsSDFwWkK" */
+
+/**
+ * Return true if the given format character, occuring count
+ * times, represents a numeric field.
+ */
+UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) {
+ UnicodeString s(NUMERIC_FORMAT_CHARS);
+ int32_t i = s.indexOf(formatChar);
+ return (i > 0 || (i == 0 && count < 3));
+}
+
+void
+SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const
+{
+ int32_t pos = parsePos.getIndex();
+ int32_t start = pos;
+ UBool ambiguousYear[] = { FALSE };
+ int32_t count = 0;
+
+ // hack, reset tztype, cast away const
+ ((SimpleDateFormat*)this)->tztype = TZTYPE_UNK;
+
+ // For parsing abutting numeric fields. 'abutPat' is the
+ // offset into 'pattern' of the first of 2 or more abutting
+ // numeric fields. 'abutStart' is the offset into 'text'
+ // where parsing the fields begins. 'abutPass' starts off as 0
+ // and increments each time we try to parse the fields.
+ int32_t abutPat = -1; // If >=0, we are in a run of abutting numeric fields
+ int32_t abutStart = 0;
+ int32_t abutPass = 0;
+ UBool inQuote = FALSE;
+
+ const UnicodeString numericFormatChars(NUMERIC_FORMAT_CHARS);
+
+ for (int32_t i=0; i<fPattern.length(); ++i) {
+ UChar ch = fPattern.charAt(i);
+
+ // Handle alphabetic field characters.
+ if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // [A-Za-z]
+ int32_t fieldPat = i;
+
+ // Count the length of this field specifier
+ count = 1;
+ while ((i+1)<fPattern.length() &&
+ fPattern.charAt(i+1) == ch) {
+ ++count;
+ ++i;
+ }
+
+ if (isNumeric(ch, count)) {
+ if (abutPat < 0) {
+ // Determine if there is an abutting numeric field. For
+ // most fields we can just look at the next characters,
+ // but the 'm' field is either numeric or text,
+ // depending on the count, so we have to look ahead for
+ // that field.
+ if ((i+1)<fPattern.length()) {
+ UBool abutting;
+ UChar nextCh = fPattern.charAt(i+1);
+ int32_t k = numericFormatChars.indexOf(nextCh);
+ if (k == 0) {
+ int32_t j = i+2;
+ while (j<fPattern.length() &&
+ fPattern.charAt(j) == nextCh) {
+ ++j;
+ }
+ abutting = (j-i) < 4; // nextCount < 3
+ } else {
+ abutting = k > 0;
+ }
+
+ // Record the start of a set of abutting numeric
+ // fields.
+ if (abutting) {
+ abutPat = fieldPat;
+ abutStart = pos;
+ abutPass = 0;
+ }
+ }
+ }
+ } else {
+ abutPat = -1; // End of any abutting fields
+ }
+
+ // Handle fields within a run of abutting numeric fields. Take
+ // the pattern "HHmmss" as an example. We will try to parse
+ // 2/2/2 characters of the input text, then if that fails,
+ // 1/2/2. We only adjust the width of the leftmost field; the
+ // others remain fixed. This allows "123456" => 12:34:56, but
+ // "12345" => 1:23:45. Likewise, for the pattern "yyyyMMdd" we
+ // try 4/2/2, 3/2/2, 2/2/2, and finally 1/2/2.
+ if (abutPat >= 0) {
+ // If we are at the start of a run of abutting fields, then
+ // shorten this field in each pass. If we can't shorten
+ // this field any more, then the parse of this set of
+ // abutting numeric fields has failed.
+ if (fieldPat == abutPat) {
+ count -= abutPass++;
+ if (count == 0) {
+ parsePos.setIndex(start);
+ parsePos.setErrorIndex(pos);
+ return;
+ }
+ }
+
+ pos = subParse(text, pos, ch, count,
+ TRUE, FALSE, ambiguousYear, cal);
+
+ // If the parse fails anywhere in the run, back up to the
+ // start of the run and retry.
+ if (pos < 0) {
+ i = abutPat - 1;
+ pos = abutStart;
+ continue;
+ }
+ }
+
+ // Handle non-numeric fields and non-abutting numeric
+ // fields.
+ else {
+ int32_t s = pos;
+ pos = subParse(text, pos, ch, count,
+ FALSE, TRUE, ambiguousYear, cal);
+
+ if (pos < 0) {
+ parsePos.setErrorIndex(s);
+ parsePos.setIndex(start);
+ return;
+ }
+ }
+ }
+
+ // Handle literal pattern characters. These are any
+ // quoted characters and non-alphabetic unquoted
+ // characters.
+ else {
+
+ abutPat = -1; // End of any abutting fields
+
+ // Handle quotes. Two consecutive quotes is a quote
+ // literal, inside or outside of quotes. Otherwise a
+ // quote indicates entry or exit from a quoted region.
+ if (ch == QUOTE) {
+ // Match a quote literal '' within OR outside of quotes
+ if ((i+1)<fPattern.length() && fPattern.charAt(i+1)==ch) {
+ ++i; // Skip over doubled quote
+ // Fall through and treat quote as a literal
+ } else {
+ // Enter or exit quoted region
+ inQuote = !inQuote;
+ continue;
+ }
+ }
+
+ // A run of white space in the pattern matches a run
+ // of white space in the input text.
+ if (uprv_isRuleWhiteSpace(ch)) {
+ // Advance over run in pattern
+ while ((i+1)<fPattern.length() &&
+ uprv_isRuleWhiteSpace(fPattern.charAt(i+1))) {
+ ++i;
+ }
+
+ // Advance over run in input text
+ int32_t s = pos;
+ while (pos<text.length() &&
+ ( u_isUWhiteSpace(text.charAt(pos)) || uprv_isRuleWhiteSpace(text.charAt(pos)))) {
+ ++pos;
+ }
+
+ // Must see at least one white space char in input
+ if (pos > s) {
+ continue;
+ }
+ } else if (pos<text.length() && text.charAt(pos)==ch) {
+ // Match a literal
+ ++pos;
+ continue;
+ }
+
+ // We fall through to this point if the match fails
+ parsePos.setIndex(start);
+ parsePos.setErrorIndex(pos);
+ return;
+ }
+ }
+
+ // At this point the fields of Calendar have been set. Calendar
+ // will fill in default values for missing fields when the time
+ // is computed.
+
+ parsePos.setIndex(pos);
+
+ // This part is a problem: When we call parsedDate.after, we compute the time.
+ // Take the date April 3 2004 at 2:30 am. When this is first set up, the year
+ // will be wrong if we're parsing a 2-digit year pattern. It will be 1904.
+ // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day. 2:30 am
+ // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am
+ // on that day. It is therefore parsed out to fields as 3:30 am. Then we
+ // add 100 years, and get April 3 2004 at 3:30 am. Note that April 3 2004 is
+ // a Saturday, so it can have a 2:30 am -- and it should. [LIU]
+ /*
+ UDate parsedDate = calendar.getTime();
+ if( ambiguousYear[0] && !parsedDate.after(fDefaultCenturyStart) ) {
+ calendar.add(Calendar.YEAR, 100);
+ parsedDate = calendar.getTime();
+ }
+ */
+ // Because of the above condition, save off the fields in case we need to readjust.
+ // The procedure we use here is not particularly efficient, but there is no other
+ // way to do this given the API restrictions present in Calendar. We minimize
+ // inefficiency by only performing this computation when it might apply, that is,
+ // when the two-digit year is equal to the start year, and thus might fall at the
+ // front or the back of the default century. This only works because we adjust
+ // the year correctly to start with in other cases -- see subParse().
+ UErrorCode status = U_ZERO_ERROR;
+ if (ambiguousYear[0] || tztype != TZTYPE_UNK) // If this is true then the two-digit year == the default start year
+ {
+ // We need a copy of the fields, and we need to avoid triggering a call to
+ // complete(), which will recalculate the fields. Since we can't access
+ // the fields[] array in Calendar, we clone the entire object. This will
+ // stop working if Calendar.clone() is ever rewritten to call complete().
+ Calendar *copy;
+ if (ambiguousYear[0]) {
+ copy = cal.clone();
+ UDate parsedDate = copy->getTime(status);
+ // {sfb} check internalGetDefaultCenturyStart
+ if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) {
+ // We can't use add here because that does a complete() first.
+ cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100);
+ }
+ delete copy;
+ }
+
+ if (tztype != TZTYPE_UNK) {
+ copy = cal.clone();
+ const TimeZone & tz = cal.getTimeZone();
+ BasicTimeZone *btz = NULL;
+
+ if (tz.getDynamicClassID() == OlsonTimeZone::getStaticClassID()
+ || tz.getDynamicClassID() == SimpleTimeZone::getStaticClassID()
+ || tz.getDynamicClassID() == RuleBasedTimeZone::getStaticClassID()
+ || tz.getDynamicClassID() == VTimeZone::getStaticClassID()) {
+ btz = (BasicTimeZone*)&tz;
+ }
+
+ // Get local millis
+ copy->set(UCAL_ZONE_OFFSET, 0);
+ copy->set(UCAL_DST_OFFSET, 0);
+ UDate localMillis = copy->getTime(status);
+
+ // Make sure parsed time zone type (Standard or Daylight)
+ // matches the rule used by the parsed time zone.
+ int32_t raw, dst;
+ if (btz != NULL) {
+ if (tztype == TZTYPE_STD) {
+ btz->getOffsetFromLocal(localMillis,
+ BasicTimeZone::kStandard, BasicTimeZone::kStandard, raw, dst, status);
+ } else {
+ btz->getOffsetFromLocal(localMillis,
+ BasicTimeZone::kDaylight, BasicTimeZone::kDaylight, raw, dst, status);
+ }
+ } else {
+ // No good way to resolve ambiguous time at transition,
+ // but following code work in most case.
+ tz.getOffset(localMillis, TRUE, raw, dst, status);
+ }
+
+ // Now, compare the results with parsed type, either standard or daylight saving time
+ int32_t resolvedSavings = dst;
+ if (tztype == TZTYPE_STD) {
+ if (dst != 0) {
+ // Override DST_OFFSET = 0 in the result calendar
+ resolvedSavings = 0;
+ }
+ } else { // tztype == TZTYPE_DST
+ if (dst == 0) {
+ if (btz != NULL) {
+ UDate time = localMillis + raw;
+ // We use the nearest daylight saving time rule.
+ TimeZoneTransition beforeTrs, afterTrs;
+ UDate beforeT = time, afterT = time;
+ int32_t beforeSav = 0, afterSav = 0;
+ UBool beforeTrsAvail, afterTrsAvail;
+
+ // Search for DST rule before or on the time
+ while (TRUE) {
+ beforeTrsAvail = btz->getPreviousTransition(beforeT, TRUE, beforeTrs);
+ if (!beforeTrsAvail) {
+ break;
+ }
+ beforeT = beforeTrs.getTime() - 1;
+ beforeSav = beforeTrs.getFrom()->getDSTSavings();
+ if (beforeSav != 0) {
+ break;
+ }
+ }
+
+ // Search for DST rule after the time
+ while (TRUE) {
+ afterTrsAvail = btz->getNextTransition(afterT, FALSE, afterTrs);
+ if (!afterTrsAvail) {
+ break;
+ }
+ afterT = afterTrs.getTime();
+ afterSav = afterTrs.getTo()->getDSTSavings();
+ if (afterSav != 0) {
+ break;
+ }
+ }
+
+ if (beforeTrsAvail && afterTrsAvail) {
+ if (time - beforeT > afterT - time) {
+ resolvedSavings = afterSav;
+ } else {
+ resolvedSavings = beforeSav;
+ }
+ } else if (beforeTrsAvail && beforeSav != 0) {
+ resolvedSavings = beforeSav;
+ } else if (afterTrsAvail && afterSav != 0) {
+ resolvedSavings = afterSav;
+ } else {
+ resolvedSavings = btz->getDSTSavings();
+ }
+ } else {
+ resolvedSavings = tz.getDSTSavings();
+ }
+ if (resolvedSavings == 0) {
+ // final fallback
+ resolvedSavings = U_MILLIS_PER_HOUR;
+ }
+ }
+ }
+ cal.set(UCAL_ZONE_OFFSET, raw);
+ cal.set(UCAL_DST_OFFSET, resolvedSavings);
+ delete copy;
+ }
+ }
+
+ // If any Calendar calls failed, we pretend that we
+ // couldn't parse the string, when in reality this isn't quite accurate--
+ // we did parse it; the Calendar calls just failed.
+ if (U_FAILURE(status)) {
+ parsePos.setErrorIndex(pos);
+ parsePos.setIndex(start);
+ }
+}
+
+UDate
+SimpleDateFormat::parse( const UnicodeString& text,
+ ParsePosition& pos) const {
+ // redefined here because the other parse() function hides this function's
+ // cunterpart on DateFormat
+ return DateFormat::parse(text, pos);
+}
+
+UDate
+SimpleDateFormat::parse(const UnicodeString& text, UErrorCode& status) const
+{
+ // redefined here because the other parse() function hides this function's
+ // counterpart on DateFormat
+ return DateFormat::parse(text, status);
+}
+//----------------------------------------------------------------------
+
+int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
+ int32_t start,
+ UCalendarDateFields field,
+ const UnicodeString* data,
+ int32_t dataCount,
+ Calendar& cal) const
+{
+ int32_t i = 0;
+ int32_t count = dataCount;
+
+ // There may be multiple strings in the data[] array which begin with
+ // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
+ // We keep track of the longest match, and return that. Note that this
+ // unfortunately requires us to test all array elements.
+ int32_t bestMatchLength = 0, bestMatch = -1;
+
+ // {sfb} kludge to support case-insensitive comparison
+ // {markus 2002oct11} do not just use caseCompareBetween because we do not know
+ // the length of the match after case folding
+ // {alan 20040607} don't case change the whole string, since the length
+ // can change
+ // TODO we need a case-insensitive startsWith function
+ UnicodeString lcase, lcaseText;
+ text.extract(start, INT32_MAX, lcaseText);
+ lcaseText.foldCase();
+
+ for (; i < count; ++i)
+ {
+ // Always compare if we have no match yet; otherwise only compare
+ // against potentially better matches (longer strings).
+
+ lcase.fastCopyFrom(data[i]).foldCase();
+ int32_t length = lcase.length();
+
+ if (length > bestMatchLength &&
+ lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
+ {
+ bestMatch = i;
+ bestMatchLength = length;
+ }
+ }
+ if (bestMatch >= 0)
+ {
+ cal.set(field, bestMatch * 3);
+
+ // Once we have a match, we have to determine the length of the
+ // original source string. This will usually be == the length of
+ // the case folded string, but it may differ (e.g. sharp s).
+ lcase.fastCopyFrom(data[bestMatch]).foldCase();
+
+ // Most of the time, the length will be the same as the length
+ // of the string from the locale data. Sometimes it will be
+ // different, in which case we will have to figure it out by
+ // adding a character at a time, until we have a match. We do
+ // this all in one loop, where we try 'len' first (at index
+ // i==0).
+ int32_t len = data[bestMatch].length(); // 99+% of the time
+ int32_t n = text.length() - start;
+ for (i=0; i<=n; ++i) {
+ int32_t j=i;
+ if (i == 0) {
+ j = len;
+ } else if (i == len) {
+ continue; // already tried this when i was 0
+ }
+ text.extract(start, j, lcaseText);
+ lcaseText.foldCase();
+ if (lcase == lcaseText) {
+ return start + j;
+ }
+ }
+ }
+
+ return -start;
+}
+
+//----------------------------------------------------------------------
+
+int32_t SimpleDateFormat::matchString(const UnicodeString& text,
+ int32_t start,
+ UCalendarDateFields field,
+ const UnicodeString* data,
+ int32_t dataCount,
+ Calendar& cal) const
+{
+ int32_t i = 0;
+ int32_t count = dataCount;
+
+ if (field == UCAL_DAY_OF_WEEK) i = 1;
+
+ // There may be multiple strings in the data[] array which begin with
+ // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
+ // We keep track of the longest match, and return that. Note that this
+ // unfortunately requires us to test all array elements.
+ int32_t bestMatchLength = 0, bestMatch = -1;
+
+ // {sfb} kludge to support case-insensitive comparison
+ // {markus 2002oct11} do not just use caseCompareBetween because we do not know
+ // the length of the match after case folding
+ // {alan 20040607} don't case change the whole string, since the length
+ // can change
+ // TODO we need a case-insensitive startsWith function
+ UnicodeString lcase, lcaseText;
+ text.extract(start, INT32_MAX, lcaseText);
+ lcaseText.foldCase();
+
+ for (; i < count; ++i)
+ {
+ // Always compare if we have no match yet; otherwise only compare
+ // against potentially better matches (longer strings).
+
+ lcase.fastCopyFrom(data[i]).foldCase();
+ int32_t length = lcase.length();
+
+ if (length > bestMatchLength &&
+ lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
+ {
+ bestMatch = i;
+ bestMatchLength = length;
+ }
+ }
+ if (bestMatch >= 0)
+ {
+ cal.set(field, bestMatch);
+
+ // Once we have a match, we have to determine the length of the
+ // original source string. This will usually be == the length of
+ // the case folded string, but it may differ (e.g. sharp s).
+ lcase.fastCopyFrom(data[bestMatch]).foldCase();
+
+ // Most of the time, the length will be the same as the length
+ // of the string from the locale data. Sometimes it will be
+ // different, in which case we will have to figure it out by
+ // adding a character at a time, until we have a match. We do
+ // this all in one loop, where we try 'len' first (at index
+ // i==0).
+ int32_t len = data[bestMatch].length(); // 99+% of the time
+ int32_t n = text.length() - start;
+ for (i=0; i<=n; ++i) {
+ int32_t j=i;
+ if (i == 0) {
+ j = len;
+ } else if (i == len) {
+ continue; // already tried this when i was 0
+ }
+ text.extract(start, j, lcaseText);
+ lcaseText.foldCase();
+ if (lcase == lcaseText) {
+ return start + j;
+ }
+ }
+ }
+
+ return -start;
+}
+
+//----------------------------------------------------------------------
+
+void
+SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
+{
+ parseAmbiguousDatesAsAfter(d, status);
+}
+
+/**
+ * Private member function that converts the parsed date strings into
+ * timeFields. Returns -start (for ParsePosition) if failed.
+ * @param text the time text to be parsed.
+ * @param start where to start parsing.
+ * @param ch the pattern character for the date field text to be parsed.
+ * @param count the count of a pattern character.
+ * @return the new start position if matching succeeded; a negative number
+ * indicating matching failure, otherwise.
+ */
+int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
+ UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], Calendar& cal) const
+{
+ Formattable number;
+ int32_t value = 0;
+ int32_t i;
+ ParsePosition pos(0);
+ int32_t patternCharIndex;
+ UnicodeString temp;
+ UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
+
+#if defined (U_DEBUG_CAL)
+ //fprintf(stderr, "%s:%d - [%c] st=%d \n", __FILE__, __LINE__, (char) ch, start);
+#endif
+
+ if (patternCharPtr == NULL) {
+ return -start;
+ }
+
+ patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
+
+ UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
+
+ // If there are any spaces here, skip over them. If we hit the end
+ // of the string, then fail.
+ for (;;) {
+ if (start >= text.length()) {
+ return -start;
+ }
+ UChar32 c = text.char32At(start);
+ if (!u_isUWhiteSpace(c)) {
+ break;
+ }
+ start += UTF_CHAR_LENGTH(c);
+ }
+ pos.setIndex(start);
+
+ // We handle a few special cases here where we need to parse
+ // a number value. We handle further, more generic cases below. We need
+ // to handle some of them here because some fields require extra processing on
+ // the parsed value.
+ if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||
+ patternCharIndex == UDAT_HOUR1_FIELD ||
+ (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) ||
+ (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) ||
+ (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) ||
+ (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) ||
+ patternCharIndex == UDAT_YEAR_FIELD ||
+ patternCharIndex == UDAT_YEAR_WOY_FIELD ||
+ patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)
+ {
+ int32_t parseStart = pos.getIndex();
+ // It would be good to unify this with the obeyCount logic below,
+ // but that's going to be difficult.
+ const UnicodeString* src;
+
+ if (obeyCount) {
+ if ((start+count) > text.length()) {
+ return -start;
+ }
+
+ text.extractBetween(0, start + count, temp);
+ src = &temp;
+ } else {
+ src = &text;
+ }
+
+ parseInt(*src, number, pos, allowNegative);
+
+ if (pos.getIndex() == parseStart)
+ return -start;
+ value = number.getLong();
+ }
+
+ switch (patternCharIndex) {
+ case UDAT_ERA_FIELD:
+ if (count == 4) {
+ return matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, cal);
+ }
+
+ return matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, cal);
+
+ case UDAT_YEAR_FIELD:
+ // If there are 3 or more YEAR pattern characters, this indicates
+ // that the year value is to be treated literally, without any
+ // two-digit year adjustments (e.g., from "01" to 2001). Otherwise
+ // we made adjustments to place the 2-digit year in the proper
+ // century, for parsed strings from "00" to "99". Any other string
+ // is treated literally: "2250", "-1", "1", "002".
+ if (count <= 2 && (pos.getIndex() - start) == 2
+ && u_isdigit(text.charAt(start))
+ && u_isdigit(text.charAt(start+1)))
+ {
+ // Assume for example that the defaultCenturyStart is 6/18/1903.
+ // This means that two-digit years will be forced into the range
+ // 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02
+ // correspond to 2000, 2001, and 2002. Years 04, 05, etc. correspond
+ // to 1904, 1905, etc. If the year is 03, then it is 2003 if the
+ // other fields specify a date before 6/18, or 1903 if they specify a
+ // date afterwards. As a result, 03 is an ambiguous year. All other
+ // two-digit years are unambiguous.
+ if(fHaveDefaultCentury) { // check if this formatter even has a pivot year
+ int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
+ ambiguousYear[0] = (value == ambiguousTwoDigitYear);
+ value += (fDefaultCenturyStartYear/100)*100 +
+ (value < ambiguousTwoDigitYear ? 100 : 0);
+ }
+ }
+ cal.set(UCAL_YEAR, value);
+ return pos.getIndex();
+
+ case UDAT_YEAR_WOY_FIELD:
+ // Comment is the same as for UDAT_Year_FIELDs - look above
+ if (count <= 2 && (pos.getIndex() - start) == 2
+ && u_isdigit(text.charAt(start))
+ && u_isdigit(text.charAt(start+1))
+ && fHaveDefaultCentury )
+ {
+ int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
+ ambiguousYear[0] = (value == ambiguousTwoDigitYear);
+ value += (fDefaultCenturyStartYear/100)*100 +
+ (value < ambiguousTwoDigitYear ? 100 : 0);
+ }
+ cal.set(UCAL_YEAR_WOY, value);
+ return pos.getIndex();
+
+ case UDAT_MONTH_FIELD:
+ if (count <= 2) // i.e., M or MM.
+ {
+ // Don't want to parse the month if it is a string
+ // while pattern uses numeric style: M or MM.
+ // [We computed 'value' above.]
+ cal.set(UCAL_MONTH, value - 1);
+ return pos.getIndex();
+ } else {
+ // count >= 3 // i.e., MMM or MMMM
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 first:
+ int32_t newStart = 0;
+
+ if ((newStart = matchString(text, start, UCAL_MONTH,
+ fSymbols->fMonths, fSymbols->fMonthsCount, cal)) > 0)
+ return newStart;
+ else // count == 4 failed, now try count == 3
+ return matchString(text, start, UCAL_MONTH,
+ fSymbols->fShortMonths, fSymbols->fShortMonthsCount, cal);
+ }
+
+ case UDAT_STANDALONE_MONTH_FIELD:
+ if (count <= 2) // i.e., L or LL.
+ {
+ // Don't want to parse the month if it is a string
+ // while pattern uses numeric style: M or MM.
+ // [We computed 'value' above.]
+ cal.set(UCAL_MONTH, value - 1);
+ return pos.getIndex();
+ } else {
+ // count >= 3 // i.e., LLL or LLLL
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 first:
+ int32_t newStart = 0;
+
+ if ((newStart = matchString(text, start, UCAL_MONTH,
+ fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, cal)) > 0)
+ return newStart;
+ else // count == 4 failed, now try count == 3
+ return matchString(text, start, UCAL_MONTH,
+ fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, cal);
+ }
+
+ case UDAT_HOUR_OF_DAY1_FIELD:
+ // [We computed 'value' above.]
+ if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
+ value = 0;
+ cal.set(UCAL_HOUR_OF_DAY, value);
+ return pos.getIndex();
+
+ case UDAT_FRACTIONAL_SECOND_FIELD:
+ // Fractional seconds left-justify
+ i = pos.getIndex() - start;
+ if (i < 3) {
+ while (i < 3) {
+ value *= 10;
+ i++;
+ }
+ } else {
+ int32_t a = 1;
+ while (i > 3) {
+ a *= 10;
+ i--;
+ }
+ value = (value + (a>>1)) / a;
+ }
+ cal.set(UCAL_MILLISECOND, value);
+ return pos.getIndex();
+
+ case UDAT_DAY_OF_WEEK_FIELD:
+ {
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 (DDDD) first:
+ int32_t newStart = 0;
+ if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
+ fSymbols->fWeekdays, fSymbols->fWeekdaysCount, cal)) > 0)
+ return newStart;
+ else // DDDD failed, now try DDD
+ return matchString(text, start, UCAL_DAY_OF_WEEK,
+ fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, cal);
+ }
+
+ case UDAT_STANDALONE_DAY_FIELD:
+ {
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 (DDDD) first:
+ int32_t newStart = 0;
+ if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
+ fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, cal)) > 0)
+ return newStart;
+ else // DDDD failed, now try DDD
+ return matchString(text, start, UCAL_DAY_OF_WEEK,
+ fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, cal);
+ }
+
+ case UDAT_AM_PM_FIELD:
+ return matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, cal);
+
+ case UDAT_HOUR1_FIELD:
+ // [We computed 'value' above.]
+ if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
+ value = 0;
+ cal.set(UCAL_HOUR, value);
+ return pos.getIndex();
+
+ case UDAT_QUARTER_FIELD:
+ if (count <= 2) // i.e., Q or QQ.
+ {
+ // Don't want to parse the month if it is a string
+ // while pattern uses numeric style: Q or QQ.
+ // [We computed 'value' above.]
+ cal.set(UCAL_MONTH, (value - 1) * 3);
+ return pos.getIndex();
+ } else {
+ // count >= 3 // i.e., QQQ or QQQQ
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 first:
+ int32_t newStart = 0;
+
+ if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
+ fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0)
+ return newStart;
+ else // count == 4 failed, now try count == 3
+ return matchQuarterString(text, start, UCAL_MONTH,
+ fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal);
+ }
+
+ case UDAT_STANDALONE_QUARTER_FIELD:
+ if (count <= 2) // i.e., q or qq.
+ {
+ // Don't want to parse the month if it is a string
+ // while pattern uses numeric style: q or q.
+ // [We computed 'value' above.]
+ cal.set(UCAL_MONTH, (value - 1) * 3);
+ return pos.getIndex();
+ } else {
+ // count >= 3 // i.e., qqq or qqqq
+ // Want to be able to parse both short and long forms.
+ // Try count == 4 first:
+ int32_t newStart = 0;
+
+ if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
+ fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0)
+ return newStart;
+ else // count == 4 failed, now try count == 3
+ return matchQuarterString(text, start, UCAL_MONTH,
+ fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal);
+ }
+
+ case UDAT_TIMEZONE_FIELD:
+ case UDAT_TIMEZONE_RFC_FIELD:
+ case UDAT_TIMEZONE_GENERIC_FIELD:
+ case UDAT_TIMEZONE_SPECIAL_FIELD:
+ {
+ int32_t offset = 0;
+ UBool parsed = FALSE;
+
+ // Step 1
+ // Check if this is a long GMT offset string (either localized or default)
+ offset = parseGMT(text, pos);
+ if (pos.getIndex() - start > 0) {
+ parsed = TRUE;
+ }
+ if (!parsed) {
+ // Step 2
+ // Check if this is an RFC822 time zone offset.
+ // ICU supports the standard RFC822 format [+|-]HHmm
+ // and its extended form [+|-]HHmmSS.
+ do {
+ int32_t sign = 0;
+ UChar signChar = text.charAt(start);
+ if (signChar == (UChar)0x002B /* '+' */) {
+ sign = 1;
+ } else if (signChar == (UChar)0x002D /* '-' */) {
+ sign = -1;
+ } else {
+ // Not an RFC822 offset string
+ break;
+ }
+
+ // Parse digits
+ int32_t orgPos = start + 1;
+ pos.setIndex(orgPos);
+ parseInt(text, number, 6, pos, FALSE);
+ int32_t numLen = pos.getIndex() - orgPos;
+ if (numLen <= 0) {
+ break;
+ }
+
+ // Followings are possible format (excluding sign char)
+ // HHmmSS
+ // HmmSS
+ // HHmm
+ // Hmm
+ // HH
+ // H
+ int32_t val = number.getLong();
+ int32_t hour = 0, min = 0, sec = 0;
+ switch(numLen) {
+ case 1: // H
+ case 2: // HH
+ hour = val;
+ break;
+ case 3: // Hmm
+ case 4: // HHmm
+ hour = val / 100;
+ min = val % 100;
+ break;
+ case 5: // Hmmss
+ case 6: // HHmmss
+ hour = val / 10000;
+ min = (val % 10000) / 100;
+ sec = val % 100;
+ break;
+ }
+ if (hour > 23 || min > 59 || sec > 59) {
+ // Invalid value range
+ break;
+ }
+ offset = (((hour * 60) + min) * 60 + sec) * 1000 * sign;
+ parsed = TRUE;
+ } while (FALSE);
+
+ if (!parsed) {
+ // Failed to parse. Reset the position.
+ pos.setIndex(start);
+ }
+ }
+
+ if (parsed) {
+ // offset was successfully parsed as either a long GMT string or RFC822 zone offset
+ // string. Create normalized zone ID for the offset.
+
+ UnicodeString tzID(gGmt);
+ formatRFC822TZ(tzID, offset);
+ //TimeZone *customTZ = TimeZone::createTimeZone(tzID);
+ TimeZone *customTZ = new SimpleTimeZone(offset, tzID); // faster than TimeZone::createTimeZone
+ cal.adoptTimeZone(customTZ);
+
+ return pos.getIndex();
+ }
+
+ // Step 3
+ // At this point, check for named time zones by looking through
+ // the locale data from the DateFormatZoneData strings.
+ // Want to be able to parse both short and long forms.
+ // optimize for calendar's current time zone
+ const ZoneStringFormat *zsf = fSymbols->getZoneStringFormat();
+ if (zsf) {
+ UErrorCode status = U_ZERO_ERROR;
+ const ZoneStringInfo *zsinfo = NULL;
+ int32_t matchLen;
+
+ switch (patternCharIndex) {
+ case UDAT_TIMEZONE_FIELD: // 'z'
+ if (count < 4) {
+ zsinfo = zsf->findSpecificShort(text, start, matchLen, status);
+ } else {
+ zsinfo = zsf->findSpecificLong(text, start, matchLen, status);
+ }
+ break;
+ case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
+ if (count == 1) {
+ zsinfo = zsf->findGenericShort(text, start, matchLen, status);
+ } else if (count == 4) {
+ zsinfo = zsf->findGenericLong(text, start, matchLen, status);
+ }
+ break;
+ case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
+ if (count == 1) {
+ zsinfo = zsf->findSpecificShort(text, start, matchLen, status);
+ } else if (count == 4) {
+ zsinfo = zsf->findGenericLocation(text, start, matchLen, status);
+ }
+ break;
+ }
+
+ if (U_SUCCESS(status) && zsinfo != NULL) {
+ if (zsinfo->isStandard()) {
+ ((SimpleDateFormat*)this)->tztype = TZTYPE_STD;
+ } else if (zsinfo->isDaylight()) {
+ ((SimpleDateFormat*)this)->tztype = TZTYPE_DST;
+ }
+ UnicodeString tzid;
+ zsinfo->getID(tzid);
+
+ UnicodeString current;
+ cal.getTimeZone().getID(current);
+ if (tzid != current) {
+ TimeZone *tz = TimeZone::createTimeZone(tzid);
+ cal.adoptTimeZone(tz);
+ }
+ return start + matchLen;
+ }
+ }
+ // complete failure
+ return -start;
+ }
+
+ default:
+ // Handle "generic" fields
+ int32_t parseStart = pos.getIndex();
+ const UnicodeString* src;
+ if (obeyCount) {
+ if ((start+count) > text.length()) {
+ return -start;
+ }
+ text.extractBetween(0, start + count, temp);
+ src = &temp;
+ } else {
+ src = &text;
+ }
+ parseInt(*src, number, pos, allowNegative);
+ if (pos.getIndex() != parseStart) {
+ cal.set(field, number.getLong());
+ return pos.getIndex();
+ }
+ return -start;
+ }
+}
+
+/**
+ * Parse an integer using fNumberFormat. This method is semantically
+ * const, but actually may modify fNumberFormat.
+ */
+void SimpleDateFormat::parseInt(const UnicodeString& text,
+ Formattable& number,
+ ParsePosition& pos,
+ UBool allowNegative) const {
+ parseInt(text, number, -1, pos, allowNegative);
+}
+
+/**
+ * Parse an integer using fNumberFormat up to maxDigits.
+ */
+void SimpleDateFormat::parseInt(const UnicodeString& text,
+ Formattable& number,
+ int32_t maxDigits,
+ ParsePosition& pos,
+ UBool allowNegative) const {
+ UnicodeString oldPrefix;
+ DecimalFormat* df = NULL;
+ if (!allowNegative &&
+ fNumberFormat->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ df = (DecimalFormat*)fNumberFormat;
+ df->getNegativePrefix(oldPrefix);
+ df->setNegativePrefix(SUPPRESS_NEGATIVE_PREFIX);
+ }
+ int32_t oldPos = pos.getIndex();
+ fNumberFormat->parse(text, number, pos);
+ if (df != NULL) {
+ df->setNegativePrefix(oldPrefix);
+ }
+
+ if (maxDigits > 0) {
+ // adjust the result to fit into
+ // the maxDigits and move the position back
+ int32_t nDigits = pos.getIndex() - oldPos;
+ if (nDigits > maxDigits) {
+ int32_t val = number.getLong();
+ nDigits -= maxDigits;
+ while (nDigits > 0) {
+ val /= 10;
+ nDigits--;
+ }
+ pos.setIndex(oldPos + maxDigits);
+ number.setLong(val);
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+
+void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
+ UnicodeString& translatedPattern,
+ const UnicodeString& from,
+ const UnicodeString& to,
+ UErrorCode& status)
+{
+ // run through the pattern and convert any pattern symbols from the version
+ // in "from" to the corresponding character ion "to". This code takes
+ // quoted strings into account (it doesn't try to translate them), and it signals
+ // an error if a particular "pattern character" doesn't appear in "from".
+ // Depending on the values of "from" and "to" this can convert from generic
+ // to localized patterns or localized to generic.
+ if (U_FAILURE(status))
+ return;
+
+ translatedPattern.remove();
+ UBool inQuote = FALSE;
+ for (int32_t i = 0; i < originalPattern.length(); ++i) {
+ UChar c = originalPattern[i];
+ if (inQuote) {
+ if (c == QUOTE)
+ inQuote = FALSE;
+ }
+ else {
+ if (c == QUOTE)
+ inQuote = TRUE;
+ else if ((c >= 0x0061 /*'a'*/ && c <= 0x007A) /*'z'*/
+ || (c >= 0x0041 /*'A'*/ && c <= 0x005A /*'Z'*/)) {
+ int32_t ci = from.indexOf(c);
+ if (ci == -1) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ c = to[ci];
+ }
+ }
+ translatedPattern += c;
+ }
+ if (inQuote) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+SimpleDateFormat::toPattern(UnicodeString& result) const
+{
+ result = fPattern;
+ return result;
+}
+
+//----------------------------------------------------------------------
+
+UnicodeString&
+SimpleDateFormat::toLocalizedPattern(UnicodeString& result,
+ UErrorCode& status) const
+{
+ translatePattern(fPattern, result, DateFormatSymbols::getPatternUChars(), fSymbols->fLocalPatternChars, status);
+ return result;
+}
+
+//----------------------------------------------------------------------
+
+void
+SimpleDateFormat::applyPattern(const UnicodeString& pattern)
+{
+ fPattern = pattern;
+}
+
+//----------------------------------------------------------------------
+
+void
+SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,
+ UErrorCode &status)
+{
+ translatePattern(pattern, fPattern, fSymbols->fLocalPatternChars, DateFormatSymbols::getPatternUChars(), status);
+}
+
+//----------------------------------------------------------------------
+
+const DateFormatSymbols*
+SimpleDateFormat::getDateFormatSymbols() const
+{
+ return fSymbols;
+}
+
+//----------------------------------------------------------------------
+
+void
+SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols)
+{
+ delete fSymbols;
+ fSymbols = newFormatSymbols;
+}
+
+//----------------------------------------------------------------------
+void
+SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols)
+{
+ delete fSymbols;
+ fSymbols = new DateFormatSymbols(newFormatSymbols);
+}
+
+
+//----------------------------------------------------------------------
+
+
+void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormat::adoptCalendar(calendarToAdopt);
+ delete fSymbols;
+ fSymbols=NULL;
+ initializeSymbols(fLocale, fCalendar, status); // we need new symbols
+ initializeDefaultCentury(); // we need a new century (possibly)
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/sortkey.cpp b/Build/source/libs/icu/icu-xetex/i18n/sortkey.cpp
new file mode 100644
index 00000000000..ceca9d16506
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/sortkey.cpp
@@ -0,0 +1,403 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+//===============================================================================
+//
+// File sortkey.cpp
+//
+//
+//
+// Created by: Helena Shih
+//
+// Modification History:
+//
+// Date Name Description
+//
+// 6/20/97 helena Java class name change.
+// 6/23/97 helena Added comments to make code more readable.
+// 6/26/98 erm Canged to use byte arrays instead of UnicodeString
+// 7/31/98 erm hashCode: minimum inc should be 2 not 1,
+// Cleaned up operator=
+// 07/12/99 helena HPUX 11 CC port.
+// 03/06/01 synwee Modified compareTo, to handle the result of
+// 2 string similar in contents, but one is longer
+// than the other
+//===============================================================================
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/sortkey.h"
+#include "cmemory.h"
+#include "uhash.h"
+
+U_NAMESPACE_BEGIN
+
+// A hash code of kInvalidHashCode indicates that the has code needs
+// to be computed. A hash code of kEmptyHashCode is used for empty keys
+// and for any key whose computed hash code is kInvalidHashCode.
+#define kInvalidHashCode ((int32_t)0)
+#define kEmptyHashCode ((int32_t)1)
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CollationKey)
+
+CollationKey::CollationKey()
+ : UObject(), fBogus(FALSE), fCount(0), fCapacity(0),
+ fHashCode(kEmptyHashCode), fBytes(NULL)
+{
+}
+
+// Create a collation key from a bit array.
+CollationKey::CollationKey(const uint8_t* newValues, int32_t count)
+ : UObject(), fBogus(FALSE), fCount(count), fCapacity(count),
+ fHashCode(kInvalidHashCode)
+{
+ fBytes = (uint8_t *)uprv_malloc(count);
+
+ if (fBytes == NULL)
+ {
+ setToBogus();
+ return;
+ }
+
+ uprv_memcpy(fBytes, newValues, fCount);
+}
+
+CollationKey::CollationKey(const CollationKey& other)
+: UObject(other), fBogus(FALSE), fCount(other.fCount), fCapacity(other.fCapacity),
+ fHashCode(other.fHashCode), fBytes(NULL)
+{
+ if (other.fBogus)
+ {
+ setToBogus();
+ return;
+ }
+
+ fBytes = (uint8_t *)uprv_malloc(fCapacity);
+
+ if (fBytes == NULL)
+ {
+ setToBogus();
+ return;
+ }
+
+ uprv_memcpy(fBytes, other.fBytes, other.fCount);
+ if(fCapacity>fCount) {
+ uprv_memset(fBytes+fCount, 0, fCapacity-fCount);
+ }
+}
+
+CollationKey::~CollationKey()
+{
+ uprv_free(fBytes);
+}
+
+void CollationKey::adopt(uint8_t *values, int32_t count) {
+ if(fBytes != NULL) {
+ uprv_free(fBytes);
+ }
+ fBogus = FALSE;
+ fBytes = values;
+ fCount = count;
+ fCapacity = count;
+ fHashCode = kInvalidHashCode;
+}
+
+// set the key to an empty state
+CollationKey&
+CollationKey::reset()
+{
+ fCount = 0;
+ fBogus = FALSE;
+ fHashCode = kEmptyHashCode;
+
+ return *this;
+}
+
+// set the key to a "bogus" or invalid state
+CollationKey&
+CollationKey::setToBogus()
+{
+ uprv_free(fBytes);
+ fBytes = NULL;
+
+ fCapacity = 0;
+ fCount = 0;
+ fHashCode = kInvalidHashCode;
+
+ return *this;
+}
+
+UBool
+CollationKey::operator==(const CollationKey& source) const
+{
+ return (this->fCount == source.fCount &&
+ (this->fBytes == source.fBytes ||
+ uprv_memcmp(this->fBytes, source.fBytes, this->fCount) == 0));
+}
+
+const CollationKey&
+CollationKey::operator=(const CollationKey& other)
+{
+ if (this != &other)
+ {
+ if (other.isBogus())
+ {
+ return setToBogus();
+ }
+
+ if (other.fBytes != NULL)
+ {
+ ensureCapacity(other.fCount);
+
+ if (isBogus())
+ {
+ return *this;
+ }
+
+ fHashCode = other.fHashCode;
+ uprv_memcpy(fBytes, other.fBytes, fCount);
+ }
+ else
+ {
+ fCount = 0;
+ fBogus = FALSE;
+ fHashCode = kEmptyHashCode;
+ }
+ }
+
+ return *this;
+}
+
+// Bitwise comparison for the collation keys.
+// NOTE: this is somewhat messy 'cause we can't count
+// on memcmp returning the exact values which match
+// Collator::EComparisonResult
+Collator::EComparisonResult
+CollationKey::compareTo(const CollationKey& target) const
+{
+ uint8_t *src = this->fBytes;
+ uint8_t *tgt = target.fBytes;
+
+ // are we comparing the same string
+ if (src == tgt)
+ return Collator::EQUAL;
+
+ /*
+ int count = (this->fCount < target.fCount) ? this->fCount : target.fCount;
+ if (count == 0)
+ {
+ // If count is 0, at least one of the keys is empty.
+ // An empty key is always LESS than a non-empty one
+ // and EQUAL to another empty
+ if (this->fCount < target.fCount)
+ {
+ return Collator::LESS;
+ }
+
+ if (this->fCount > target.fCount)
+ {
+ return Collator::GREATER;
+ }
+ return Collator::EQUAL;
+ }
+ */
+
+ int minLength;
+ Collator::EComparisonResult result;
+
+ // are we comparing different lengths?
+ if (this->fCount != target.fCount) {
+ if (this->fCount < target.fCount) {
+ minLength = this->fCount;
+ result = Collator::LESS;
+ }
+ else {
+ minLength = target.fCount;
+ result = Collator::GREATER;
+ }
+ }
+ else {
+ minLength = target.fCount;
+ result = Collator::EQUAL;
+ }
+
+ if (minLength > 0) {
+ int diff = uprv_memcmp(src, tgt, minLength);
+ if (diff > 0) {
+ return Collator::GREATER;
+ }
+ else
+ if (diff < 0) {
+ return Collator::LESS;
+ }
+ }
+
+ return result;
+ /*
+ if (result < 0)
+ {
+ return Collator::LESS;
+ }
+
+ if (result > 0)
+ {
+ return Collator::GREATER;
+ }
+ return Collator::EQUAL;
+ */
+}
+
+// Bitwise comparison for the collation keys.
+UCollationResult
+CollationKey::compareTo(const CollationKey& target, UErrorCode &status) const
+{
+ if(U_SUCCESS(status)) {
+ uint8_t *src = this->fBytes;
+ uint8_t *tgt = target.fBytes;
+
+ // are we comparing the same string
+ if (src == tgt)
+ return UCOL_EQUAL;
+
+ int minLength;
+ UCollationResult result;
+
+ // are we comparing different lengths?
+ if (this->fCount != target.fCount) {
+ if (this->fCount < target.fCount) {
+ minLength = this->fCount;
+ result = UCOL_LESS;
+ }
+ else {
+ minLength = target.fCount;
+ result = UCOL_GREATER;
+ }
+ }
+ else {
+ minLength = target.fCount;
+ result = UCOL_EQUAL;
+ }
+
+ if (minLength > 0) {
+ int diff = uprv_memcmp(src, tgt, minLength);
+ if (diff > 0) {
+ return UCOL_GREATER;
+ }
+ else
+ if (diff < 0) {
+ return UCOL_LESS;
+ }
+ }
+
+ return result;
+ } else {
+ return UCOL_EQUAL;
+ }
+}
+
+CollationKey&
+CollationKey::ensureCapacity(int32_t newSize)
+{
+ if (fCapacity < newSize)
+ {
+ uprv_free(fBytes);
+
+ fBytes = (uint8_t *)uprv_malloc(newSize);
+
+ if (fBytes == NULL)
+ {
+ return setToBogus();
+ }
+
+ uprv_memset(fBytes, 0, fCapacity);
+ fCapacity = newSize;
+ }
+
+ fBogus = FALSE;
+ fCount = newSize;
+ fHashCode = kInvalidHashCode;
+
+ return *this;
+}
+
+#ifdef U_USE_COLLATION_KEY_DEPRECATES
+// Create a copy of the byte array.
+uint8_t*
+CollationKey::toByteArray(int32_t& count) const
+{
+ uint8_t *result = (uint8_t*) uprv_malloc( sizeof(uint8_t) * fCount );
+
+ if (result == NULL)
+ {
+ count = 0;
+ }
+ else
+ {
+ count = fCount;
+ uprv_memcpy(result, fBytes, fCount);
+ }
+
+ return result;
+}
+#endif
+
+int32_t
+CollationKey::hashCode() const
+{
+ // (Cribbed from UnicodeString)
+ // We cache the hashCode; when it becomes invalid, due to any change to the
+ // string, we note this by setting it to kInvalidHashCode. [LIU]
+
+ // Note: This method is semantically const, but physically non-const.
+
+ if (fHashCode == kInvalidHashCode)
+ {
+ UHashTok key;
+ key.pointer = fBytes;
+ ((CollationKey *)this)->fHashCode = uhash_hashChars(key);
+#if 0
+ // We compute the hash by iterating sparsely over 64 (at most) characters
+ // spaced evenly through the string. For each character, we multiply the
+ // previous hash value by a prime number and add the new character in,
+ // in the manner of a additive linear congruential random number generator,
+ // thus producing a pseudorandom deterministic value which should be well
+ // distributed over the output range. [LIU]
+ const uint8_t *p = fBytes, *limit = fBytes + fCount;
+ int32_t inc = (fCount >= 256) ? fCount/128 : 2; // inc = max(fSize/64, 1);
+ int32_t hash = 0;
+
+ while (p < limit)
+ {
+ hash = ( hash * 37 ) + ((p[0] << 8) + p[1]);
+ p += inc;
+ }
+
+ // If we happened to get kInvalidHashCode, replace it with kEmptyHashCode
+ if (hash == kInvalidHashCode)
+ {
+ hash = kEmptyHashCode;
+ }
+
+ ((CollationKey *)this)->fHashCode = hash; // cast away const
+#endif
+ }
+
+ return fHashCode;
+}
+
+U_NAMESPACE_END
+
+U_CAPI int32_t U_EXPORT2
+ucol_keyHashCode(const uint8_t *key,
+ int32_t length)
+{
+ U_NAMESPACE_QUALIFIER CollationKey newKey(key, length);
+ return newKey.hashCode();
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/strmatch.cpp b/Build/source/libs/icu/icu-xetex/i18n/strmatch.cpp
new file mode 100644
index 00000000000..8286c7eaa07
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/strmatch.cpp
@@ -0,0 +1,289 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2004, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 07/23/01 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "strmatch.h"
+#include "rbt_data.h"
+#include "util.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_BEGIN
+
+static const UChar EMPTY[] = { 0 }; // empty string: ""
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringMatcher)
+
+StringMatcher::StringMatcher(const UnicodeString& theString,
+ int32_t start,
+ int32_t limit,
+ int32_t segmentNum,
+ const TransliterationRuleData& theData) :
+ data(&theData),
+ segmentNumber(segmentNum),
+ matchStart(-1),
+ matchLimit(-1)
+{
+ theString.extractBetween(start, limit, pattern);
+}
+
+StringMatcher::StringMatcher(const StringMatcher& o) :
+ UnicodeFunctor(o),
+ UnicodeMatcher(o),
+ UnicodeReplacer(o),
+ pattern(o.pattern),
+ data(o.data),
+ segmentNumber(o.segmentNumber),
+ matchStart(o.matchStart),
+ matchLimit(o.matchLimit)
+{
+}
+
+/**
+ * Destructor
+ */
+StringMatcher::~StringMatcher() {
+}
+
+/**
+ * Implement UnicodeFunctor
+ */
+UnicodeFunctor* StringMatcher::clone() const {
+ return new StringMatcher(*this);
+}
+
+/**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeMatcher* pointer
+ * and return the pointer.
+ */
+UnicodeMatcher* StringMatcher::toMatcher() const {
+ return (UnicodeMatcher*) this;
+}
+
+/**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
+ * and return the pointer.
+ */
+UnicodeReplacer* StringMatcher::toReplacer() const {
+ return (UnicodeReplacer*) this;
+}
+
+/**
+ * Implement UnicodeMatcher
+ */
+UMatchDegree StringMatcher::matches(const Replaceable& text,
+ int32_t& offset,
+ int32_t limit,
+ UBool incremental) {
+ int32_t i;
+ int32_t cursor = offset;
+ if (limit < cursor) {
+ // Match in the reverse direction
+ for (i=pattern.length()-1; i>=0; --i) {
+ UChar keyChar = pattern.charAt(i);
+ UnicodeMatcher* subm = data->lookupMatcher(keyChar);
+ if (subm == 0) {
+ if (cursor > limit &&
+ keyChar == text.charAt(cursor)) {
+ --cursor;
+ } else {
+ return U_MISMATCH;
+ }
+ } else {
+ UMatchDegree m =
+ subm->matches(text, cursor, limit, incremental);
+ if (m != U_MATCH) {
+ return m;
+ }
+ }
+ }
+ // Record the match position, but adjust for a normal
+ // forward start, limit, and only if a prior match does not
+ // exist -- we want the rightmost match.
+ if (matchStart < 0) {
+ matchStart = cursor+1;
+ matchLimit = offset+1;
+ }
+ } else {
+ for (i=0; i<pattern.length(); ++i) {
+ if (incremental && cursor == limit) {
+ // We've reached the context limit without a mismatch and
+ // without completing our match.
+ return U_PARTIAL_MATCH;
+ }
+ UChar keyChar = pattern.charAt(i);
+ UnicodeMatcher* subm = data->lookupMatcher(keyChar);
+ if (subm == 0) {
+ // Don't need the cursor < limit check if
+ // incremental is TRUE (because it's done above); do need
+ // it otherwise.
+ if (cursor < limit &&
+ keyChar == text.charAt(cursor)) {
+ ++cursor;
+ } else {
+ return U_MISMATCH;
+ }
+ } else {
+ UMatchDegree m =
+ subm->matches(text, cursor, limit, incremental);
+ if (m != U_MATCH) {
+ return m;
+ }
+ }
+ }
+ // Record the match position
+ matchStart = offset;
+ matchLimit = cursor;
+ }
+
+ offset = cursor;
+ return U_MATCH;
+}
+
+/**
+ * Implement UnicodeMatcher
+ */
+UnicodeString& StringMatcher::toPattern(UnicodeString& result,
+ UBool escapeUnprintable) const
+{
+ result.truncate(0);
+ UnicodeString str, quoteBuf;
+ if (segmentNumber > 0) {
+ result.append((UChar)40); /*(*/
+ }
+ for (int32_t i=0; i<pattern.length(); ++i) {
+ UChar keyChar = pattern.charAt(i);
+ const UnicodeMatcher* m = data->lookupMatcher(keyChar);
+ if (m == 0) {
+ ICU_Utility::appendToRule(result, keyChar, FALSE, escapeUnprintable, quoteBuf);
+ } else {
+ ICU_Utility::appendToRule(result, m->toPattern(str, escapeUnprintable),
+ TRUE, escapeUnprintable, quoteBuf);
+ }
+ }
+ if (segmentNumber > 0) {
+ result.append((UChar)41); /*)*/
+ }
+ // Flush quoteBuf out to result
+ ICU_Utility::appendToRule(result, -1,
+ TRUE, escapeUnprintable, quoteBuf);
+ return result;
+}
+
+/**
+ * Implement UnicodeMatcher
+ */
+UBool StringMatcher::matchesIndexValue(uint8_t v) const {
+ if (pattern.length() == 0) {
+ return TRUE;
+ }
+ UChar32 c = pattern.char32At(0);
+ const UnicodeMatcher *m = data->lookupMatcher(c);
+ return (m == 0) ? ((c & 0xFF) == v) : m->matchesIndexValue(v);
+}
+
+/**
+ * Implement UnicodeMatcher
+ */
+void StringMatcher::addMatchSetTo(UnicodeSet& toUnionTo) const {
+ UChar32 ch;
+ for (int32_t i=0; i<pattern.length(); i+=UTF_CHAR_LENGTH(ch)) {
+ ch = pattern.char32At(i);
+ const UnicodeMatcher* matcher = data->lookupMatcher(ch);
+ if (matcher == NULL) {
+ toUnionTo.add(ch);
+ } else {
+ matcher->addMatchSetTo(toUnionTo);
+ }
+ }
+}
+
+/**
+ * UnicodeReplacer API
+ */
+int32_t StringMatcher::replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& /*cursor*/) {
+
+ int32_t outLen = 0;
+
+ // Copy segment with out-of-band data
+ int32_t dest = limit;
+ // If there was no match, that means that a quantifier
+ // matched zero-length. E.g., x (a)* y matched "xy".
+ if (matchStart >= 0) {
+ if (matchStart != matchLimit) {
+ text.copy(matchStart, matchLimit, dest);
+ outLen = matchLimit - matchStart;
+ }
+ }
+
+ text.handleReplaceBetween(start, limit, EMPTY); // delete original text
+
+ return outLen;
+}
+
+/**
+ * UnicodeReplacer API
+ */
+UnicodeString& StringMatcher::toReplacerPattern(UnicodeString& rule,
+ UBool /*escapeUnprintable*/) const {
+ // assert(segmentNumber > 0);
+ rule.truncate(0);
+ rule.append((UChar)0x0024 /*$*/);
+ ICU_Utility::appendNumber(rule, segmentNumber, 10, 1);
+ return rule;
+}
+
+/**
+ * Remove any match info. This must be called before performing a
+ * set of matches with this segment.
+ */
+ void StringMatcher::resetMatch() {
+ matchStart = matchLimit = -1;
+}
+
+/**
+ * Union the set of all characters that may output by this object
+ * into the given set.
+ * @param toUnionTo the set into which to union the output characters
+ */
+void StringMatcher::addReplacementSetTo(UnicodeSet& /*toUnionTo*/) const {
+ // The output of this replacer varies; it is the source text between
+ // matchStart and matchLimit. Since this varies depending on the
+ // input text, we can't compute it here. We can either do nothing
+ // or we can add ALL characters to the set. It's probably more useful
+ // to do nothing.
+}
+
+/**
+ * Implement UnicodeFunctor
+ */
+void StringMatcher::setData(const TransliterationRuleData* d) {
+ data = d;
+ int32_t i = 0;
+ while (i<pattern.length()) {
+ UChar32 c = pattern.char32At(i);
+ UnicodeFunctor* f = data->lookup(c);
+ if (f != NULL) {
+ f->setData(data);
+ }
+ i += UTF_CHAR_LENGTH(c);
+ }
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/strmatch.h b/Build/source/libs/icu/icu-xetex/i18n/strmatch.h
new file mode 100644
index 00000000000..90cba0c1d36
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/strmatch.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2001-2004, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 07/23/01 aliu Creation.
+ **********************************************************************
+ */
+#ifndef STRMATCH_H
+#define STRMATCH_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unistr.h"
+#include "unicode/unifunct.h"
+#include "unicode/unimatch.h"
+#include "unicode/unirepl.h"
+
+U_NAMESPACE_BEGIN
+
+class TransliterationRuleData;
+
+/**
+ * An object that matches a fixed input string, implementing the
+ * UnicodeMatcher API. This object also implements the
+ * UnicodeReplacer API, allowing it to emit the matched text as
+ * output. Since the match text may contain flexible match elements,
+ * such as UnicodeSets, the emitted text is not the match pattern, but
+ * instead a substring of the actual matched text. Following
+ * convention, the output text is the leftmost match seen up to this
+ * point.
+ *
+ * A StringMatcher may represent a segment, in which case it has a
+ * positive segment number. This affects how the matcher converts
+ * itself to a pattern but does not otherwise affect its function.
+ *
+ * A StringMatcher that is not a segment should not be used as a
+ * UnicodeReplacer.
+ */
+class StringMatcher : public UnicodeFunctor, public UnicodeMatcher, public UnicodeReplacer {
+
+ public:
+
+ /**
+ * Construct a matcher that matches the given pattern string.
+ * @param string the pattern to be matched, possibly containing
+ * stand-ins that represent nested UnicodeMatcher objects.
+ * @param start inclusive start index of text to be replaced
+ * @param limit exclusive end index of text to be replaced;
+ * must be greater than or equal to start
+ * @param segmentNum the segment number from 1..n, or 0 if this is
+ * not a segment.
+ * @param data context object mapping stand-ins to
+ * UnicodeMatcher objects.
+ */
+ StringMatcher(const UnicodeString& string,
+ int32_t start,
+ int32_t limit,
+ int32_t segmentNum,
+ const TransliterationRuleData& data);
+
+ /**
+ * Copy constructor
+ * @param o the object to be copied.
+ */
+ StringMatcher(const StringMatcher& o);
+
+ /**
+ * Destructor
+ */
+ virtual ~StringMatcher();
+
+ /**
+ * Implement UnicodeFunctor
+ * @return a copy of the object.
+ */
+ virtual UnicodeFunctor* clone() const;
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeMatcher* pointer
+ * and return the pointer.
+ * @return the UnicodeMatcher point.
+ */
+ virtual UnicodeMatcher* toMatcher() const;
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
+ * and return the pointer.
+ * @return the UnicodeReplacer pointer.
+ */
+ virtual UnicodeReplacer* toReplacer() const;
+
+ /**
+ * Implement UnicodeMatcher
+ * @param text the text to be matched
+ * @param offset on input, the index into text at which to begin
+ * matching. On output, the limit of the matched text. The
+ * number of matched characters is the output value of offset
+ * minus the input value. Offset should always point to the
+ * HIGH SURROGATE (leading code unit) of a pair of surrogates,
+ * both on entry and upon return.
+ * @param limit the limit index of text to be matched. Greater
+ * than offset for a forward direction match, less than offset for
+ * a backward direction match. The last character to be
+ * considered for matching will be text.charAt(limit-1) in the
+ * forward direction or text.charAt(limit+1) in the backward
+ * direction.
+ * @param incremental if TRUE, then assume further characters may
+ * be inserted at limit and check for partial matching. Otherwise
+ * assume the text as given is complete.
+ * @return a match degree value indicating a full match, a partial
+ * match, or a mismatch. If incremental is FALSE then
+ * U_PARTIAL_MATCH should never be returned.
+ */
+ virtual UMatchDegree matches(const Replaceable& text,
+ int32_t& offset,
+ int32_t limit,
+ UBool incremental);
+
+ /**
+ * Implement UnicodeMatcher
+ * @param result Output param to receive the pattern.
+ * @param escapeUnprintable if True then escape the unprintable characters.
+ * @return A reference to 'result'.
+ */
+ virtual UnicodeString& toPattern(UnicodeString& result,
+ UBool escapeUnprintable = FALSE) const;
+
+ /**
+ * Implement UnicodeMatcher
+ * Returns TRUE if this matcher will match a character c, where c
+ * & 0xFF == v, at offset, in the forward direction (with limit >
+ * offset). This is used by <tt>RuleBasedTransliterator</tt> for
+ * indexing.
+ * @param v the given value
+ * @return TRUE if this matcher will match a character c,
+ * where c & 0xFF == v
+ */
+ virtual UBool matchesIndexValue(uint8_t v) const;
+
+ /**
+ * Implement UnicodeMatcher
+ */
+ virtual void addMatchSetTo(UnicodeSet& toUnionTo) const;
+
+ /**
+ * Implement UnicodeFunctor
+ */
+ virtual void setData(const TransliterationRuleData*);
+
+ /**
+ * Replace characters in 'text' from 'start' to 'limit' with the
+ * output text of this object. Update the 'cursor' parameter to
+ * give the cursor position and return the length of the
+ * replacement text.
+ *
+ * @param text the text to be matched
+ * @param start inclusive start index of text to be replaced
+ * @param limit exclusive end index of text to be replaced;
+ * must be greater than or equal to start
+ * @param cursor output parameter for the cursor position.
+ * Not all replacer objects will update this, but in a complete
+ * tree of replacer objects, representing the entire output side
+ * of a transliteration rule, at least one must update it.
+ * @return the number of 16-bit code units in the text replacing
+ * the characters at offsets start..(limit-1) in text
+ */
+ virtual int32_t replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& cursor);
+
+ /**
+ * Returns a string representation of this replacer. If the
+ * result of calling this function is passed to the appropriate
+ * parser, typically TransliteratorParser, it will produce another
+ * replacer that is equal to this one.
+ * @param result the string to receive the pattern. Previous
+ * contents will be deleted.
+ * @param escapeUnprintable if TRUE then convert unprintable
+ * character to their hex escape representations, \\uxxxx or
+ * \\Uxxxxxxxx. Unprintable characters are defined by
+ * Utility.isUnprintable().
+ * @return a reference to 'result'.
+ */
+ virtual UnicodeString& toReplacerPattern(UnicodeString& result,
+ UBool escapeUnprintable) const;
+
+ /**
+ * Remove any match data. This must be called before performing a
+ * set of matches with this segment.
+ */
+ void resetMatch();
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * Union the set of all characters that may output by this object
+ * into the given set.
+ * @param toUnionTo the set into which to union the output characters
+ */
+ virtual void addReplacementSetTo(UnicodeSet& toUnionTo) const;
+
+ private:
+
+ /**
+ * The text to be matched.
+ */
+ UnicodeString pattern;
+
+ /**
+ * Context object that maps stand-ins to matcher and replacer
+ * objects.
+ */
+ const TransliterationRuleData* data;
+
+ /**
+ * The segment number, 1-based, or 0 if not a segment.
+ */
+ int32_t segmentNumber;
+
+ /**
+ * Start offset, in the match text, of the <em>rightmost</em>
+ * match.
+ */
+ int32_t matchStart;
+
+ /**
+ * Limit offset, in the match text, of the <em>rightmost</em>
+ * match.
+ */
+ int32_t matchLimit;
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/strrepl.cpp b/Build/source/libs/icu/icu-xetex/i18n/strrepl.cpp
new file mode 100644
index 00000000000..4ae12b05c24
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/strrepl.cpp
@@ -0,0 +1,328 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2004, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 01/21/2002 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "strrepl.h"
+#include "rbt_data.h"
+#include "util.h"
+#include "unicode/uniset.h"
+
+U_NAMESPACE_BEGIN
+
+static const UChar EMPTY[] = { 0 }; // empty string: ""
+
+UnicodeReplacer::~UnicodeReplacer() {}
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringReplacer)
+
+/**
+ * Construct a StringReplacer that sets the emits the given output
+ * text and sets the cursor to the given position.
+ * @param theOutput text that will replace input text when the
+ * replace() method is called. May contain stand-in characters
+ * that represent nested replacers.
+ * @param theCursorPos cursor position that will be returned by
+ * the replace() method
+ * @param theData transliterator context object that translates
+ * stand-in characters to UnicodeReplacer objects
+ */
+StringReplacer::StringReplacer(const UnicodeString& theOutput,
+ int32_t theCursorPos,
+ const TransliterationRuleData* theData) {
+ output = theOutput;
+ cursorPos = theCursorPos;
+ hasCursor = TRUE;
+ data = theData;
+ isComplex = TRUE;
+}
+
+/**
+ * Construct a StringReplacer that sets the emits the given output
+ * text and does not modify the cursor.
+ * @param theOutput text that will replace input text when the
+ * replace() method is called. May contain stand-in characters
+ * that represent nested replacers.
+ * @param theData transliterator context object that translates
+ * stand-in characters to UnicodeReplacer objects
+ */
+StringReplacer::StringReplacer(const UnicodeString& theOutput,
+ const TransliterationRuleData* theData) {
+ output = theOutput;
+ cursorPos = 0;
+ hasCursor = FALSE;
+ data = theData;
+ isComplex = TRUE;
+}
+
+/**
+ * Copy constructor.
+ */
+StringReplacer::StringReplacer(const StringReplacer& other) :
+ UnicodeFunctor(other),
+ UnicodeReplacer(other)
+{
+ output = other.output;
+ cursorPos = other.cursorPos;
+ hasCursor = other.hasCursor;
+ data = other.data;
+ isComplex = other.isComplex;
+}
+
+/**
+ * Destructor
+ */
+StringReplacer::~StringReplacer() {
+}
+
+/**
+ * Implement UnicodeFunctor
+ */
+UnicodeFunctor* StringReplacer::clone() const {
+ return new StringReplacer(*this);
+}
+
+/**
+ * Implement UnicodeFunctor
+ */
+UnicodeReplacer* StringReplacer::toReplacer() const {
+ return (UnicodeReplacer*) this;
+}
+
+/**
+ * UnicodeReplacer API
+ */
+int32_t StringReplacer::replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& cursor) {
+ int32_t outLen;
+ int32_t newStart = 0;
+
+ // NOTE: It should be possible to _always_ run the complex
+ // processing code; just slower. If not, then there is a bug
+ // in the complex processing code.
+
+ // Simple (no nested replacers) Processing Code :
+ if (!isComplex) {
+ text.handleReplaceBetween(start, limit, output);
+ outLen = output.length();
+
+ // Setup default cursor position (for cursorPos within output)
+ newStart = cursorPos;
+ }
+
+ // Complex (nested replacers) Processing Code :
+ else {
+ /* When there are segments to be copied, use the Replaceable.copy()
+ * API in order to retain out-of-band data. Copy everything to the
+ * end of the string, then copy them back over the key. This preserves
+ * the integrity of indices into the key and surrounding context while
+ * generating the output text.
+ */
+ UnicodeString buf;
+ int32_t oOutput; // offset into 'output'
+ isComplex = FALSE;
+
+ // The temporary buffer starts at tempStart, and extends
+ // to destLimit. The start of the buffer has a single
+ // character from before the key. This provides style
+ // data when addition characters are filled into the
+ // temporary buffer. If there is nothing to the left, use
+ // the non-character U+FFFF, which Replaceable subclasses
+ // should treat specially as a "no-style character."
+ // destStart points to the point after the style context
+ // character, so it is tempStart+1 or tempStart+2.
+ int32_t tempStart = text.length(); // start of temp buffer
+ int32_t destStart = tempStart; // copy new text to here
+ if (start > 0) {
+ int32_t len = UTF_CHAR_LENGTH(text.char32At(start-1));
+ text.copy(start-len, start, tempStart);
+ destStart += len;
+ } else {
+ UnicodeString str((UChar) 0xFFFF);
+ text.handleReplaceBetween(tempStart, tempStart, str);
+ destStart++;
+ }
+ int32_t destLimit = destStart;
+
+ for (oOutput=0; oOutput<output.length(); ) {
+ if (oOutput == cursorPos) {
+ // Record the position of the cursor
+ newStart = destLimit - destStart; // relative to start
+ }
+ UChar32 c = output.char32At(oOutput);
+ UnicodeReplacer* r = data->lookupReplacer(c);
+ if (r == NULL) {
+ // Accumulate straight (non-segment) text.
+ buf.append(c);
+ } else {
+ isComplex = TRUE;
+
+ // Insert any accumulated straight text.
+ if (buf.length() > 0) {
+ text.handleReplaceBetween(destLimit, destLimit, buf);
+ destLimit += buf.length();
+ buf.truncate(0);
+ }
+
+ // Delegate output generation to replacer object
+ int32_t len = r->replace(text, destLimit, destLimit, cursor);
+ destLimit += len;
+ }
+ oOutput += UTF_CHAR_LENGTH(c);
+ }
+ // Insert any accumulated straight text.
+ if (buf.length() > 0) {
+ text.handleReplaceBetween(destLimit, destLimit, buf);
+ destLimit += buf.length();
+ }
+ if (oOutput == cursorPos) {
+ // Record the position of the cursor
+ newStart = destLimit - destStart; // relative to start
+ }
+
+ outLen = destLimit - destStart;
+
+ // Copy new text to start, and delete it
+ text.copy(destStart, destLimit, start);
+ text.handleReplaceBetween(tempStart + outLen, destLimit + outLen, EMPTY);
+
+ // Delete the old text (the key)
+ text.handleReplaceBetween(start + outLen, limit + outLen, EMPTY);
+ }
+
+ if (hasCursor) {
+ // Adjust the cursor for positions outside the key. These
+ // refer to code points rather than code units. If cursorPos
+ // is within the output string, then use newStart, which has
+ // already been set above.
+ if (cursorPos < 0) {
+ newStart = start;
+ int32_t n = cursorPos;
+ // Outside the output string, cursorPos counts code points
+ while (n < 0 && newStart > 0) {
+ newStart -= UTF_CHAR_LENGTH(text.char32At(newStart-1));
+ ++n;
+ }
+ newStart += n;
+ } else if (cursorPos > output.length()) {
+ newStart = start + outLen;
+ int32_t n = cursorPos - output.length();
+ // Outside the output string, cursorPos counts code points
+ while (n > 0 && newStart < text.length()) {
+ newStart += UTF_CHAR_LENGTH(text.char32At(newStart));
+ --n;
+ }
+ newStart += n;
+ } else {
+ // Cursor is within output string. It has been set up above
+ // to be relative to start.
+ newStart += start;
+ }
+
+ cursor = newStart;
+ }
+
+ return outLen;
+}
+
+/**
+ * UnicodeReplacer API
+ */
+UnicodeString& StringReplacer::toReplacerPattern(UnicodeString& rule,
+ UBool escapeUnprintable) const {
+ rule.truncate(0);
+ UnicodeString quoteBuf;
+
+ int32_t cursor = cursorPos;
+
+ // Handle a cursor preceding the output
+ if (hasCursor && cursor < 0) {
+ while (cursor++ < 0) {
+ ICU_Utility::appendToRule(rule, (UChar)0x0040 /*@*/, TRUE, escapeUnprintable, quoteBuf);
+ }
+ // Fall through and append '|' below
+ }
+
+ for (int32_t i=0; i<output.length(); ++i) {
+ if (hasCursor && i == cursor) {
+ ICU_Utility::appendToRule(rule, (UChar)0x007C /*|*/, TRUE, escapeUnprintable, quoteBuf);
+ }
+ UChar c = output.charAt(i); // Ok to use 16-bits here
+
+ UnicodeReplacer* r = data->lookupReplacer(c);
+ if (r == NULL) {
+ ICU_Utility::appendToRule(rule, c, FALSE, escapeUnprintable, quoteBuf);
+ } else {
+ UnicodeString buf;
+ r->toReplacerPattern(buf, escapeUnprintable);
+ buf.insert(0, (UChar)0x20);
+ buf.append((UChar)0x20);
+ ICU_Utility::appendToRule(rule, buf,
+ TRUE, escapeUnprintable, quoteBuf);
+ }
+ }
+
+ // Handle a cursor after the output. Use > rather than >= because
+ // if cursor == output.length() it is at the end of the output,
+ // which is the default position, so we need not emit it.
+ if (hasCursor && cursor > output.length()) {
+ cursor -= output.length();
+ while (cursor-- > 0) {
+ ICU_Utility::appendToRule(rule, (UChar)0x0040 /*@*/, TRUE, escapeUnprintable, quoteBuf);
+ }
+ ICU_Utility::appendToRule(rule, (UChar)0x007C /*|*/, TRUE, escapeUnprintable, quoteBuf);
+ }
+ // Flush quoteBuf out to result
+ ICU_Utility::appendToRule(rule, -1,
+ TRUE, escapeUnprintable, quoteBuf);
+
+ return rule;
+}
+
+/**
+ * Implement UnicodeReplacer
+ */
+void StringReplacer::addReplacementSetTo(UnicodeSet& toUnionTo) const {
+ UChar32 ch;
+ for (int32_t i=0; i<output.length(); i+=UTF_CHAR_LENGTH(ch)) {
+ ch = output.char32At(i);
+ UnicodeReplacer* r = data->lookupReplacer(ch);
+ if (r == NULL) {
+ toUnionTo.add(ch);
+ } else {
+ r->addReplacementSetTo(toUnionTo);
+ }
+ }
+}
+
+/**
+ * UnicodeFunctor API
+ */
+void StringReplacer::setData(const TransliterationRuleData* d) {
+ data = d;
+ int32_t i = 0;
+ while (i<output.length()) {
+ UChar32 c = output.char32At(i);
+ UnicodeFunctor* f = data->lookup(c);
+ if (f != NULL) {
+ f->setData(data);
+ }
+ i += UTF_CHAR_LENGTH(c);
+ }
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/strrepl.h b/Build/source/libs/icu/icu-xetex/i18n/strrepl.h
new file mode 100644
index 00000000000..67a93e961f7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/strrepl.h
@@ -0,0 +1,165 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2004, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 01/21/2002 aliu Creation.
+**********************************************************************
+*/
+
+#ifndef STRREPL_H
+#define STRREPL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifunct.h"
+#include "unicode/unirepl.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_BEGIN
+
+class TransliterationRuleData;
+
+/**
+ * A replacer that produces static text as its output. The text may
+ * contain transliterator stand-in characters that represent nested
+ * UnicodeReplacer objects, making it possible to encode a tree of
+ * replacers in a StringReplacer. A StringReplacer that contains such
+ * stand-ins is called a <em>complex</em> StringReplacer. A complex
+ * StringReplacer has a slower processing loop than a non-complex one.
+ * @author Alan Liu
+ */
+class StringReplacer : public UnicodeFunctor, public UnicodeReplacer {
+
+ private:
+
+ /**
+ * Output text, possibly containing stand-in characters that
+ * represent nested UnicodeReplacers.
+ */
+ UnicodeString output;
+
+ /**
+ * Cursor position. Value is ignored if hasCursor is false.
+ */
+ int32_t cursorPos;
+
+ /**
+ * True if this object outputs a cursor position.
+ */
+ UBool hasCursor;
+
+ /**
+ * A complex object contains nested replacers and requires more
+ * complex processing. StringReplacers are initially assumed to
+ * be complex. If no nested replacers are seen during processing,
+ * then isComplex is set to false, and future replacements are
+ * short circuited for better performance.
+ */
+ UBool isComplex;
+
+ /**
+ * Object that translates stand-in characters in 'output' to
+ * UnicodeReplacer objects.
+ */
+ const TransliterationRuleData* data;
+
+ public:
+
+ /**
+ * Construct a StringReplacer that sets the emits the given output
+ * text and sets the cursor to the given position.
+ * @param theOutput text that will replace input text when the
+ * replace() method is called. May contain stand-in characters
+ * that represent nested replacers.
+ * @param theCursorPos cursor position that will be returned by
+ * the replace() method
+ * @param theData transliterator context object that translates
+ * stand-in characters to UnicodeReplacer objects
+ */
+ StringReplacer(const UnicodeString& theOutput,
+ int32_t theCursorPos,
+ const TransliterationRuleData* theData);
+
+ /**
+ * Construct a StringReplacer that sets the emits the given output
+ * text and does not modify the cursor.
+ * @param theOutput text that will replace input text when the
+ * replace() method is called. May contain stand-in characters
+ * that represent nested replacers.
+ * @param theData transliterator context object that translates
+ * stand-in characters to UnicodeReplacer objects
+ */
+ StringReplacer(const UnicodeString& theOutput,
+ const TransliterationRuleData* theData);
+
+ /**
+ * Copy constructor.
+ */
+ StringReplacer(const StringReplacer& other);
+
+ /**
+ * Destructor
+ */
+ virtual ~StringReplacer();
+
+ /**
+ * Implement UnicodeFunctor
+ */
+ virtual UnicodeFunctor* clone() const;
+
+ /**
+ * UnicodeFunctor API. Cast 'this' to a UnicodeReplacer* pointer
+ * and return the pointer.
+ */
+ virtual UnicodeReplacer* toReplacer() const;
+
+ /**
+ * UnicodeReplacer API
+ */
+ virtual int32_t replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& cursor);
+
+ /**
+ * UnicodeReplacer API
+ */
+ virtual UnicodeString& toReplacerPattern(UnicodeString& result,
+ UBool escapeUnprintable) const;
+
+ /**
+ * Implement UnicodeReplacer
+ */
+ virtual void addReplacementSetTo(UnicodeSet& toUnionTo) const;
+
+ /**
+ * UnicodeFunctor API
+ */
+ virtual void setData(const TransliterationRuleData*);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/stsearch.cpp b/Build/source/libs/icu/icu-xetex/i18n/stsearch.cpp
new file mode 100644
index 00000000000..464e42fa667
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/stsearch.cpp
@@ -0,0 +1,461 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2006 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 03/22/2000 helena Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/stsearch.h"
+#include "usrchimp.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(StringSearch)
+
+// public constructors and destructors -----------------------------------
+
+StringSearch::StringSearch(const UnicodeString &pattern,
+ const UnicodeString &text,
+ const Locale &locale,
+ BreakIterator *breakiter,
+ UErrorCode &status) :
+ SearchIterator(text, breakiter),
+ m_collator_(),
+ m_pattern_(pattern)
+{
+ if (U_FAILURE(status)) {
+ m_strsrch_ = NULL;
+ return;
+ }
+
+ m_strsrch_ = usearch_open(m_pattern_.getBuffer(), m_pattern_.length(),
+ m_text_.getBuffer(), m_text_.length(),
+ locale.getName(), (UBreakIterator *)breakiter,
+ &status);
+ uprv_free(m_search_);
+ m_search_ = NULL;
+
+ // !!! dlf m_collator_ is an odd beast. basically it is an aliasing
+ // wrapper around the internal collator and rules, which (here) are
+ // owned by this stringsearch object. this means 1) it's destructor
+ // _should not_ delete the ucollator or rules, and 2) changes made
+ // to the exposed collator (setStrength etc) _should_ modify the
+ // ucollator. thus the collator is not a copy-on-write alias, and it
+ // needs to distinguish itself not merely from 'stand alone' colators
+ // but also from copy-on-write ones. it needs additional state, which
+ // setUCollator should set.
+
+ if (U_SUCCESS(status)) {
+ // Alias the collator
+ m_collator_.setUCollator((UCollator *)m_strsrch_->collator);
+ // m_search_ has been created by the base SearchIterator class
+ m_search_ = m_strsrch_->search;
+ }
+}
+
+StringSearch::StringSearch(const UnicodeString &pattern,
+ const UnicodeString &text,
+ RuleBasedCollator *coll,
+ BreakIterator *breakiter,
+ UErrorCode &status) :
+ SearchIterator(text, breakiter),
+ m_collator_(),
+ m_pattern_(pattern)
+{
+ if (U_FAILURE(status)) {
+ m_strsrch_ = NULL;
+ return;
+ }
+ if (coll == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ m_strsrch_ = NULL;
+ return;
+ }
+ m_strsrch_ = usearch_openFromCollator(m_pattern_.getBuffer(),
+ m_pattern_.length(),
+ m_text_.getBuffer(),
+ m_text_.length(), coll->ucollator,
+ (UBreakIterator *)breakiter,
+ &status);
+ uprv_free(m_search_);
+ m_search_ = NULL;
+
+ if (U_SUCCESS(status)) {
+ // Alias the collator
+ m_collator_.setUCollator((UCollator *)m_strsrch_->collator);
+ // m_search_ has been created by the base SearchIterator class
+ m_search_ = m_strsrch_->search;
+ }
+}
+
+StringSearch::StringSearch(const UnicodeString &pattern,
+ CharacterIterator &text,
+ const Locale &locale,
+ BreakIterator *breakiter,
+ UErrorCode &status) :
+ SearchIterator(text, breakiter),
+ m_collator_(),
+ m_pattern_(pattern)
+{
+ if (U_FAILURE(status)) {
+ m_strsrch_ = NULL;
+ return;
+ }
+ m_strsrch_ = usearch_open(m_pattern_.getBuffer(), m_pattern_.length(),
+ m_text_.getBuffer(), m_text_.length(),
+ locale.getName(), (UBreakIterator *)breakiter,
+ &status);
+ uprv_free(m_search_);
+ m_search_ = NULL;
+
+ if (U_SUCCESS(status)) {
+ // Alias the collator
+ m_collator_.setUCollator((UCollator *)m_strsrch_->collator);
+ // m_search_ has been created by the base SearchIterator class
+ m_search_ = m_strsrch_->search;
+ }
+}
+
+StringSearch::StringSearch(const UnicodeString &pattern,
+ CharacterIterator &text,
+ RuleBasedCollator *coll,
+ BreakIterator *breakiter,
+ UErrorCode &status) :
+ SearchIterator(text, breakiter),
+ m_collator_(),
+ m_pattern_(pattern)
+{
+ if (U_FAILURE(status)) {
+ m_strsrch_ = NULL;
+ return;
+ }
+ if (coll == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ m_strsrch_ = NULL;
+ return;
+ }
+ m_strsrch_ = usearch_openFromCollator(m_pattern_.getBuffer(),
+ m_pattern_.length(),
+ m_text_.getBuffer(),
+ m_text_.length(), coll->ucollator,
+ (UBreakIterator *)breakiter,
+ &status);
+ uprv_free(m_search_);
+ m_search_ = NULL;
+
+ if (U_SUCCESS(status)) {
+ // Alias the collator
+ m_collator_.setUCollator((UCollator *)m_strsrch_->collator);
+ // m_search_ has been created by the base SearchIterator class
+ m_search_ = m_strsrch_->search;
+ }
+}
+
+StringSearch::StringSearch(const StringSearch &that) :
+ SearchIterator(that.m_text_, that.m_breakiterator_),
+ m_collator_(),
+ m_pattern_(that.m_pattern_)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Free m_search_ from the superclass
+ uprv_free(m_search_);
+ m_search_ = NULL;
+
+ if (that.m_strsrch_ == NULL) {
+ // This was not a good copy
+ m_strsrch_ = NULL;
+ }
+ else {
+ // Make a deep copy
+ m_strsrch_ = usearch_openFromCollator(m_pattern_.getBuffer(),
+ m_pattern_.length(),
+ m_text_.getBuffer(),
+ m_text_.length(),
+ that.m_strsrch_->collator,
+ (UBreakIterator *)that.m_breakiterator_,
+ &status);
+ if (U_SUCCESS(status)) {
+ // Alias the collator
+ m_collator_.setUCollator((UCollator *)m_strsrch_->collator);
+ // m_search_ has been created by the base SearchIterator class
+ m_search_ = m_strsrch_->search;
+ }
+ }
+}
+
+StringSearch::~StringSearch()
+{
+ if (m_strsrch_ != NULL) {
+ usearch_close(m_strsrch_);
+ m_search_ = NULL;
+ }
+}
+
+StringSearch *
+StringSearch::clone() const {
+ return new StringSearch(*this);
+}
+
+// operator overloading ---------------------------------------------
+StringSearch & StringSearch::operator=(const StringSearch &that)
+{
+ if ((*this) != that) {
+ UErrorCode status = U_ZERO_ERROR;
+ m_text_ = that.m_text_;
+ m_breakiterator_ = that.m_breakiterator_;
+ m_pattern_ = that.m_pattern_;
+ // all m_search_ in the parent class is linked up with m_strsrch_
+ usearch_close(m_strsrch_);
+ m_strsrch_ = usearch_openFromCollator(m_pattern_.getBuffer(),
+ m_pattern_.length(),
+ m_text_.getBuffer(),
+ m_text_.length(),
+ that.m_strsrch_->collator,
+ NULL, &status);
+ // Alias the collator
+ m_collator_.setUCollator((UCollator *)m_strsrch_->collator);
+ m_search_ = m_strsrch_->search;
+ }
+ return *this;
+}
+
+UBool StringSearch::operator==(const SearchIterator &that) const
+{
+ if (this == &that) {
+ return TRUE;
+ }
+ if (SearchIterator::operator ==(that)) {
+ StringSearch &thatsrch = (StringSearch &)that;
+ return (this->m_pattern_ == thatsrch.m_pattern_ &&
+ this->m_strsrch_->collator == thatsrch.m_strsrch_->collator);
+ }
+ return FALSE;
+}
+
+// public get and set methods ----------------------------------------
+
+void StringSearch::setOffset(int32_t position, UErrorCode &status)
+{
+ // status checked in usearch_setOffset
+ usearch_setOffset(m_strsrch_, position, &status);
+}
+
+int32_t StringSearch::getOffset(void) const
+{
+ return usearch_getOffset(m_strsrch_);
+}
+
+void StringSearch::setText(const UnicodeString &text, UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ m_text_ = text;
+ usearch_setText(m_strsrch_, text.getBuffer(), text.length(), &status);
+ }
+}
+
+void StringSearch::setText(CharacterIterator &text, UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ text.getText(m_text_);
+ usearch_setText(m_strsrch_, m_text_.getBuffer(), m_text_.length(), &status);
+ }
+}
+
+RuleBasedCollator * StringSearch::getCollator() const
+{
+ return (RuleBasedCollator *)&m_collator_;
+}
+
+void StringSearch::setCollator(RuleBasedCollator *coll, UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ usearch_setCollator(m_strsrch_, coll->getUCollator(), &status);
+ // Alias the collator
+ m_collator_.setUCollator((UCollator *)m_strsrch_->collator);
+ }
+}
+
+void StringSearch::setPattern(const UnicodeString &pattern,
+ UErrorCode &status)
+{
+ if (U_SUCCESS(status)) {
+ m_pattern_ = pattern;
+ usearch_setPattern(m_strsrch_, m_pattern_.getBuffer(), m_pattern_.length(),
+ &status);
+ }
+}
+
+const UnicodeString & StringSearch::getPattern() const
+{
+ return m_pattern_;
+}
+
+// public methods ----------------------------------------------------
+
+void StringSearch::reset()
+{
+ usearch_reset(m_strsrch_);
+}
+
+SearchIterator * StringSearch::safeClone(void) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *result = new StringSearch(m_pattern_, m_text_,
+ (RuleBasedCollator *)&m_collator_,
+ m_breakiterator_,
+ status);
+ /* test for NULL */
+ if (result == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ result->setOffset(getOffset(), status);
+ result->setMatchStart(m_strsrch_->search->matchedIndex);
+ result->setMatchLength(m_strsrch_->search->matchedLength);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ return result;
+}
+
+// protected method -------------------------------------------------
+
+int32_t StringSearch::handleNext(int32_t position, UErrorCode &status)
+{
+ // values passed here are already in the pre-shift position
+ if (U_SUCCESS(status)) {
+ if (m_strsrch_->pattern.CELength == 0) {
+ m_search_->matchedIndex =
+ m_search_->matchedIndex == USEARCH_DONE ?
+ getOffset() : m_search_->matchedIndex + 1;
+ m_search_->matchedLength = 0;
+ ucol_setOffset(m_strsrch_->textIter, m_search_->matchedIndex,
+ &status);
+ if (m_search_->matchedIndex == m_search_->textLength) {
+ m_search_->matchedIndex = USEARCH_DONE;
+ }
+ }
+ else {
+ // looking at usearch.cpp, this part is shifted out to
+ // StringSearch instead of SearchIterator because m_strsrch_ is
+ // not accessible in SearchIterator
+ if (position + m_strsrch_->pattern.defaultShiftSize
+ > m_search_->textLength) {
+ setMatchNotFound();
+ return USEARCH_DONE;
+ }
+ if (m_search_->matchedLength <= 0) {
+ // the flipping direction issue has already been handled
+ // in next()
+ // for boundary check purposes. this will ensure that the
+ // next match will not preceed the current offset
+ // note search->matchedIndex will always be set to something
+ // in the code
+ m_search_->matchedIndex = position - 1;
+ }
+
+ ucol_setOffset(m_strsrch_->textIter, position, &status);
+ for (;;) {
+ if (m_search_->isCanonicalMatch) {
+ // can't use exact here since extra accents are allowed.
+ usearch_handleNextCanonical(m_strsrch_, &status);
+ }
+ else {
+ usearch_handleNextExact(m_strsrch_, &status);
+ }
+ if (U_FAILURE(status)) {
+ return USEARCH_DONE;
+ }
+ if (m_breakiterator_ == NULL
+#if !UCONFIG_NO_BREAK_ITERATION
+ ||
+ m_search_->matchedIndex == USEARCH_DONE ||
+ (m_breakiterator_->isBoundary(m_search_->matchedIndex) &&
+ m_breakiterator_->isBoundary(m_search_->matchedIndex +
+ m_search_->matchedLength))
+#endif
+ ) {
+ if (m_search_->matchedIndex == USEARCH_DONE) {
+ ucol_setOffset(m_strsrch_->textIter,
+ m_search_->textLength, &status);
+ }
+ else {
+ ucol_setOffset(m_strsrch_->textIter,
+ m_search_->matchedIndex, &status);
+ }
+ return m_search_->matchedIndex;
+ }
+ }
+ }
+ }
+ return USEARCH_DONE;
+}
+
+int32_t StringSearch::handlePrev(int32_t position, UErrorCode &status)
+{
+ // values passed here are already in the pre-shift position
+ if (U_SUCCESS(status)) {
+ if (m_strsrch_->pattern.CELength == 0) {
+ m_search_->matchedIndex =
+ (m_search_->matchedIndex == USEARCH_DONE ? getOffset() :
+ m_search_->matchedIndex);
+ if (m_search_->matchedIndex == 0) {
+ setMatchNotFound();
+ }
+ else {
+ m_search_->matchedIndex --;
+ ucol_setOffset(m_strsrch_->textIter, m_search_->matchedIndex,
+ &status);
+ m_search_->matchedLength = 0;
+ }
+ }
+ else {
+ // looking at usearch.cpp, this part is shifted out to
+ // StringSearch instead of SearchIterator because m_strsrch_ is
+ // not accessible in SearchIterator
+ if (!m_search_->isOverlap &&
+ position - m_strsrch_->pattern.defaultShiftSize < 0) {
+ setMatchNotFound();
+ return USEARCH_DONE;
+ }
+ for (;;) {
+ if (m_search_->isCanonicalMatch) {
+ // can't use exact here since extra accents are allowed.
+ usearch_handlePreviousCanonical(m_strsrch_, &status);
+ }
+ else {
+ usearch_handlePreviousExact(m_strsrch_, &status);
+ }
+ if (U_FAILURE(status)) {
+ return USEARCH_DONE;
+ }
+ if (m_breakiterator_ == NULL
+#if !UCONFIG_NO_BREAK_ITERATION
+ ||
+ m_search_->matchedIndex == USEARCH_DONE ||
+ (m_breakiterator_->isBoundary(m_search_->matchedIndex) &&
+ m_breakiterator_->isBoundary(m_search_->matchedIndex +
+ m_search_->matchedLength))
+#endif
+ ) {
+ return m_search_->matchedIndex;
+ }
+ }
+ }
+
+ return m_search_->matchedIndex;
+ }
+ return USEARCH_DONE;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/taiwncal.cpp b/Build/source/libs/icu/icu-xetex/i18n/taiwncal.cpp
new file mode 100644
index 00000000000..60098c15fdf
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/taiwncal.cpp
@@ -0,0 +1,222 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2003-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ *
+ * File TAIWNCAL.CPP
+ *
+ * Modification History:
+ * 05/13/2003 srl copied from gregocal.cpp
+ * 06/29/2007 srl copied from buddhcal.cpp
+ *
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "taiwncal.h"
+#include "unicode/gregocal.h"
+#include "umutex.h"
+#include <float.h>
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TaiwanCalendar)
+
+static const int32_t kTaiwanEraStart = 1911; // 1911 (Gregorian)
+
+static const int32_t kGregorianEpoch = 1970;
+
+TaiwanCalendar::TaiwanCalendar(const Locale& aLocale, UErrorCode& success)
+: GregorianCalendar(aLocale, success)
+{
+ setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
+}
+
+TaiwanCalendar::~TaiwanCalendar()
+{
+}
+
+TaiwanCalendar::TaiwanCalendar(const TaiwanCalendar& source)
+: GregorianCalendar(source)
+{
+}
+
+TaiwanCalendar& TaiwanCalendar::operator= ( const TaiwanCalendar& right)
+{
+ GregorianCalendar::operator=(right);
+ return *this;
+}
+
+Calendar* TaiwanCalendar::clone(void) const
+{
+ return new TaiwanCalendar(*this);
+}
+
+const char *TaiwanCalendar::getType() const
+{
+ return "taiwan";
+}
+
+int32_t TaiwanCalendar::handleGetExtendedYear()
+{
+ // EXTENDED_YEAR in TaiwanCalendar is a Gregorian year
+ // The default value of EXTENDED_YEAR is 1970 (Minguo 59)
+ int32_t year = kGregorianEpoch;
+
+ if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR
+ && newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
+ year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
+ } else {
+ int32_t era = internalGet(UCAL_ERA, MINGUO);
+ if(era == MINGUO) {
+ year = internalGet(UCAL_YEAR, 1) + kTaiwanEraStart;
+ } else if(era == BEFORE_MINGUO) {
+ year = 1 - internalGet(UCAL_YEAR, 1) + kTaiwanEraStart;
+ }
+ }
+ return year;
+}
+
+void TaiwanCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
+{
+ GregorianCalendar::handleComputeFields(julianDay, status);
+ int32_t y = internalGet(UCAL_EXTENDED_YEAR) - kTaiwanEraStart;
+ if(y>0) {
+ internalSet(UCAL_ERA, MINGUO);
+ internalSet(UCAL_YEAR, y);
+ } else {
+ internalSet(UCAL_ERA, BEFORE_MINGUO);
+ internalSet(UCAL_YEAR, 1-y);
+ }
+}
+
+int32_t TaiwanCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
+{
+ if(field == UCAL_ERA) {
+ if(limitType == UCAL_LIMIT_MINIMUM || limitType == UCAL_LIMIT_GREATEST_MINIMUM) {
+ return BEFORE_MINGUO;
+ } else {
+ return MINGUO;
+ }
+ } else {
+ return GregorianCalendar::handleGetLimit(field,limitType);
+ }
+}
+
+#if 0
+void TaiwanCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& status)
+{
+ //Calendar::timeToFields(theTime, quick, status);
+
+ int32_t era = internalGet(UCAL_ERA);
+ int32_t year = internalGet(UCAL_YEAR);
+
+ if(era == GregorianCalendar::BC) {
+ year = 1-year;
+ era = TaiwanCalendar::MINGUO;
+ } else if(era == GregorianCalendar::AD) {
+ era = TaiwanCalendar::MINGUO;
+ } else {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ }
+
+ year = year - kTaiwanEraStart;
+
+ internalSet(UCAL_ERA, era);
+ internalSet(UCAL_YEAR, year);
+}
+#endif
+
+// default century
+const UDate TaiwanCalendar::fgSystemDefaultCentury = DBL_MIN;
+const int32_t TaiwanCalendar::fgSystemDefaultCenturyYear = -1;
+
+UDate TaiwanCalendar::fgSystemDefaultCenturyStart = DBL_MIN;
+int32_t TaiwanCalendar::fgSystemDefaultCenturyStartYear = -1;
+
+
+UBool TaiwanCalendar::haveDefaultCentury() const
+{
+ return TRUE;
+}
+
+UDate TaiwanCalendar::defaultCenturyStart() const
+{
+ return internalGetDefaultCenturyStart();
+}
+
+int32_t TaiwanCalendar::defaultCenturyStartYear() const
+{
+ return internalGetDefaultCenturyStartYear();
+}
+
+UDate
+TaiwanCalendar::internalGetDefaultCenturyStart() const
+{
+ // lazy-evaluate systemDefaultCenturyStart
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStart
+
+ return fgSystemDefaultCenturyStart;
+}
+
+int32_t
+TaiwanCalendar::internalGetDefaultCenturyStartYear() const
+{
+ // lazy-evaluate systemDefaultCenturyStartYear
+ UBool needsUpdate;
+ UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate);
+
+ if (needsUpdate) {
+ initializeSystemDefaultCentury();
+ }
+
+ // use defaultCenturyStart unless it's the flag value;
+ // then use systemDefaultCenturyStartYear
+
+ return fgSystemDefaultCenturyStartYear;
+}
+
+void
+TaiwanCalendar::initializeSystemDefaultCentury()
+{
+ // initialize systemDefaultCentury and systemDefaultCenturyYear based
+ // on the current time. They'll be set to 80 years before
+ // the current time.
+ // No point in locking as it should be idempotent.
+ if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ TaiwanCalendar calendar(Locale("@calendar=Taiwan"),status);
+ if (U_SUCCESS(status))
+ {
+ calendar.setTime(Calendar::getNow(), status);
+ calendar.add(UCAL_YEAR, -80, status);
+ UDate newStart = calendar.getTime(status);
+ int32_t newYear = calendar.get(UCAL_YEAR, status);
+ {
+ umtx_lock(NULL);
+ fgSystemDefaultCenturyStart = newStart;
+ fgSystemDefaultCenturyStartYear = newYear;
+ umtx_unlock(NULL);
+ }
+ }
+ // We have no recourse upon failure unless we want to propagate the failure
+ // out.
+ }
+}
+
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/taiwncal.h b/Build/source/libs/icu/icu-xetex/i18n/taiwncal.h
new file mode 100644
index 00000000000..fe6f89b1902
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/taiwncal.h
@@ -0,0 +1,225 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ********************************************************************************
+ *
+ * File BUDDHCAL.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 05/13/2003 srl copied from gregocal.h
+ * 06/29/2007 srl copied from buddhcal.h
+ ********************************************************************************
+ */
+
+#ifndef TAIWNCAL_H
+#define TAIWNCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Concrete class which provides the Taiwan calendar.
+ * <P>
+ * <code>TaiwanCalendar</code> is a subclass of <code>GregorianCalendar</code>
+ * that numbers years since 1912
+ * <p>
+ * The Taiwan calendar is identical to the Gregorian calendar in all respects
+ * except for the year and era. Years are numbered since 1912 AD (Gregorian),
+ * so that 1912 AD (Gregorian) is equivalent to 1 MINGUO (Minguo Era) and 1998 AD is 87 MINGUO.
+ * <p>
+ * The Taiwan Calendar has two eras: <code>BEFORE_MINGUO</code> and <code>MINGUO</code>.
+ * <p>
+ * @internal
+ */
+class TaiwanCalendar : public GregorianCalendar {
+public:
+
+ /**
+ * Useful constants for TaiwanCalendar. Only one Era.
+ * @internal
+ */
+ enum EEras {
+ BEFORE_MINGUO = 0,
+ MINGUO = 1
+ };
+
+ /**
+ * Constructs a TaiwanCalendar based on the current time in the default time zone
+ * with the given locale.
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the status of TaiwanCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @internal
+ */
+ TaiwanCalendar(const Locale& aLocale, UErrorCode& success);
+
+
+ /**
+ * Destructor
+ * @internal
+ */
+ virtual ~TaiwanCalendar();
+
+ /**
+ * Copy constructor
+ * @param source the object to be copied.
+ * @internal
+ */
+ TaiwanCalendar(const TaiwanCalendar& source);
+
+ /**
+ * Default assignment operator
+ * @param right the object to be copied.
+ * @internal
+ */
+ TaiwanCalendar& operator=(const TaiwanCalendar& right);
+
+ /**
+ * Create and return a polymorphic copy of this calendar.
+ * @return return a polymorphic copy of this calendar.
+ * @internal
+ */
+ virtual Calendar* clone(void) const;
+
+public:
+ /**
+ * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
+ * override. This method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
+ * this method.
+ *
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @internal
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to a return
+ * value from getDynamicClassID(). For example:
+ *
+ * Base* polymorphic_pointer = createPolymorphicObject();
+ * if (polymorphic_pointer->getDynamicClassID() ==
+ * Derived::getStaticClassID()) ...
+ *
+ * @return The class ID for all objects of this class.
+ * @internal
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * return the calendar type, "Taiwan".
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+private:
+ TaiwanCalendar(); // default constructor not implemented
+
+ protected:
+ /**
+ * Return the extended year defined by the current fields. This will
+ * use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
+ * as UCAL_ERA) specific to the calendar system, depending on which set of
+ * fields is newer.
+ * @return the extended year
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+ /**
+ * Subclasses may override this method to compute several fields
+ * specific to each calendar system.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode& status);
+ /**
+ * Subclass API for defining limits of different types.
+ * @param field one of the field numbers
+ * @param limitType one of <code>MINIMUM</code>, <code>GREATEST_MINIMUM</code>,
+ * <code>LEAST_MAXIMUM</code>, or <code>MAXIMUM</code>
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+
+ /**
+ * Returns TRUE because the Taiwan Calendar does have a default century
+ * @internal
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * Returns the date of the start of the default century
+ * @return start of century - in milliseconds since epoch, 1970
+ * @internal
+ */
+ virtual UDate defaultCenturyStart() const;
+
+ /**
+ * Returns the year in which the default century begins
+ * @internal
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+ private: // default century stuff.
+ /**
+ * The system maintains a static default century start date. This is initialized
+ * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
+ * indicate an uninitialized state. Once the system default century date and year
+ * are set, they do not change.
+ */
+ static UDate fgSystemDefaultCenturyStart;
+
+ /**
+ * See documentation for systemDefaultCenturyStart.
+ */
+ static int32_t fgSystemDefaultCenturyStartYear;
+
+ /**
+ * Default value that indicates the defaultCenturyStartYear is unitialized
+ */
+ static const int32_t fgSystemDefaultCenturyYear;
+
+ /**
+ * start of default century, as a date
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * Returns the beginning date of the 100-year window that dates
+ * with 2-digit years are considered to fall within.
+ */
+ UDate internalGetDefaultCenturyStart(void) const;
+
+ /**
+ * Returns the first year of the 100-year window that dates with
+ * 2-digit years are considered to fall within.
+ */
+ int32_t internalGetDefaultCenturyStartYear(void) const;
+
+ /**
+ * Initializes the 100-year window that dates with 2-digit years
+ * are considered to fall within so that its start date is 80 years
+ * before the current time.
+ */
+ static void initializeSystemDefaultCentury(void);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _TAIWNCAL
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/tblcoll.cpp b/Build/source/libs/icu/icu-xetex/i18n/tblcoll.cpp
new file mode 100644
index 00000000000..bd367fd33b2
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/tblcoll.cpp
@@ -0,0 +1,702 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ ******************************************************************************
+ */
+
+/**
+ * File tblcoll.cpp
+ *
+ * Created by: Helena Shih
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 2/5/97 aliu Added streamIn and streamOut methods. Added
+ * constructor which reads RuleBasedCollator object from
+ * a binary file. Added writeToFile method which streams
+ * RuleBasedCollator out to a binary file. The streamIn
+ * and streamOut methods use istream and ostream objects
+ * in binary mode.
+ * 2/11/97 aliu Moved declarations out of for loop initializer.
+ * Added Mac compatibility #ifdef for ios::nocreate.
+ * 2/12/97 aliu Modified to use TableCollationData sub-object to
+ * hold invariant data.
+ * 2/13/97 aliu Moved several methods into this class from Collation.
+ * Added a private RuleBasedCollator(Locale&) constructor,
+ * to be used by Collator::getInstance(). General
+ * clean up. Made use of UErrorCode variables consistent.
+ * 2/20/97 helena Added clone, operator==, operator!=, operator=, and copy
+ * constructor and getDynamicClassID.
+ * 3/5/97 aliu Changed compaction cycle to improve performance. We
+ * use the maximum allowable value which is kBlockCount.
+ * Modified getRules() to load rules dynamically. Changed
+ * constructFromFile() call to accomodate this (added
+ * parameter to specify whether binary loading is to
+ * take place).
+ * 05/06/97 helena Added memory allocation error check.
+ * 6/20/97 helena Java class name change.
+ * 6/23/97 helena Adding comments to make code more readable.
+ * 09/03/97 helena Added createCollationKeyValues().
+ * 06/26/98 erm Changes for CollationKeys using byte arrays.
+ * 08/10/98 erm Synched with 1.2 version of RuleBasedCollator.java
+ * 04/23/99 stephen Removed EDecompositionMode, merged with
+ * Normalizer::EMode
+ * 06/14/99 stephen Removed kResourceBundleSuffix
+ * 06/22/99 stephen Fixed logic in constructFromFile() since .ctx
+ * files are no longer used.
+ * 11/02/99 helena Collator performance enhancements. Special case
+ * for NO_OP situations.
+ * 11/17/99 srl More performance enhancements. Inlined some internal functions.
+ * 12/15/99 aliu Update to support Thai collation. Move NormalizerIterator
+ * to implementation file.
+ * 01/29/01 synwee Modified into a C++ wrapper calling C APIs (ucol.h)
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "unicode/ures.h"
+#include "unicode/uset.h"
+#include "ucol_imp.h"
+#include "uresimp.h"
+#include "uhash.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "putilimp.h"
+
+/* public RuleBasedCollator constructor ---------------------------------- */
+
+U_NAMESPACE_BEGIN
+
+/**
+* Copy constructor, aliasing, not write-through
+*/
+RuleBasedCollator::RuleBasedCollator(const RuleBasedCollator& that)
+: Collator(that)
+, dataIsOwned(FALSE)
+, isWriteThroughAlias(FALSE)
+, ucollator(NULL)
+{
+ RuleBasedCollator::operator=(that);
+}
+
+RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules,
+ UErrorCode& status) :
+dataIsOwned(FALSE)
+{
+ construct(rules,
+ UCOL_DEFAULT_STRENGTH,
+ UCOL_DEFAULT,
+ status);
+}
+
+RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules,
+ ECollationStrength collationStrength,
+ UErrorCode& status) : dataIsOwned(FALSE)
+{
+ construct(rules,
+ getUCollationStrength(collationStrength),
+ UCOL_DEFAULT,
+ status);
+}
+
+RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules,
+ UColAttributeValue decompositionMode,
+ UErrorCode& status) :
+dataIsOwned(FALSE)
+{
+ construct(rules,
+ UCOL_DEFAULT_STRENGTH,
+ decompositionMode,
+ status);
+}
+
+RuleBasedCollator::RuleBasedCollator(const UnicodeString& rules,
+ ECollationStrength collationStrength,
+ UColAttributeValue decompositionMode,
+ UErrorCode& status) : dataIsOwned(FALSE)
+{
+ construct(rules,
+ getUCollationStrength(collationStrength),
+ decompositionMode,
+ status);
+}
+RuleBasedCollator::RuleBasedCollator(const uint8_t *bin, int32_t length,
+ const RuleBasedCollator *base,
+ UErrorCode &status) :
+dataIsOwned(TRUE),
+isWriteThroughAlias(FALSE)
+{
+ ucollator = ucol_openBinary(bin, length, base->ucollator, &status);
+}
+
+void
+RuleBasedCollator::setRuleStringFromCollator()
+{
+ int32_t length;
+ const UChar *r = ucol_getRules(ucollator, &length);
+
+ if (r && length > 0) {
+ // alias the rules string
+ urulestring.setTo(TRUE, r, length);
+ }
+ else {
+ urulestring.truncate(0); // Clear string.
+ }
+}
+
+// not aliasing, not write-through
+void
+RuleBasedCollator::construct(const UnicodeString& rules,
+ UColAttributeValue collationStrength,
+ UColAttributeValue decompositionMode,
+ UErrorCode& status)
+{
+ ucollator = ucol_openRules(rules.getBuffer(), rules.length(),
+ decompositionMode, collationStrength,
+ NULL, &status);
+
+ dataIsOwned = TRUE; // since we own a collator now, we need to get rid of it
+ isWriteThroughAlias = FALSE;
+
+ if(ucollator == NULL) {
+ if(U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return; // Failure
+ }
+
+ setRuleStringFromCollator();
+}
+
+/* RuleBasedCollator public destructor ----------------------------------- */
+
+RuleBasedCollator::~RuleBasedCollator()
+{
+ if (dataIsOwned)
+ {
+ ucol_close(ucollator);
+ }
+ ucollator = 0;
+}
+
+/* RuleBaseCollator public methods --------------------------------------- */
+
+UBool RuleBasedCollator::operator==(const Collator& that) const
+{
+ /* only checks for address equals here */
+ if (Collator::operator==(that))
+ return TRUE;
+
+ if (getDynamicClassID() != that.getDynamicClassID())
+ return FALSE; /* not the same class */
+
+ RuleBasedCollator& thatAlias = (RuleBasedCollator&)that;
+
+ // weiv: use C function, commented code below is wrong
+ return ucol_equals(this->ucollator, thatAlias.ucollator);
+ /*
+ synwee : orginal code does not check for data compatibility
+ */
+ /*
+ if (ucollator != thatAlias.ucollator)
+ return FALSE;
+
+ return TRUE;
+ */
+}
+
+UBool RuleBasedCollator::operator!=(const Collator& other) const
+{
+ return !(*this == other);
+}
+
+// aliasing, not write-through
+RuleBasedCollator& RuleBasedCollator::operator=(const RuleBasedCollator& that)
+{
+ if (this != &that)
+ {
+ if (dataIsOwned)
+ {
+ ucol_close(ucollator);
+ }
+
+ urulestring.truncate(0); // empty the rule string
+ dataIsOwned = TRUE;
+ isWriteThroughAlias = FALSE;
+
+ UErrorCode intStatus = U_ZERO_ERROR;
+ int32_t buffersize = U_COL_SAFECLONE_BUFFERSIZE;
+ ucollator = ucol_safeClone(that.ucollator, NULL, &buffersize,
+ &intStatus);
+ if (U_SUCCESS(intStatus)) {
+ setRuleStringFromCollator();
+ }
+ }
+ return *this;
+}
+
+// aliasing, not write-through
+Collator* RuleBasedCollator::clone() const
+{
+ return new RuleBasedCollator(*this);
+}
+
+CollationElementIterator* RuleBasedCollator::createCollationElementIterator
+ (const UnicodeString& source) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ CollationElementIterator *result = new CollationElementIterator(source, this,
+ status);
+ if (U_FAILURE(status)) {
+ delete result;
+ return NULL;
+ }
+
+ return result;
+}
+
+/**
+* Create a CollationElementIterator object that will iterate over the
+* elements in a string, using the collation rules defined in this
+* RuleBasedCollator
+*/
+CollationElementIterator* RuleBasedCollator::createCollationElementIterator
+ (const CharacterIterator& source) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ CollationElementIterator *result = new CollationElementIterator(source, this,
+ status);
+
+ if (U_FAILURE(status)) {
+ delete result;
+ return NULL;
+ }
+
+ return result;
+}
+
+/**
+* Return a string representation of this collator's rules. The string can
+* later be passed to the constructor that takes a UnicodeString argument,
+* which will construct a collator that's functionally identical to this one.
+* You can also allow users to edit the string in order to change the collation
+* data, or you can print it out for inspection, or whatever.
+*/
+const UnicodeString& RuleBasedCollator::getRules() const
+{
+ return urulestring;
+}
+
+void RuleBasedCollator::getRules(UColRuleOption delta, UnicodeString &buffer)
+{
+ int32_t rulesize = ucol_getRulesEx(ucollator, delta, NULL, -1);
+
+ if (rulesize > 0) {
+ UChar *rules = (UChar*) uprv_malloc( sizeof(UChar) * (rulesize) );
+ if(rules != NULL) {
+ ucol_getRulesEx(ucollator, delta, rules, rulesize);
+ buffer.setTo(rules, rulesize);
+ uprv_free(rules);
+ } else { // couldn't allocate
+ buffer.remove();
+ }
+ }
+ else {
+ buffer.remove();
+ }
+}
+
+UnicodeSet *
+RuleBasedCollator::getTailoredSet(UErrorCode &status) const
+{
+ if(U_FAILURE(status)) {
+ return NULL;
+ }
+ return (UnicodeSet *)ucol_getTailoredSet(this->ucollator, &status);
+}
+
+
+void RuleBasedCollator::getVersion(UVersionInfo versionInfo) const
+{
+ if (versionInfo!=NULL){
+ ucol_getVersion(ucollator, versionInfo);
+ }
+}
+
+Collator::EComparisonResult RuleBasedCollator::compare(
+ const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ return getEComparisonResult(compare(source.getBuffer(), uprv_min(length,source.length()), target.getBuffer(), uprv_min(length,target.length()), status));
+}
+
+UCollationResult RuleBasedCollator::compare(
+ const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length,
+ UErrorCode &status) const
+{
+ return compare(source.getBuffer(), uprv_min(length,source.length()), target.getBuffer(), uprv_min(length,target.length()), status);
+}
+
+Collator::EComparisonResult RuleBasedCollator::compare(const UChar* source,
+ int32_t sourceLength,
+ const UChar* target,
+ int32_t targetLength)
+ const
+{
+ return getEComparisonResult(ucol_strcoll(ucollator, source, sourceLength,
+ target, targetLength));
+}
+
+UCollationResult RuleBasedCollator::compare(const UChar* source,
+ int32_t sourceLength,
+ const UChar* target,
+ int32_t targetLength,
+ UErrorCode &status) const
+{
+ if(U_SUCCESS(status)) {
+ return ucol_strcoll(ucollator, source, sourceLength, target, targetLength);
+ } else {
+ return UCOL_EQUAL;
+ }
+}
+
+/**
+* Compare two strings using this collator
+*/
+Collator::EComparisonResult RuleBasedCollator::compare(
+ const UnicodeString& source,
+ const UnicodeString& target) const
+{
+ return getEComparisonResult(ucol_strcoll(ucollator, source.getBuffer(), source.length(),
+ target.getBuffer(), target.length()));
+}
+
+UCollationResult RuleBasedCollator::compare(
+ const UnicodeString& source,
+ const UnicodeString& target,
+ UErrorCode &status) const
+{
+ if(U_SUCCESS(status)) {
+ return ucol_strcoll(ucollator, source.getBuffer(), source.length(),
+ target.getBuffer(), target.length());
+ } else {
+ return UCOL_EQUAL;
+ }
+}
+
+/**
+* Retrieve a collation key for the specified string. The key can be compared
+* with other collation keys using a bitwise comparison (e.g. memcmp) to find
+* the ordering of their respective source strings. This is handy when doing a
+* sort, where each sort key must be compared many times.
+*
+* The basic algorithm here is to find all of the collation elements for each
+* character in the source string, convert them to an ASCII representation, and
+* put them into the collation key. But it's trickier than that. Each
+* collation element in a string has three components: primary ('A' vs 'B'),
+* secondary ('u' vs '\u00FC'), and tertiary ('A' vs 'a'), and a primary difference
+* at the end of a string takes precedence over a secondary or tertiary
+* difference earlier in the string.
+*
+* To account for this, we put all of the primary orders at the beginning of
+* the string, followed by the secondary and tertiary orders. Each set of
+* orders is terminated by nulls so that a key for a string which is a initial
+* substring of another key will compare less without any special case.
+*
+* Here's a hypothetical example, with the collation element represented as a
+* three-digit number, one digit for primary, one for secondary, etc.
+*
+* String: A a B \u00C9
+* Collation Elements: 101 100 201 511
+* Collation Key: 1125<null>0001<null>1011<null>
+*
+* To make things even trickier, secondary differences (accent marks) are
+* compared starting at the *end* of the string in languages with French
+* secondary ordering. But when comparing the accent marks on a single base
+* character, they are compared from the beginning. To handle this, we reverse
+* all of the accents that belong to each base character, then we reverse the
+* entire string of secondary orderings at the end.
+*/
+CollationKey& RuleBasedCollator::getCollationKey(
+ const UnicodeString& source,
+ CollationKey& sortkey,
+ UErrorCode& status) const
+{
+ return getCollationKey(source.getBuffer(), source.length(), sortkey, status);
+}
+
+CollationKey& RuleBasedCollator::getCollationKey(const UChar* source,
+ int32_t sourceLen,
+ CollationKey& sortkey,
+ UErrorCode& status) const
+{
+ if (U_FAILURE(status))
+ {
+ return sortkey.setToBogus();
+ }
+
+ if ((!source) || (sourceLen == 0)) {
+ return sortkey.reset();
+ }
+
+ uint8_t *result;
+ int32_t resultLen = ucol_getSortKeyWithAllocation(ucollator,
+ source, sourceLen,
+ &result,
+ &status);
+ sortkey.adopt(result, resultLen);
+ return sortkey;
+}
+
+/**
+ * Return the maximum length of any expansion sequences that end with the
+ * specified comparison order.
+ * @param order a collation order returned by previous or next.
+ * @return the maximum length of any expansion seuences ending with the
+ * specified order or 1 if collation order does not occur at the end of any
+ * expansion sequence.
+ * @see CollationElementIterator#getMaxExpansion
+ */
+int32_t RuleBasedCollator::getMaxExpansion(int32_t order) const
+{
+ uint8_t result;
+ UCOL_GETMAXEXPANSION(ucollator, (uint32_t)order, result);
+ return result;
+}
+
+uint8_t* RuleBasedCollator::cloneRuleData(int32_t &length,
+ UErrorCode &status)
+{
+ return ucol_cloneRuleData(ucollator, &length, &status);
+}
+
+
+int32_t RuleBasedCollator::cloneBinary(uint8_t *buffer, int32_t capacity, UErrorCode &status)
+{
+ return ucol_cloneBinary(ucollator, buffer, capacity, &status);
+}
+
+void RuleBasedCollator::setAttribute(UColAttribute attr,
+ UColAttributeValue value,
+ UErrorCode &status)
+{
+ if (U_FAILURE(status))
+ return;
+ checkOwned();
+ ucol_setAttribute(ucollator, attr, value, &status);
+}
+
+UColAttributeValue RuleBasedCollator::getAttribute(UColAttribute attr,
+ UErrorCode &status)
+{
+ if (U_FAILURE(status))
+ return UCOL_DEFAULT;
+ return ucol_getAttribute(ucollator, attr, &status);
+}
+
+uint32_t RuleBasedCollator::setVariableTop(const UChar *varTop, int32_t len, UErrorCode &status) {
+ checkOwned();
+ return ucol_setVariableTop(ucollator, varTop, len, &status);
+}
+
+uint32_t RuleBasedCollator::setVariableTop(const UnicodeString varTop, UErrorCode &status) {
+ checkOwned();
+ return ucol_setVariableTop(ucollator, varTop.getBuffer(), varTop.length(), &status);
+}
+
+void RuleBasedCollator::setVariableTop(const uint32_t varTop, UErrorCode &status) {
+ checkOwned();
+ ucol_restoreVariableTop(ucollator, varTop, &status);
+}
+
+uint32_t RuleBasedCollator::getVariableTop(UErrorCode &status) const {
+ return ucol_getVariableTop(ucollator, &status);
+}
+
+Collator* RuleBasedCollator::safeClone(void)
+{
+ UErrorCode intStatus = U_ZERO_ERROR;
+ int32_t buffersize = U_COL_SAFECLONE_BUFFERSIZE;
+ UCollator *ucol = ucol_safeClone(ucollator, NULL, &buffersize,
+ &intStatus);
+ if (U_FAILURE(intStatus)) {
+ return NULL;
+ }
+
+ RuleBasedCollator *result = new RuleBasedCollator();
+ result->ucollator = ucol;
+ result->dataIsOwned = TRUE;
+ result->isWriteThroughAlias = FALSE;
+ setRuleStringFromCollator();
+
+ return result;
+}
+
+
+int32_t RuleBasedCollator::getSortKey(const UnicodeString& source,
+ uint8_t *result, int32_t resultLength)
+ const
+{
+ return ucol_getSortKey(ucollator, source.getBuffer(), source.length(), result, resultLength);
+}
+
+int32_t RuleBasedCollator::getSortKey(const UChar *source,
+ int32_t sourceLength, uint8_t *result,
+ int32_t resultLength) const
+{
+ return ucol_getSortKey(ucollator, source, sourceLength, result, resultLength);
+}
+
+Collator::ECollationStrength RuleBasedCollator::getStrength(void) const
+{
+ UErrorCode intStatus = U_ZERO_ERROR;
+ return getECollationStrength(ucol_getAttribute(ucollator, UCOL_STRENGTH,
+ &intStatus));
+}
+
+void RuleBasedCollator::setStrength(ECollationStrength newStrength)
+{
+ checkOwned();
+ UErrorCode intStatus = U_ZERO_ERROR;
+ UCollationStrength strength = getUCollationStrength(newStrength);
+ ucol_setAttribute(ucollator, UCOL_STRENGTH, strength, &intStatus);
+}
+
+/**
+* Create a hash code for this collation. Just hash the main rule table -- that
+* should be good enough for almost any use.
+*/
+int32_t RuleBasedCollator::hashCode() const
+{
+ int32_t length;
+ const UChar *rules = ucol_getRules(ucollator, &length);
+ return uhash_hashUCharsN(rules, length);
+}
+
+/**
+* return the locale of this collator
+*/
+const Locale RuleBasedCollator::getLocale(ULocDataLocaleType type, UErrorCode &status) const {
+ const char *result = ucol_getLocale(ucollator, type, &status);
+ if(result == NULL) {
+ Locale res("");
+ res.setToBogus();
+ return res;
+ } else {
+ return Locale(result);
+ }
+}
+
+void
+RuleBasedCollator::setLocales(const Locale& requestedLocale, const Locale& validLocale) {
+ checkOwned();
+ size_t rlen = uprv_strlen(requestedLocale.getName());
+ char* rloc = (char *)uprv_malloc((rlen+1)*sizeof(char));
+ if (rloc) {
+ uprv_strcpy(rloc, requestedLocale.getName());
+ size_t vlen = uprv_strlen(validLocale.getName());
+ char* vloc = (char*)uprv_malloc((vlen+1)*sizeof(char));
+ if (vloc) {
+ uprv_strcpy(vloc, validLocale.getName());
+ ucol_setReqValidLocales(ucollator, rloc, vloc);
+ return;
+ }
+ uprv_free(rloc);
+ }
+}
+
+// RuleBaseCollatorNew private constructor ----------------------------------
+
+RuleBasedCollator::RuleBasedCollator()
+ : dataIsOwned(FALSE), isWriteThroughAlias(FALSE), ucollator(NULL)
+{
+}
+
+RuleBasedCollator::RuleBasedCollator(const Locale& desiredLocale,
+ UErrorCode& status)
+ : dataIsOwned(FALSE), isWriteThroughAlias(FALSE), ucollator(NULL)
+{
+ if (U_FAILURE(status))
+ return;
+
+ /*
+ Try to load, in order:
+ 1. The desired locale's collation.
+ 2. A fallback of the desired locale.
+ 3. The default locale's collation.
+ 4. A fallback of the default locale.
+ 5. The default collation rules, which contains en_US collation rules.
+
+ To reiterate, we try:
+ Specific:
+ language+country+variant
+ language+country
+ language
+ Default:
+ language+country+variant
+ language+country
+ language
+ Root: (aka DEFAULTRULES)
+ steps 1-5 are handled by resource bundle fallback mechanism.
+ however, in a very unprobable situation that no resource bundle
+ data exists, step 5 is repeated with hardcoded default rules.
+ */
+
+ setUCollator(desiredLocale, status);
+
+ if (U_FAILURE(status))
+ {
+ status = U_ZERO_ERROR;
+
+ setUCollator(kRootLocaleName, status);
+ if (status == U_ZERO_ERROR) {
+ status = U_USING_DEFAULT_WARNING;
+ }
+ }
+
+ if (U_SUCCESS(status))
+ {
+ setRuleStringFromCollator();
+ }
+}
+
+void
+RuleBasedCollator::setUCollator(const char *locale,
+ UErrorCode &status)
+{
+ if (U_FAILURE(status))
+ return;
+ if (ucollator && dataIsOwned)
+ ucol_close(ucollator);
+ ucollator = ucol_open_internal(locale, &status);
+ dataIsOwned = TRUE;
+ isWriteThroughAlias = FALSE;
+}
+
+
+void
+RuleBasedCollator::checkOwned() {
+ if (!(dataIsOwned || isWriteThroughAlias)) {
+ UErrorCode status = U_ZERO_ERROR;
+ ucollator = ucol_safeClone(ucollator, NULL, NULL, &status);
+ setRuleStringFromCollator();
+ dataIsOwned = TRUE;
+ isWriteThroughAlias = FALSE;
+ }
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedCollator)
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/timezone.cpp b/Build/source/libs/icu/icu-xetex/i18n/timezone.cpp
new file mode 100644
index 00000000000..566561173d6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/timezone.cpp
@@ -0,0 +1,1411 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*
+* File TIMEZONE.CPP
+*
+* Modification History:
+*
+* Date Name Description
+* 12/05/96 clhuang Creation.
+* 04/21/97 aliu General clean-up and bug fixing.
+* 05/08/97 aliu Fixed Hashtable code per code review.
+* 07/09/97 helena Changed createInstance to createDefault.
+* 07/29/97 aliu Updated with all-new list of 96 UNIX-derived
+* TimeZones. Changed mechanism to load from static
+* array rather than resource bundle.
+* 07/07/1998 srl Bugfixes from the Java side: UTC GMT CAT NST
+* Added getDisplayName API
+* going to add custom parsing.
+*
+* ISSUES:
+* - should getDisplayName cache something?
+* - should custom time zones be cached? [probably]
+* 08/10/98 stephen Brought getDisplayName() API in-line w/ conventions
+* 08/19/98 stephen Changed createTimeZone() to never return 0
+* 09/02/98 stephen Added getOffset(monthLen) and hasSameRules()
+* 09/15/98 stephen Added getStaticClassID()
+* 02/22/99 stephen Removed character literals for EBCDIC safety
+* 05/04/99 stephen Changed initDefault() for Mutex issues
+* 07/12/99 helena HPUX 11 CC Port.
+* 12/03/99 aliu Moved data out of static table into icudata.dll.
+* Substantial rewrite of zone lookup, default zone, and
+* available IDs code. Misc. cleanup.
+*********************************************************************************/
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+
+#ifdef U_DEBUG_TZ
+# include <stdio.h>
+# include "uresimp.h" // for debugging
+
+static void debug_tz_loc(const char *f, int32_t l)
+{
+ fprintf(stderr, "%s:%d: ", f, l);
+}
+
+static void debug_tz_msg(const char *pat, ...)
+{
+ va_list ap;
+ va_start(ap, pat);
+ vfprintf(stderr, pat, ap);
+ fflush(stderr);
+}
+static char gStrBuf[256];
+#define U_DEBUG_TZ_STR(x) u_austrncpy(gStrBuf,x,sizeof(gStrBuf)-1)
+// must use double parens, i.e.: U_DEBUG_TZ_MSG(("four is: %d",4));
+#define U_DEBUG_TZ_MSG(x) {debug_tz_loc(__FILE__,__LINE__);debug_tz_msg x;}
+#else
+#define U_DEBUG_TZ_MSG(x)
+#endif
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/simpletz.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "unicode/ures.h"
+#include "gregoimp.h"
+#include "uresimp.h" // struct UResourceBundle
+#include "olsontz.h"
+#include "mutex.h"
+#include "unicode/udata.h"
+#include "ucln_in.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "unicode/strenum.h"
+#include "uassert.h"
+
+#define kZONEINFO "zoneinfo"
+#define kREGIONS "Regions"
+#define kZONES "Zones"
+#define kRULES "Rules"
+#define kNAMES "Names"
+#define kDEFAULT "Default"
+#define kMAX_CUSTOM_HOUR 23
+#define kMAX_CUSTOM_MIN 59
+#define kMAX_CUSTOM_SEC 59
+#define MINUS 0x002D
+#define PLUS 0x002B
+#define ZERO_DIGIT 0x0030
+
+// Static data and constants
+
+static const UChar GMT_ID[] = {0x47, 0x4D, 0x54, 0x00}; /* "GMT" */
+static const UChar Z_STR[] = {0x7A, 0x00}; /* "z" */
+static const UChar ZZZZ_STR[] = {0x7A, 0x7A, 0x7A, 0x7A, 0x00}; /* "zzzz" */
+static const int32_t GMT_ID_LENGTH = 3;
+
+static UMTX LOCK;
+static UMTX TZSET_LOCK;
+static U_NAMESPACE_QUALIFIER TimeZone* DEFAULT_ZONE = NULL;
+static U_NAMESPACE_QUALIFIER TimeZone* _GMT = NULL; // cf. TimeZone::GMT
+
+static char TZDATA_VERSION[16] = "";
+
+#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
+static U_NAMESPACE_QUALIFIER UnicodeString* OLSON_IDS = 0;
+#endif
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV timeZone_cleanup(void)
+{
+#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
+ delete []OLSON_IDS;
+ OLSON_IDS = 0;
+#endif
+
+ delete DEFAULT_ZONE;
+ DEFAULT_ZONE = NULL;
+
+ delete _GMT;
+ _GMT = NULL;
+
+ uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION));
+
+ if (LOCK) {
+ umtx_destroy(&LOCK);
+ LOCK = NULL;
+ }
+ if (TZSET_LOCK) {
+ umtx_destroy(&TZSET_LOCK);
+ TZSET_LOCK = NULL;
+ }
+
+ return TRUE;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+/**
+ * The Olson data is stored the "zoneinfo" resource bundle.
+ * Sub-resources are organized into three ranges of data: Zones, final
+ * rules, and country tables. There is also a meta-data resource
+ * which has 3 integers: The number of zones, rules, and countries,
+ * respectively. The country count includes the non-country 'Default'.
+ */
+static int32_t OLSON_ZONE_START = -1; // starting index of zones
+static int32_t OLSON_ZONE_COUNT = 0; // count of zones
+
+/**
+ * Given a pointer to an open "zoneinfo" resource, load up the Olson
+ * meta-data. Return TRUE if successful.
+ */
+static UBool getOlsonMeta(const UResourceBundle* top) {
+ if (OLSON_ZONE_START < 0) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ ures_getByKey(top, kZONES, &res, &ec);
+ if(U_SUCCESS(ec)) {
+ OLSON_ZONE_COUNT = ures_getSize(&res);
+ OLSON_ZONE_START = 0;
+ U_DEBUG_TZ_MSG(("OZC%d OZS%d\n",OLSON_ZONE_COUNT, OLSON_ZONE_START));
+ }
+ ures_close(&res);
+ }
+ return (OLSON_ZONE_START >= 0);
+}
+
+/**
+ * Load up the Olson meta-data. Return TRUE if successful.
+ */
+static UBool getOlsonMeta() {
+ if (OLSON_ZONE_START < 0) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ if (U_SUCCESS(ec)) {
+ getOlsonMeta(top);
+ }
+ ures_close(top);
+ }
+ return (OLSON_ZONE_START >= 0);
+}
+
+static int32_t findInStringArray(UResourceBundle* array, const UnicodeString& id, UErrorCode &status)
+{
+ UnicodeString copy;
+ const UChar *u;
+ int32_t len;
+
+ int32_t start = 0;
+ int32_t limit = ures_getSize(array);
+ int32_t mid;
+ int32_t lastMid = INT32_MAX;
+ if(U_FAILURE(status) || (limit < 1)) {
+ return -1;
+ }
+ U_DEBUG_TZ_MSG(("fisa: Looking for %s, between %d and %d\n", U_DEBUG_TZ_STR(UnicodeString(id).getTerminatedBuffer()), start, limit));
+
+ for (;;) {
+ mid = (int32_t)((start + limit) / 2);
+ if (lastMid == mid) { /* Have we moved? */
+ break; /* We haven't moved, and it wasn't found. */
+ }
+ lastMid = mid;
+ u = ures_getStringByIndex(array, mid, &len, &status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ U_DEBUG_TZ_MSG(("tz: compare to %s, %d .. [%d] .. %d\n", U_DEBUG_TZ_STR(u), start, mid, limit));
+ copy.setTo(TRUE, u, len);
+ int r = id.compare(copy);
+ if(r==0) {
+ U_DEBUG_TZ_MSG(("fisa: found at %d\n", mid));
+ return mid;
+ } else if(r<0) {
+ limit = mid;
+ } else {
+ start = mid;
+ }
+ }
+ U_DEBUG_TZ_MSG(("fisa: not found\n"));
+ return -1;
+}
+
+/**
+ * Fetch a specific zone by name. Replaces the getByKey call.
+ * @param top Top timezone resource
+ * @param id Time zone ID
+ * @param oldbundle Bundle for reuse (or NULL). see 'ures_open()'
+ * @return the zone's bundle if found, or undefined if error. Reuses oldbundle.
+ */
+static UResourceBundle* getZoneByName(const UResourceBundle* top, const UnicodeString& id, UResourceBundle *oldbundle, UErrorCode& status) {
+ // load the Rules object
+ UResourceBundle *tmp = ures_getByKey(top, kNAMES, NULL, &status);
+
+ // search for the string
+ int32_t idx = findInStringArray(tmp, id, status);
+
+ if((idx == -1) && U_SUCCESS(status)) {
+ // not found
+ status = U_MISSING_RESOURCE_ERROR;
+ //ures_close(oldbundle);
+ //oldbundle = NULL;
+ } else {
+ U_DEBUG_TZ_MSG(("gzbn: oldbundle= size %d, type %d, %s\n", ures_getSize(tmp), ures_getType(tmp), u_errorName(status)));
+ tmp = ures_getByKey(top, kZONES, tmp, &status); // get Zones object from top
+ U_DEBUG_TZ_MSG(("gzbn: loaded ZONES, size %d, type %d, path %s %s\n", ures_getSize(tmp), ures_getType(tmp), ures_getPath(tmp), u_errorName(status)));
+ oldbundle = ures_getByIndex(tmp, idx, oldbundle, &status); // get nth Zone object
+ U_DEBUG_TZ_MSG(("gzbn: loaded z#%d, size %d, type %d, path %s, %s\n", idx, ures_getSize(oldbundle), ures_getType(oldbundle), ures_getPath(oldbundle), u_errorName(status)));
+ }
+ ures_close(tmp);
+ if(U_FAILURE(status)) {
+ //ures_close(oldbundle);
+ return NULL;
+ } else {
+ return oldbundle;
+ }
+}
+
+
+UResourceBundle* TimeZone::loadRule(const UResourceBundle* top, const UnicodeString& ruleid, UResourceBundle* oldbundle, UErrorCode& status) {
+ char key[64];
+ ruleid.extract(0, sizeof(key)-1, key, (int32_t)sizeof(key)-1, US_INV);
+ U_DEBUG_TZ_MSG(("loadRule(%s)\n", key));
+ UResourceBundle *r = ures_getByKey(top, kRULES, oldbundle, &status);
+ U_DEBUG_TZ_MSG(("loadRule(%s) -> kRULES [%s]\n", key, u_errorName(status)));
+ r = ures_getByKey(r, key, r, &status);
+ U_DEBUG_TZ_MSG(("loadRule(%s) -> item [%s]\n", key, u_errorName(status)));
+ return r;
+}
+
+/**
+ * Given an ID, open the appropriate resource for the given time zone.
+ * Dereference aliases if necessary.
+ * @param id zone id
+ * @param res resource, which must be ready for use (initialized but not open)
+ * @param ec input-output error code
+ * @return top-level resource bundle
+ */
+static UResourceBundle* openOlsonResource(const UnicodeString& id,
+ UResourceBundle& res,
+ UErrorCode& ec)
+{
+#if U_DEBUG_TZ
+ char buf[128];
+ id.extract(0, sizeof(buf)-1, buf, sizeof(buf), "");
+#endif
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ U_DEBUG_TZ_MSG(("pre: res sz=%d\n", ures_getSize(&res)));
+ /* &res = */ getZoneByName(top, id, &res, ec);
+ // Dereference if this is an alias. Docs say result should be 1
+ // but it is 0 in 2.8 (?).
+ U_DEBUG_TZ_MSG(("Loading zone '%s' (%s, size %d) - %s\n", buf, ures_getKey((UResourceBundle*)&res), ures_getSize(&res), u_errorName(ec)));
+ if (ures_getSize(&res) <= 1 && getOlsonMeta(top)) {
+ int32_t deref = ures_getInt(&res, &ec) + 0;
+ U_DEBUG_TZ_MSG(("getInt: %s - type is %d\n", u_errorName(ec), ures_getType(&res)));
+ UResourceBundle *ares = ures_getByKey(top, kZONES, NULL, &ec); // dereference Zones section
+ ures_getByIndex(ares, deref, &res, &ec);
+ ures_close(ares);
+ U_DEBUG_TZ_MSG(("alias to #%d (%s) - %s\n", deref, "??", u_errorName(ec)));
+ } else {
+ U_DEBUG_TZ_MSG(("not an alias - size %d\n", ures_getSize(&res)));
+ }
+ U_DEBUG_TZ_MSG(("%s - final status is %s\n", buf, u_errorName(ec)));
+ return top;
+}
+
+#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
+
+/**
+ * Load all the ids from the "zoneinfo" resource bundle into a static
+ * array that we hang onto. This is _only_ used to implement the
+ * deprecated createAvailableIDs() API.
+ */
+static UBool loadOlsonIDs() {
+ if (OLSON_IDS != 0) {
+ return TRUE;
+ }
+
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString* ids = 0;
+ int32_t count = 0;
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ UResourceBundle *nres = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Names section
+ if (U_SUCCESS(ec)) {
+ getOlsonMeta(top);
+ int32_t start = 0;
+ count = ures_getSize(nres);
+ ids = new UnicodeString[(count > 0) ? count : 1];
+ for (int32_t i=0; i<count; ++i) {
+ int32_t idLen = 0;
+ const UChar* id = ures_getStringByIndex(nres, i, &idLen, &ec);
+ ids[i].fastCopyFrom(UnicodeString(TRUE, id, idLen));
+ if (U_FAILURE(ec)) {
+ break;
+ }
+ }
+ }
+ ures_close(nres);
+ ures_close(top);
+
+ if (U_FAILURE(ec)) {
+ delete[] ids;
+ return FALSE;
+ }
+
+ // Keep mutexed operations as short as possible by doing all
+ // computations first, then doing pointer copies within the mutex.
+ umtx_lock(&LOCK);
+ if (OLSON_IDS == 0) {
+ OLSON_IDS = ids;
+ ids = 0;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+ umtx_unlock(&LOCK);
+
+ // If another thread initialized the statics first, then delete
+ // our unused data.
+ delete[] ids;
+ return TRUE;
+}
+
+#endif
+
+// -------------------------------------
+
+const TimeZone* U_EXPORT2
+TimeZone::getGMT(void)
+{
+ UBool needsInit;
+ UMTX_CHECK(&LOCK, (_GMT == NULL), needsInit); /* This is here to prevent race conditions. */
+
+ // Initialize _GMT independently of other static data; it should
+ // be valid even if we can't load the time zone UDataMemory.
+ if (needsInit) {
+ umtx_lock(&LOCK);
+ if (_GMT == 0) {
+ _GMT = new SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH));
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+ umtx_unlock(&LOCK);
+ }
+ return _GMT;
+}
+
+// *****************************************************************************
+// class TimeZone
+// *****************************************************************************
+
+UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(TimeZone)
+
+TimeZone::TimeZone()
+ : UObject(), fID()
+{
+}
+
+// -------------------------------------
+
+TimeZone::TimeZone(const UnicodeString &id)
+ : UObject(), fID(id)
+{
+}
+
+// -------------------------------------
+
+TimeZone::~TimeZone()
+{
+}
+
+// -------------------------------------
+
+TimeZone::TimeZone(const TimeZone &source)
+ : UObject(source), fID(source.fID)
+{
+}
+
+// -------------------------------------
+
+TimeZone &
+TimeZone::operator=(const TimeZone &right)
+{
+ if (this != &right) fID = right.fID;
+ return *this;
+}
+
+// -------------------------------------
+
+UBool
+TimeZone::operator==(const TimeZone& that) const
+{
+ return getDynamicClassID() == that.getDynamicClassID() &&
+ fID == that.fID;
+}
+
+// -------------------------------------
+
+TimeZone* U_EXPORT2
+TimeZone::createTimeZone(const UnicodeString& ID)
+{
+ /* We first try to lookup the zone ID in our system list. If this
+ * fails, we try to parse it as a custom string GMT[+-]hh:mm. If
+ * all else fails, we return GMT, which is probably not what the
+ * user wants, but at least is a functioning TimeZone object.
+ *
+ * We cannot return NULL, because that would break compatibility
+ * with the JDK.
+ */
+ TimeZone* result = createSystemTimeZone(ID);
+
+ if (result == 0) {
+ U_DEBUG_TZ_MSG(("failed to load system time zone with id - falling to custom"));
+ result = createCustomTimeZone(ID);
+ }
+ if (result == 0) {
+ U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to GMT"));
+ result = getGMT()->clone();
+ }
+ return result;
+}
+
+/**
+ * Lookup the given name in our system zone table. If found,
+ * instantiate a new zone of that name and return it. If not
+ * found, return 0.
+ */
+TimeZone*
+TimeZone::createSystemTimeZone(const UnicodeString& id) {
+ TimeZone* z = 0;
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ U_DEBUG_TZ_MSG(("pre-err=%s\n", u_errorName(ec)));
+ UResourceBundle *top = openOlsonResource(id, res, ec);
+ U_DEBUG_TZ_MSG(("post-err=%s\n", u_errorName(ec)));
+ if (U_SUCCESS(ec)) {
+ z = new OlsonTimeZone(top, &res, ec);
+ if (z) {
+ z->setID(id);
+ } else {
+ U_DEBUG_TZ_MSG(("cstz: olson time zone failed to initialize - err %s\n", u_errorName(ec)));
+ }
+ }
+ ures_close(&res);
+ ures_close(top);
+ if (U_FAILURE(ec)) {
+ U_DEBUG_TZ_MSG(("cstz: failed to create, err %s\n", u_errorName(ec)));
+ delete z;
+ z = 0;
+ }
+ return z;
+}
+
+// -------------------------------------
+
+/**
+ * Initialize DEFAULT_ZONE from the system default time zone. The
+ * caller should confirm that DEFAULT_ZONE is NULL before calling.
+ * Upon return, DEFAULT_ZONE will not be NULL, unless operator new()
+ * returns NULL.
+ *
+ * Must be called OUTSIDE mutex.
+ */
+void
+TimeZone::initDefault()
+{
+ // We access system timezone data through TPlatformUtilities,
+ // including tzset(), timezone, and tzname[].
+ int32_t rawOffset = 0;
+ const char *hostID;
+
+ // First, try to create a system timezone, based
+ // on the string ID in tzname[0].
+ {
+ // NOTE: Local mutex here. TimeZone mutex below
+ // mutexed to avoid threading issues in the platform functions.
+ // Some of the locale/timezone OS functions may not be thread safe,
+ // so the intent is that any setting from anywhere within ICU
+ // happens while the ICU mutex is held.
+ // The operating system might actually use ICU to implement timezones.
+ // So we may have ICU calling ICU here, like on AIX.
+ // In order to prevent a double lock of a non-reentrant mutex in a
+ // different part of ICU, we use TZSET_LOCK to allow only one instance
+ // of ICU to query these thread unsafe OS functions at any given time.
+ Mutex lock(&TZSET_LOCK);
+
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ uprv_tzset(); // Initialize tz... system data
+
+ // Get the timezone ID from the host. This function should do
+ // any required host-specific remapping; e.g., on Windows this
+ // function maps the Date and Time control panel setting to an
+ // ICU timezone ID.
+ hostID = uprv_tzname(0);
+
+ // Invert sign because UNIX semantics are backwards
+ rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND;
+ }
+
+ UBool initialized;
+ UMTX_CHECK(&LOCK, (DEFAULT_ZONE != NULL), initialized);
+ if (initialized) {
+ /* Hrmph? Either a race condition happened, or tzset initialized ICU. */
+ return;
+ }
+
+ TimeZone* default_zone = NULL;
+
+ /* Make sure that the string is NULL terminated to prevent BoundsChecker/Purify warnings. */
+ UnicodeString hostStrID(hostID, -1, US_INV);
+ hostStrID.append((UChar)0);
+ hostStrID.truncate(hostStrID.length()-1);
+ default_zone = createSystemTimeZone(hostStrID);
+
+ int32_t hostIDLen = hostStrID.length();
+ if (default_zone != NULL && rawOffset != default_zone->getRawOffset()
+ && (3 <= hostIDLen && hostIDLen <= 4))
+ {
+ // Uh oh. This probably wasn't a good id.
+ // It was probably an ambiguous abbreviation
+ delete default_zone;
+ default_zone = NULL;
+ }
+
+#if 0
+ // NOTE: As of ICU 2.8, we no longer have an offsets table, since
+ // historical zones can change offset over time. If we add
+ // build-time heuristics to infer the "most frequent" raw offset
+ // of a zone, we can build tables and institute defaults, as done
+ // in ICU <= 2.6.
+
+ // If we couldn't get the time zone ID from the host, use
+ // the default host timezone offset. Further refinements
+ // to this include querying the host to determine if DST
+ // is in use or not and possibly using the host locale to
+ // select from multiple zones at a the same offset. We
+ // don't do any of this now, but we could easily add this.
+ if (default_zone == NULL) {
+ // Use the designated default in the time zone list that has the
+ // appropriate GMT offset, if there is one.
+
+ const OffsetIndex* index = INDEX_BY_OFFSET;
+
+ for (;;) {
+ if (index->gmtOffset > rawOffset) {
+ // Went past our desired offset; no match found
+ break;
+ }
+ if (index->gmtOffset == rawOffset) {
+ // Found our desired offset
+ default_zone = createSystemTimeZone(ZONE_IDS[index->defaultZone]);
+ break;
+ }
+ // Compute the position of the next entry. If the delta value
+ // in this entry is zero, then there is no next entry.
+ uint16_t delta = index->nextEntryDelta;
+ if (delta == 0) {
+ break;
+ }
+ index = (const OffsetIndex*)((int8_t*)index + delta);
+ }
+ }
+#endif
+
+ // Construct a fixed standard zone with the host's ID
+ // and raw offset.
+ if (default_zone == NULL) {
+ default_zone = new SimpleTimeZone(rawOffset, hostStrID);
+ }
+
+ // If we _still_ don't have a time zone, use GMT.
+ if (default_zone == NULL) {
+ default_zone = getGMT()->clone();
+ }
+
+ // If DEFAULT_ZONE is still NULL, set it up.
+ umtx_lock(&LOCK);
+ if (DEFAULT_ZONE == NULL) {
+ DEFAULT_ZONE = default_zone;
+ default_zone = NULL;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+ umtx_unlock(&LOCK);
+
+ delete default_zone;
+}
+
+// -------------------------------------
+
+TimeZone* U_EXPORT2
+TimeZone::createDefault()
+{
+ /* This is here to prevent race conditions. */
+ UBool needsInit;
+ UMTX_CHECK(&LOCK, (DEFAULT_ZONE == NULL), needsInit);
+ if (needsInit) {
+ initDefault();
+ }
+
+ Mutex lock(&LOCK); // In case adoptDefault is called
+ return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL;
+}
+
+// -------------------------------------
+
+void U_EXPORT2
+TimeZone::adoptDefault(TimeZone* zone)
+{
+ if (zone != NULL)
+ {
+ TimeZone* old = NULL;
+
+ umtx_init(&LOCK); /* This is here to prevent race conditions. */
+ umtx_lock(&LOCK);
+ old = DEFAULT_ZONE;
+ DEFAULT_ZONE = zone;
+ umtx_unlock(&LOCK);
+
+ delete old;
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+}
+// -------------------------------------
+
+void U_EXPORT2
+TimeZone::setDefault(const TimeZone& zone)
+{
+ adoptDefault(zone.clone());
+}
+
+//----------------------------------------------------------------------
+
+/**
+ * This is the default implementation for subclasses that do not
+ * override this method. This implementation calls through to the
+ * 8-argument getOffset() method after suitable computations, and
+ * correctly adjusts GMT millis to local millis when necessary.
+ */
+void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& ec) const {
+ if (U_FAILURE(ec)) {
+ return;
+ }
+
+ rawOffset = getRawOffset();
+ if (!local) {
+ date += rawOffset; // now in local standard millis
+ }
+
+ // When local == TRUE, date might not be in local standard
+ // millis. getOffset taking 7 parameters used here assume
+ // the given time in day is local standard time.
+ // At STD->DST transition, there is a range of time which
+ // does not exist. When 'date' is in this time range
+ // (and local == TRUE), this method interprets the specified
+ // local time as DST. At DST->STD transition, there is a
+ // range of time which occurs twice. In this case, this
+ // method interprets the specified local time as STD.
+ // To support the behavior above, we need to call getOffset
+ // (with 7 args) twice when local == true and DST is
+ // detected in the initial call.
+ for (int32_t pass=0; ; ++pass) {
+ int32_t year, month, dom, dow;
+ double day = uprv_floor(date / U_MILLIS_PER_DAY);
+ int32_t millis = (int32_t) (date - day * U_MILLIS_PER_DAY);
+
+ Grego::dayToFields(day, year, month, dom, dow);
+
+ dstOffset = getOffset(GregorianCalendar::AD, year, month, dom,
+ (uint8_t) dow, millis,
+ Grego::monthLength(year, month),
+ ec) - rawOffset;
+
+ // Recompute if local==TRUE, dstOffset!=0.
+ if (pass!=0 || !local || dstOffset == 0) {
+ break;
+ }
+ // adjust to local standard millis
+ date -= dstOffset;
+ }
+}
+
+// -------------------------------------
+
+// New available IDs API as of ICU 2.4. Uses StringEnumeration API.
+
+class TZEnumeration : public StringEnumeration {
+private:
+
+ // Map into to zones. Our results are zone[map[i]] for
+ // i=0..len-1, where zone[i] is the i-th Olson zone. If map==NULL
+ // then our results are zone[i] for i=0..len-1. Len will be zero
+ // iff the zone data could not be loaded.
+ int32_t* map;
+ int32_t len;
+ int32_t pos;
+
+ UBool getID(int32_t i) {
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t idLen = 0;
+ const UChar* id = NULL;
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ top = ures_getByKey(top, kNAMES, top, &ec); // dereference Zones section
+ id = ures_getStringByIndex(top, i, &idLen, &ec);
+ if(U_FAILURE(ec)) {
+ unistr.truncate(0);
+ }
+ else {
+ unistr.fastCopyFrom(UnicodeString(TRUE, id, idLen));
+ }
+ ures_close(top);
+ return U_SUCCESS(ec);
+ }
+
+public:
+ TZEnumeration() : map(NULL), len(0), pos(0) {
+ if (getOlsonMeta()) {
+ len = OLSON_ZONE_COUNT;
+ }
+ }
+
+ TZEnumeration(int32_t rawOffset) : map(NULL), len(0), pos(0) {
+ if (!getOlsonMeta()) {
+ return;
+ }
+
+ // Allocate more space than we'll need. The end of the array will
+ // be blank.
+ map = (int32_t*)uprv_malloc(OLSON_ZONE_COUNT * sizeof(int32_t));
+ if (map == 0) {
+ return;
+ }
+
+ uprv_memset(map, 0, sizeof(int32_t) * OLSON_ZONE_COUNT);
+
+ UnicodeString s;
+ for (int32_t i=0; i<OLSON_ZONE_COUNT; ++i) {
+ if (getID(i)) {
+ // This is VERY inefficient.
+ TimeZone* z = TimeZone::createTimeZone(unistr);
+ // Make sure we get back the ID we wanted (if the ID is
+ // invalid we get back GMT).
+ if (z != 0 && z->getID(s) == unistr &&
+ z->getRawOffset() == rawOffset) {
+ map[len++] = i;
+ }
+ delete z;
+ }
+ }
+ }
+
+ TZEnumeration(const char* country) : map(NULL), len(0), pos(0) {
+ if (!getOlsonMeta()) {
+ return;
+ }
+
+ char key[] = {0, 0, 0, 0,0, 0, 0,0, 0, 0,0}; // e.g., "US", or "Default" for no country
+ if (country) {
+ uprv_strncat(key, country, 2);
+ } else {
+ uprv_strcpy(key, kDEFAULT);
+ }
+
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ top = ures_getByKey(top, kREGIONS, top, &ec); // dereference 'Regions' section
+ if (U_SUCCESS(ec)) {
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ ures_getByKey(top, key, &res, &ec);
+ // The list of zones is a list of integers, from 0..n-1,
+ // where n is the total number of system zones.
+ const int32_t* v = ures_getIntVector(&res, &len, &ec);
+ if (U_SUCCESS(ec)) {
+ U_ASSERT(len > 0);
+ map = (int32_t*)uprv_malloc(sizeof(int32_t) * len);
+ if (map != 0) {
+ for (uint16_t i=0; i<len; ++i) {
+ U_ASSERT(v[i] >= 0 && v[i] < OLSON_ZONE_COUNT);
+ map[i] = v[i];
+ }
+ }
+ } else {
+ U_DEBUG_TZ_MSG(("Failed to load tz for region %s: %s\n", country, u_errorName(ec)));
+ }
+ ures_close(&res);
+ }
+ ures_close(top);
+ }
+
+ TZEnumeration(const TZEnumeration &other) : StringEnumeration(), map(NULL), len(0), pos(0) {
+ if(other.len > 0) {
+ if(other.map != NULL) {
+ map = (int32_t *)uprv_malloc(other.len * sizeof(int32_t));
+ if(map != NULL) {
+ len = other.len;
+ uprv_memcpy(map, other.map, len * sizeof(int32_t));
+ pos = other.pos;
+ }
+ } else {
+ len = other.len;
+ pos = other.pos;
+ }
+ }
+ }
+
+ virtual ~TZEnumeration() {
+ uprv_free(map);
+ }
+
+ virtual StringEnumeration *clone() const {
+ return new TZEnumeration(*this);
+ }
+
+ virtual int32_t count(UErrorCode& status) const {
+ return U_FAILURE(status) ? 0 : len;
+ }
+
+ virtual const UnicodeString* snext(UErrorCode& status) {
+ if (U_SUCCESS(status) && pos < len) {
+ getID((map == 0) ? pos : map[pos]);
+ ++pos;
+ return &unistr;
+ }
+ return 0;
+ }
+
+ virtual void reset(UErrorCode& /*status*/) {
+ pos = 0;
+ }
+
+public:
+ static UClassID U_EXPORT2 getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TZEnumeration)
+
+StringEnumeration* U_EXPORT2
+TimeZone::createEnumeration() {
+ return new TZEnumeration();
+}
+
+StringEnumeration* U_EXPORT2
+TimeZone::createEnumeration(int32_t rawOffset) {
+ return new TZEnumeration(rawOffset);
+}
+
+StringEnumeration* U_EXPORT2
+TimeZone::createEnumeration(const char* country) {
+ return new TZEnumeration(country);
+}
+
+// -------------------------------------
+
+#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
+
+const UnicodeString**
+TimeZone::createAvailableIDs(int32_t rawOffset, int32_t& numIDs)
+{
+ // We are creating a new array to existing UnicodeString pointers.
+ // The caller will delete the array when done, but not the pointers
+ // in the array.
+
+ numIDs = 0;
+ if (!loadOlsonIDs()) {
+ return 0;
+ }
+
+ // Allocate more space than we'll need. The end of the array will
+ // be blank.
+ const UnicodeString** ids =
+ (const UnicodeString** )uprv_malloc(OLSON_ZONE_COUNT * sizeof(UnicodeString *));
+ if (ids == 0) {
+ return 0;
+ }
+
+ uprv_memset(ids, 0, sizeof(UnicodeString*) * OLSON_ZONE_COUNT);
+
+ UnicodeString s;
+ for (int32_t i=0; i<OLSON_ZONE_COUNT; ++i) {
+ // This is VERY inefficient.
+ TimeZone* z = TimeZone::createTimeZone(OLSON_IDS[i]);
+ // Make sure we get back the ID we wanted (if the ID is
+ // invalid we get back GMT).
+ if (z != 0 && z->getID(s) == OLSON_IDS[i] &&
+ z->getRawOffset() == rawOffset) {
+ ids[numIDs++] = &OLSON_IDS[i]; // [sic]
+ }
+ delete z;
+ }
+
+ return ids;
+}
+
+// -------------------------------------
+
+const UnicodeString**
+TimeZone::createAvailableIDs(const char* country, int32_t& numIDs) {
+
+ // We are creating a new array to existing UnicodeString pointers.
+ // The caller will delete the array when done, but not the pointers
+ // in the array.
+
+ numIDs = 0;
+ if (!loadOlsonIDs()) {
+ return 0;
+ }
+
+ char key[] = { 0, 0, 0,0, 0, 0,0, 0, 0 }; // e.g., "US", or "Default" for non-country zones
+ if (country) {
+ uprv_strncat(key, country, 2);
+ } else {
+ uprv_strcpy(key, kDEFAULT);
+ }
+
+ const UnicodeString** ids = 0;
+
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ UResourceBundle *ares = ures_getByKey(top, kREGIONS, NULL, &ec); // dereference Regions section
+ if (U_SUCCESS(ec)) {
+ getOlsonMeta(top);
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ ures_getByKey(ares, key, &res, &ec);
+ U_DEBUG_TZ_MSG(("caI: on %s, err %s\n", country, u_errorName(ec)));
+ if (U_SUCCESS(ec)) {
+ /* The list of zones is a list of integers, from 0..n-1,
+ * where n is the total number of system zones. The
+ * numbering corresponds exactly to the ordering of
+ * OLSON_IDS.
+ */
+ const int32_t* v = ures_getIntVector(&res, &numIDs, &ec);
+ ids = (const UnicodeString**)
+ uprv_malloc(numIDs * sizeof(UnicodeString*));
+ if (ids == 0) {
+ numIDs = 0;
+ } else {
+ for (int32_t i=0; i<numIDs; ++i) {
+ ids[i] = &OLSON_IDS[v[i]]; // [sic]
+ }
+ }
+ }
+ ures_close(&res);
+ }
+ ures_close(ares);
+ ures_close(top);
+
+ return ids;
+}
+
+// -------------------------------------
+
+const UnicodeString**
+TimeZone::createAvailableIDs(int32_t& numIDs)
+{
+ // We are creating a new array to existing UnicodeString pointers.
+ // The caller will delete the array when done, but not the pointers
+ // in the array.
+ numIDs = 0;
+ if (!loadOlsonIDs()) {
+ return 0;
+ }
+
+ const UnicodeString** ids =
+ (const UnicodeString** )uprv_malloc(OLSON_ZONE_COUNT * sizeof(UnicodeString *));
+ if (ids != 0) {
+ numIDs = OLSON_ZONE_COUNT;
+ for (int32_t i=0; i<numIDs; ++i) {
+ ids[i] = &OLSON_IDS[i];
+ }
+ }
+
+ return ids;
+}
+
+#endif
+
+// ---------------------------------------
+
+int32_t U_EXPORT2
+TimeZone::countEquivalentIDs(const UnicodeString& id) {
+ int32_t result = 0;
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ U_DEBUG_TZ_MSG(("countEquivalentIDs..\n"));
+ UResourceBundle *top = openOlsonResource(id, res, ec);
+ if (U_SUCCESS(ec)) {
+ int32_t size = ures_getSize(&res);
+ U_DEBUG_TZ_MSG(("cEI: success (size %d, key %s)..\n", size, ures_getKey(&res)));
+ if (size == 4 || size == 6) {
+ UResourceBundle r;
+ ures_initStackObject(&r);
+ ures_getByIndex(&res, size-1, &r, &ec);
+ //result = ures_getSize(&r); // doesn't work
+ ures_getIntVector(&r, &result, &ec);
+ U_DEBUG_TZ_MSG(("ceI: result %d, err %s\n", result, u_errorName(ec)));
+ ures_close(&r);
+ }
+ } else {
+ U_DEBUG_TZ_MSG(("cEI: fail, %s\n", u_errorName(ec)));
+ }
+ ures_close(&res);
+ ures_close(top);
+ return result;
+}
+
+// ---------------------------------------
+
+const UnicodeString U_EXPORT2
+TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
+ U_DEBUG_TZ_MSG(("gEI(%d)\n", index));
+ UnicodeString result;
+ UErrorCode ec = U_ZERO_ERROR;
+ UResourceBundle res;
+ ures_initStackObject(&res);
+ UResourceBundle *top = openOlsonResource(id, res, ec);
+ int32_t zone = -1;
+ if (U_SUCCESS(ec)) {
+ int32_t size = ures_getSize(&res);
+ if (size == 4 || size == 6) {
+ UResourceBundle r;
+ ures_initStackObject(&r);
+ ures_getByIndex(&res, size-1, &r, &ec);
+ const int32_t* v = ures_getIntVector(&r, &size, &ec);
+ if (index >= 0 && index < size && getOlsonMeta()) {
+ zone = v[index];
+ }
+ ures_close(&r);
+ }
+ }
+ ures_close(&res);
+ if (zone >= 0) {
+ UResourceBundle *ares = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Zones section
+ if (U_SUCCESS(ec)) {
+ int32_t idLen = 0;
+ const UChar* id = ures_getStringByIndex(ares, zone, &idLen, &ec);
+ result.fastCopyFrom(UnicodeString(TRUE, id, idLen));
+ U_DEBUG_TZ_MSG(("gei(%d) -> %d, len%d, %s\n", index, zone, result.length(), u_errorName(ec)));
+ }
+ ures_close(ares);
+ }
+ ures_close(top);
+#if defined(U_DEBUG_TZ)
+ if(result.length() ==0) {
+ U_DEBUG_TZ_MSG(("equiv [__, #%d] -> 0 (%s)\n", index, u_errorName(ec)));
+ }
+#endif
+ return result;
+}
+
+// ---------------------------------------
+
+UnicodeString&
+TimeZone::getOlsonCanonicalID(const UnicodeString &id, UnicodeString &canonical) {
+ UErrorCode ec = U_ZERO_ERROR;
+ canonical.remove();
+ UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
+ UResourceBundle *res = getZoneByName(top, id, NULL, ec);
+ if (U_SUCCESS(ec)) {
+ if (ures_getSize(res) == 1) {
+ int32_t deref = ures_getInt(res, &ec);
+ UResourceBundle *nres = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Names section
+ int32_t len;
+ const UChar* tmp = ures_getStringByIndex(nres, deref, &len, &ec);
+ if (U_SUCCESS(ec)) {
+ canonical.setTo(tmp, len);
+ }
+ ures_close(nres);
+ } else {
+ canonical.setTo(id);
+ }
+ }
+ ures_close(res);
+ ures_close(top);
+ return canonical;
+}
+
+// ---------------------------------------
+
+
+UnicodeString&
+TimeZone::getDisplayName(UnicodeString& result) const
+{
+ return getDisplayName(FALSE,LONG,Locale::getDefault(), result);
+}
+
+UnicodeString&
+TimeZone::getDisplayName(const Locale& locale, UnicodeString& result) const
+{
+ return getDisplayName(FALSE, LONG, locale, result);
+}
+
+UnicodeString&
+TimeZone::getDisplayName(UBool daylight, EDisplayType style, UnicodeString& result) const
+{
+ return getDisplayName(daylight,style, Locale::getDefault(), result);
+}
+//--------------------------------------
+int32_t
+TimeZone::getDSTSavings()const {
+ if (useDaylightTime()) {
+ return 3600000;
+ }
+ return 0;
+}
+//---------------------------------------
+UnicodeString&
+TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& locale, UnicodeString& result) const
+{
+ // SRL TODO: cache the SDF, just like java.
+ UErrorCode status = U_ZERO_ERROR;
+#ifdef U_DEBUG_TZ
+ char buf[128];
+ fID.extract(0, sizeof(buf)-1, buf, sizeof(buf), "");
+#endif
+ SimpleDateFormat format(style == LONG ? ZZZZ_STR : Z_STR,locale,status);
+ U_DEBUG_TZ_MSG(("getDisplayName(%s)\n", buf));
+ if(!U_SUCCESS(status))
+ {
+#ifdef U_DEBUG_TZ
+ char buf2[128];
+ result.extract(0, sizeof(buf2)-1, buf2, sizeof(buf2), "");
+ U_DEBUG_TZ_MSG(("getDisplayName(%s) -> %s\n", buf, buf2));
+#endif
+ return result.remove();
+ }
+
+ // Create a new SimpleTimeZone as a stand-in for this zone; the
+ // stand-in will have no DST, or all DST, but the same ID and offset,
+ // and hence the same display name.
+ // We don't cache these because they're small and cheap to create.
+ UnicodeString tempID;
+ SimpleTimeZone *tz = NULL;
+ if(daylight && useDaylightTime()){
+ // For the pure-DST zone, we use JANUARY and DECEMBER
+ int savings = getDSTSavings();
+ tz = new SimpleTimeZone(getRawOffset(), getID(tempID),
+ UCAL_JANUARY, 1, 0, 0,
+ UCAL_FEBRUARY, 1, 0, 0,
+ savings, status);
+ }else{
+ tz = new SimpleTimeZone(getRawOffset(), getID(tempID));
+ }
+ format.applyPattern(style == LONG ? ZZZZ_STR : Z_STR);
+ Calendar *myCalendar = (Calendar*)format.getCalendar();
+ myCalendar->setTimeZone(*tz); // copy
+
+ delete tz;
+
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ return format.format(UDate(864000000L), result, pos); // Must use a valid date here.
+}
+
+
+/**
+ * Parse a custom time zone identifier and return a corresponding zone.
+ * @param id a string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or
+ * GMT[+-]hh.
+ * @return a newly created SimpleTimeZone with the given offset and
+ * no Daylight Savings Time, or null if the id cannot be parsed.
+*/
+TimeZone*
+TimeZone::createCustomTimeZone(const UnicodeString& id)
+{
+ static const int32_t kParseFailed = -99999;
+
+ NumberFormat* numberFormat = 0;
+
+ UnicodeString idUppercase = id;
+ idUppercase.toUpper();
+
+ if (id.length() > GMT_ID_LENGTH &&
+ idUppercase.startsWith(GMT_ID))
+ {
+ ParsePosition pos(GMT_ID_LENGTH);
+ UBool negative = FALSE;
+ int32_t hour = 0;
+ int32_t min = 0;
+ int32_t sec = 0;
+
+ if (id[pos.getIndex()] == MINUS /*'-'*/)
+ negative = TRUE;
+ else if (id[pos.getIndex()] != PLUS /*'+'*/)
+ return NULL;
+ pos.setIndex(pos.getIndex() + 1);
+
+ UErrorCode success = U_ZERO_ERROR;
+ numberFormat = NumberFormat::createInstance(success);
+ if(U_FAILURE(success)){
+ return NULL;
+ }
+ numberFormat->setParseIntegerOnly(TRUE);
+
+
+ // Look for either hh:mm, hhmm, or hh
+ int32_t start = pos.getIndex();
+
+ Formattable n(kParseFailed);
+
+ numberFormat->parse(id, n, pos);
+ if (pos.getIndex() == start) {
+ delete numberFormat;
+ return NULL;
+ }
+ hour = n.getLong();
+
+ if (pos.getIndex() < id.length()) {
+ if (pos.getIndex() - start > 2
+ || id[pos.getIndex()] != 0x003A /*':'*/) {
+ delete numberFormat;
+ return NULL;
+ }
+ // hh:mm
+ pos.setIndex(pos.getIndex() + 1);
+ int32_t oldPos = pos.getIndex();
+ n.setLong(kParseFailed);
+ numberFormat->parse(id, n, pos);
+ if ((pos.getIndex() - oldPos) != 2) {
+ // must be 2 digits
+ delete numberFormat;
+ return NULL;
+ }
+ min = n.getLong();
+ if (pos.getIndex() < id.length()) {
+ if (id[pos.getIndex()] != 0x003A /*':'*/) {
+ delete numberFormat;
+ return NULL;
+ }
+ // [:ss]
+ pos.setIndex(pos.getIndex() + 1);
+ oldPos = pos.getIndex();
+ n.setLong(kParseFailed);
+ numberFormat->parse(id, n, pos);
+ if (pos.getIndex() != id.length()
+ || (pos.getIndex() - oldPos) != 2) {
+ delete numberFormat;
+ return NULL;
+ }
+ sec = n.getLong();
+ }
+ } else {
+ // Supported formats are below -
+ //
+ // HHmmss
+ // Hmmss
+ // HHmm
+ // Hmm
+ // HH
+ // H
+
+ int32_t length = pos.getIndex() - start;
+ if (length <= 0 || 6 < length) {
+ // invalid length
+ delete numberFormat;
+ return NULL;
+ }
+ switch (length) {
+ case 1:
+ case 2:
+ // already set to hour
+ break;
+ case 3:
+ case 4:
+ min = hour % 100;
+ hour /= 100;
+ break;
+ case 5:
+ case 6:
+ sec = hour % 100;
+ min = (hour/100) % 100;
+ hour /= 10000;
+ break;
+ }
+ }
+
+ delete numberFormat;
+
+ if (hour > kMAX_CUSTOM_HOUR || min > kMAX_CUSTOM_MIN || sec > kMAX_CUSTOM_SEC) {
+ return 0;
+ }
+
+ // Create time zone ID - GMT[+|-]hhmm[ss]
+ UnicodeString tzID(GMT_ID);
+ if (hour | min | sec) {
+ if (negative) {
+ tzID += (UChar)MINUS;
+ } else {
+ tzID += (UChar)PLUS;
+ }
+
+ if (hour < 10) {
+ tzID += (UChar)ZERO_DIGIT;
+ } else {
+ tzID += (UChar)(ZERO_DIGIT + hour/10);
+ }
+ tzID += (UChar)(ZERO_DIGIT + hour%10);
+
+ if (min < 10) {
+ tzID += (UChar)ZERO_DIGIT;
+ } else {
+ tzID += (UChar)(ZERO_DIGIT + min/10);
+ }
+ tzID += (UChar)(ZERO_DIGIT + min%10);
+
+ if (sec) {
+ if (sec < 10) {
+ tzID += (UChar)ZERO_DIGIT;
+ } else {
+ tzID += (UChar)(ZERO_DIGIT + sec/10);
+ }
+ tzID += (UChar)(ZERO_DIGIT + sec%10);
+ }
+ }
+
+ int32_t offset = ((hour * 60 + min) * 60 + sec) * 1000;
+ if (negative) {
+ offset = -offset;
+ }
+ return new SimpleTimeZone(offset, tzID);
+ }
+ return NULL;
+}
+
+
+UBool
+TimeZone::hasSameRules(const TimeZone& other) const
+{
+ return (getRawOffset() == other.getRawOffset() &&
+ useDaylightTime() == other.useDaylightTime());
+}
+
+const char*
+TimeZone::getTZDataVersion(UErrorCode& status)
+{
+ /* This is here to prevent race conditions. */
+ UBool needsInit;
+ UMTX_CHECK(&LOCK, (TZDATA_VERSION[0] == 0), needsInit);
+ if (needsInit) {
+ int32_t len = sizeof(TZDATA_VERSION);
+ UResourceBundle *bundle = ures_openDirect(NULL, "zoneinfo", &status);
+ const UChar *tzver = ures_getStringByKey(bundle, "TZVersion",
+ &len, &status);
+
+ umtx_lock(&LOCK);
+ if (U_SUCCESS(status)) {
+ u_UCharsToChars(tzver, TZDATA_VERSION, len+1);
+ ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+ }
+ umtx_unlock(&LOCK);
+
+ ures_close(bundle);
+ }
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ return (const char*)TZDATA_VERSION;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/titletrn.cpp b/Build/source/libs/icu/icu-xetex/i18n/titletrn.cpp
new file mode 100644
index 00000000000..76c17d1bad7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/titletrn.cpp
@@ -0,0 +1,167 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/24/01 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/ustring.h"
+#include "titletrn.h"
+#include "umutex.h"
+#include "ucase.h"
+#include "cpputils.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TitlecaseTransliterator)
+
+TitlecaseTransliterator::TitlecaseTransliterator() :
+ CaseMapTransliterator(UNICODE_STRING("Any-Title", 9), NULL)
+{
+ // Need to look back 2 characters in the case of "can't"
+ setMaximumContextLength(2);
+}
+
+/**
+ * Destructor.
+ */
+TitlecaseTransliterator::~TitlecaseTransliterator() {
+}
+
+/**
+ * Copy constructor.
+ */
+TitlecaseTransliterator::TitlecaseTransliterator(const TitlecaseTransliterator& o) :
+ CaseMapTransliterator(o)
+{
+}
+
+/**
+ * Assignment operator.
+ */
+/*TitlecaseTransliterator& TitlecaseTransliterator::operator=(
+ const TitlecaseTransliterator& o) {
+ CaseMapTransliterator::operator=(o);
+ return *this;
+}*/
+
+/**
+ * Transliterator API.
+ */
+Transliterator* TitlecaseTransliterator::clone(void) const {
+ return new TitlecaseTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void TitlecaseTransliterator::handleTransliterate(
+ Replaceable& text, UTransPosition& offsets,
+ UBool isIncremental) const
+{
+ // TODO reimplement, see ustrcase.c
+ // using a real word break iterator
+ // instead of just looking for a transition between cased and uncased characters
+ // call CaseMapTransliterator::handleTransliterate() for lowercasing? (set fMap)
+ // needs to take isIncremental into account because case mappings are context-sensitive
+ // also detect when lowercasing function did not finish because of context
+
+ if (offsets.start >= offsets.limit) {
+ return;
+ }
+
+ // case type: >0 cased (UCASE_LOWER etc.) ==0 uncased <0 case-ignorable
+ int32_t type;
+
+ // Our mode; we are either converting letter toTitle or
+ // toLower.
+ UBool doTitle = TRUE;
+
+ // Determine if there is a preceding context of cased case-ignorable*,
+ // in which case we want to start in toLower mode. If the
+ // prior context is anything else (including empty) then start
+ // in toTitle mode.
+ UChar32 c;
+ int32_t start;
+ for (start = offsets.start - 1; start >= offsets.contextStart; start -= U16_LENGTH(c)) {
+ c = text.char32At(start);
+ type=ucase_getTypeOrIgnorable(fCsp, c);
+ if(type>0) { // cased
+ doTitle=FALSE;
+ break;
+ } else if(type==0) { // uncased but not ignorable
+ break;
+ }
+ // else (type<0) case-ignorable: continue
+ }
+
+ // Convert things after a cased character toLower; things
+ // after an uncased, non-case-ignorable character toTitle. Case-ignorable
+ // characters are copied directly and do not change the mode.
+ UCaseContext csc;
+ uprv_memset(&csc, 0, sizeof(csc));
+ csc.p = &text;
+ csc.start = offsets.contextStart;
+ csc.limit = offsets.contextLimit;
+
+ UnicodeString tmp;
+ const UChar *s;
+ int32_t textPos, delta, result, locCache=0;
+
+ for(textPos=offsets.start; textPos<offsets.limit;) {
+ csc.cpStart=textPos;
+ c=text.char32At(textPos);
+ csc.cpLimit=textPos+=U16_LENGTH(c);
+
+ type=ucase_getTypeOrIgnorable(fCsp, c);
+ if(type>=0) { // not case-ignorable
+ if(doTitle) {
+ result=ucase_toFullTitle(fCsp, c, utrans_rep_caseContextIterator, &csc, &s, "", &locCache);
+ } else {
+ result=ucase_toFullLower(fCsp, c, utrans_rep_caseContextIterator, &csc, &s, "", &locCache);
+ }
+ doTitle = (UBool)(type==0); // doTitle=isUncased
+
+ if(csc.b1 && isIncremental) {
+ // fMap() tried to look beyond the context limit
+ // wait for more input
+ offsets.start=csc.cpStart;
+ return;
+ }
+
+ if(result>=0) {
+ // replace the current code point with its full case mapping result
+ // see UCASE_MAX_STRING_LENGTH
+ if(result<=UCASE_MAX_STRING_LENGTH) {
+ // string s[result]
+ tmp.setTo(FALSE, s, result);
+ delta=result-U16_LENGTH(c);
+ } else {
+ // single code point
+ tmp.setTo(result);
+ delta=tmp.length()-U16_LENGTH(c);
+ }
+ text.handleReplaceBetween(csc.cpStart, textPos, tmp);
+ if(delta!=0) {
+ textPos+=delta;
+ csc.limit=offsets.contextLimit+=delta;
+ offsets.limit+=delta;
+ }
+ }
+ }
+ }
+ offsets.start=textPos;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/titletrn.h b/Build/source/libs/icu/icu-xetex/i18n/titletrn.h
new file mode 100644
index 00000000000..a093152b66c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/titletrn.h
@@ -0,0 +1,90 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/24/01 aliu Creation.
+**********************************************************************
+*/
+#ifndef TITLETRN_H
+#define TITLETRN_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "ucase.h"
+#include "casetrn.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that converts all letters (as defined by
+ * <code>UCharacter.isLetter()</code>) to lower case, except for those
+ * letters preceded by non-letters. The latter are converted to title
+ * case using <code>u_totitle()</code>.
+ * @author Alan Liu
+ */
+class TitlecaseTransliterator : public CaseMapTransliterator {
+ public:
+
+ /**
+ * Constructs a transliterator.
+ * @param loc the given locale.
+ */
+ TitlecaseTransliterator();
+
+ /**
+ * Destructor.
+ */
+ virtual ~TitlecaseTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ TitlecaseTransliterator(const TitlecaseTransliterator&);
+
+ /**
+ * Transliterator API.
+ * @return a copy of the object.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+protected:
+
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param offset the start and limit of the text, the position
+ * of the cursor, and the start and limit of transliteration.
+ * @param incremental if true, assume more text may be coming after
+ * pos.contextLimit. Otherwise, assume the text is complete.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& offset,
+ UBool isIncremental) const;
+
+private:
+ /**
+ * Assignment operator.
+ */
+ TitlecaseTransliterator& operator=(const TitlecaseTransliterator&);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/tolowtrn.cpp b/Build/source/libs/icu/icu-xetex/i18n/tolowtrn.cpp
new file mode 100644
index 00000000000..c93f4d0eff8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/tolowtrn.cpp
@@ -0,0 +1,65 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/24/01 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "tolowtrn.h"
+#include "ustr_imp.h"
+#include "cpputils.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LowercaseTransliterator)
+
+/**
+ * Constructs a transliterator.
+ */
+LowercaseTransliterator::LowercaseTransliterator() :
+ CaseMapTransliterator(UNICODE_STRING("Any-Lower", 9), ucase_toFullLower)
+{
+}
+
+/**
+ * Destructor.
+ */
+LowercaseTransliterator::~LowercaseTransliterator() {
+}
+
+/**
+ * Copy constructor.
+ */
+LowercaseTransliterator::LowercaseTransliterator(const LowercaseTransliterator& o) :
+ CaseMapTransliterator(o)
+{
+}
+
+/**
+ * Assignment operator.
+ */
+/*LowercaseTransliterator& LowercaseTransliterator::operator=(
+ const LowercaseTransliterator& o) {
+ CaseMapTransliterator::operator=(o);
+ return *this;
+}*/
+
+/**
+ * Transliterator API.
+ */
+Transliterator* LowercaseTransliterator::clone(void) const {
+ return new LowercaseTransliterator(*this);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/tolowtrn.h b/Build/source/libs/icu/icu-xetex/i18n/tolowtrn.h
new file mode 100644
index 00000000000..564b215a728
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/tolowtrn.h
@@ -0,0 +1,74 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/24/01 aliu Creation.
+**********************************************************************
+*/
+#ifndef TOLOWTRN_H
+#define TOLOWTRN_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "casetrn.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that performs locale-sensitive toLower()
+ * case mapping.
+ * @author Alan Liu
+ */
+class LowercaseTransliterator : public CaseMapTransliterator {
+
+ public:
+
+ /**
+ * Constructs a transliterator.
+ * @param loc the given locale.
+ */
+ LowercaseTransliterator();
+
+ /**
+ * Destructor.
+ */
+ virtual ~LowercaseTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ LowercaseTransliterator(const LowercaseTransliterator&);
+
+ /**
+ * Transliterator API.
+ * @return a copy of the object.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+private:
+
+ /**
+ * Assignment operator.
+ */
+ LowercaseTransliterator& operator=(const LowercaseTransliterator&);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/toupptrn.cpp b/Build/source/libs/icu/icu-xetex/i18n/toupptrn.cpp
new file mode 100644
index 00000000000..4b7c7d06aca
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/toupptrn.cpp
@@ -0,0 +1,65 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/24/01 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "toupptrn.h"
+#include "ustr_imp.h"
+#include "cpputils.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UppercaseTransliterator)
+
+/**
+ * Constructs a transliterator.
+ */
+UppercaseTransliterator::UppercaseTransliterator() :
+ CaseMapTransliterator(UNICODE_STRING("Any-Upper", 9), ucase_toFullUpper)
+{
+}
+
+/**
+ * Destructor.
+ */
+UppercaseTransliterator::~UppercaseTransliterator() {
+}
+
+/**
+ * Copy constructor.
+ */
+UppercaseTransliterator::UppercaseTransliterator(const UppercaseTransliterator& o) :
+ CaseMapTransliterator(o)
+{
+}
+
+/**
+ * Assignment operator.
+ */
+/*UppercaseTransliterator& UppercaseTransliterator::operator=(
+ const UppercaseTransliterator& o) {
+ CaseMapTransliterator::operator=(o);
+ return *this;
+}*/
+
+/**
+ * Transliterator API.
+ */
+Transliterator* UppercaseTransliterator::clone(void) const {
+ return new UppercaseTransliterator(*this);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/toupptrn.h b/Build/source/libs/icu/icu-xetex/i18n/toupptrn.h
new file mode 100644
index 00000000000..77799acbfd6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/toupptrn.h
@@ -0,0 +1,74 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/24/01 aliu Creation.
+**********************************************************************
+*/
+#ifndef TOUPPTRN_H
+#define TOUPPTRN_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "casetrn.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that performs locale-sensitive toUpper()
+ * case mapping.
+ * @author Alan Liu
+ */
+class UppercaseTransliterator : public CaseMapTransliterator {
+
+ public:
+
+ /**
+ * Constructs a transliterator.
+ * @param loc the given locale.
+ */
+ UppercaseTransliterator();
+
+ /**
+ * Destructor.
+ */
+ virtual ~UppercaseTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ UppercaseTransliterator(const UppercaseTransliterator&);
+
+ /**
+ * Transliterator API.
+ * @return a copy of the object.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+ /**
+ * Assignment operator.
+ */
+ UppercaseTransliterator& operator=(const UppercaseTransliterator&);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/translit.cpp b/Build/source/libs/icu/icu-xetex/i18n/translit.cpp
new file mode 100644
index 00000000000..6e9446e208a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/translit.cpp
@@ -0,0 +1,1584 @@
+/*
+ **********************************************************************
+ * Copyright (C) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 11/17/99 aliu Creation.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/putil.h"
+#include "unicode/translit.h"
+#include "unicode/locid.h"
+#include "unicode/msgfmt.h"
+#include "unicode/rep.h"
+#include "unicode/resbund.h"
+#include "unicode/unifilt.h"
+#include "unicode/uniset.h"
+#include "unicode/uscript.h"
+#include "unicode/strenum.h"
+#include "cpdtrans.h"
+#include "nultrans.h"
+#include "rbt_data.h"
+#include "rbt_pars.h"
+#include "rbt.h"
+#include "transreg.h"
+#include "name2uni.h"
+#include "nortrans.h"
+#include "remtrans.h"
+#include "titletrn.h"
+#include "tolowtrn.h"
+#include "toupptrn.h"
+#include "uni2name.h"
+#include "esctrn.h"
+#include "unesctrn.h"
+#include "tridpars.h"
+#include "anytrans.h"
+#include "util.h"
+#include "hash.h"
+#include "mutex.h"
+#include "ucln_in.h"
+#include "uassert.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uinvchar.h"
+
+static const UChar TARGET_SEP = 0x002D; /*-*/
+static const UChar ID_DELIM = 0x003B; /*;*/
+static const UChar VARIANT_SEP = 0x002F; // '/'
+
+/**
+ * Prefix for resource bundle key for the display name for a
+ * transliterator. The ID is appended to this to form the key.
+ * The resource bundle value should be a String.
+ */
+static const char RB_DISPLAY_NAME_PREFIX[] = "%Translit%%";
+
+/**
+ * Prefix for resource bundle key for the display name for a
+ * transliterator SCRIPT. The ID is appended to this to form the key.
+ * The resource bundle value should be a String.
+ */
+static const char RB_SCRIPT_DISPLAY_NAME_PREFIX[] = "%Translit%";
+
+/**
+ * Resource bundle key for display name pattern.
+ * The resource bundle value should be a String forming a
+ * MessageFormat pattern, e.g.:
+ * "{0,choice,0#|1#{1} Transliterator|2#{1} to {2} Transliterator}".
+ */
+static const char RB_DISPLAY_NAME_PATTERN[] = "TransliteratorNamePattern";
+
+/**
+ * Resource bundle key for the list of RuleBasedTransliterator IDs.
+ * The resource bundle value should be a String[] with each element
+ * being a valid ID. The ID will be appended to RB_RULE_BASED_PREFIX
+ * to obtain the class name in which the RB_RULE key will be sought.
+ */
+static const char RB_RULE_BASED_IDS[] = "RuleBasedTransliteratorIDs";
+
+/**
+ * The mutex controlling access to registry object.
+ */
+static UMTX registryMutex = 0;
+
+/**
+ * System transliterator registry; non-null when initialized.
+ */
+static U_NAMESPACE_QUALIFIER TransliteratorRegistry* registry = 0;
+
+// Macro to check/initialize the registry. ONLY USE WITHIN
+// MUTEX. Avoids function call when registry is initialized.
+#define HAVE_REGISTRY (registry!=0 || initializeRegistry())
+
+// Empty string
+static const UChar EMPTY[] = {0}; //""
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(Transliterator)
+
+/**
+ * Return TRUE if the given UTransPosition is valid for text of
+ * the given length.
+ */
+static inline UBool positionIsValid(UTransPosition& index, int32_t len) {
+ return !(index.contextStart < 0 ||
+ index.start < index.contextStart ||
+ index.limit < index.start ||
+ index.contextLimit < index.limit ||
+ len < index.contextLimit);
+}
+
+/**
+ * Default constructor.
+ * @param theID the string identifier for this transliterator
+ * @param theFilter the filter. Any character for which
+ * <tt>filter.contains()</tt> returns <tt>FALSE</tt> will not be
+ * altered by this transliterator. If <tt>filter</tt> is
+ * <tt>null</tt> then no filtering is applied.
+ */
+Transliterator::Transliterator(const UnicodeString& theID,
+ UnicodeFilter* adoptedFilter) :
+ UObject(), ID(theID), filter(adoptedFilter),
+ maximumContextLength(0)
+{
+ // NUL-terminate the ID string, which is a non-aliased copy.
+ ID.append((UChar)0);
+ ID.truncate(ID.length()-1);
+}
+
+/**
+ * Destructor.
+ */
+Transliterator::~Transliterator() {
+ if (filter) {
+ delete filter;
+ }
+}
+
+/**
+ * Copy constructor.
+ */
+Transliterator::Transliterator(const Transliterator& other) :
+ UObject(other), ID(other.ID), filter(0),
+ maximumContextLength(other.maximumContextLength)
+{
+ // NUL-terminate the ID string, which is a non-aliased copy.
+ ID.append((UChar)0);
+ ID.truncate(ID.length()-1);
+
+ if (other.filter != 0) {
+ // We own the filter, so we must have our own copy
+ filter = (UnicodeFilter*) other.filter->clone();
+ }
+}
+
+Transliterator* Transliterator::clone() const {
+ return NULL;
+}
+
+/**
+ * Assignment operator.
+ */
+Transliterator& Transliterator::operator=(const Transliterator& other) {
+ ID = other.ID;
+ // NUL-terminate the ID string
+ ID.getTerminatedBuffer();
+
+ maximumContextLength = other.maximumContextLength;
+ adoptFilter((other.filter == 0) ? 0 : (UnicodeFilter*) other.filter->clone());
+ return *this;
+}
+
+/**
+ * Transliterates a segment of a string. <code>Transliterator</code> API.
+ * @param text the string to be transliterated
+ * @param start the beginning index, inclusive; <code>0 <= start
+ * <= limit</code>.
+ * @param limit the ending index, exclusive; <code>start <= limit
+ * <= text.length()</code>.
+ * @return the new limit index, or -1
+ */
+int32_t Transliterator::transliterate(Replaceable& text,
+ int32_t start, int32_t limit) const {
+ if (start < 0 ||
+ limit < start ||
+ text.length() < limit) {
+ return -1;
+ }
+
+ UTransPosition offsets;
+ offsets.contextStart= start;
+ offsets.contextLimit = limit;
+ offsets.start = start;
+ offsets.limit = limit;
+ filteredTransliterate(text, offsets, FALSE, TRUE);
+ return offsets.limit;
+}
+
+/**
+ * Transliterates an entire string in place. Convenience method.
+ * @param text the string to be transliterated
+ */
+void Transliterator::transliterate(Replaceable& text) const {
+ transliterate(text, 0, text.length());
+}
+
+/**
+ * Transliterates the portion of the text buffer that can be
+ * transliterated unambiguosly after new text has been inserted,
+ * typically as a result of a keyboard event. The new text in
+ * <code>insertion</code> will be inserted into <code>text</code>
+ * at <code>index.contextLimit</code>, advancing
+ * <code>index.contextLimit</code> by <code>insertion.length()</code>.
+ * Then the transliterator will try to transliterate characters of
+ * <code>text</code> between <code>index.start</code> and
+ * <code>index.contextLimit</code>. Characters before
+ * <code>index.start</code> will not be changed.
+ *
+ * <p>Upon return, values in <code>index</code> will be updated.
+ * <code>index.contextStart</code> will be advanced to the first
+ * character that future calls to this method will read.
+ * <code>index.start</code> and <code>index.contextLimit</code> will
+ * be adjusted to delimit the range of text that future calls to
+ * this method may change.
+ *
+ * <p>Typical usage of this method begins with an initial call
+ * with <code>index.contextStart</code> and <code>index.contextLimit</code>
+ * set to indicate the portion of <code>text</code> to be
+ * transliterated, and <code>index.start == index.contextStart</code>.
+ * Thereafter, <code>index</code> can be used without
+ * modification in future calls, provided that all changes to
+ * <code>text</code> are made via this method.
+ *
+ * <p>This method assumes that future calls may be made that will
+ * insert new text into the buffer. As a result, it only performs
+ * unambiguous transliterations. After the last call to this
+ * method, there may be untransliterated text that is waiting for
+ * more input to resolve an ambiguity. In order to perform these
+ * pending transliterations, clients should call {@link
+ * #finishKeyboardTransliteration} after the last call to this
+ * method has been made.
+ *
+ * @param text the buffer holding transliterated and untransliterated text
+ * @param index an array of three integers.
+ *
+ * <ul><li><code>index.contextStart</code>: the beginning index,
+ * inclusive; <code>0 <= index.contextStart <= index.contextLimit</code>.
+ *
+ * <li><code>index.contextLimit</code>: the ending index, exclusive;
+ * <code>index.contextStart <= index.contextLimit <= text.length()</code>.
+ * <code>insertion</code> is inserted at
+ * <code>index.contextLimit</code>.
+ *
+ * <li><code>index.start</code>: the next character to be
+ * considered for transliteration; <code>index.contextStart <=
+ * index.start <= index.contextLimit</code>. Characters before
+ * <code>index.start</code> will not be changed by future calls
+ * to this method.</ul>
+ *
+ * @param insertion text to be inserted and possibly
+ * transliterated into the translation buffer at
+ * <code>index.contextLimit</code>. If <code>null</code> then no text
+ * is inserted.
+ * @see #START
+ * @see #LIMIT
+ * @see #CURSOR
+ * @see #handleTransliterate
+ * @exception IllegalArgumentException if <code>index</code>
+ * is invalid
+ */
+void Transliterator::transliterate(Replaceable& text,
+ UTransPosition& index,
+ const UnicodeString& insertion,
+ UErrorCode &status) const {
+ _transliterate(text, index, &insertion, status);
+}
+
+/**
+ * Transliterates the portion of the text buffer that can be
+ * transliterated unambiguosly after a new character has been
+ * inserted, typically as a result of a keyboard event. This is a
+ * convenience method; see {@link
+ * #transliterate(Replaceable, int[], String)} for details.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param index an array of three integers. See {@link
+ * #transliterate(Replaceable, int[], String)}.
+ * @param insertion text to be inserted and possibly
+ * transliterated into the translation buffer at
+ * <code>index.contextLimit</code>.
+ * @see #transliterate(Replaceable, int[], String)
+ */
+void Transliterator::transliterate(Replaceable& text,
+ UTransPosition& index,
+ UChar32 insertion,
+ UErrorCode& status) const {
+ UnicodeString str(insertion);
+ _transliterate(text, index, &str, status);
+}
+
+/**
+ * Transliterates the portion of the text buffer that can be
+ * transliterated unambiguosly. This is a convenience method; see
+ * {@link #transliterate(Replaceable, int[], String)} for
+ * details.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param index an array of three integers. See {@link
+ * #transliterate(Replaceable, int[], String)}.
+ * @see #transliterate(Replaceable, int[], String)
+ */
+void Transliterator::transliterate(Replaceable& text,
+ UTransPosition& index,
+ UErrorCode& status) const {
+ _transliterate(text, index, 0, status);
+}
+
+/**
+ * Finishes any pending transliterations that were waiting for
+ * more characters. Clients should call this method as the last
+ * call after a sequence of one or more calls to
+ * <code>transliterate()</code>.
+ * @param text the buffer holding transliterated and
+ * untransliterated text.
+ * @param index the array of indices previously passed to {@link
+ * #transliterate}
+ */
+void Transliterator::finishTransliteration(Replaceable& text,
+ UTransPosition& index) const {
+ if (!positionIsValid(index, text.length())) {
+ return;
+ }
+
+ filteredTransliterate(text, index, FALSE, TRUE);
+}
+
+/**
+ * This internal method does keyboard transliteration. If the
+ * 'insertion' is non-null then we append it to 'text' before
+ * proceeding. This method calls through to the pure virtual
+ * framework method handleTransliterate() to do the actual
+ * work.
+ */
+void Transliterator::_transliterate(Replaceable& text,
+ UTransPosition& index,
+ const UnicodeString* insertion,
+ UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (!positionIsValid(index, text.length())) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+// int32_t originalStart = index.contextStart;
+ if (insertion != 0) {
+ text.handleReplaceBetween(index.limit, index.limit, *insertion);
+ index.limit += insertion->length();
+ index.contextLimit += insertion->length();
+ }
+
+ if (index.limit > 0 &&
+ UTF_IS_LEAD(text.charAt(index.limit - 1))) {
+ // Oops, there is a dangling lead surrogate in the buffer.
+ // This will break most transliterators, since they will
+ // assume it is part of a pair. Don't transliterate until
+ // more text comes in.
+ return;
+ }
+
+ filteredTransliterate(text, index, TRUE, TRUE);
+
+#if 0
+ // TODO
+ // I CAN'T DO what I'm attempting below now that the Kleene star
+ // operator is supported. For example, in the rule
+
+ // ([:Lu:]+) { x } > $1;
+
+ // what is the maximum context length? getMaximumContextLength()
+ // will return 1, but this is just the length of the ante context
+ // part of the pattern string -- 1 character, which is a standin
+ // for a Quantifier, which contains a StringMatcher, which
+ // contains a UnicodeSet.
+
+ // There is a complicated way to make this work again, and that's
+ // to add a "maximum left context" protocol into the
+ // UnicodeMatcher hierarchy. At present I'm not convinced this is
+ // worth it.
+
+ // ---
+
+ // The purpose of the code below is to keep the context small
+ // while doing incremental transliteration. When part of the left
+ // context (between contextStart and start) is no longer needed,
+ // we try to advance contextStart past that portion. We use the
+ // maximum context length to do so.
+ int32_t newCS = index.start;
+ int32_t n = getMaximumContextLength();
+ while (newCS > originalStart && n-- > 0) {
+ --newCS;
+ newCS -= UTF_CHAR_LENGTH(text.char32At(newCS)) - 1;
+ }
+ index.contextStart = uprv_max(newCS, originalStart);
+#endif
+}
+
+/**
+ * This method breaks up the input text into runs of unfiltered
+ * characters. It passes each such run to
+ * <subclass>.handleTransliterate(). Subclasses that can handle the
+ * filter logic more efficiently themselves may override this method.
+ *
+ * All transliteration calls in this class go through this method.
+ */
+void Transliterator::filteredTransliterate(Replaceable& text,
+ UTransPosition& index,
+ UBool incremental,
+ UBool rollback) const {
+ // Short circuit path for transliterators with no filter in
+ // non-incremental mode.
+ if (filter == 0 && !rollback) {
+ handleTransliterate(text, index, incremental);
+ return;
+ }
+
+ //----------------------------------------------------------------------
+ // This method processes text in two groupings:
+ //
+ // RUNS -- A run is a contiguous group of characters which are contained
+ // in the filter for this transliterator (filter.contains(ch) == TRUE).
+ // Text outside of runs may appear as context but it is not modified.
+ // The start and limit Position values are narrowed to each run.
+ //
+ // PASSES (incremental only) -- To make incremental mode work correctly,
+ // each run is broken up into n passes, where n is the length (in code
+ // points) of the run. Each pass contains the first n characters. If a
+ // pass is completely transliterated, it is committed, and further passes
+ // include characters after the committed text. If a pass is blocked,
+ // and does not transliterate completely, then this method rolls back
+ // the changes made during the pass, extends the pass by one code point,
+ // and tries again.
+ //----------------------------------------------------------------------
+
+ // globalLimit is the limit value for the entire operation. We
+ // set index.limit to the end of each unfiltered run before
+ // calling handleTransliterate(), so we need to maintain the real
+ // value of index.limit here. After each transliteration, we
+ // update globalLimit for insertions or deletions that have
+ // happened.
+ int32_t globalLimit = index.limit;
+
+ // If there is a non-null filter, then break the input text up. Say the
+ // input text has the form:
+ // xxxabcxxdefxx
+ // where 'x' represents a filtered character (filter.contains('x') ==
+ // false). Then we break this up into:
+ // xxxabc xxdef xx
+ // Each pass through the loop consumes a run of filtered
+ // characters (which are ignored) and a subsequent run of
+ // unfiltered characters (which are transliterated).
+
+ for (;;) {
+
+ if (filter != NULL) {
+ // Narrow the range to be transliterated to the first segment
+ // of unfiltered characters at or after index.start.
+
+ // Advance past filtered chars
+ UChar32 c;
+ while (index.start < globalLimit &&
+ !filter->contains(c=text.char32At(index.start))) {
+ index.start += UTF_CHAR_LENGTH(c);
+ }
+
+ // Find the end of this run of unfiltered chars
+ index.limit = index.start;
+ while (index.limit < globalLimit &&
+ filter->contains(c=text.char32At(index.limit))) {
+ index.limit += UTF_CHAR_LENGTH(c);
+ }
+ }
+
+ // Check to see if the unfiltered run is empty. This only
+ // happens at the end of the string when all the remaining
+ // characters are filtered.
+ if (index.limit == index.start) {
+ // assert(index.start == globalLimit);
+ break;
+ }
+
+ // Is this run incremental? If there is additional
+ // filtered text (if limit < globalLimit) then we pass in
+ // an incremental value of FALSE to force the subclass to
+ // complete the transliteration for this run.
+ UBool isIncrementalRun =
+ (index.limit < globalLimit ? FALSE : incremental);
+
+ int32_t delta;
+
+ // Implement rollback. To understand the need for rollback,
+ // consider the following transliterator:
+ //
+ // "t" is "a > A;"
+ // "u" is "A > b;"
+ // "v" is a compound of "t; NFD; u" with a filter [:Ll:]
+ //
+ // Now apply "c" to the input text "a". The result is "b". But if
+ // the transliteration is done incrementally, then the NFD holds
+ // things up after "t" has already transformed "a" to "A". When
+ // finishTransliterate() is called, "A" is _not_ processed because
+ // it gets excluded by the [:Ll:] filter, and the end result is "A"
+ // -- incorrect. The problem is that the filter is applied to a
+ // partially-transliterated result, when we only want it to apply to
+ // input text. Although this example hinges on a compound
+ // transliterator containing NFD and a specific filter, it can
+ // actually happen with any transliterator which may do a partial
+ // transformation in incremental mode into characters outside its
+ // filter.
+ //
+ // To handle this, when in incremental mode we supply characters to
+ // handleTransliterate() in several passes. Each pass adds one more
+ // input character to the input text. That is, for input "ABCD", we
+ // first try "A", then "AB", then "ABC", and finally "ABCD". If at
+ // any point we block (upon return, start < limit) then we roll
+ // back. If at any point we complete the run (upon return start ==
+ // limit) then we commit that run.
+
+ if (rollback && isIncrementalRun) {
+
+ int32_t runStart = index.start;
+ int32_t runLimit = index.limit;
+ int32_t runLength = runLimit - runStart;
+
+ // Make a rollback copy at the end of the string
+ int32_t rollbackOrigin = text.length();
+ text.copy(runStart, runLimit, rollbackOrigin);
+
+ // Variables reflecting the commitment of completely
+ // transliterated text. passStart is the runStart, advanced
+ // past committed text. rollbackStart is the rollbackOrigin,
+ // advanced past rollback text that corresponds to committed
+ // text.
+ int32_t passStart = runStart;
+ int32_t rollbackStart = rollbackOrigin;
+
+ // The limit for each pass; we advance by one code point with
+ // each iteration.
+ int32_t passLimit = index.start;
+
+ // Total length, in 16-bit code units, of uncommitted text.
+ // This is the length to be rolled back.
+ int32_t uncommittedLength = 0;
+
+ // Total delta (change in length) for all passes
+ int32_t totalDelta = 0;
+
+ // PASS MAIN LOOP -- Start with a single character, and extend
+ // the text by one character at a time. Roll back partial
+ // transliterations and commit complete transliterations.
+ for (;;) {
+ // Length of additional code point, either one or two
+ int32_t charLength =
+ UTF_CHAR_LENGTH(text.char32At(passLimit));
+ passLimit += charLength;
+ if (passLimit > runLimit) {
+ break;
+ }
+ uncommittedLength += charLength;
+
+ index.limit = passLimit;
+
+ // Delegate to subclass for actual transliteration. Upon
+ // return, start will be updated to point after the
+ // transliterated text, and limit and contextLimit will be
+ // adjusted for length changes.
+ handleTransliterate(text, index, TRUE);
+
+ delta = index.limit - passLimit; // change in length
+
+ // We failed to completely transliterate this pass.
+ // Roll back the text. Indices remain unchanged; reset
+ // them where necessary.
+ if (index.start != index.limit) {
+ // Find the rollbackStart, adjusted for length changes
+ // and the deletion of partially transliterated text.
+ int32_t rs = rollbackStart + delta - (index.limit - passStart);
+
+ // Delete the partially transliterated text
+ text.handleReplaceBetween(passStart, index.limit, EMPTY);
+
+ // Copy the rollback text back
+ text.copy(rs, rs + uncommittedLength, passStart);
+
+ // Restore indices to their original values
+ index.start = passStart;
+ index.limit = passLimit;
+ index.contextLimit -= delta;
+ }
+
+ // We did completely transliterate this pass. Update the
+ // commit indices to record how far we got. Adjust indices
+ // for length change.
+ else {
+ // Move the pass indices past the committed text.
+ passStart = passLimit = index.start;
+
+ // Adjust the rollbackStart for length changes and move
+ // it past the committed text. All characters we've
+ // processed to this point are committed now, so zero
+ // out the uncommittedLength.
+ rollbackStart += delta + uncommittedLength;
+ uncommittedLength = 0;
+
+ // Adjust indices for length changes.
+ runLimit += delta;
+ totalDelta += delta;
+ }
+ }
+
+ // Adjust overall limit and rollbackOrigin for insertions and
+ // deletions. Don't need to worry about contextLimit because
+ // handleTransliterate() maintains that.
+ rollbackOrigin += totalDelta;
+ globalLimit += totalDelta;
+
+ // Delete the rollback copy
+ text.handleReplaceBetween(rollbackOrigin, rollbackOrigin + runLength, EMPTY);
+
+ // Move start past committed text
+ index.start = passStart;
+ }
+
+ else {
+ // Delegate to subclass for actual transliteration.
+ int32_t limit = index.limit;
+ handleTransliterate(text, index, isIncrementalRun);
+ delta = index.limit - limit; // change in length
+
+ // In a properly written transliterator, start == limit after
+ // handleTransliterate() returns when incremental is false.
+ // Catch cases where the subclass doesn't do this, and throw
+ // an exception. (Just pinning start to limit is a bad idea,
+ // because what's probably happening is that the subclass
+ // isn't transliterating all the way to the end, and it should
+ // in non-incremental mode.)
+ if (!incremental && index.start != index.limit) {
+ // We can't throw an exception, so just fudge things
+ index.start = index.limit;
+ }
+
+ // Adjust overall limit for insertions/deletions. Don't need
+ // to worry about contextLimit because handleTransliterate()
+ // maintains that.
+ globalLimit += delta;
+ }
+
+ if (filter == NULL || isIncrementalRun) {
+ break;
+ }
+
+ // If we did completely transliterate this
+ // run, then repeat with the next unfiltered run.
+ }
+
+ // Start is valid where it is. Limit needs to be put back where
+ // it was, modulo adjustments for deletions/insertions.
+ index.limit = globalLimit;
+}
+
+void Transliterator::filteredTransliterate(Replaceable& text,
+ UTransPosition& index,
+ UBool incremental) const {
+ filteredTransliterate(text, index, incremental, FALSE);
+}
+
+/**
+ * Method for subclasses to use to set the maximum context length.
+ * @see #getMaximumContextLength
+ */
+void Transliterator::setMaximumContextLength(int32_t maxContextLength) {
+ maximumContextLength = maxContextLength;
+}
+
+/**
+ * Returns a programmatic identifier for this transliterator.
+ * If this identifier is passed to <code>getInstance()</code>, it
+ * will return this object, if it has been registered.
+ * @see #registerInstance
+ * @see #getAvailableIDs
+ */
+const UnicodeString& Transliterator::getID(void) const {
+ return ID;
+}
+
+/**
+ * Returns a name for this transliterator that is appropriate for
+ * display to the user in the default locale. See {@link
+ * #getDisplayName(Locale)} for details.
+ */
+UnicodeString& U_EXPORT2 Transliterator::getDisplayName(const UnicodeString& ID,
+ UnicodeString& result) {
+ return getDisplayName(ID, Locale::getDefault(), result);
+}
+
+/**
+ * Returns a name for this transliterator that is appropriate for
+ * display to the user in the given locale. This name is taken
+ * from the locale resource data in the standard manner of the
+ * <code>java.text</code> package.
+ *
+ * <p>If no localized names exist in the system resource bundles,
+ * a name is synthesized using a localized
+ * <code>MessageFormat</code> pattern from the resource data. The
+ * arguments to this pattern are an integer followed by one or two
+ * strings. The integer is the number of strings, either 1 or 2.
+ * The strings are formed by splitting the ID for this
+ * transliterator at the first TARGET_SEP. If there is no TARGET_SEP, then the
+ * entire ID forms the only string.
+ * @param inLocale the Locale in which the display name should be
+ * localized.
+ * @see java.text.MessageFormat
+ */
+UnicodeString& U_EXPORT2 Transliterator::getDisplayName(const UnicodeString& id,
+ const Locale& inLocale,
+ UnicodeString& result) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ ResourceBundle bundle(U_ICUDATA_TRANSLIT, inLocale, status);
+
+ // Suspend checking status until later...
+
+ result.truncate(0);
+
+ // Normalize the ID
+ UnicodeString source, target, variant;
+ UBool sawSource;
+ TransliteratorIDParser::IDtoSTV(id, source, target, variant, sawSource);
+ if (target.length() < 1) {
+ // No target; malformed id
+ return result;
+ }
+ if (variant.length() > 0) { // Change "Foo" to "/Foo"
+ variant.insert(0, VARIANT_SEP);
+ }
+ UnicodeString ID(source);
+ ID.append(TARGET_SEP).append(target).append(variant);
+
+ // build the char* key
+ if (uprv_isInvariantUString(ID.getBuffer(), ID.length())) {
+ char key[200];
+ uprv_strcpy(key, RB_DISPLAY_NAME_PREFIX);
+ int32_t length=(int32_t)uprv_strlen(RB_DISPLAY_NAME_PREFIX);
+ ID.extract(0, (int32_t)(sizeof(key)-length), key+length, (int32_t)(sizeof(key)-length), US_INV);
+
+ // Try to retrieve a UnicodeString from the bundle.
+ UnicodeString resString = bundle.getStringEx(key, status);
+
+ if (U_SUCCESS(status) && resString.length() != 0) {
+ return result = resString; // [sic] assign & return
+ }
+
+#if !UCONFIG_NO_FORMATTING
+ // We have failed to get a name from the locale data. This is
+ // typical, since most transliterators will not have localized
+ // name data. The next step is to retrieve the MessageFormat
+ // pattern from the locale data and to use it to synthesize the
+ // name from the ID.
+
+ status = U_ZERO_ERROR;
+ resString = bundle.getStringEx(RB_DISPLAY_NAME_PATTERN, status);
+
+ if (U_SUCCESS(status) && resString.length() != 0) {
+ MessageFormat msg(resString, inLocale, status);
+ // Suspend checking status until later...
+
+ // We pass either 2 or 3 Formattable objects to msg.
+ Formattable args[3];
+ int32_t nargs;
+ args[0].setLong(2); // # of args to follow
+ args[1].setString(source);
+ args[2].setString(target);
+ nargs = 3;
+
+ // Use display names for the scripts, if they exist
+ UnicodeString s;
+ length=(int32_t)uprv_strlen(RB_SCRIPT_DISPLAY_NAME_PREFIX);
+ for (int j=1; j<=2; ++j) {
+ status = U_ZERO_ERROR;
+ uprv_strcpy(key, RB_SCRIPT_DISPLAY_NAME_PREFIX);
+ args[j].getString(s);
+ if (uprv_isInvariantUString(s.getBuffer(), s.length())) {
+ s.extract(0, sizeof(key)-length-1, key+length, (int32_t)sizeof(key)-length-1, US_INV);
+
+ resString = bundle.getStringEx(key, status);
+
+ if (U_SUCCESS(status)) {
+ args[j] = resString;
+ }
+ }
+ }
+
+ status = U_ZERO_ERROR;
+ FieldPosition pos; // ignored by msg
+ msg.format(args, nargs, result, pos, status);
+ if (U_SUCCESS(status)) {
+ result.append(variant);
+ return result;
+ }
+ }
+#endif
+ }
+
+ // We should not reach this point unless there is something
+ // wrong with the build or the RB_DISPLAY_NAME_PATTERN has
+ // been deleted from the root RB_LOCALE_ELEMENTS resource.
+ result = ID;
+ return result;
+}
+
+/**
+ * Returns the filter used by this transliterator, or <tt>null</tt>
+ * if this transliterator uses no filter. Caller musn't delete
+ * the result!
+ */
+const UnicodeFilter* Transliterator::getFilter(void) const {
+ return filter;
+}
+
+/**
+ * Returns the filter used by this transliterator, or
+ * <tt>NULL</tt> if this transliterator uses no filter. The
+ * caller must eventually delete the result. After this call,
+ * this transliterator's filter is set to <tt>NULL</tt>.
+ */
+UnicodeFilter* Transliterator::orphanFilter(void) {
+ UnicodeFilter *result = filter;
+ filter = NULL;
+ return result;
+}
+
+/**
+ * Changes the filter used by this transliterator. If the filter
+ * is set to <tt>null</tt> then no filtering will occur.
+ *
+ * <p>Callers must take care if a transliterator is in use by
+ * multiple threads. The filter should not be changed by one
+ * thread while another thread may be transliterating.
+ */
+void Transliterator::adoptFilter(UnicodeFilter* filterToAdopt) {
+ delete filter;
+ filter = filterToAdopt;
+}
+
+/**
+ * Returns this transliterator's inverse. See the class
+ * documentation for details. This implementation simply inverts
+ * the two entities in the ID and attempts to retrieve the
+ * resulting transliterator. That is, if <code>getID()</code>
+ * returns "A-B", then this method will return the result of
+ * <code>getInstance("B-A")</code>, or <code>null</code> if that
+ * call fails.
+ *
+ * <p>This method does not take filtering into account. The
+ * returned transliterator will have no filter.
+ *
+ * <p>Subclasses with knowledge of their inverse may wish to
+ * override this method.
+ *
+ * @return a transliterator that is an inverse, not necessarily
+ * exact, of this transliterator, or <code>null</code> if no such
+ * transliterator is registered.
+ * @see #registerInstance
+ */
+Transliterator* Transliterator::createInverse(UErrorCode& status) const {
+ UParseError parseError;
+ return Transliterator::createInstance(ID, UTRANS_REVERSE,parseError,status);
+}
+
+Transliterator* U_EXPORT2
+Transliterator::createInstance(const UnicodeString& ID,
+ UTransDirection dir,
+ UErrorCode& status)
+{
+ UParseError parseError;
+ return createInstance(ID, dir, parseError, status);
+}
+
+/**
+ * Returns a <code>Transliterator</code> object given its ID.
+ * The ID must be either a system transliterator ID or a ID registered
+ * using <code>registerInstance()</code>.
+ *
+ * @param ID a valid ID, as enumerated by <code>getAvailableIDs()</code>
+ * @return A <code>Transliterator</code> object with the given ID
+ * @see #registerInstance
+ * @see #getAvailableIDs
+ * @see #getID
+ */
+Transliterator* U_EXPORT2
+Transliterator::createInstance(const UnicodeString& ID,
+ UTransDirection dir,
+ UParseError& parseError,
+ UErrorCode& status)
+{
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ UnicodeString canonID;
+ UVector list(status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ UnicodeSet* globalFilter;
+ // TODO add code for parseError...currently unused, but
+ // later may be used by parsing code...
+ if (!TransliteratorIDParser::parseCompoundID(ID, dir, canonID, list, globalFilter)) {
+ status = U_INVALID_ID;
+ return NULL;
+ }
+
+ TransliteratorIDParser::instantiateList(list, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ U_ASSERT(list.size() > 0);
+ Transliterator* t = NULL;
+
+ if (list.size() > 1 || canonID.indexOf(ID_DELIM) >= 0) {
+ // [NOTE: If it's a compoundID, we instantiate a CompoundTransliterator even if it only
+ // has one child transliterator. This is so that toRules() will return the right thing
+ // (without any inactive ID), but our main ID still comes out correct. That is, if we
+ // instantiate "(Lower);Latin-Greek;", we want the rules to come out as "::Latin-Greek;"
+ // even though the ID is "(Lower);Latin-Greek;".
+ t = new CompoundTransliterator(list, parseError, status);
+ }
+ else {
+ t = (Transliterator*)list.elementAt(0);
+ }
+
+ t->setID(canonID);
+ if (globalFilter != NULL) {
+ t->adoptFilter(globalFilter);
+ }
+ return t;
+}
+
+/**
+ * Create a transliterator from a basic ID. This is an ID
+ * containing only the forward direction source, target, and
+ * variant.
+ * @param id a basic ID of the form S-T or S-T/V.
+ * @return a newly created Transliterator or null if the ID is
+ * invalid.
+ */
+Transliterator* Transliterator::createBasicInstance(const UnicodeString& id,
+ const UnicodeString* canon) {
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ TransliteratorAlias* alias = 0;
+ Transliterator* t = 0;
+
+ umtx_init(&registryMutex);
+ umtx_lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ t = registry->get(id, alias, ec);
+ }
+ umtx_unlock(&registryMutex);
+
+ if (U_FAILURE(ec)) {
+ delete t;
+ delete alias;
+ return 0;
+ }
+
+ // We may have not gotten a transliterator: Because we can't
+ // instantiate a transliterator from inside TransliteratorRegistry::
+ // get() (that would deadlock), we sometimes pass back an alias. This
+ // contains the data we need to finish the instantiation outside the
+ // registry mutex. The alias may, in turn, generate another alias, so
+ // we handle aliases in a loop. The max times through the loop is two.
+ // [alan]
+ while (alias != 0) {
+ U_ASSERT(t==0);
+ // Rule-based aliases are handled with TransliteratorAlias::
+ // parse(), followed by TransliteratorRegistry::reget().
+ // Other aliases are handled with TransliteratorAlias::create().
+ if (alias->isRuleBased()) {
+ // Step 1. parse
+ TransliteratorParser parser(ec);
+ alias->parse(parser, pe, ec);
+ delete alias;
+ alias = 0;
+
+ // Step 2. reget
+ umtx_lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ t = registry->reget(id, parser, alias, ec);
+ }
+ umtx_unlock(&registryMutex);
+
+ // Step 3. Loop back around!
+ } else {
+ t = alias->create(pe, ec);
+ delete alias;
+ alias = 0;
+ break;
+ }
+ if (U_FAILURE(ec)) {
+ delete t;
+ delete alias;
+ t = NULL;
+ break;
+ }
+ }
+
+ if (t != NULL && canon != NULL) {
+ t->setID(*canon);
+ }
+
+ return t;
+}
+
+/**
+ * Returns a <code>Transliterator</code> object constructed from
+ * the given rule string. This will be a RuleBasedTransliterator,
+ * if the rule string contains only rules, or a
+ * CompoundTransliterator, if it contains ID blocks, or a
+ * NullTransliterator, if it contains ID blocks which parse as
+ * empty for the given direction.
+ */
+Transliterator* U_EXPORT2
+Transliterator::createFromRules(const UnicodeString& ID,
+ const UnicodeString& rules,
+ UTransDirection dir,
+ UParseError& parseError,
+ UErrorCode& status)
+{
+ Transliterator* t = NULL;
+
+ TransliteratorParser parser(status);
+ parser.parse(rules, dir, parseError, status);
+
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ // NOTE: The logic here matches that in TransliteratorRegistry.
+ if (parser.idBlockVector.size() == 0 && parser.dataVector.size() == 0) {
+ t = new NullTransliterator();
+ }
+ else if (parser.idBlockVector.size() == 0 && parser.dataVector.size() == 1) {
+ t = new RuleBasedTransliterator(ID, (TransliterationRuleData*)parser.dataVector.orphanElementAt(0), TRUE);
+ }
+ else if (parser.idBlockVector.size() == 1 && parser.dataVector.size() == 0) {
+ // idBlock, no data -- this is an alias. The ID has
+ // been munged from reverse into forward mode, if
+ // necessary, so instantiate the ID in the forward
+ // direction.
+ if (parser.compoundFilter != NULL) {
+ UnicodeString filterPattern;
+ parser.compoundFilter->toPattern(filterPattern, FALSE);
+ t = createInstance(filterPattern + UnicodeString(ID_DELIM)
+ + *((UnicodeString*)parser.idBlockVector.elementAt(0)), UTRANS_FORWARD, parseError, status);
+ }
+ else
+ t = createInstance(*((UnicodeString*)parser.idBlockVector.elementAt(0)), UTRANS_FORWARD, parseError, status);
+
+
+ if (t != NULL) {
+ t->setID(ID);
+ }
+ }
+ else {
+ UVector transliterators(status);
+ int32_t passNumber = 1;
+
+ int32_t limit = parser.idBlockVector.size();
+ if (parser.dataVector.size() > limit)
+ limit = parser.dataVector.size();
+
+ for (int32_t i = 0; i < limit; i++) {
+ if (i < parser.idBlockVector.size()) {
+ UnicodeString* idBlock = (UnicodeString*)parser.idBlockVector.elementAt(i);
+ if (!idBlock->isEmpty()) {
+ Transliterator* temp = createInstance(*idBlock, UTRANS_FORWARD, parseError, status);
+ if (temp != NULL && temp->getDynamicClassID() != NullTransliterator::getStaticClassID())
+ transliterators.addElement(temp, status);
+ else
+ delete temp;
+ }
+ }
+ if (!parser.dataVector.isEmpty()) {
+ TransliterationRuleData* data = (TransliterationRuleData*)parser.dataVector.orphanElementAt(0);
+ transliterators.addElement(
+ new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + (passNumber++),
+ data, TRUE), status);
+ }
+ }
+
+ t = new CompoundTransliterator(transliterators, passNumber - 1, parseError, status);
+ t->setID(ID);
+ t->adoptFilter(parser.orphanCompoundFilter());
+ }
+ return t;
+}
+
+UnicodeString& Transliterator::toRules(UnicodeString& rulesSource,
+ UBool escapeUnprintable) const {
+ // The base class implementation of toRules munges the ID into
+ // the correct format. That is: foo => ::foo
+ if (escapeUnprintable) {
+ rulesSource.truncate(0);
+ UnicodeString id = getID();
+ for (int32_t i=0; i<id.length();) {
+ UChar32 c = id.char32At(i);
+ if (!ICU_Utility::escapeUnprintable(rulesSource, c)) {
+ rulesSource.append(c);
+ }
+ i += UTF_CHAR_LENGTH(c);
+ }
+ } else {
+ rulesSource = getID();
+ }
+ // KEEP in sync with rbt_pars
+ rulesSource.insert(0, UNICODE_STRING_SIMPLE("::"));
+ rulesSource.append(ID_DELIM);
+ return rulesSource;
+}
+
+int32_t Transliterator::countElements() const {
+ return (this->getDynamicClassID() ==
+ CompoundTransliterator::getStaticClassID()) ?
+ ((const CompoundTransliterator*) this)->getCount() : 0;
+}
+
+const Transliterator& Transliterator::getElement(int32_t index, UErrorCode& ec) const {
+ if (U_FAILURE(ec)) {
+ return *this;
+ }
+ const CompoundTransliterator* cpd =
+ (this->getDynamicClassID() == CompoundTransliterator::getStaticClassID()) ?
+ (const CompoundTransliterator*) this : 0;
+ int32_t n = (cpd == NULL) ? 1 : cpd->getCount();
+ if (index < 0 || index >= n) {
+ ec = U_INDEX_OUTOFBOUNDS_ERROR;
+ return *this;
+ } else {
+ return (n == 1) ? *this : cpd->getTransliterator(index);
+ }
+}
+
+UnicodeSet& Transliterator::getSourceSet(UnicodeSet& result) const {
+ handleGetSourceSet(result);
+ if (filter != NULL) {
+ UnicodeSet* filterSet;
+ UBool deleteFilterSet = FALSE;
+ // Most, but not all filters will be UnicodeSets. Optimize for
+ // the high-runner case.
+ if (filter->getDynamicClassID() == UnicodeSet::getStaticClassID()) {
+ filterSet = (UnicodeSet*) filter;
+ } else {
+ filterSet = new UnicodeSet();
+ deleteFilterSet = TRUE;
+ filter->addMatchSetTo(*filterSet);
+ }
+ result.retainAll(*filterSet);
+ if (deleteFilterSet) {
+ delete filterSet;
+ }
+ }
+ return result;
+}
+
+void Transliterator::handleGetSourceSet(UnicodeSet& result) const {
+ result.clear();
+}
+
+UnicodeSet& Transliterator::getTargetSet(UnicodeSet& result) const {
+ return result.clear();
+}
+
+// For public consumption
+void U_EXPORT2 Transliterator::registerFactory(const UnicodeString& id,
+ Transliterator::Factory factory,
+ Transliterator::Token context) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ _registerFactory(id, factory, context);
+ }
+}
+
+// To be called only by Transliterator subclasses that are called
+// to register themselves by initializeRegistry().
+void Transliterator::_registerFactory(const UnicodeString& id,
+ Transliterator::Factory factory,
+ Transliterator::Token context) {
+ registry->put(id, factory, context, TRUE);
+}
+
+// To be called only by Transliterator subclasses that are called
+// to register themselves by initializeRegistry().
+void Transliterator::_registerSpecialInverse(const UnicodeString& target,
+ const UnicodeString& inverseTarget,
+ UBool bidirectional) {
+ UErrorCode status = U_ZERO_ERROR;
+ TransliteratorIDParser::registerSpecialInverse(target, inverseTarget, bidirectional, status);
+}
+
+/**
+ * Registers a instance <tt>obj</tt> of a subclass of
+ * <code>Transliterator</code> with the system. This object must
+ * implement the <tt>clone()</tt> method. When
+ * <tt>getInstance()</tt> is called with an ID string that is
+ * equal to <tt>obj.getID()</tt>, then <tt>obj.clone()</tt> is
+ * returned.
+ *
+ * @param obj an instance of subclass of
+ * <code>Transliterator</code> that defines <tt>clone()</tt>
+ * @see #getInstance
+ * @see #unregister
+ */
+void U_EXPORT2 Transliterator::registerInstance(Transliterator* adoptedPrototype) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ _registerInstance(adoptedPrototype);
+ }
+}
+
+void Transliterator::_registerInstance(Transliterator* adoptedPrototype) {
+ registry->put(adoptedPrototype, TRUE);
+}
+
+void U_EXPORT2 Transliterator::registerAlias(const UnicodeString& aliasID,
+ const UnicodeString& realID) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ _registerAlias(aliasID, realID);
+ }
+}
+
+void Transliterator::_registerAlias(const UnicodeString& aliasID,
+ const UnicodeString& realID) {
+ registry->put(aliasID, realID, FALSE, TRUE);
+}
+
+/**
+ * Unregisters a transliterator or class. This may be either
+ * a system transliterator or a user transliterator or class.
+ *
+ * @param ID the ID of the transliterator or class
+ * @see #registerInstance
+
+ */
+void U_EXPORT2 Transliterator::unregister(const UnicodeString& ID) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ registry->remove(ID);
+ }
+}
+
+/**
+ * == OBSOLETE - remove in ICU 3.4 ==
+ * Return the number of IDs currently registered with the system.
+ * To retrieve the actual IDs, call getAvailableID(i) with
+ * i from 0 to countAvailableIDs() - 1.
+ */
+int32_t U_EXPORT2 Transliterator::countAvailableIDs(void) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ return HAVE_REGISTRY ? registry->countAvailableIDs() : 0;
+}
+
+/**
+ * == OBSOLETE - remove in ICU 3.4 ==
+ * Return the index-th available ID. index must be between 0
+ * and countAvailableIDs() - 1, inclusive. If index is out of
+ * range, the result of getAvailableID(0) is returned.
+ */
+const UnicodeString& U_EXPORT2 Transliterator::getAvailableID(int32_t index) {
+ const UnicodeString* result = NULL;
+ umtx_init(&registryMutex);
+ umtx_lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ result = &registry->getAvailableID(index);
+ }
+ umtx_unlock(&registryMutex);
+ U_ASSERT(result != NULL); // fail if no registry
+ return *result;
+}
+
+StringEnumeration* U_EXPORT2 Transliterator::getAvailableIDs(UErrorCode& ec) {
+ if (U_FAILURE(ec)) return NULL;
+ StringEnumeration* result = NULL;
+ umtx_init(&registryMutex);
+ umtx_lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ result = registry->getAvailableIDs();
+ }
+ umtx_unlock(&registryMutex);
+ if (result == NULL) {
+ ec = U_INTERNAL_TRANSLITERATOR_ERROR;
+ }
+ return result;
+}
+
+int32_t U_EXPORT2 Transliterator::countAvailableSources(void) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ return HAVE_REGISTRY ? _countAvailableSources() : 0;
+}
+
+UnicodeString& U_EXPORT2 Transliterator::getAvailableSource(int32_t index,
+ UnicodeString& result) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ _getAvailableSource(index, result);
+ }
+ return result;
+}
+
+int32_t U_EXPORT2 Transliterator::countAvailableTargets(const UnicodeString& source) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ return HAVE_REGISTRY ? _countAvailableTargets(source) : 0;
+}
+
+UnicodeString& U_EXPORT2 Transliterator::getAvailableTarget(int32_t index,
+ const UnicodeString& source,
+ UnicodeString& result) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ _getAvailableTarget(index, source, result);
+ }
+ return result;
+}
+
+int32_t U_EXPORT2 Transliterator::countAvailableVariants(const UnicodeString& source,
+ const UnicodeString& target) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ return HAVE_REGISTRY ? _countAvailableVariants(source, target) : 0;
+}
+
+UnicodeString& U_EXPORT2 Transliterator::getAvailableVariant(int32_t index,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ UnicodeString& result) {
+ umtx_init(&registryMutex);
+ Mutex lock(&registryMutex);
+ if (HAVE_REGISTRY) {
+ _getAvailableVariant(index, source, target, result);
+ }
+ return result;
+}
+
+int32_t Transliterator::_countAvailableSources(void) {
+ return registry->countAvailableSources();
+}
+
+UnicodeString& Transliterator::_getAvailableSource(int32_t index,
+ UnicodeString& result) {
+ return registry->getAvailableSource(index, result);
+}
+
+int32_t Transliterator::_countAvailableTargets(const UnicodeString& source) {
+ return registry->countAvailableTargets(source);
+}
+
+UnicodeString& Transliterator::_getAvailableTarget(int32_t index,
+ const UnicodeString& source,
+ UnicodeString& result) {
+ return registry->getAvailableTarget(index, source, result);
+}
+
+int32_t Transliterator::_countAvailableVariants(const UnicodeString& source,
+ const UnicodeString& target) {
+ return registry->countAvailableVariants(source, target);
+}
+
+UnicodeString& Transliterator::_getAvailableVariant(int32_t index,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ UnicodeString& result) {
+ return registry->getAvailableVariant(index, source, target, result);
+}
+
+#ifdef U_USE_DEPRECATED_TRANSLITERATOR_API
+
+/**
+ * Method for subclasses to use to obtain a character in the given
+ * string, with filtering.
+ * @deprecated the new architecture provides filtering at the top
+ * level. This method will be removed Dec 31 2001.
+ */
+UChar Transliterator::filteredCharAt(const Replaceable& text, int32_t i) const {
+ UChar c;
+ const UnicodeFilter* localFilter = getFilter();
+ return (localFilter == 0) ? text.charAt(i) :
+ (localFilter->contains(c = text.charAt(i)) ? c : (UChar)0xFFFE);
+}
+
+#endif
+
+/**
+ * If the registry is initialized, return TRUE. If not, initialize it
+ * and return TRUE. If the registry cannot be initialized, return
+ * FALSE (rare).
+ *
+ * IMPORTANT: Upon entry, registryMutex must be LOCKED. The entirely
+ * initialization is done with the lock held. There is NO REASON to
+ * unlock, since no other thread that is waiting on the registryMutex
+ * cannot itself proceed until the registry is initialized.
+ */
+UBool Transliterator::initializeRegistry() {
+ if (registry != 0) {
+ return TRUE;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ registry = new TransliteratorRegistry(status);
+ if (registry == 0 || U_FAILURE(status)) {
+ delete registry;
+ registry = 0;
+ return FALSE; // can't create registry, no recovery
+ }
+
+ /* The following code parses the index table located in
+ * icu/data/translit/root.txt. The index is an n x 4 table
+ * that follows this format:
+ * <id>{
+ * file{
+ * resource{"<resource>"}
+ * direction{"<direction>"}
+ * }
+ * }
+ * <id>{
+ * internal{
+ * resource{"<resource>"}
+ * direction{"<direction"}
+ * }
+ * }
+ * <id>{
+ * alias{"<getInstanceArg"}
+ * }
+ * <id> is the ID of the system transliterator being defined. These
+ * are public IDs enumerated by Transliterator.getAvailableIDs(),
+ * unless the second field is "internal".
+ *
+ * <resource> is a ResourceReader resource name. Currently these refer
+ * to file names under com/ibm/text/resources. This string is passed
+ * directly to ResourceReader, together with <encoding>.
+ *
+ * <direction> is either "FORWARD" or "REVERSE".
+ *
+ * <getInstanceArg> is a string to be passed directly to
+ * Transliterator.getInstance(). The returned Transliterator object
+ * then has its ID changed to <id> and is returned.
+ *
+ * The extra blank field on "alias" lines is to make the array square.
+ */
+ //static const char translit_index[] = "translit_index";
+
+ UResourceBundle *bundle, *transIDs, *colBund;
+ bundle = ures_open(U_ICUDATA_TRANSLIT, NULL/*open default locale*/, &status);
+ transIDs = ures_getByKey(bundle, RB_RULE_BASED_IDS, 0, &status);
+
+ int32_t row, maxRows;
+ if (U_SUCCESS(status)) {
+ maxRows = ures_getSize(transIDs);
+ for (row = 0; row < maxRows; row++) {
+ colBund = ures_getByIndex(transIDs, row, 0, &status);
+ if (U_SUCCESS(status)) {
+ UnicodeString id(ures_getKey(colBund), -1, US_INV);
+ UResourceBundle* res = ures_getNextResource(colBund, NULL, &status);
+ const char* typeStr = ures_getKey(res);
+ UChar type;
+ u_charsToUChars(typeStr, &type, 1);
+
+ if (U_SUCCESS(status)) {
+ int32_t len = 0;
+ const UChar *resString;
+ switch (type) {
+ case 0x66: // 'f'
+ case 0x69: // 'i'
+ // 'file' or 'internal';
+ // row[2]=resource, row[3]=direction
+ {
+
+ resString = ures_getStringByKey(res, "resource", &len, &status);
+ UBool visible = (type == 0x0066 /*f*/);
+ UTransDirection dir =
+ (ures_getUnicodeStringByKey(res, "direction", &status).charAt(0) ==
+ 0x0046 /*F*/) ?
+ UTRANS_FORWARD : UTRANS_REVERSE;
+ registry->put(id, UnicodeString(TRUE, resString, len), dir, TRUE, visible);
+ }
+ break;
+ case 0x61: // 'a'
+ // 'alias'; row[2]=createInstance argument
+ resString = ures_getString(res, &len, &status);
+ registry->put(id, UnicodeString(TRUE, resString, len), TRUE, TRUE);
+ break;
+ }
+ }
+ ures_close(res);
+ }
+ ures_close(colBund);
+ }
+ }
+
+ ures_close(transIDs);
+ ures_close(bundle);
+
+ // Manually add prototypes that the system knows about to the
+ // cache. This is how new non-rule-based transliterators are
+ // added to the system.
+
+ registry->put(new NullTransliterator(), TRUE);
+ registry->put(new LowercaseTransliterator(), TRUE);
+ registry->put(new UppercaseTransliterator(), TRUE);
+ registry->put(new TitlecaseTransliterator(), TRUE);
+ registry->put(new UnicodeNameTransliterator(), TRUE);
+ registry->put(new NameUnicodeTransliterator(), TRUE);
+
+ RemoveTransliterator::registerIDs(); // Must be within mutex
+ EscapeTransliterator::registerIDs();
+ UnescapeTransliterator::registerIDs();
+ NormalizationTransliterator::registerIDs();
+ AnyTransliterator::registerIDs();
+
+ _registerSpecialInverse(UNICODE_STRING_SIMPLE("Null"),
+ UNICODE_STRING_SIMPLE("Null"), FALSE);
+ _registerSpecialInverse(UNICODE_STRING_SIMPLE("Upper"),
+ UNICODE_STRING_SIMPLE("Lower"), TRUE);
+ _registerSpecialInverse(UNICODE_STRING_SIMPLE("Title"),
+ UNICODE_STRING_SIMPLE("Lower"), FALSE);
+
+ ucln_i18n_registerCleanup(UCLN_I18N_TRANSLITERATOR, transliterator_cleanup);
+
+ return TRUE;
+}
+
+U_NAMESPACE_END
+
+// Defined in ucln_in.h:
+
+/**
+ * Release all static memory held by transliterator. This will
+ * necessarily invalidate any rule-based transliterators held by the
+ * user, because RBTs hold pointers to common data objects.
+ */
+U_CFUNC UBool transliterator_cleanup(void) {
+ U_NAMESPACE_USE
+ TransliteratorIDParser::cleanup();
+ if (registry) {
+ delete registry;
+ registry = NULL;
+ }
+ umtx_destroy(&registryMutex);
+ return TRUE;
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/transreg.cpp b/Build/source/libs/icu/icu-xetex/i18n/transreg.cpp
new file mode 100644
index 00000000000..834e4ce8077
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/transreg.cpp
@@ -0,0 +1,1313 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 08/10/2001 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "unicode/resbund.h"
+#include "unicode/uniset.h"
+#include "unicode/uscript.h"
+#include "rbt.h"
+#include "cpdtrans.h"
+#include "nultrans.h"
+#include "transreg.h"
+#include "rbt_data.h"
+#include "rbt_pars.h"
+#include "tridpars.h"
+#include "charstr.h"
+#include "uassert.h"
+#include "locutil.h"
+
+// Enable the following symbol to add debugging code that tracks the
+// allocation, deletion, and use of Entry objects. BoundsChecker has
+// reported dangling pointer errors with these objects, but I have
+// been unable to confirm them. I suspect BoundsChecker is getting
+// confused with pointers going into and coming out of a UHashtable,
+// despite the hinting code that is designed to help it.
+// #define DEBUG_MEM
+#ifdef DEBUG_MEM
+#include <stdio.h>
+#endif
+
+// UChar constants
+static const UChar LOCALE_SEP = 95; // '_'
+//static const UChar ID_SEP = 0x002D; /*-*/
+//static const UChar VARIANT_SEP = 0x002F; // '/'
+
+// String constants
+static const UChar NO_VARIANT[] = { 0 }; // empty string
+static const UChar ANY[] = { 65, 110, 121, 0 }; // Any
+
+/**
+ * Resource bundle key for the RuleBasedTransliterator rule.
+ */
+//static const char RB_RULE[] = "Rule";
+
+U_NAMESPACE_BEGIN
+
+//------------------------------------------------------------------
+// Alias
+//------------------------------------------------------------------
+
+TransliteratorAlias::TransliteratorAlias(const UnicodeString& theAliasID,
+ const UnicodeSet* cpdFilter) :
+ ID(),
+ aliasesOrRules(theAliasID),
+ transes(0),
+ compoundFilter(cpdFilter),
+ direction(UTRANS_FORWARD),
+ type(TransliteratorAlias::SIMPLE) {
+}
+
+TransliteratorAlias::TransliteratorAlias(const UnicodeString& theID,
+ const UnicodeString& idBlocks,
+ UVector* adoptedTransliterators,
+ const UnicodeSet* cpdFilter) :
+ ID(theID),
+ aliasesOrRules(idBlocks),
+ transes(adoptedTransliterators),
+ compoundFilter(cpdFilter),
+ direction(UTRANS_FORWARD),
+ type(TransliteratorAlias::COMPOUND) {
+}
+
+TransliteratorAlias::TransliteratorAlias(const UnicodeString& theID,
+ const UnicodeString& rules,
+ UTransDirection dir) :
+ ID(theID),
+ aliasesOrRules(rules),
+ transes(0),
+ compoundFilter(0),
+ direction(dir),
+ type(TransliteratorAlias::RULES) {
+}
+
+TransliteratorAlias::~TransliteratorAlias() {
+ delete transes;
+}
+
+
+Transliterator* TransliteratorAlias::create(UParseError& pe,
+ UErrorCode& ec) {
+ if (U_FAILURE(ec)) {
+ return 0;
+ }
+ Transliterator *t = NULL;
+ switch (type) {
+ case SIMPLE:
+ t = Transliterator::createInstance(aliasesOrRules, UTRANS_FORWARD, pe, ec);
+ if(U_FAILURE(ec)){
+ return 0;
+ }
+ if (compoundFilter != 0)
+ t->adoptFilter((UnicodeSet*)compoundFilter->clone());
+ break;
+ case COMPOUND:
+ {
+ // the total number of transliterators in the compound is the total number of anonymous transliterators
+ // plus the total number of ID blocks-- we start by assuming the list begins and ends with an ID
+ // block and that each pair anonymous transliterators has an ID block between them. Then we go back
+ // to see whether there really are ID blocks at the beginning and end (by looking for U+FFFF, which
+ // marks the position where an anonymous transliterator goes) and adjust accordingly
+ int32_t anonymousRBTs = transes->size();
+ int32_t transCount = anonymousRBTs * 2 + 1;
+ if (!aliasesOrRules.isEmpty() && aliasesOrRules[0] == (UChar)(0xffff))
+ --transCount;
+ if (aliasesOrRules.length() >= 2 && aliasesOrRules[aliasesOrRules.length() - 1] == (UChar)(0xffff))
+ --transCount;
+ UnicodeString noIDBlock((UChar)(0xffff));
+ noIDBlock += ((UChar)(0xffff));
+ int32_t pos = aliasesOrRules.indexOf(noIDBlock);
+ while (pos >= 0) {
+ --transCount;
+ pos = aliasesOrRules.indexOf(noIDBlock, pos + 1);
+ }
+
+ UVector transliterators(ec);
+ UnicodeString idBlock;
+ int32_t blockSeparatorPos = aliasesOrRules.indexOf((UChar)(0xffff));
+ while (blockSeparatorPos >= 0) {
+ aliasesOrRules.extract(0, blockSeparatorPos, idBlock);
+ aliasesOrRules.remove(0, blockSeparatorPos + 1);
+ if (!idBlock.isEmpty())
+ transliterators.addElement(Transliterator::createInstance(idBlock, UTRANS_FORWARD, pe, ec), ec);
+ if (!transes->isEmpty())
+ transliterators.addElement(transes->orphanElementAt(0), ec);
+ blockSeparatorPos = aliasesOrRules.indexOf((UChar)(0xffff));
+ }
+ if (!aliasesOrRules.isEmpty())
+ transliterators.addElement(Transliterator::createInstance(aliasesOrRules, UTRANS_FORWARD, pe, ec), ec);
+ while (!transes->isEmpty())
+ transliterators.addElement(transes->orphanElementAt(0), ec);
+
+ if (U_SUCCESS(ec)) {
+ t = new CompoundTransliterator(ID, transliterators,
+ (compoundFilter ? (UnicodeSet*)(compoundFilter->clone()) : 0),
+ anonymousRBTs, pe, ec);
+ if (t == 0) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ } else {
+ for (int32_t i = 0; i < transliterators.size(); i++)
+ delete (Transliterator*)(transliterators.elementAt(i));
+ }
+ }
+ break;
+ case RULES:
+ U_ASSERT(FALSE); // don't call create() if isRuleBased() returns TRUE!
+ break;
+ }
+ return t;
+}
+
+UBool TransliteratorAlias::isRuleBased() const {
+ return type == RULES;
+}
+
+void TransliteratorAlias::parse(TransliteratorParser& parser,
+ UParseError& pe, UErrorCode& ec) const {
+ U_ASSERT(type == RULES);
+ if (U_FAILURE(ec)) {
+ return;
+ }
+
+ parser.parse(aliasesOrRules, direction, pe, ec);
+}
+
+//----------------------------------------------------------------------
+// class Spec
+//----------------------------------------------------------------------
+
+/**
+ * A Spec is a string specifying either a source or a target. In more
+ * general terms, it may also specify a variant, but we only use the
+ * Spec class for sources and targets.
+ *
+ * A Spec may be a locale or a script. If it is a locale, it has a
+ * fallback chain that goes xx_YY_ZZZ -> xx_YY -> xx -> ssss, where
+ * ssss is the script mapping of xx_YY_ZZZ. The Spec API methods
+ * hasFallback(), next(), and reset() iterate over this fallback
+ * sequence.
+ *
+ * The Spec class canonicalizes itself, so the locale is put into
+ * canonical form, or the script is transformed from an abbreviation
+ * to a full name.
+ */
+class Spec : public UMemory {
+ public:
+ Spec(const UnicodeString& spec);
+ ~Spec();
+
+ const UnicodeString& get() const;
+ UBool hasFallback() const;
+ const UnicodeString& next();
+ void reset();
+
+ UBool isLocale() const;
+ ResourceBundle& getBundle() const;
+
+ operator const UnicodeString&() const { return get(); }
+ const UnicodeString& getTop() const { return top; }
+
+ private:
+ void setupNext();
+
+ UnicodeString top;
+ UnicodeString spec;
+ UnicodeString nextSpec;
+ UnicodeString scriptName;
+ UBool isSpecLocale; // TRUE if spec is a locale
+ UBool isNextLocale; // TRUE if nextSpec is a locale
+ ResourceBundle* res;
+
+ Spec(const Spec &other); // forbid copying of this class
+ Spec &operator=(const Spec &other); // forbid copying of this class
+};
+
+Spec::Spec(const UnicodeString& theSpec)
+: top(theSpec),
+ res(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ CharString topch(theSpec);
+ Locale topLoc("");
+ LocaleUtility::initLocaleFromName(theSpec, topLoc);
+ if (!topLoc.isBogus()) {
+ res = new ResourceBundle(U_ICUDATA_TRANSLIT, topLoc, status);
+ /* test for NULL */
+ if (res == 0) {
+ return;
+ }
+ if (U_FAILURE(status) || status == U_USING_DEFAULT_WARNING) {
+ delete res;
+ res = 0;
+ }
+ }
+
+ // Canonicalize script name -or- do locale->script mapping
+ status = U_ZERO_ERROR;
+ static const int32_t capacity = 10;
+ UScriptCode script[capacity]={USCRIPT_INVALID_CODE};
+ int32_t num = uscript_getCode(topch,script,capacity, &status);
+ if (num > 0 && script[0] != USCRIPT_INVALID_CODE) {
+ scriptName = UnicodeString(uscript_getName(script[0]), -1, US_INV);
+ }
+
+ // Canonicalize top
+ if (res != 0) {
+ // Canonicalize locale name
+ UnicodeString locStr;
+ LocaleUtility::initNameFromLocale(topLoc, locStr);
+ if (!locStr.isBogus()) {
+ top = locStr;
+ }
+ } else if (scriptName.length() != 0) {
+ // We are a script; use canonical name
+ top = scriptName;
+ }
+
+ // assert(spec != top);
+ reset();
+}
+
+Spec::~Spec() {
+ delete res;
+}
+
+UBool Spec::hasFallback() const {
+ return nextSpec.length() != 0;
+}
+
+void Spec::reset() {
+ if (spec != top) {
+ spec = top;
+ isSpecLocale = (res != 0);
+ setupNext();
+ }
+}
+
+void Spec::setupNext() {
+ isNextLocale = FALSE;
+ if (isSpecLocale) {
+ nextSpec = spec;
+ int32_t i = nextSpec.lastIndexOf(LOCALE_SEP);
+ // If i == 0 then we have _FOO, so we fall through
+ // to the scriptName.
+ if (i > 0) {
+ nextSpec.truncate(i);
+ isNextLocale = TRUE;
+ } else {
+ nextSpec = scriptName; // scriptName may be empty
+ }
+ } else {
+ // spec is a script, so we are at the end
+ nextSpec.truncate(0);
+ }
+}
+
+// Protocol:
+// for(const UnicodeString& s(spec.get());
+// spec.hasFallback(); s(spec.next())) { ...
+
+const UnicodeString& Spec::next() {
+ spec = nextSpec;
+ isSpecLocale = isNextLocale;
+ setupNext();
+ return spec;
+}
+
+const UnicodeString& Spec::get() const {
+ return spec;
+}
+
+UBool Spec::isLocale() const {
+ return isSpecLocale;
+}
+
+ResourceBundle& Spec::getBundle() const {
+ return *res;
+}
+
+//----------------------------------------------------------------------
+
+#ifdef DEBUG_MEM
+
+// Vector of Entry pointers currently in use
+static UVector* DEBUG_entries = NULL;
+
+static void DEBUG_setup() {
+ if (DEBUG_entries == NULL) {
+ UErrorCode ec = U_ZERO_ERROR;
+ DEBUG_entries = new UVector(ec);
+ }
+}
+
+// Caller must call DEBUG_setup first. Return index of given Entry,
+// if it is in use (not deleted yet), or -1 if not found.
+static int DEBUG_findEntry(Entry* e) {
+ for (int i=0; i<DEBUG_entries->size(); ++i) {
+ if (e == (Entry*) DEBUG_entries->elementAt(i)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// Track object creation
+static void DEBUG_newEntry(Entry* e) {
+ DEBUG_setup();
+ if (DEBUG_findEntry(e) >= 0) {
+ // This should really never happen unless the heap is broken
+ printf("ERROR DEBUG_newEntry duplicate new pointer %08X\n", e);
+ return;
+ }
+ UErrorCode ec = U_ZERO_ERROR;
+ DEBUG_entries->addElement(e, ec);
+}
+
+// Track object deletion
+static void DEBUG_delEntry(Entry* e) {
+ DEBUG_setup();
+ int i = DEBUG_findEntry(e);
+ if (i < 0) {
+ printf("ERROR DEBUG_delEntry possible double deletion %08X\n", e);
+ return;
+ }
+ DEBUG_entries->removeElementAt(i);
+}
+
+// Track object usage
+static void DEBUG_useEntry(Entry* e) {
+ if (e == NULL) return;
+ DEBUG_setup();
+ int i = DEBUG_findEntry(e);
+ if (i < 0) {
+ printf("ERROR DEBUG_useEntry possible dangling pointer %08X\n", e);
+ }
+}
+
+#else
+// If we're not debugging then make these macros into NOPs
+#define DEBUG_newEntry(x)
+#define DEBUG_delEntry(x)
+#define DEBUG_useEntry(x)
+#endif
+
+//----------------------------------------------------------------------
+// class Entry
+//----------------------------------------------------------------------
+
+/**
+ * The Entry object stores objects of different types and
+ * singleton objects as placeholders for rule-based transliterators to
+ * be built as needed. Instances of this struct can be placeholders,
+ * can represent prototype transliterators to be cloned, or can
+ * represent TransliteratorData objects. We don't support storing
+ * classes in the registry because we don't have the rtti infrastructure
+ * for it. We could easily add this if there is a need for it in the
+ * future.
+ */
+class Entry : public UMemory {
+public:
+ enum Type {
+ RULES_FORWARD,
+ RULES_REVERSE,
+ LOCALE_RULES,
+ PROTOTYPE,
+ RBT_DATA,
+ COMPOUND_RBT,
+ ALIAS,
+ FACTORY,
+ NONE // Only used for uninitialized entries
+ } entryType;
+ // NOTE: stringArg cannot go inside the union because
+ // it has a copy constructor
+ UnicodeString stringArg; // For RULES_*, ALIAS, COMPOUND_RBT
+ int32_t intArg; // For COMPOUND_RBT, LOCALE_RULES
+ UnicodeSet* compoundFilter; // For COMPOUND_RBT
+ union {
+ Transliterator* prototype; // For PROTOTYPE
+ TransliterationRuleData* data; // For RBT_DATA
+ UVector* dataVector; // For COMPOUND_RBT
+ struct {
+ Transliterator::Factory function;
+ Transliterator::Token context;
+ } factory; // For FACTORY
+ } u;
+ Entry();
+ ~Entry();
+ void adoptPrototype(Transliterator* adopted);
+ void setFactory(Transliterator::Factory factory,
+ Transliterator::Token context);
+
+private:
+
+ Entry(const Entry &other); // forbid copying of this class
+ Entry &operator=(const Entry &other); // forbid copying of this class
+};
+
+Entry::Entry() {
+ u.prototype = 0;
+ compoundFilter = NULL;
+ entryType = NONE;
+ DEBUG_newEntry(this);
+}
+
+Entry::~Entry() {
+ DEBUG_delEntry(this);
+ if (entryType == PROTOTYPE) {
+ delete u.prototype;
+ } else if (entryType == RBT_DATA) {
+ // The data object is shared between instances of RBT. The
+ // entry object owns it. It should only be deleted when the
+ // transliterator component is being cleaned up. Doing so
+ // invalidates any RBTs that the user has instantiated.
+ delete u.data;
+ } else if (entryType == COMPOUND_RBT) {
+ while (u.dataVector != NULL && !u.dataVector->isEmpty())
+ delete (TransliterationRuleData*)u.dataVector->orphanElementAt(0);
+ delete u.dataVector;
+ }
+ delete compoundFilter;
+}
+
+void Entry::adoptPrototype(Transliterator* adopted) {
+ if (entryType == PROTOTYPE) {
+ delete u.prototype;
+ }
+ entryType = PROTOTYPE;
+ u.prototype = adopted;
+}
+
+void Entry::setFactory(Transliterator::Factory factory,
+ Transliterator::Token context) {
+ if (entryType == PROTOTYPE) {
+ delete u.prototype;
+ }
+ entryType = FACTORY;
+ u.factory.function = factory;
+ u.factory.context = context;
+}
+
+// UObjectDeleter for Hashtable::setValueDeleter
+U_CDECL_BEGIN
+static void U_CALLCONV
+deleteEntry(void* obj) {
+ delete (Entry*) obj;
+}
+U_CDECL_END
+
+//----------------------------------------------------------------------
+// class TransliteratorRegistry: Basic public API
+//----------------------------------------------------------------------
+
+TransliteratorRegistry::TransliteratorRegistry(UErrorCode& status) :
+ registry(TRUE, status),
+ specDAG(TRUE, status),
+ availableIDs(status)
+{
+ registry.setValueDeleter(deleteEntry);
+ availableIDs.setDeleter(uhash_deleteUnicodeString);
+ availableIDs.setComparer(uhash_compareCaselessUnicodeString);
+ specDAG.setValueDeleter(uhash_deleteHashtable);
+}
+
+TransliteratorRegistry::~TransliteratorRegistry() {
+ // Through the magic of C++, everything cleans itself up
+}
+
+Transliterator* TransliteratorRegistry::get(const UnicodeString& ID,
+ TransliteratorAlias*& aliasReturn,
+ UErrorCode& status) {
+ U_ASSERT(aliasReturn == NULL);
+ Entry *entry = find(ID);
+ return (entry == 0) ? 0
+ : instantiateEntry(ID, entry, aliasReturn, status);
+}
+
+Transliterator* TransliteratorRegistry::reget(const UnicodeString& ID,
+ TransliteratorParser& parser,
+ TransliteratorAlias*& aliasReturn,
+ UErrorCode& status) {
+ U_ASSERT(aliasReturn == NULL);
+ Entry *entry = find(ID);
+
+ if (entry == 0) {
+ // We get to this point if there are two threads, one of which
+ // is instantiating an ID, and another of which is removing
+ // the same ID from the registry, and the timing is just right.
+ return 0;
+ }
+
+ // The usage model for the caller is that they will first call
+ // reg->get() inside the mutex, they'll get back an alias, they call
+ // alias->isRuleBased(), and if they get TRUE, they call alias->parse()
+ // outside the mutex, then reg->reget() inside the mutex again. A real
+ // mess, but it gets things working for ICU 3.0. [alan].
+
+ // Note: It's possible that in between the caller calling
+ // alias->parse() and reg->reget(), that another thread will have
+ // called reg->reget(), and the entry will already have been fixed up.
+ // We have to detect this so we don't stomp over existing entry
+ // data members and potentially leak memory (u.data and compoundFilter).
+
+ if (entry->entryType == Entry::RULES_FORWARD ||
+ entry->entryType == Entry::RULES_REVERSE ||
+ entry->entryType == Entry::LOCALE_RULES) {
+
+ if (parser.idBlockVector.isEmpty() && parser.dataVector.isEmpty()) {
+ entry->u.data = 0;
+ entry->entryType = Entry::ALIAS;
+ entry->stringArg = UNICODE_STRING_SIMPLE("Any-NULL");
+ }
+ else if (parser.idBlockVector.isEmpty() && parser.dataVector.size() == 1) {
+ entry->u.data = (TransliterationRuleData*)parser.dataVector.orphanElementAt(0);
+ entry->entryType = Entry::RBT_DATA;
+ }
+ else if (parser.idBlockVector.size() == 1 && parser.dataVector.isEmpty()) {
+ entry->stringArg = *(UnicodeString*)(parser.idBlockVector.elementAt(0));
+ entry->compoundFilter = parser.orphanCompoundFilter();
+ entry->entryType = Entry::ALIAS;
+ }
+ else {
+ entry->entryType = Entry::COMPOUND_RBT;
+ entry->compoundFilter = parser.orphanCompoundFilter();
+ entry->u.dataVector = new UVector(status);
+ entry->stringArg.remove();
+
+ int32_t limit = parser.idBlockVector.size();
+ if (parser.dataVector.size() > limit)
+ limit = parser.dataVector.size();
+
+ for (int32_t i = 0; i < limit; i++) {
+ if (i < parser.idBlockVector.size()) {
+ UnicodeString* idBlock = (UnicodeString*)parser.idBlockVector.elementAt(i);
+ if (!idBlock->isEmpty())
+ entry->stringArg += *idBlock;
+ }
+ if (!parser.dataVector.isEmpty()) {
+ TransliterationRuleData* data = (TransliterationRuleData*)parser.dataVector.orphanElementAt(0);
+ entry->u.dataVector->addElement(data, status);
+ entry->stringArg += (UChar)0xffff; // use U+FFFF to mark position of RBTs in ID block
+ }
+ }
+ }
+ }
+
+ Transliterator *t =
+ instantiateEntry(ID, entry, aliasReturn, status);
+ return t;
+}
+
+void TransliteratorRegistry::put(Transliterator* adoptedProto,
+ UBool visible) {
+ Entry *entry = new Entry();
+ entry->adoptPrototype(adoptedProto);
+ registerEntry(adoptedProto->getID(), entry, visible);
+}
+
+void TransliteratorRegistry::put(const UnicodeString& ID,
+ Transliterator::Factory factory,
+ Transliterator::Token context,
+ UBool visible) {
+ Entry *entry = new Entry();
+ entry->setFactory(factory, context);
+ registerEntry(ID, entry, visible);
+}
+
+void TransliteratorRegistry::put(const UnicodeString& ID,
+ const UnicodeString& resourceName,
+ UTransDirection dir,
+ UBool readonlyResourceAlias,
+ UBool visible) {
+ Entry *entry = new Entry();
+ entry->entryType = (dir == UTRANS_FORWARD) ? Entry::RULES_FORWARD
+ : Entry::RULES_REVERSE;
+ if (readonlyResourceAlias) {
+ entry->stringArg.setTo(TRUE, resourceName.getBuffer(), -1);
+ }
+ else {
+ entry->stringArg = resourceName;
+ }
+ registerEntry(ID, entry, visible);
+}
+
+void TransliteratorRegistry::put(const UnicodeString& ID,
+ const UnicodeString& alias,
+ UBool readonlyAliasAlias,
+ UBool visible) {
+ Entry *entry = new Entry();
+ entry->entryType = Entry::ALIAS;
+ if (readonlyAliasAlias) {
+ entry->stringArg.setTo(TRUE, alias.getBuffer(), -1);
+ }
+ else {
+ entry->stringArg = alias;
+ }
+ registerEntry(ID, entry, visible);
+}
+
+void TransliteratorRegistry::remove(const UnicodeString& ID) {
+ UnicodeString source, target, variant;
+ UBool sawSource;
+ TransliteratorIDParser::IDtoSTV(ID, source, target, variant, sawSource);
+ // Only need to do this if ID.indexOf('-') < 0
+ UnicodeString id;
+ TransliteratorIDParser::STVtoID(source, target, variant, id);
+ registry.remove(id);
+ removeSTV(source, target, variant);
+ availableIDs.removeElement((void*) &id);
+}
+
+//----------------------------------------------------------------------
+// class TransliteratorRegistry: Public ID and spec management
+//----------------------------------------------------------------------
+
+/**
+ * == OBSOLETE - remove in ICU 3.4 ==
+ * Return the number of IDs currently registered with the system.
+ * To retrieve the actual IDs, call getAvailableID(i) with
+ * i from 0 to countAvailableIDs() - 1.
+ */
+int32_t TransliteratorRegistry::countAvailableIDs(void) const {
+ return availableIDs.size();
+}
+
+/**
+ * == OBSOLETE - remove in ICU 3.4 ==
+ * Return the index-th available ID. index must be between 0
+ * and countAvailableIDs() - 1, inclusive. If index is out of
+ * range, the result of getAvailableID(0) is returned.
+ */
+const UnicodeString& TransliteratorRegistry::getAvailableID(int32_t index) const {
+ if (index < 0 || index >= availableIDs.size()) {
+ index = 0;
+ }
+ return *(const UnicodeString*) availableIDs[index];
+}
+
+StringEnumeration* TransliteratorRegistry::getAvailableIDs() const {
+ return new Enumeration(*this);
+}
+
+int32_t TransliteratorRegistry::countAvailableSources(void) const {
+ return specDAG.count();
+}
+
+UnicodeString& TransliteratorRegistry::getAvailableSource(int32_t index,
+ UnicodeString& result) const {
+ int32_t pos = -1;
+ const UHashElement *e = 0;
+ while (index-- >= 0) {
+ e = specDAG.nextElement(pos);
+ if (e == 0) {
+ break;
+ }
+ }
+ if (e == 0) {
+ result.truncate(0);
+ } else {
+ result = *(UnicodeString*) e->key.pointer;
+ }
+ return result;
+}
+
+int32_t TransliteratorRegistry::countAvailableTargets(const UnicodeString& source) const {
+ Hashtable *targets = (Hashtable*) specDAG.get(source);
+ return (targets == 0) ? 0 : targets->count();
+}
+
+UnicodeString& TransliteratorRegistry::getAvailableTarget(int32_t index,
+ const UnicodeString& source,
+ UnicodeString& result) const {
+ Hashtable *targets = (Hashtable*) specDAG.get(source);
+ if (targets == 0) {
+ result.truncate(0); // invalid source
+ return result;
+ }
+ int32_t pos = -1;
+ const UHashElement *e = 0;
+ while (index-- >= 0) {
+ e = targets->nextElement(pos);
+ if (e == 0) {
+ break;
+ }
+ }
+ if (e == 0) {
+ result.truncate(0); // invalid index
+ } else {
+ result = *(UnicodeString*) e->key.pointer;
+ }
+ return result;
+}
+
+int32_t TransliteratorRegistry::countAvailableVariants(const UnicodeString& source,
+ const UnicodeString& target) const {
+ Hashtable *targets = (Hashtable*) specDAG.get(source);
+ if (targets == 0) {
+ return 0;
+ }
+ UVector *variants = (UVector*) targets->get(target);
+ // variants may be 0 if the source/target are invalid
+ return (variants == 0) ? 0 : variants->size();
+}
+
+UnicodeString& TransliteratorRegistry::getAvailableVariant(int32_t index,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ UnicodeString& result) const {
+ Hashtable *targets = (Hashtable*) specDAG.get(source);
+ if (targets == 0) {
+ result.truncate(0); // invalid source
+ return result;
+ }
+ UVector *variants = (UVector*) targets->get(target);
+ if (variants == 0) {
+ result.truncate(0); // invalid target
+ return result;
+ }
+ UnicodeString *v = (UnicodeString*) variants->elementAt(index);
+ if (v == 0) {
+ result.truncate(0); // invalid index
+ } else {
+ result = *v;
+ }
+ return result;
+}
+
+//----------------------------------------------------------------------
+// class TransliteratorRegistry::Enumeration
+//----------------------------------------------------------------------
+
+TransliteratorRegistry::Enumeration::Enumeration(const TransliteratorRegistry& _reg) :
+ index(0), reg(_reg) {
+}
+
+TransliteratorRegistry::Enumeration::~Enumeration() {
+}
+
+int32_t TransliteratorRegistry::Enumeration::count(UErrorCode& /*status*/) const {
+ return reg.availableIDs.size();
+}
+
+const UnicodeString* TransliteratorRegistry::Enumeration::snext(UErrorCode& status) {
+ // This is sloppy but safe -- if we get out of sync with the underlying
+ // registry, we will still return legal strings, but they might not
+ // correspond to the snapshot at construction time. So there could be
+ // duplicate IDs or omitted IDs if insertions or deletions occur in one
+ // thread while another is iterating. To be more rigorous, add a timestamp,
+ // which is incremented with any modification, and validate this iterator
+ // against the timestamp at construction time. This probably isn't worth
+ // doing as long as there is some possibility of removing this code in favor
+ // of some new code based on Doug's service framework.
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ int32_t n = reg.availableIDs.size();
+ if (index > n) {
+ status = U_ENUM_OUT_OF_SYNC_ERROR;
+ }
+ // index == n is okay -- this means we've reached the end
+ if (index < n) {
+ // Copy the string! This avoids lifetime problems.
+ unistr = *(const UnicodeString*)reg.availableIDs[index++];
+ return &unistr;
+ } else {
+ return NULL;
+ }
+}
+
+void TransliteratorRegistry::Enumeration::reset(UErrorCode& /*status*/) {
+ index = 0;
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TransliteratorRegistry::Enumeration)
+
+//----------------------------------------------------------------------
+// class TransliteratorRegistry: internal
+//----------------------------------------------------------------------
+
+/**
+ * Convenience method. Calls 6-arg registerEntry().
+ */
+void TransliteratorRegistry::registerEntry(const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant,
+ Entry* adopted,
+ UBool visible) {
+ UnicodeString ID;
+ UnicodeString s(source);
+ if (s.length() == 0) {
+ s = ANY;
+ }
+ TransliteratorIDParser::STVtoID(source, target, variant, ID);
+ registerEntry(ID, s, target, variant, adopted, visible);
+}
+
+/**
+ * Convenience method. Calls 6-arg registerEntry().
+ */
+void TransliteratorRegistry::registerEntry(const UnicodeString& ID,
+ Entry* adopted,
+ UBool visible) {
+ UnicodeString source, target, variant;
+ UBool sawSource;
+ TransliteratorIDParser::IDtoSTV(ID, source, target, variant, sawSource);
+ // Only need to do this if ID.indexOf('-') < 0
+ UnicodeString id;
+ TransliteratorIDParser::STVtoID(source, target, variant, id);
+ registerEntry(id, source, target, variant, adopted, visible);
+}
+
+/**
+ * Register an entry object (adopted) with the given ID, source,
+ * target, and variant strings.
+ */
+void TransliteratorRegistry::registerEntry(const UnicodeString& ID,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant,
+ Entry* adopted,
+ UBool visible) {
+ UErrorCode status = U_ZERO_ERROR;
+ registry.put(ID, adopted, status);
+ if (visible) {
+ registerSTV(source, target, variant);
+ if (!availableIDs.contains((void*) &ID)) {
+ UnicodeString *newID = (UnicodeString *)ID.clone();
+ // NUL-terminate the ID string
+ newID->getTerminatedBuffer();
+ availableIDs.addElement(newID, status);
+ }
+ } else {
+ removeSTV(source, target, variant);
+ availableIDs.removeElement((void*) &ID);
+ }
+}
+
+/**
+ * Register a source-target/variant in the specDAG. Variant may be
+ * empty, but source and target must not be. If variant is empty then
+ * the special variant NO_VARIANT is stored in slot zero of the
+ * UVector of variants.
+ */
+void TransliteratorRegistry::registerSTV(const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant) {
+ // assert(source.length() > 0);
+ // assert(target.length() > 0);
+ UErrorCode status = U_ZERO_ERROR;
+ Hashtable *targets = (Hashtable*) specDAG.get(source);
+ if (targets == 0) {
+ targets = new Hashtable(TRUE, status);
+ if (U_FAILURE(status) || targets == 0) {
+ return;
+ }
+ targets->setValueDeleter(uhash_deleteUVector);
+ specDAG.put(source, targets, status);
+ }
+ UVector *variants = (UVector*) targets->get(target);
+ if (variants == 0) {
+ variants = new UVector(uhash_deleteUnicodeString,
+ uhash_compareCaselessUnicodeString, status);
+ if (variants == 0) {
+ return;
+ }
+ targets->put(target, variants, status);
+ }
+ // assert(NO_VARIANT == "");
+ // We add the variant string. If it is the special "no variant"
+ // string, that is, the empty string, we add it at position zero.
+ if (!variants->contains((void*) &variant)) {
+ if (variant.length() > 0) {
+ variants->addElement(new UnicodeString(variant), status);
+ } else {
+ variants->insertElementAt(new UnicodeString(NO_VARIANT), 0, status);
+ }
+ }
+}
+
+/**
+ * Remove a source-target/variant from the specDAG.
+ */
+void TransliteratorRegistry::removeSTV(const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant) {
+ // assert(source.length() > 0);
+ // assert(target.length() > 0);
+// UErrorCode status = U_ZERO_ERROR;
+ Hashtable *targets = (Hashtable*) specDAG.get(source);
+ if (targets == 0) {
+ return; // should never happen for valid s-t/v
+ }
+ UVector *variants = (UVector*) targets->get(target);
+ if (variants == 0) {
+ return; // should never happen for valid s-t/v
+ }
+ variants->removeElement((void*) &variant);
+ if (variants->size() == 0) {
+ targets->remove(target); // should delete variants
+ if (targets->count() == 0) {
+ specDAG.remove(source); // should delete targets
+ }
+ }
+}
+
+/**
+ * Attempt to find a source-target/variant in the dynamic registry
+ * store. Return 0 on failure.
+ *
+ * Caller does NOT own returned object.
+ */
+Entry* TransliteratorRegistry::findInDynamicStore(const Spec& src,
+ const Spec& trg,
+ const UnicodeString& variant) const {
+ UnicodeString ID;
+ TransliteratorIDParser::STVtoID(src, trg, variant, ID);
+ Entry *e = (Entry*) registry.get(ID);
+ DEBUG_useEntry(e);
+ return e;
+}
+
+/**
+ * Attempt to find a source-target/variant in the static locale
+ * resource store. Do not perform fallback. Return 0 on failure.
+ *
+ * On success, create a new entry object, register it in the dynamic
+ * store, and return a pointer to it, but do not make it public --
+ * just because someone requested something, we do not expand the
+ * available ID list (or spec DAG).
+ *
+ * Caller does NOT own returned object.
+ */
+Entry* TransliteratorRegistry::findInStaticStore(const Spec& src,
+ const Spec& trg,
+ const UnicodeString& variant) {
+ Entry* entry = 0;
+ if (src.isLocale()) {
+ entry = findInBundle(src, trg, variant, UTRANS_FORWARD);
+ } else if (trg.isLocale()) {
+ entry = findInBundle(trg, src, variant, UTRANS_REVERSE);
+ }
+
+ // If we found an entry, store it in the Hashtable for next
+ // time.
+ if (entry != 0) {
+ registerEntry(src.getTop(), trg.getTop(), variant, entry, FALSE);
+ }
+
+ return entry;
+}
+
+// As of 2.0, resource bundle keys cannot contain '_'
+static const UChar TRANSLITERATE_TO[] = {84,114,97,110,115,108,105,116,101,114,97,116,101,84,111,0}; // "TransliterateTo"
+
+static const UChar TRANSLITERATE_FROM[] = {84,114,97,110,115,108,105,116,101,114,97,116,101,70,114,111,109,0}; // "TransliterateFrom"
+
+static const UChar TRANSLITERATE[] = {84,114,97,110,115,108,105,116,101,114,97,116,101,0}; // "Transliterate"
+
+/**
+ * Attempt to find an entry in a single resource bundle. This is
+ * a one-sided lookup. findInStaticStore() performs up to two such
+ * lookups, one for the source, and one for the target.
+ *
+ * Do not perform fallback. Return 0 on failure.
+ *
+ * On success, create a new Entry object, populate it, and return it.
+ * The caller owns the returned object.
+ */
+Entry* TransliteratorRegistry::findInBundle(const Spec& specToOpen,
+ const Spec& specToFind,
+ const UnicodeString& variant,
+ UTransDirection direction)
+{
+ UnicodeString utag;
+ UnicodeString resStr;
+ int32_t pass;
+
+ for (pass=0; pass<2; ++pass) {
+ utag.truncate(0);
+ // First try either TransliteratorTo_xxx or
+ // TransliterateFrom_xxx, then try the bidirectional
+ // Transliterate_xxx. This precedence order is arbitrary
+ // but must be consistent and documented.
+ if (pass == 0) {
+ utag.append(direction == UTRANS_FORWARD ?
+ TRANSLITERATE_TO : TRANSLITERATE_FROM);
+ } else {
+ utag.append(TRANSLITERATE);
+ }
+ UnicodeString s(specToFind.get());
+ utag.append(s.toUpper(""));
+ CharString tag(utag);
+
+ UErrorCode status = U_ZERO_ERROR;
+ ResourceBundle subres(specToOpen.getBundle().get(tag, status));
+ if (U_FAILURE(status) || status == U_USING_DEFAULT_WARNING) {
+ continue;
+ }
+
+ s.truncate(0);
+ if (specToOpen.get() != LocaleUtility::initNameFromLocale(subres.getLocale(), s)) {
+ continue;
+ }
+
+ if (variant.length() != 0) {
+ CharString var(variant);
+ status = U_ZERO_ERROR;
+ resStr = subres.getStringEx(var, status);
+ if (U_SUCCESS(status)) {
+ // Exit loop successfully
+ break;
+ }
+ }
+
+ else {
+ // Variant is empty, which means match the first variant listed.
+ status = U_ZERO_ERROR;
+ resStr = subres.getStringEx(1, status);
+ if (U_SUCCESS(status)) {
+ // Exit loop successfully
+ break;
+ }
+ }
+ }
+
+ if (pass==2) {
+ // Failed
+ return NULL;
+ }
+
+ // We have succeeded in loading a string from the locale
+ // resources. Create a new registry entry to hold it and return it.
+ Entry *entry = new Entry();
+ if (entry != 0) {
+ // The direction is always forward for the
+ // TransliterateTo_xxx and TransliterateFrom_xxx
+ // items; those are unidirectional forward rules.
+ // For the bidirectional Transliterate_xxx items,
+ // the direction is the value passed in to this
+ // function.
+ int32_t dir = (pass == 0) ? UTRANS_FORWARD : direction;
+ entry->entryType = Entry::LOCALE_RULES;
+ entry->stringArg = resStr;
+ entry->intArg = dir;
+ }
+
+ return entry;
+}
+
+/**
+ * Convenience method. Calls 3-arg find().
+ */
+Entry* TransliteratorRegistry::find(const UnicodeString& ID) {
+ UnicodeString source, target, variant;
+ UBool sawSource;
+ TransliteratorIDParser::IDtoSTV(ID, source, target, variant, sawSource);
+ return find(source, target, variant);
+}
+
+/**
+ * Top-level find method. Attempt to find a source-target/variant in
+ * either the dynamic or the static (locale resource) store. Perform
+ * fallback.
+ *
+ * Lookup sequence for ss_SS_SSS-tt_TT_TTT/v:
+ *
+ * ss_SS_SSS-tt_TT_TTT/v -- in hashtable
+ * ss_SS_SSS-tt_TT_TTT/v -- in ss_SS_SSS (no fallback)
+ *
+ * repeat with t = tt_TT_TTT, tt_TT, tt, and tscript
+ *
+ * ss_SS_SSS-t/ *
+ * ss_SS-t/ *
+ * ss-t/ *
+ * sscript-t/ *
+ *
+ * Here * matches the first variant listed.
+ *
+ * Caller does NOT own returned object. Return 0 on failure.
+ */
+Entry* TransliteratorRegistry::find(UnicodeString& source,
+ UnicodeString& target,
+ UnicodeString& variant) {
+
+ Spec src(source);
+ Spec trg(target);
+ Entry* entry;
+
+ if (variant.length() != 0) {
+
+ // Seek exact match in hashtable
+ entry = findInDynamicStore(src, trg, variant);
+ if (entry != 0) {
+ return entry;
+ }
+
+ // Seek exact match in locale resources
+ entry = findInStaticStore(src, trg, variant);
+ if (entry != 0) {
+ return entry;
+ }
+ }
+
+ for (;;) {
+ src.reset();
+ for (;;) {
+ // Seek match in hashtable
+ entry = findInDynamicStore(src, trg, NO_VARIANT);
+ if (entry != 0) {
+ return entry;
+ }
+
+ // Seek match in locale resources
+ entry = findInStaticStore(src, trg, NO_VARIANT);
+ if (entry != 0) {
+ return entry;
+ }
+ if (!src.hasFallback()) {
+ break;
+ }
+ src.next();
+ }
+ if (!trg.hasFallback()) {
+ break;
+ }
+ trg.next();
+ }
+
+ return 0;
+}
+
+/**
+ * Given an Entry object, instantiate it. Caller owns result. Return
+ * 0 on failure.
+ *
+ * Return a non-empty aliasReturn value if the ID points to an alias.
+ * We cannot instantiate it ourselves because the alias may contain
+ * filters or compounds, which we do not understand. Caller should
+ * make aliasReturn empty before calling.
+ *
+ * The entry object is assumed to reside in the dynamic store. It may be
+ * modified.
+ */
+Transliterator* TransliteratorRegistry::instantiateEntry(const UnicodeString& ID,
+ Entry *entry,
+ TransliteratorAlias* &aliasReturn,
+ UErrorCode& status) {
+ Transliterator *t = 0;
+ U_ASSERT(aliasReturn == 0);
+
+ switch (entry->entryType) {
+ case Entry::RBT_DATA:
+ t = new RuleBasedTransliterator(ID, entry->u.data);
+ if (t == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return t;
+ case Entry::PROTOTYPE:
+ t = entry->u.prototype->clone();
+ if (t == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return t;
+ case Entry::ALIAS:
+ aliasReturn = new TransliteratorAlias(entry->stringArg, entry->compoundFilter);
+ if (aliasReturn == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return 0;
+ case Entry::FACTORY:
+ t = entry->u.factory.function(ID, entry->u.factory.context);
+ if (t == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return t;
+ case Entry::COMPOUND_RBT:
+ {
+ UVector* rbts = new UVector(status);
+ int32_t passNumber = 1;
+ for (int32_t i = 0; U_SUCCESS(status) && i < entry->u.dataVector->size(); i++) {
+ Transliterator* t = new RuleBasedTransliterator(UnicodeString(CompoundTransliterator::PASS_STRING) + (passNumber++),
+ (TransliterationRuleData*)(entry->u.dataVector->elementAt(i)), FALSE);
+ if (t == 0)
+ status = U_MEMORY_ALLOCATION_ERROR;
+ else
+ rbts->addElement(t, status);
+ }
+ if (U_FAILURE(status))
+ return 0;
+ aliasReturn = new TransliteratorAlias(ID, entry->stringArg, rbts, entry->compoundFilter);
+ }
+ if (aliasReturn == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return 0;
+ case Entry::LOCALE_RULES:
+ aliasReturn = new TransliteratorAlias(ID, entry->stringArg,
+ (UTransDirection) entry->intArg);
+ if (aliasReturn == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return 0;
+ case Entry::RULES_FORWARD:
+ case Entry::RULES_REVERSE:
+ // Process the rule data into a TransliteratorRuleData object,
+ // and possibly also into an ::id header and/or footer. Then
+ // we modify the registry with the parsed data and retry.
+ {
+ TransliteratorParser parser(status);
+
+ // We use the file name, taken from another resource bundle
+ // 2-d array at static init time, as a locale language. We're
+ // just using the locale mechanism to map through to a file
+ // name; this in no way represents an actual locale.
+ //CharString ch(entry->stringArg);
+ //UResourceBundle *bundle = ures_openDirect(0, ch, &status);
+ UnicodeString rules = entry->stringArg;
+ //ures_close(bundle);
+
+ //if (U_FAILURE(status)) {
+ // We have a failure of some kind. Remove the ID from the
+ // registry so we don't keep trying. NOTE: This will throw off
+ // anyone who is, at the moment, trying to iterate over the
+ // available IDs. That's acceptable since we should never
+ // really get here except under installation, configuration,
+ // or unrecoverable run time memory failures.
+ // remove(ID);
+ //} else {
+
+ // If the status indicates a failure, then we don't have any
+ // rules -- there is probably an installation error. The list
+ // in the root locale should correspond to all the installed
+ // transliterators; if it lists something that's not
+ // installed, we'll get an error from ResourceBundle.
+ aliasReturn = new TransliteratorAlias(ID, rules,
+ ((entry->entryType == Entry::RULES_REVERSE) ?
+ UTRANS_REVERSE : UTRANS_FORWARD));
+ if (aliasReturn == 0) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ //}
+ }
+ return 0;
+ default:
+ U_ASSERT(FALSE); // can't get here
+ return 0;
+ }
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/transreg.h b/Build/source/libs/icu/icu-xetex/i18n/transreg.h
new file mode 100644
index 00000000000..e74cfe43fed
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/transreg.h
@@ -0,0 +1,458 @@
+/*
+**********************************************************************
+* Copyright (c) 2001-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 08/10/2001 aliu Creation.
+**********************************************************************
+*/
+#ifndef _TRANSREG_H
+#define _TRANSREG_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uobject.h"
+#include "unicode/translit.h"
+#include "hash.h"
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+class Entry;
+class Spec;
+class UnicodeString;
+
+//------------------------------------------------------------------
+// TransliteratorAlias
+//------------------------------------------------------------------
+
+/**
+ * A TransliteratorAlias object is returned by get() if the given ID
+ * actually translates into something else. The caller then invokes
+ * the create() method on the alias to create the actual
+ * transliterator, and deletes the alias.
+ *
+ * Why all the shenanigans? To prevent circular calls between
+ * the registry code and the transliterator code that deadlocks.
+ */
+class TransliteratorAlias : public UMemory {
+ public:
+ /**
+ * Construct a simple alias (type == SIMPLE)
+ * @param aliasID the given id.
+ */
+ TransliteratorAlias(const UnicodeString& aliasID, const UnicodeSet* compoundFilter);
+
+ /**
+ * Construct a compound RBT alias (type == COMPOUND)
+ */
+ TransliteratorAlias(const UnicodeString& ID, const UnicodeString& idBlocks,
+ UVector* adoptedTransliterators,
+ const UnicodeSet* compoundFilter);
+
+ /**
+ * Construct a rules alias (type = RULES)
+ */
+ TransliteratorAlias(const UnicodeString& theID,
+ const UnicodeString& rules,
+ UTransDirection dir);
+
+ ~TransliteratorAlias();
+
+ /**
+ * The whole point of create() is that the caller must invoke
+ * it when the registry mutex is NOT held, to prevent deadlock.
+ * It may only be called once.
+ *
+ * Note: Only call create() if isRuleBased() returns FALSE.
+ *
+ * This method must be called *outside* of the TransliteratorRegistry
+ * mutex.
+ */
+ Transliterator* create(UParseError&, UErrorCode&);
+
+ /**
+ * Return TRUE if this alias is rule-based. If so, the caller
+ * must call parse() on it, then call TransliteratorRegistry::reget().
+ */
+ UBool isRuleBased() const;
+
+ /**
+ * If isRuleBased() returns TRUE, then the caller must call this
+ * method, followed by TransliteratorRegistry::reget(). The latter
+ * method must be called inside the TransliteratorRegistry mutex.
+ *
+ * Note: Only call parse() if isRuleBased() returns TRUE.
+ *
+ * This method must be called *outside* of the TransliteratorRegistry
+ * mutex, because it can instantiate Transliterators embedded in
+ * the rules via the "&Latin-Arabic()" syntax.
+ */
+ void parse(TransliteratorParser& parser,
+ UParseError& pe, UErrorCode& ec) const;
+
+ private:
+ // We actually come in three flavors:
+ // 1. Simple alias
+ // Here aliasID is the alias string. Everything else is
+ // null, zero, empty.
+ // 2. CompoundRBT
+ // Here ID is the ID, aliasID is the idBlock, trans is the
+ // contained RBT, and idSplitPoint is the offet in aliasID
+ // where the contained RBT goes. compoundFilter is the
+ // compound filter, and it is _not_ owned.
+ // 3. Rules
+ // Here ID is the ID, aliasID is the rules string.
+ // idSplitPoint is the UTransDirection.
+ UnicodeString ID;
+ UnicodeString aliasesOrRules;
+ UVector* transes; // owned
+ const UnicodeSet* compoundFilter; // alias
+ UTransDirection direction;
+ enum { SIMPLE, COMPOUND, RULES } type;
+
+ TransliteratorAlias(const TransliteratorAlias &other); // forbid copying of this class
+ TransliteratorAlias &operator=(const TransliteratorAlias &other); // forbid copying of this class
+};
+
+
+/**
+ * A registry of system transliterators. This is the data structure
+ * that implements the mapping between transliterator IDs and the data
+ * or function pointers used to create the corresponding
+ * transliterators. There is one instance of the registry that is
+ * created statically.
+ *
+ * The registry consists of a dynamic component -- a hashtable -- and
+ * a static component -- locale resource bundles. The dynamic store
+ * is semantically overlaid on the static store, so the static mapping
+ * can be dynamically overridden.
+ *
+ * This is an internal class that is only used by Transliterator.
+ * Transliterator maintains one static instance of this class and
+ * delegates all registry-related operations to it.
+ *
+ * @author Alan Liu
+ */
+class TransliteratorRegistry : public UMemory {
+
+ public:
+
+ /**
+ * Contructor
+ * @param status Output param set to success/failure code.
+ */
+ TransliteratorRegistry(UErrorCode& status);
+
+ /**
+ * Nonvirtual destructor -- this class is not subclassable.
+ */
+ ~TransliteratorRegistry();
+
+ //------------------------------------------------------------------
+ // Basic public API
+ //------------------------------------------------------------------
+
+ /**
+ * Given a simple ID (forward direction, no inline filter, not
+ * compound) attempt to instantiate it from the registry. Return
+ * 0 on failure.
+ *
+ * Return a non-NULL aliasReturn value if the ID points to an alias.
+ * We cannot instantiate it ourselves because the alias may contain
+ * filters or compounds, which we do not understand. Caller should
+ * make aliasReturn NULL before calling.
+ * @param ID the given ID
+ * @param aliasReturn output param to receive TransliteratorAlias;
+ * should be NULL on entry
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered
+ * @param status Output param set to success/failure code.
+ */
+ Transliterator* get(const UnicodeString& ID,
+ TransliteratorAlias*& aliasReturn,
+ UErrorCode& status);
+
+ /**
+ * The caller must call this after calling get(), if [a] calling get()
+ * returns an alias, and [b] the alias is rule based. In that
+ * situation the caller must call alias->parse() to do the parsing
+ * OUTSIDE THE REGISTRY MUTEX, then call this method to retry
+ * instantiating the transliterator.
+ *
+ * Note: Another alias might be returned by this method.
+ *
+ * This method (like all public methods of this class) must be called
+ * from within the TransliteratorRegistry mutex.
+ *
+ * @param aliasReturn output param to receive TransliteratorAlias;
+ * should be NULL on entry
+ */
+ Transliterator* reget(const UnicodeString& ID,
+ TransliteratorParser& parser,
+ TransliteratorAlias*& aliasReturn,
+ UErrorCode& status);
+
+ /**
+ * Register a prototype (adopted). This adds an entry to the
+ * dynamic store, or replaces an existing entry. Any entry in the
+ * underlying static locale resource store is masked.
+ */
+ void put(Transliterator* adoptedProto,
+ UBool visible);
+
+ /**
+ * Register an ID and a factory function pointer. This adds an
+ * entry to the dynamic store, or replaces an existing entry. Any
+ * entry in the underlying static locale resource store is masked.
+ */
+ void put(const UnicodeString& ID,
+ Transliterator::Factory factory,
+ Transliterator::Token context,
+ UBool visible);
+
+ /**
+ * Register an ID and a resource name. This adds an entry to the
+ * dynamic store, or replaces an existing entry. Any entry in the
+ * underlying static locale resource store is masked.
+ */
+ void put(const UnicodeString& ID,
+ const UnicodeString& resourceName,
+ UTransDirection dir,
+ UBool readonlyResourceAlias,
+ UBool visible);
+
+ /**
+ * Register an ID and an alias ID. This adds an entry to the
+ * dynamic store, or replaces an existing entry. Any entry in the
+ * underlying static locale resource store is masked.
+ */
+ void put(const UnicodeString& ID,
+ const UnicodeString& alias,
+ UBool readonlyAliasAlias,
+ UBool visible);
+
+ /**
+ * Unregister an ID. This removes an entry from the dynamic store
+ * if there is one. The static locale resource store is
+ * unaffected.
+ * @param ID the given ID.
+ */
+ void remove(const UnicodeString& ID);
+
+ //------------------------------------------------------------------
+ // Public ID and spec management
+ //------------------------------------------------------------------
+
+ /**
+ * Return a StringEnumeration over the IDs currently registered
+ * with the system.
+ * @internal
+ */
+ StringEnumeration* getAvailableIDs() const;
+
+ /**
+ * == OBSOLETE - remove in ICU 3.4 ==
+ * Return the number of IDs currently registered with the system.
+ * To retrieve the actual IDs, call getAvailableID(i) with
+ * i from 0 to countAvailableIDs() - 1.
+ * @return the number of IDs currently registered with the system.
+ * @internal
+ */
+ int32_t countAvailableIDs(void) const;
+
+ /**
+ * == OBSOLETE - remove in ICU 3.4 ==
+ * Return the index-th available ID. index must be between 0
+ * and countAvailableIDs() - 1, inclusive. If index is out of
+ * range, the result of getAvailableID(0) is returned.
+ * @param index the given index.
+ * @return the index-th available ID. index must be between 0
+ * and countAvailableIDs() - 1, inclusive. If index is out of
+ * range, the result of getAvailableID(0) is returned.
+ * @internal
+ */
+ const UnicodeString& getAvailableID(int32_t index) const;
+
+ /**
+ * Return the number of registered source specifiers.
+ * @return the number of registered source specifiers.
+ */
+ int32_t countAvailableSources(void) const;
+
+ /**
+ * Return a registered source specifier.
+ * @param index which specifier to return, from 0 to n-1, where
+ * n = countAvailableSources()
+ * @param result fill-in paramter to receive the source specifier.
+ * If index is out of range, result will be empty.
+ * @return reference to result
+ */
+ UnicodeString& getAvailableSource(int32_t index,
+ UnicodeString& result) const;
+
+ /**
+ * Return the number of registered target specifiers for a given
+ * source specifier.
+ * @param source the given source specifier.
+ * @return the number of registered target specifiers for a given
+ * source specifier.
+ */
+ int32_t countAvailableTargets(const UnicodeString& source) const;
+
+ /**
+ * Return a registered target specifier for a given source.
+ * @param index which specifier to return, from 0 to n-1, where
+ * n = countAvailableTargets(source)
+ * @param source the source specifier
+ * @param result fill-in paramter to receive the target specifier.
+ * If source is invalid or if index is out of range, result will
+ * be empty.
+ * @return reference to result
+ */
+ UnicodeString& getAvailableTarget(int32_t index,
+ const UnicodeString& source,
+ UnicodeString& result) const;
+
+ /**
+ * Return the number of registered variant specifiers for a given
+ * source-target pair. There is always at least one variant: If
+ * just source-target is registered, then the single variant
+ * NO_VARIANT is returned. If source-target/variant is registered
+ * then that variant is returned.
+ * @param source the source specifiers
+ * @param target the target specifiers
+ * @return the number of registered variant specifiers for a given
+ * source-target pair.
+ */
+ int32_t countAvailableVariants(const UnicodeString& source,
+ const UnicodeString& target) const;
+
+ /**
+ * Return a registered variant specifier for a given source-target
+ * pair. If NO_VARIANT is one of the variants, then it will be
+ * at index 0.
+ * @param index which specifier to return, from 0 to n-1, where
+ * n = countAvailableVariants(source, target)
+ * @param source the source specifier
+ * @param target the target specifier
+ * @param result fill-in paramter to receive the variant
+ * specifier. If source is invalid or if target is invalid or if
+ * index is out of range, result will be empty.
+ * @return reference to result
+ */
+ UnicodeString& getAvailableVariant(int32_t index,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ UnicodeString& result) const;
+
+ private:
+
+ //----------------------------------------------------------------
+ // Private implementation
+ //----------------------------------------------------------------
+
+ Entry* find(const UnicodeString& ID);
+
+ Entry* find(UnicodeString& source,
+ UnicodeString& target,
+ UnicodeString& variant);
+
+ Entry* findInDynamicStore(const Spec& src,
+ const Spec& trg,
+ const UnicodeString& variant) const;
+
+ Entry* findInStaticStore(const Spec& src,
+ const Spec& trg,
+ const UnicodeString& variant);
+
+ static Entry* findInBundle(const Spec& specToOpen,
+ const Spec& specToFind,
+ const UnicodeString& variant,
+ UTransDirection direction);
+
+ void registerEntry(const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant,
+ Entry* adopted,
+ UBool visible);
+
+ void registerEntry(const UnicodeString& ID,
+ Entry* adopted,
+ UBool visible);
+
+ void registerEntry(const UnicodeString& ID,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant,
+ Entry* adopted,
+ UBool visible);
+
+ void registerSTV(const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant);
+
+ void removeSTV(const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant);
+
+ Transliterator* instantiateEntry(const UnicodeString& ID,
+ Entry *entry,
+ TransliteratorAlias*& aliasReturn,
+ UErrorCode& status);
+
+ /**
+ * A StringEnumeration over the registered IDs in this object.
+ */
+ class Enumeration : public StringEnumeration {
+ public:
+ Enumeration(const TransliteratorRegistry& reg);
+ virtual ~Enumeration();
+ virtual int32_t count(UErrorCode& status) const;
+ virtual const UnicodeString* snext(UErrorCode& status);
+ virtual void reset(UErrorCode& status);
+ static UClassID U_EXPORT2 getStaticClassID();
+ virtual UClassID getDynamicClassID() const;
+ private:
+ int32_t index;
+ const TransliteratorRegistry& reg;
+ };
+ friend class Enumeration;
+
+ private:
+
+ /**
+ * Dynamic registry mapping full IDs to Entry objects. This
+ * contains both public and internal entities. The visibility is
+ * controlled by whether an entry is listed in availableIDs and
+ * specDAG or not.
+ */
+ Hashtable registry;
+
+ /**
+ * DAG of visible IDs by spec. Hashtable: source => (Hashtable:
+ * target => (UVector: variant)) The UVector of variants is never
+ * empty. For a source-target with no variant, the special
+ * variant NO_VARIANT (the empty string) is stored in slot zero of
+ * the UVector.
+ */
+ Hashtable specDAG;
+
+ /**
+ * Vector of public full IDs.
+ */
+ UVector availableIDs;
+
+ TransliteratorRegistry(const TransliteratorRegistry &other); // forbid copying of this class
+ TransliteratorRegistry &operator=(const TransliteratorRegistry &other); // forbid copying of this class
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/tridpars.cpp b/Build/source/libs/icu/icu-xetex/i18n/tridpars.cpp
new file mode 100644
index 00000000000..f0338de254f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/tridpars.cpp
@@ -0,0 +1,905 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2006, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 01/14/2002 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "tridpars.h"
+#include "hash.h"
+#include "mutex.h"
+#include "ucln_in.h"
+#include "unicode/parsepos.h"
+#include "unicode/translit.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/unistr.h"
+#include "unicode/utrans.h"
+#include "util.h"
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+static const UChar ID_DELIM = 0x003B; // ;
+static const UChar TARGET_SEP = 0x002D; // -
+static const UChar VARIANT_SEP = 0x002F; // /
+static const UChar OPEN_REV = 0x0028; // (
+static const UChar CLOSE_REV = 0x0029; // )
+
+//static const UChar EMPTY[] = {0}; // ""
+static const UChar ANY[] = {65,110,121,0}; // "Any"
+static const UChar ANY_NULL[] = {65,110,121,45,78,117,108,108,0}; // "Any-Null"
+
+static const int32_t FORWARD = UTRANS_FORWARD;
+static const int32_t REVERSE = UTRANS_REVERSE;
+
+static Hashtable* SPECIAL_INVERSES = NULL;
+
+/**
+ * The mutex controlling access to SPECIAL_INVERSES
+ */
+static UMTX LOCK = 0;
+
+TransliteratorIDParser::Specs::Specs(const UnicodeString& s, const UnicodeString& t,
+ const UnicodeString& v, UBool sawS,
+ const UnicodeString& f) {
+ source = s;
+ target = t;
+ variant = v;
+ sawSource = sawS;
+ filter = f;
+}
+
+TransliteratorIDParser::SingleID::SingleID(const UnicodeString& c, const UnicodeString& b,
+ const UnicodeString& f) {
+ canonID = c;
+ basicID = b;
+ filter = f;
+}
+
+TransliteratorIDParser::SingleID::SingleID(const UnicodeString& c, const UnicodeString& b) {
+ canonID = c;
+ basicID = b;
+}
+
+Transliterator* TransliteratorIDParser::SingleID::createInstance() {
+ Transliterator* t;
+ if (basicID.length() == 0) {
+ t = createBasicInstance(ANY_NULL, &canonID);
+ } else {
+ t = createBasicInstance(basicID, &canonID);
+ }
+ if (t != NULL) {
+ if (filter.length() != 0) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeSet *set = new UnicodeSet(filter, ec);
+ if (U_FAILURE(ec)) {
+ delete set;
+ } else {
+ t->adoptFilter(set);
+ }
+ }
+ }
+ return t;
+}
+
+
+/**
+ * Parse a single ID, that is, an ID of the general form
+ * "[f1] s1-t1/v1 ([f2] s2-t3/v2)", with the parenthesized element
+ * optional, the filters optional, and the variants optional.
+ * @param id the id to be parsed
+ * @param pos INPUT-OUTPUT parameter. On input, the position of
+ * the first character to parse. On output, the position after
+ * the last character parsed.
+ * @param dir the direction. If the direction is REVERSE then the
+ * SingleID is constructed for the reverse direction.
+ * @return a SingleID object or NULL
+ */
+TransliteratorIDParser::SingleID*
+TransliteratorIDParser::parseSingleID(const UnicodeString& id, int32_t& pos,
+ int32_t dir, UErrorCode& status) {
+
+ int32_t start = pos;
+
+ // The ID will be of the form A, A(), A(B), or (B), where
+ // A and B are filter IDs.
+ Specs* specsA = NULL;
+ Specs* specsB = NULL;
+ UBool sawParen = FALSE;
+
+ // On the first pass, look for (B) or (). If this fails, then
+ // on the second pass, look for A, A(B), or A().
+ for (int32_t pass=1; pass<=2; ++pass) {
+ if (pass == 2) {
+ specsA = parseFilterID(id, pos, TRUE);
+ if (specsA == NULL) {
+ pos = start;
+ return NULL;
+ }
+ }
+ if (ICU_Utility::parseChar(id, pos, OPEN_REV)) {
+ sawParen = TRUE;
+ if (!ICU_Utility::parseChar(id, pos, CLOSE_REV)) {
+ specsB = parseFilterID(id, pos, TRUE);
+ // Must close with a ')'
+ if (specsB == NULL || !ICU_Utility::parseChar(id, pos, CLOSE_REV)) {
+ delete specsA;
+ pos = start;
+ return NULL;
+ }
+ }
+ break;
+ }
+ }
+
+ // Assemble return results
+ SingleID* single;
+ if (sawParen) {
+ if (dir == FORWARD) {
+ SingleID* b = specsToID(specsB, FORWARD);
+ single = specsToID(specsA, FORWARD);
+ single->canonID.append(OPEN_REV)
+ .append(b->canonID).append(CLOSE_REV);
+ if (specsA != NULL) {
+ single->filter = specsA->filter;
+ }
+ delete b;
+ } else {
+ SingleID* a = specsToID(specsA, FORWARD);
+ single = specsToID(specsB, FORWARD);
+ single->canonID.append(OPEN_REV)
+ .append(a->canonID).append(CLOSE_REV);
+ if (specsB != NULL) {
+ single->filter = specsB->filter;
+ }
+ delete a;
+ }
+ } else {
+ // assert(specsA != NULL);
+ if (dir == FORWARD) {
+ single = specsToID(specsA, FORWARD);
+ } else {
+ single = specsToSpecialInverse(*specsA, status);
+ if (single == NULL) {
+ single = specsToID(specsA, REVERSE);
+ }
+ }
+ single->filter = specsA->filter;
+ }
+
+ delete specsA;
+ delete specsB;
+
+ return single;
+}
+
+/**
+ * Parse a filter ID, that is, an ID of the general form
+ * "[f1] s1-t1/v1", with the filters optional, and the variants optional.
+ * @param id the id to be parsed
+ * @param pos INPUT-OUTPUT parameter. On input, the position of
+ * the first character to parse. On output, the position after
+ * the last character parsed.
+ * @return a SingleID object or null if the parse fails
+ */
+TransliteratorIDParser::SingleID*
+TransliteratorIDParser::parseFilterID(const UnicodeString& id, int32_t& pos) {
+
+ int32_t start = pos;
+
+ Specs* specs = parseFilterID(id, pos, TRUE);
+ if (specs == NULL) {
+ pos = start;
+ return NULL;
+ }
+
+ // Assemble return results
+ SingleID* single = specsToID(specs, FORWARD);
+ single->filter = specs->filter;
+ delete specs;
+ return single;
+}
+
+/**
+ * Parse a global filter of the form "[f]" or "([f])", depending
+ * on 'withParens'.
+ * @param id the pattern the parse
+ * @param pos INPUT-OUTPUT parameter. On input, the position of
+ * the first character to parse. On output, the position after
+ * the last character parsed.
+ * @param dir the direction.
+ * @param withParens INPUT-OUTPUT parameter. On entry, if
+ * withParens is 0, then parens are disallowed. If it is 1,
+ * then parens are requires. If it is -1, then parens are
+ * optional, and the return result will be set to 0 or 1.
+ * @param canonID OUTPUT parameter. The pattern for the filter
+ * added to the canonID, either at the end, if dir is FORWARD, or
+ * at the start, if dir is REVERSE. The pattern will be enclosed
+ * in parentheses if appropriate, and will be suffixed with an
+ * ID_DELIM character. May be NULL.
+ * @return a UnicodeSet object or NULL. A non-NULL results
+ * indicates a successful parse, regardless of whether the filter
+ * applies to the given direction. The caller should discard it
+ * if withParens != (dir == REVERSE).
+ */
+UnicodeSet* TransliteratorIDParser::parseGlobalFilter(const UnicodeString& id, int32_t& pos,
+ int32_t dir,
+ int32_t& withParens,
+ UnicodeString* canonID) {
+ UnicodeSet* filter = NULL;
+ int32_t start = pos;
+
+ if (withParens == -1) {
+ withParens = ICU_Utility::parseChar(id, pos, OPEN_REV) ? 1 : 0;
+ } else if (withParens == 1) {
+ if (!ICU_Utility::parseChar(id, pos, OPEN_REV)) {
+ pos = start;
+ return NULL;
+ }
+ }
+
+ ICU_Utility::skipWhitespace(id, pos, TRUE);
+
+ if (UnicodeSet::resemblesPattern(id, pos)) {
+ ParsePosition ppos(pos);
+ UErrorCode ec = U_ZERO_ERROR;
+ filter = new UnicodeSet(id, ppos, USET_IGNORE_SPACE, NULL, ec);
+ /* test for NULL */
+ if (filter == 0) {
+ pos = start;
+ return 0;
+ }
+ if (U_FAILURE(ec)) {
+ delete filter;
+ pos = start;
+ return NULL;
+ }
+
+ UnicodeString pattern;
+ id.extractBetween(pos, ppos.getIndex(), pattern);
+ pos = ppos.getIndex();
+
+ if (withParens == 1 && !ICU_Utility::parseChar(id, pos, CLOSE_REV)) {
+ pos = start;
+ return NULL;
+ }
+
+ // In the forward direction, append the pattern to the
+ // canonID. In the reverse, insert it at zero, and invert
+ // the presence of parens ("A" <-> "(A)").
+ if (canonID != NULL) {
+ if (dir == FORWARD) {
+ if (withParens == 1) {
+ pattern.insert(0, OPEN_REV);
+ pattern.append(CLOSE_REV);
+ }
+ canonID->append(pattern).append(ID_DELIM);
+ } else {
+ if (withParens == 0) {
+ pattern.insert(0, OPEN_REV);
+ pattern.append(CLOSE_REV);
+ }
+ canonID->insert(0, pattern);
+ canonID->insert(pattern.length(), ID_DELIM);
+ }
+ }
+ }
+
+ return filter;
+}
+
+U_CDECL_BEGIN
+static void U_CALLCONV _deleteSingleID(void* obj) {
+ delete (TransliteratorIDParser::SingleID*) obj;
+}
+
+static void U_CALLCONV _deleteTransliteratorTrIDPars(void* obj) {
+ delete (Transliterator*) obj;
+}
+U_CDECL_END
+
+/**
+ * Parse a compound ID, consisting of an optional forward global
+ * filter, a separator, one or more single IDs delimited by
+ * separators, an an optional reverse global filter. The
+ * separator is a semicolon. The global filters are UnicodeSet
+ * patterns. The reverse global filter must be enclosed in
+ * parentheses.
+ * @param id the pattern the parse
+ * @param dir the direction.
+ * @param canonID OUTPUT parameter that receives the canonical ID,
+ * consisting of canonical IDs for all elements, as returned by
+ * parseSingleID(), separated by semicolons. Previous contents
+ * are discarded.
+ * @param list OUTPUT parameter that receives a list of SingleID
+ * objects representing the parsed IDs. Previous contents are
+ * discarded.
+ * @param globalFilter OUTPUT parameter that receives a pointer to
+ * a newly created global filter for this ID in this direction, or
+ * NULL if there is none.
+ * @return TRUE if the parse succeeds, that is, if the entire
+ * id is consumed without syntax error.
+ */
+UBool TransliteratorIDParser::parseCompoundID(const UnicodeString& id, int32_t dir,
+ UnicodeString& canonID,
+ UVector& list,
+ UnicodeSet*& globalFilter) {
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t i;
+ int32_t pos = 0;
+ int32_t withParens = 1;
+ list.removeAllElements();
+ UnicodeSet* filter;
+ globalFilter = NULL;
+ canonID.truncate(0);
+
+ // Parse leading global filter, if any
+ withParens = 0; // parens disallowed
+ filter = parseGlobalFilter(id, pos, dir, withParens, &canonID);
+ if (filter != NULL) {
+ if (!ICU_Utility::parseChar(id, pos, ID_DELIM)) {
+ // Not a global filter; backup and resume
+ canonID.truncate(0);
+ pos = 0;
+ }
+ if (dir == FORWARD) {
+ globalFilter = filter;
+ } else {
+ delete filter;
+ }
+ filter = NULL;
+ }
+
+ UBool sawDelimiter = TRUE;
+ for (;;) {
+ SingleID* single = parseSingleID(id, pos, dir, ec);
+ if (single == NULL) {
+ break;
+ }
+ if (dir == FORWARD) {
+ list.addElement(single, ec);
+ } else {
+ list.insertElementAt(single, 0, ec);
+ }
+ if (U_FAILURE(ec)) {
+ goto FAIL;
+ }
+ if (!ICU_Utility::parseChar(id, pos, ID_DELIM)) {
+ sawDelimiter = FALSE;
+ break;
+ }
+ }
+
+ if (list.size() == 0) {
+ goto FAIL;
+ }
+
+ // Construct canonical ID
+ for (i=0; i<list.size(); ++i) {
+ SingleID* single = (SingleID*) list.elementAt(i);
+ canonID.append(single->canonID);
+ if (i != (list.size()-1)) {
+ canonID.append(ID_DELIM);
+ }
+ }
+
+ // Parse trailing global filter, if any, and only if we saw
+ // a trailing delimiter after the IDs.
+ if (sawDelimiter) {
+ withParens = 1; // parens required
+ filter = parseGlobalFilter(id, pos, dir, withParens, &canonID);
+ if (filter != NULL) {
+ // Don't require trailing ';', but parse it if present
+ ICU_Utility::parseChar(id, pos, ID_DELIM);
+
+ if (dir == REVERSE) {
+ globalFilter = filter;
+ } else {
+ delete filter;
+ }
+ filter = NULL;
+ }
+ }
+
+ // Trailing unparsed text is a syntax error
+ ICU_Utility::skipWhitespace(id, pos, TRUE);
+ if (pos != id.length()) {
+ goto FAIL;
+ }
+
+ return TRUE;
+
+ FAIL:
+ UObjectDeleter *save = list.setDeleter(_deleteSingleID);
+ list.removeAllElements();
+ list.setDeleter(save);
+ delete globalFilter;
+ globalFilter = NULL;
+ return FALSE;
+}
+
+/**
+ * Convert the elements of the 'list' vector, which are SingleID
+ * objects, into actual Transliterator objects. In the course of
+ * this, some (or all) entries may be removed. If all entries
+ * are removed, the NULL transliterator will be added.
+ *
+ * Delete entries with empty basicIDs; these are generated by
+ * elements like "(A)" in the forward direction, or "A()" in
+ * the reverse. THIS MAY RESULT IN AN EMPTY VECTOR. Convert
+ * SingleID entries to actual transliterators.
+ *
+ * @param list vector of SingleID objects. On exit, vector
+ * of one or more Transliterators.
+ * @return new value of insertIndex. The index will shift if
+ * there are empty items, like "(Lower)", with indices less than
+ * insertIndex.
+ */
+void TransliteratorIDParser::instantiateList(UVector& list,
+ UErrorCode& ec) {
+ UVector tlist(ec);
+ if (U_FAILURE(ec)) {
+ goto RETURN;
+ }
+ tlist.setDeleter(_deleteTransliteratorTrIDPars);
+
+ Transliterator* t;
+ int32_t i;
+ for (i=0; i<=list.size(); ++i) { // [sic]: i<=list.size()
+ // We run the loop too long by one, so we can
+ // do an insert after the last element
+ if (i==list.size()) {
+ break;
+ }
+
+ SingleID* single = (SingleID*) list.elementAt(i);
+ if (single->basicID.length() != 0) {
+ t = single->createInstance();
+ if (t == NULL) {
+ ec = U_INVALID_ID;
+ goto RETURN;
+ }
+ tlist.addElement(t, ec);
+ if (U_FAILURE(ec)) {
+ delete t;
+ goto RETURN;
+ }
+ }
+ }
+
+ // An empty list is equivalent to a NULL transliterator.
+ if (tlist.size() == 0) {
+ t = createBasicInstance(ANY_NULL, NULL);
+ if (t == NULL) {
+ // Should never happen
+ ec = U_INTERNAL_TRANSLITERATOR_ERROR;
+ }
+ tlist.addElement(t, ec);
+ if (U_FAILURE(ec)) {
+ delete t;
+ }
+ }
+
+ RETURN:
+
+ UObjectDeleter *save = list.setDeleter(_deleteSingleID);
+ list.removeAllElements();
+
+ if (U_SUCCESS(ec)) {
+ list.setDeleter(_deleteTransliteratorTrIDPars);
+
+ while (tlist.size() > 0) {
+ t = (Transliterator*) tlist.orphanElementAt(0);
+ list.addElement(t, ec);
+ if (U_FAILURE(ec)) {
+ delete t;
+ list.removeAllElements();
+ break;
+ }
+ }
+ }
+
+ list.setDeleter(save);
+}
+
+/**
+ * Parse an ID into pieces. Take IDs of the form T, T/V, S-T,
+ * S-T/V, or S/V-T. If the source is missing, return a source of
+ * ANY.
+ * @param id the id string, in any of several forms
+ * @return an array of 4 strings: source, target, variant, and
+ * isSourcePresent. If the source is not present, ANY will be
+ * given as the source, and isSourcePresent will be NULL. Otherwise
+ * isSourcePresent will be non-NULL. The target may be empty if the
+ * id is not well-formed. The variant may be empty.
+ */
+void TransliteratorIDParser::IDtoSTV(const UnicodeString& id,
+ UnicodeString& source,
+ UnicodeString& target,
+ UnicodeString& variant,
+ UBool& isSourcePresent) {
+ source = ANY;
+ target.truncate(0);
+ variant.truncate(0);
+
+ int32_t sep = id.indexOf(TARGET_SEP);
+ int32_t var = id.indexOf(VARIANT_SEP);
+ if (var < 0) {
+ var = id.length();
+ }
+ isSourcePresent = FALSE;
+
+ if (sep < 0) {
+ // Form: T/V or T (or /V)
+ id.extractBetween(0, var, target);
+ id.extractBetween(var, id.length(), variant);
+ } else if (sep < var) {
+ // Form: S-T/V or S-T (or -T/V or -T)
+ if (sep > 0) {
+ id.extractBetween(0, sep, source);
+ isSourcePresent = TRUE;
+ }
+ id.extractBetween(++sep, var, target);
+ id.extractBetween(var, id.length(), variant);
+ } else {
+ // Form: (S/V-T or /V-T)
+ if (var > 0) {
+ id.extractBetween(0, var, source);
+ isSourcePresent = TRUE;
+ }
+ id.extractBetween(var, sep++, variant);
+ id.extractBetween(sep, id.length(), target);
+ }
+
+ if (variant.length() > 0) {
+ variant.remove(0, 1);
+ }
+}
+
+/**
+ * Given source, target, and variant strings, concatenate them into a
+ * full ID. If the source is empty, then "Any" will be used for the
+ * source, so the ID will always be of the form s-t/v or s-t.
+ */
+void TransliteratorIDParser::STVtoID(const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant,
+ UnicodeString& id) {
+ id = source;
+ if (id.length() == 0) {
+ id = ANY;
+ }
+ id.append(TARGET_SEP).append(target);
+ if (variant.length() != 0) {
+ id.append(VARIANT_SEP).append(variant);
+ }
+ // NUL-terminate the ID string for getTerminatedBuffer.
+ // This prevents valgrind and Purify warnings.
+ id.append((UChar)0);
+ id.truncate(id.length()-1);
+}
+
+/**
+ * Register two targets as being inverses of one another. For
+ * example, calling registerSpecialInverse("NFC", "NFD", TRUE) causes
+ * Transliterator to form the following inverse relationships:
+ *
+ * <pre>NFC => NFD
+ * Any-NFC => Any-NFD
+ * NFD => NFC
+ * Any-NFD => Any-NFC</pre>
+ *
+ * (Without the special inverse registration, the inverse of NFC
+ * would be NFC-Any.) Note that NFD is shorthand for Any-NFD, but
+ * that the presence or absence of "Any-" is preserved.
+ *
+ * <p>The relationship is symmetrical; registering (a, b) is
+ * equivalent to registering (b, a).
+ *
+ * <p>The relevant IDs must still be registered separately as
+ * factories or classes.
+ *
+ * <p>Only the targets are specified. Special inverses always
+ * have the form Any-Target1 <=> Any-Target2. The target should
+ * have canonical casing (the casing desired to be produced when
+ * an inverse is formed) and should contain no whitespace or other
+ * extraneous characters.
+ *
+ * @param target the target against which to register the inverse
+ * @param inverseTarget the inverse of target, that is
+ * Any-target.getInverse() => Any-inverseTarget
+ * @param bidirectional if TRUE, register the reverse relation
+ * as well, that is, Any-inverseTarget.getInverse() => Any-target
+ */
+void TransliteratorIDParser::registerSpecialInverse(const UnicodeString& target,
+ const UnicodeString& inverseTarget,
+ UBool bidirectional,
+ UErrorCode &status) {
+ init(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // If target == inverseTarget then force bidirectional => FALSE
+ if (bidirectional && 0==target.caseCompare(inverseTarget, U_FOLD_CASE_DEFAULT)) {
+ bidirectional = FALSE;
+ }
+
+ umtx_init(&LOCK);
+ Mutex lock(&LOCK);
+
+ SPECIAL_INVERSES->put(target, new UnicodeString(inverseTarget), status);
+ if (bidirectional) {
+ SPECIAL_INVERSES->put(inverseTarget, new UnicodeString(target), status);
+ }
+}
+
+//----------------------------------------------------------------
+// Private implementation
+//----------------------------------------------------------------
+
+/**
+ * Parse an ID into component pieces. Take IDs of the form T,
+ * T/V, S-T, S-T/V, or S/V-T. If the source is missing, return a
+ * source of ANY.
+ * @param id the id string, in any of several forms
+ * @param pos INPUT-OUTPUT parameter. On input, pos is the
+ * offset of the first character to parse in id. On output,
+ * pos is the offset after the last parsed character. If the
+ * parse failed, pos will be unchanged.
+ * @param allowFilter2 if TRUE, a UnicodeSet pattern is allowed
+ * at any location between specs or delimiters, and is returned
+ * as the fifth string in the array.
+ * @return a Specs object, or NULL if the parse failed. If
+ * neither source nor target was seen in the parsed id, then the
+ * parse fails. If allowFilter is TRUE, then the parsed filter
+ * pattern is returned in the Specs object, otherwise the returned
+ * filter reference is NULL. If the parse fails for any reason
+ * NULL is returned.
+ */
+TransliteratorIDParser::Specs*
+TransliteratorIDParser::parseFilterID(const UnicodeString& id, int32_t& pos,
+ UBool allowFilter) {
+ UnicodeString first;
+ UnicodeString source;
+ UnicodeString target;
+ UnicodeString variant;
+ UnicodeString filter;
+ UChar delimiter = 0;
+ int32_t specCount = 0;
+ int32_t start = pos;
+
+ // This loop parses one of the following things with each
+ // pass: a filter, a delimiter character (either '-' or '/'),
+ // or a spec (source, target, or variant).
+ for (;;) {
+ ICU_Utility::skipWhitespace(id, pos, TRUE);
+ if (pos == id.length()) {
+ break;
+ }
+
+ // Parse filters
+ if (allowFilter && filter.length() == 0 &&
+ UnicodeSet::resemblesPattern(id, pos)) {
+
+ ParsePosition ppos(pos);
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeSet set(id, ppos, USET_IGNORE_SPACE, NULL, ec);
+ if (U_FAILURE(ec)) {
+ pos = start;
+ return NULL;
+ }
+ id.extractBetween(pos, ppos.getIndex(), filter);
+ pos = ppos.getIndex();
+ continue;
+ }
+
+ if (delimiter == 0) {
+ UChar c = id.charAt(pos);
+ if ((c == TARGET_SEP && target.length() == 0) ||
+ (c == VARIANT_SEP && variant.length() == 0)) {
+ delimiter = c;
+ ++pos;
+ continue;
+ }
+ }
+
+ // We are about to try to parse a spec with no delimiter
+ // when we can no longer do so (we can only do so at the
+ // start); break.
+ if (delimiter == 0 && specCount > 0) {
+ break;
+ }
+
+ UnicodeString spec = ICU_Utility::parseUnicodeIdentifier(id, pos);
+ if (spec.length() == 0) {
+ // Note that if there was a trailing delimiter, we
+ // consume it. So Foo-, Foo/, Foo-Bar/, and Foo/Bar-
+ // are legal.
+ break;
+ }
+
+ switch (delimiter) {
+ case 0:
+ first = spec;
+ break;
+ case TARGET_SEP:
+ target = spec;
+ break;
+ case VARIANT_SEP:
+ variant = spec;
+ break;
+ }
+ ++specCount;
+ delimiter = 0;
+ }
+
+ // A spec with no prior character is either source or target,
+ // depending on whether an explicit "-target" was seen.
+ if (first.length() != 0) {
+ if (target.length() == 0) {
+ target = first;
+ } else {
+ source = first;
+ }
+ }
+
+ // Must have either source or target
+ if (source.length() == 0 && target.length() == 0) {
+ pos = start;
+ return NULL;
+ }
+
+ // Empty source or target defaults to ANY
+ UBool sawSource = TRUE;
+ if (source.length() == 0) {
+ source = ANY;
+ sawSource = FALSE;
+ }
+ if (target.length() == 0) {
+ target = ANY;
+ }
+
+ return new Specs(source, target, variant, sawSource, filter);
+}
+
+/**
+ * Givens a Spec object, convert it to a SingleID object. The
+ * Spec object is a more unprocessed parse result. The SingleID
+ * object contains information about canonical and basic IDs.
+ * @return a SingleID; never returns NULL. Returned object always
+ * has 'filter' field of NULL.
+ */
+TransliteratorIDParser::SingleID*
+TransliteratorIDParser::specsToID(const Specs* specs, int32_t dir) {
+ UnicodeString canonID;
+ UnicodeString basicID;
+ UnicodeString basicPrefix;
+ if (specs != NULL) {
+ UnicodeString buf;
+ if (dir == FORWARD) {
+ if (specs->sawSource) {
+ buf.append(specs->source).append(TARGET_SEP);
+ } else {
+ basicPrefix = specs->source;
+ basicPrefix.append(TARGET_SEP);
+ }
+ buf.append(specs->target);
+ } else {
+ buf.append(specs->target).append(TARGET_SEP).append(specs->source);
+ }
+ if (specs->variant.length() != 0) {
+ buf.append(VARIANT_SEP).append(specs->variant);
+ }
+ basicID = basicPrefix;
+ basicID.append(buf);
+ if (specs->filter.length() != 0) {
+ buf.insert(0, specs->filter);
+ }
+ canonID = buf;
+ }
+ return new SingleID(canonID, basicID);
+}
+
+/**
+ * Given a Specs object, return a SingleID representing the
+ * special inverse of that ID. If there is no special inverse
+ * then return NULL.
+ * @return a SingleID or NULL. Returned object always has
+ * 'filter' field of NULL.
+ */
+TransliteratorIDParser::SingleID*
+TransliteratorIDParser::specsToSpecialInverse(const Specs& specs, UErrorCode &status) {
+ if (0!=specs.source.caseCompare(ANY, U_FOLD_CASE_DEFAULT)) {
+ return NULL;
+ }
+ init(status);
+
+ UnicodeString* inverseTarget;
+
+ umtx_init(&LOCK);
+ umtx_lock(&LOCK);
+ inverseTarget = (UnicodeString*) SPECIAL_INVERSES->get(specs.target);
+ umtx_unlock(&LOCK);
+
+ if (inverseTarget != NULL) {
+ // If the original ID contained "Any-" then make the
+ // special inverse "Any-Foo"; otherwise make it "Foo".
+ // So "Any-NFC" => "Any-NFD" but "NFC" => "NFD".
+ UnicodeString buf;
+ if (specs.filter.length() != 0) {
+ buf.append(specs.filter);
+ }
+ if (specs.sawSource) {
+ buf.append(ANY).append(TARGET_SEP);
+ }
+ buf.append(*inverseTarget);
+
+ UnicodeString basicID(ANY);
+ basicID.append(TARGET_SEP).append(*inverseTarget);
+
+ if (specs.variant.length() != 0) {
+ buf.append(VARIANT_SEP).append(specs.variant);
+ basicID.append(VARIANT_SEP).append(specs.variant);
+ }
+ return new SingleID(buf, basicID);
+ }
+ return NULL;
+}
+
+/**
+ * Glue method to get around access problems in C++. This would
+ * ideally be inline but we want to avoid a circular header
+ * dependency.
+ */
+Transliterator* TransliteratorIDParser::createBasicInstance(const UnicodeString& id, const UnicodeString* canonID) {
+ return Transliterator::createBasicInstance(id, canonID);
+}
+
+/**
+ * Initialize static memory.
+ */
+void TransliteratorIDParser::init(UErrorCode &status) {
+ if (SPECIAL_INVERSES != NULL) {
+ return;
+ }
+
+ Hashtable* special_inverses = new Hashtable(TRUE, status);
+ special_inverses->setValueDeleter(uhash_deleteUnicodeString);
+
+ umtx_init(&LOCK);
+ umtx_lock(&LOCK);
+ if (SPECIAL_INVERSES == NULL) {
+ SPECIAL_INVERSES = special_inverses;
+ special_inverses = NULL;
+ }
+ umtx_unlock(&LOCK);
+ delete special_inverses; /*null instance*/
+
+ ucln_i18n_registerCleanup(UCLN_I18N_TRANSLITERATOR, transliterator_cleanup);
+}
+
+/**
+ * Free static memory.
+ */
+void TransliteratorIDParser::cleanup() {
+ if (SPECIAL_INVERSES) {
+ delete SPECIAL_INVERSES;
+ SPECIAL_INVERSES = NULL;
+ }
+ umtx_destroy(&LOCK);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/tridpars.h b/Build/source/libs/icu/icu-xetex/i18n/tridpars.h
new file mode 100644
index 00000000000..e86f104ffd7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/tridpars.h
@@ -0,0 +1,361 @@
+/*
+ **************************************************************************
+ * Copyright (c) 2002-2005, International Business Machines Corporation *
+ * and others. All Rights Reserved. *
+ **************************************************************************
+ * Date Name Description *
+ * 01/28/2002 aliu Creation. *
+ **************************************************************************
+ */
+#ifndef TRIDPARS_H
+#define TRIDPARS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_BEGIN
+
+class Transliterator;
+class UnicodeSet;
+class UVector;
+
+/**
+ * Parsing component for transliterator IDs. This class contains only
+ * static members; it cannot be instantiated. Methods in this class
+ * parse various ID formats, including the following:
+ *
+ * A basic ID, which contains source, target, and variant, but no
+ * filter and no explicit inverse. Examples include
+ * "Latin-Greek/UNGEGN" and "Null".
+ *
+ * A single ID, which is a basic ID plus optional filter and optional
+ * explicit inverse. Examples include "[a-zA-Z] Latin-Greek" and
+ * "Lower (Upper)".
+ *
+ * A compound ID, which is a sequence of one or more single IDs,
+ * separated by semicolons, with optional forward and reverse global
+ * filters. The global filters are UnicodeSet patterns prepended or
+ * appended to the IDs, separated by semicolons. An appended filter
+ * must be enclosed in parentheses and applies in the reverse
+ * direction.
+ *
+ * @author Alan Liu
+ */
+class TransliteratorIDParser /* not : public UObject because all methods are static */ {
+
+ public:
+
+ /**
+ * A structure containing the parsed data of a filtered ID, that
+ * is, a basic ID optionally with a filter.
+ *
+ * 'source' and 'target' will always be non-null. The 'variant'
+ * will be non-null only if a non-empty variant was parsed.
+ *
+ * 'sawSource' is true if there was an explicit source in the
+ * parsed id. If there was no explicit source, then an implied
+ * source of ANY is returned and 'sawSource' is set to false.
+ *
+ * 'filter' is the parsed filter pattern, or null if there was no
+ * filter.
+ */
+ class Specs : public UMemory {
+ public:
+ UnicodeString source; // not null
+ UnicodeString target; // not null
+ UnicodeString variant; // may be null
+ UnicodeString filter; // may be null
+ UBool sawSource;
+ Specs(const UnicodeString& s, const UnicodeString& t,
+ const UnicodeString& v, UBool sawS,
+ const UnicodeString& f);
+
+ private:
+
+ Specs(const Specs &other); // forbid copying of this class
+ Specs &operator=(const Specs &other); // forbid copying of this class
+ };
+
+ /**
+ * A structure containing the canonicalized data of a filtered ID,
+ * that is, a basic ID optionally with a filter.
+ *
+ * 'canonID' is always non-null. It may be the empty string "".
+ * It is the id that should be assigned to the created
+ * transliterator. It _cannot_ be instantiated directly.
+ *
+ * 'basicID' is always non-null and non-empty. It is always of
+ * the form S-T or S-T/V. It is designed to be fed to low-level
+ * instantiation code that only understands these two formats.
+ *
+ * 'filter' may be null, if there is none, or non-null and
+ * non-empty.
+ */
+ class SingleID : public UMemory {
+ public:
+ UnicodeString canonID;
+ UnicodeString basicID;
+ UnicodeString filter;
+ SingleID(const UnicodeString& c, const UnicodeString& b,
+ const UnicodeString& f);
+ SingleID(const UnicodeString& c, const UnicodeString& b);
+ Transliterator* createInstance();
+
+ private:
+
+ SingleID(const SingleID &other); // forbid copying of this class
+ SingleID &operator=(const SingleID &other); // forbid copying of this class
+ };
+
+ /**
+ * Parse a filter ID, that is, an ID of the general form
+ * "[f1] s1-t1/v1", with the filters optional, and the variants optional.
+ * @param id the id to be parsed
+ * @param pos INPUT-OUTPUT parameter. On input, the position of
+ * the first character to parse. On output, the position after
+ * the last character parsed.
+ * @return a SingleID object or null if the parse fails
+ */
+ static SingleID* parseFilterID(const UnicodeString& id, int32_t& pos);
+
+ /**
+ * Parse a single ID, that is, an ID of the general form
+ * "[f1] s1-t1/v1 ([f2] s2-t3/v2)", with the parenthesized element
+ * optional, the filters optional, and the variants optional.
+ * @param id the id to be parsed
+ * @param pos INPUT-OUTPUT parameter. On input, the position of
+ * the first character to parse. On output, the position after
+ * the last character parsed.
+ * @param dir the direction. If the direction is REVERSE then the
+ * SingleID is constructed for the reverse direction.
+ * @return a SingleID object or null
+ */
+ static SingleID* parseSingleID(const UnicodeString& id, int32_t& pos,
+ int32_t dir, UErrorCode& status);
+
+ /**
+ * Parse a global filter of the form "[f]" or "([f])", depending
+ * on 'withParens'.
+ * @param id the pattern the parse
+ * @param pos INPUT-OUTPUT parameter. On input, the position of
+ * the first character to parse. On output, the position after
+ * the last character parsed.
+ * @param dir the direction.
+ * @param withParens INPUT-OUTPUT parameter. On entry, if
+ * withParens[0] is 0, then parens are disallowed. If it is 1,
+ * then parens are requires. If it is -1, then parens are
+ * optional, and the return result will be set to 0 or 1.
+ * @param canonID OUTPUT parameter. The pattern for the filter
+ * added to the canonID, either at the end, if dir is FORWARD, or
+ * at the start, if dir is REVERSE. The pattern will be enclosed
+ * in parentheses if appropriate, and will be suffixed with an
+ * ID_DELIM character. May be null.
+ * @return a UnicodeSet object or null. A non-null results
+ * indicates a successful parse, regardless of whether the filter
+ * applies to the given direction. The caller should discard it
+ * if withParens != (dir == REVERSE).
+ */
+ static UnicodeSet* parseGlobalFilter(const UnicodeString& id, int32_t& pos,
+ int32_t dir,
+ int32_t& withParens,
+ UnicodeString* canonID);
+
+ /**
+ * Parse a compound ID, consisting of an optional forward global
+ * filter, a separator, one or more single IDs delimited by
+ * separators, an an optional reverse global filter. The
+ * separator is a semicolon. The global filters are UnicodeSet
+ * patterns. The reverse global filter must be enclosed in
+ * parentheses.
+ * @param id the pattern the parse
+ * @param dir the direction.
+ * @param canonID OUTPUT parameter that receives the canonical ID,
+ * consisting of canonical IDs for all elements, as returned by
+ * parseSingleID(), separated by semicolons. Previous contents
+ * are discarded.
+ * @param list OUTPUT parameter that receives a list of SingleID
+ * objects representing the parsed IDs. Previous contents are
+ * discarded.
+ * @param globalFilter OUTPUT parameter that receives a pointer to
+ * a newly created global filter for this ID in this direction, or
+ * null if there is none.
+ * @return true if the parse succeeds, that is, if the entire
+ * id is consumed without syntax error.
+ */
+ static UBool parseCompoundID(const UnicodeString& id, int32_t dir,
+ UnicodeString& canonID,
+ UVector& list,
+ UnicodeSet*& globalFilter);
+
+ /**
+ * Convert the elements of the 'list' vector, which are SingleID
+ * objects, into actual Transliterator objects. In the course of
+ * this, some (or all) entries may be removed. If all entries
+ * are removed, the Null transliterator will be added.
+ *
+ * Delete entries with empty basicIDs; these are generated by
+ * elements like "(A)" in the forward direction, or "A()" in
+ * the reverse. THIS MAY RESULT IN AN EMPTY VECTOR. Convert
+ * SingleID entries to actual transliterators.
+ *
+ * @param list vector of SingleID objects. On exit, vector
+ * of one or more Transliterators.
+ * @param ec Output param to receive a success or an error code.
+ * @return new value of insertIndex. The index will shift if
+ * there are empty items, like "(Lower)", with indices less than
+ * insertIndex.
+ */
+ static void instantiateList(UVector& list,
+ UErrorCode& ec);
+
+ /**
+ * Parse an ID into pieces. Take IDs of the form T, T/V, S-T,
+ * S-T/V, or S/V-T. If the source is missing, return a source of
+ * ANY.
+ * @param id the id string, in any of several forms
+ * @param source the given source.
+ * @param target the given target.
+ * @param variant the given variant
+ * @param isSourcePresent If TRUE then the source is present.
+ * If the source is not present, ANY will be
+ * given as the source, and isSourcePresent will be null
+ * @return an array of 4 strings: source, target, variant, and
+ * isSourcePresent. If the source is not present, ANY will be
+ * given as the source, and isSourcePresent will be null. Otherwise
+ * isSourcePresent will be non-null. The target may be empty if the
+ * id is not well-formed. The variant may be empty.
+ */
+ static void IDtoSTV(const UnicodeString& id,
+ UnicodeString& source,
+ UnicodeString& target,
+ UnicodeString& variant,
+ UBool& isSourcePresent);
+
+ /**
+ * Given source, target, and variant strings, concatenate them into a
+ * full ID. If the source is empty, then "Any" will be used for the
+ * source, so the ID will always be of the form s-t/v or s-t.
+ */
+ static void STVtoID(const UnicodeString& source,
+ const UnicodeString& target,
+ const UnicodeString& variant,
+ UnicodeString& id);
+
+ /**
+ * Register two targets as being inverses of one another. For
+ * example, calling registerSpecialInverse("NFC", "NFD", true) causes
+ * Transliterator to form the following inverse relationships:
+ *
+ * <pre>NFC => NFD
+ * Any-NFC => Any-NFD
+ * NFD => NFC
+ * Any-NFD => Any-NFC</pre>
+ *
+ * (Without the special inverse registration, the inverse of NFC
+ * would be NFC-Any.) Note that NFD is shorthand for Any-NFD, but
+ * that the presence or absence of "Any-" is preserved.
+ *
+ * <p>The relationship is symmetrical; registering (a, b) is
+ * equivalent to registering (b, a).
+ *
+ * <p>The relevant IDs must still be registered separately as
+ * factories or classes.
+ *
+ * <p>Only the targets are specified. Special inverses always
+ * have the form Any-Target1 <=> Any-Target2. The target should
+ * have canonical casing (the casing desired to be produced when
+ * an inverse is formed) and should contain no whitespace or other
+ * extraneous characters.
+ *
+ * @param target the target against which to register the inverse
+ * @param inverseTarget the inverse of target, that is
+ * Any-target.getInverse() => Any-inverseTarget
+ * @param bidirectional if true, register the reverse relation
+ * as well, that is, Any-inverseTarget.getInverse() => Any-target
+ */
+ static void registerSpecialInverse(const UnicodeString& target,
+ const UnicodeString& inverseTarget,
+ UBool bidirectional,
+ UErrorCode &status);
+
+ /**
+ * Free static memory.
+ */
+ static void cleanup();
+
+ private:
+ //----------------------------------------------------------------
+ // Private implementation
+ //----------------------------------------------------------------
+
+ // forbid instantiation
+ TransliteratorIDParser();
+
+ /**
+ * Parse an ID into component pieces. Take IDs of the form T,
+ * T/V, S-T, S-T/V, or S/V-T. If the source is missing, return a
+ * source of ANY.
+ * @param id the id string, in any of several forms
+ * @param pos INPUT-OUTPUT parameter. On input, pos[0] is the
+ * offset of the first character to parse in id. On output,
+ * pos[0] is the offset after the last parsed character. If the
+ * parse failed, pos[0] will be unchanged.
+ * @param allowFilter if true, a UnicodeSet pattern is allowed
+ * at any location between specs or delimiters, and is returned
+ * as the fifth string in the array.
+ * @return a Specs object, or null if the parse failed. If
+ * neither source nor target was seen in the parsed id, then the
+ * parse fails. If allowFilter is true, then the parsed filter
+ * pattern is returned in the Specs object, otherwise the returned
+ * filter reference is null. If the parse fails for any reason
+ * null is returned.
+ */
+ static Specs* parseFilterID(const UnicodeString& id, int32_t& pos,
+ UBool allowFilter);
+
+ /**
+ * Givens a Specs object, convert it to a SingleID object. The
+ * Spec object is a more unprocessed parse result. The SingleID
+ * object contains information about canonical and basic IDs.
+ * @param specs the given Specs object.
+ * @param dir either FORWARD or REVERSE.
+ * @return a SingleID; never returns null. Returned object always
+ * has 'filter' field of null.
+ */
+ static SingleID* specsToID(const Specs* specs, int32_t dir);
+
+ /**
+ * Given a Specs object, return a SingleID representing the
+ * special inverse of that ID. If there is no special inverse
+ * then return null.
+ * @param specs the given Specs.
+ * @return a SingleID or null. Returned object always has
+ * 'filter' field of null.
+ */
+ static SingleID* specsToSpecialInverse(const Specs& specs, UErrorCode &status);
+
+ /**
+ * Glue method to get around access problems in C++.
+ * @param id the id string for the transliterator, in any of several forms
+ * @param canonID the given canonical ID
+ */
+ static Transliterator* createBasicInstance(const UnicodeString& id,
+ const UnicodeString* canonID);
+
+ /**
+ * Initialize static memory.
+ */
+ static void init(UErrorCode &status);
+
+ friend class SingleID;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/tzrule.cpp b/Build/source/libs/icu/icu-xetex/i18n/tzrule.cpp
new file mode 100644
index 00000000000..1326149053e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/tzrule.cpp
@@ -0,0 +1,629 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/tzrule.h"
+#include "unicode/ucal.h"
+#include "gregoimp.h"
+#include "cmemory.h"
+#include "uarrsort.h"
+
+U_CDECL_BEGIN
+// UComparator function for sorting start times
+static int32_t U_CALLCONV
+compareDates(const void * /*context*/, const void *left, const void *right) {
+ UDate l = *((UDate*)left);
+ UDate r = *((UDate*)right);
+ int32_t res = l < r ? -1 : (l == r ? 0 : 1);
+ return res;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+TimeZoneRule::TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings)
+: UObject(), fName(name), fRawOffset(rawOffset), fDSTSavings(dstSavings) {
+}
+
+TimeZoneRule::TimeZoneRule(const TimeZoneRule& source)
+: UObject(source), fName(source.fName), fRawOffset(source.fRawOffset), fDSTSavings(source.fDSTSavings) {
+}
+
+TimeZoneRule::~TimeZoneRule() {
+}
+
+TimeZoneRule&
+TimeZoneRule::operator=(const TimeZoneRule& right) {
+ if (this != &right) {
+ fName = right.fName;
+ fRawOffset = right.fRawOffset;
+ fDSTSavings = right.fDSTSavings;
+ }
+ return *this;
+}
+
+UBool
+TimeZoneRule::operator==(const TimeZoneRule& that) const {
+ return ((this == &that) ||
+ (getDynamicClassID() == that.getDynamicClassID() &&
+ fName == that.fName &&
+ fRawOffset == that.fRawOffset &&
+ fDSTSavings == that.fDSTSavings));
+}
+
+UBool
+TimeZoneRule::operator!=(const TimeZoneRule& that) const {
+ return !operator==(that);
+}
+
+UnicodeString&
+TimeZoneRule::getName(UnicodeString& name) const {
+ name = fName;
+ return name;
+}
+
+int32_t
+TimeZoneRule::getRawOffset(void) const {
+ return fRawOffset;
+}
+
+int32_t
+TimeZoneRule::getDSTSavings(void) const {
+ return fDSTSavings;
+}
+
+UBool
+TimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
+ return ((this == &other) ||
+ (getDynamicClassID() == other.getDynamicClassID() &&
+ fRawOffset == other.fRawOffset &&
+ fDSTSavings == other.fDSTSavings));
+}
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(InitialTimeZoneRule)
+
+InitialTimeZoneRule::InitialTimeZoneRule(const UnicodeString& name,
+ int32_t rawOffset,
+ int32_t dstSavings)
+: TimeZoneRule(name, rawOffset, dstSavings) {
+}
+
+InitialTimeZoneRule::InitialTimeZoneRule(const InitialTimeZoneRule& source)
+: TimeZoneRule(source) {
+}
+
+InitialTimeZoneRule::~InitialTimeZoneRule() {
+}
+
+InitialTimeZoneRule*
+InitialTimeZoneRule::clone(void) const {
+ return new InitialTimeZoneRule(*this);
+}
+
+InitialTimeZoneRule&
+InitialTimeZoneRule::operator=(const InitialTimeZoneRule& right) {
+ if (this != &right) {
+ TimeZoneRule::operator=(right);
+ }
+ return *this;
+}
+
+UBool
+InitialTimeZoneRule::operator==(const TimeZoneRule& that) const {
+ return ((this == &that) ||
+ (getDynamicClassID() == that.getDynamicClassID() &&
+ TimeZoneRule::operator==(that)));
+}
+
+UBool
+InitialTimeZoneRule::operator!=(const TimeZoneRule& that) const {
+ return !operator==(that);
+}
+
+UBool
+InitialTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ if (getDynamicClassID() != other.getDynamicClassID() ||
+ TimeZoneRule::isEquivalentTo(other) == FALSE) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+UBool
+InitialTimeZoneRule::getFirstStart(int32_t /*prevRawOffset*/,
+ int32_t /*prevDSTSavings*/,
+ UDate& /*result*/) const {
+ return FALSE;
+}
+
+UBool
+InitialTimeZoneRule::getFinalStart(int32_t /*prevRawOffset*/,
+ int32_t /*prevDSTSavings*/,
+ UDate& /*result*/) const {
+ return FALSE;
+}
+
+UBool
+InitialTimeZoneRule::getNextStart(const UDate /*base*/,
+ int32_t /*prevRawOffset*/,
+ int32_t /*prevDSTSavings*/,
+ UBool /*inclusive*/,
+ UDate& /*result*/) const {
+ return FALSE;
+}
+
+UBool
+InitialTimeZoneRule::getPreviousStart(const UDate /*base*/,
+ int32_t /*prevRawOffset*/,
+ int32_t /*prevDSTSavings*/,
+ UBool /*inclusive*/,
+ UDate& /*result*/) const {
+ return FALSE;
+}
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AnnualTimeZoneRule)
+
+const int32_t AnnualTimeZoneRule::MAX_YEAR = 0x7FFFFFFF; /* max signed int32 */
+
+AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
+ int32_t rawOffset,
+ int32_t dstSavings,
+ const DateTimeRule& dateTimeRule,
+ int32_t startYear,
+ int32_t endYear)
+: TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(new DateTimeRule(dateTimeRule)),
+ fStartYear(startYear), fEndYear(endYear) {
+}
+
+AnnualTimeZoneRule::AnnualTimeZoneRule(const UnicodeString& name,
+ int32_t rawOffset,
+ int32_t dstSavings,
+ DateTimeRule* dateTimeRule,
+ int32_t startYear,
+ int32_t endYear)
+: TimeZoneRule(name, rawOffset, dstSavings), fDateTimeRule(dateTimeRule),
+ fStartYear(startYear), fEndYear(endYear) {
+}
+
+AnnualTimeZoneRule::AnnualTimeZoneRule(const AnnualTimeZoneRule& source)
+: TimeZoneRule(source), fDateTimeRule(new DateTimeRule(*(source.fDateTimeRule))),
+ fStartYear(source.fStartYear), fEndYear(source.fEndYear) {
+}
+
+AnnualTimeZoneRule::~AnnualTimeZoneRule() {
+ delete fDateTimeRule;
+}
+
+AnnualTimeZoneRule*
+AnnualTimeZoneRule::clone(void) const {
+ return new AnnualTimeZoneRule(*this);
+}
+
+AnnualTimeZoneRule&
+AnnualTimeZoneRule::operator=(const AnnualTimeZoneRule& right) {
+ if (this != &right) {
+ TimeZoneRule::operator=(right);
+ delete fDateTimeRule;
+ fDateTimeRule = right.fDateTimeRule->clone();
+ fStartYear = right.fStartYear;
+ fEndYear = right.fEndYear;
+ }
+ return *this;
+}
+
+UBool
+AnnualTimeZoneRule::operator==(const TimeZoneRule& that) const {
+ if (this == &that) {
+ return TRUE;
+ }
+ if (getDynamicClassID() != that.getDynamicClassID()) {
+ return FALSE;
+ }
+ AnnualTimeZoneRule *atzr = (AnnualTimeZoneRule*)&that;
+ return (*fDateTimeRule == *(atzr->fDateTimeRule) &&
+ fStartYear == atzr->fStartYear &&
+ fEndYear == atzr->fEndYear);
+}
+
+UBool
+AnnualTimeZoneRule::operator!=(const TimeZoneRule& that) const {
+ return !operator==(that);
+}
+
+const DateTimeRule*
+AnnualTimeZoneRule::getRule() const {
+ return fDateTimeRule;
+}
+
+int32_t
+AnnualTimeZoneRule::getStartYear() const {
+ return fStartYear;
+}
+
+int32_t
+AnnualTimeZoneRule::getEndYear() const {
+ return fEndYear;
+}
+
+UBool
+AnnualTimeZoneRule::getStartInYear(int32_t year,
+ int32_t prevRawOffset,
+ int32_t prevDSTSavings,
+ UDate &result) const {
+ if (year < fStartYear || year > fEndYear) {
+ return FALSE;
+ }
+ double ruleDay;
+ DateTimeRule::DateRuleType type = fDateTimeRule->getDateRuleType();
+ if (type == DateTimeRule::DOM) {
+ ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), fDateTimeRule->getRuleDayOfMonth());
+ } else {
+ UBool after = TRUE;
+ if (type == DateTimeRule::DOW) {
+ // Normalize DOW rule into DOW_GEQ_DOM or DOW_LEQ_DOM
+ int32_t weeks = fDateTimeRule->getRuleWeekInMonth();
+ if (weeks > 0) {
+ ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(), 1);
+ ruleDay += 7 * (weeks - 1);
+ } else {
+ after = FALSE;
+ ruleDay = Grego::fieldsToDay(year, fDateTimeRule->getRuleMonth(),
+ Grego::monthLength(year, fDateTimeRule->getRuleMonth()));
+ ruleDay += 7 * (weeks + 1);
+ }
+ } else {
+ int32_t month = fDateTimeRule->getRuleMonth();
+ int32_t dom = fDateTimeRule->getRuleDayOfMonth();
+ if (type == DateTimeRule::DOW_LEQ_DOM) {
+ after = FALSE;
+ // Handle Feb <=29
+ if (month == UCAL_FEBRUARY && dom == 29 && !Grego::isLeapYear(year)) {
+ dom--;
+ }
+ }
+ ruleDay = Grego::fieldsToDay(year, month, dom);
+ }
+ int32_t dow = Grego::dayOfWeek(ruleDay);
+ int32_t delta = fDateTimeRule->getRuleDayOfWeek() - dow;
+ if (after) {
+ delta = delta < 0 ? delta + 7 : delta;
+ } else {
+ delta = delta > 0 ? delta - 7 : delta;
+ }
+ ruleDay += delta;
+ }
+
+ result = ruleDay*U_MILLIS_PER_DAY + fDateTimeRule->getRuleMillisInDay();
+ if (fDateTimeRule->getTimeRuleType() != DateTimeRule::UTC_TIME) {
+ result -= prevRawOffset;
+ }
+ if (fDateTimeRule->getTimeRuleType() == DateTimeRule::WALL_TIME) {
+ result -= prevDSTSavings;
+ }
+ return TRUE;
+}
+
+UBool
+AnnualTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ if (getDynamicClassID() != other.getDynamicClassID() ||
+ TimeZoneRule::isEquivalentTo(other) == FALSE) {
+ return FALSE;
+ }
+ AnnualTimeZoneRule* that = (AnnualTimeZoneRule*)&other;
+ return (*fDateTimeRule == *(that->fDateTimeRule) &&
+ fStartYear == that->fStartYear &&
+ fEndYear == that->fEndYear);
+}
+
+UBool
+AnnualTimeZoneRule::getFirstStart(int32_t prevRawOffset,
+ int32_t prevDSTSavings,
+ UDate& result) const {
+ return getStartInYear(fStartYear, prevRawOffset, prevDSTSavings, result);
+}
+
+UBool
+AnnualTimeZoneRule::getFinalStart(int32_t prevRawOffset,
+ int32_t prevDSTSavings,
+ UDate& result) const {
+ if (fEndYear == MAX_YEAR) {
+ return FALSE;
+ }
+ return getStartInYear(fEndYear, prevRawOffset, prevDSTSavings, result);
+}
+
+UBool
+AnnualTimeZoneRule::getNextStart(const UDate base,
+ int32_t prevRawOffset,
+ int32_t prevDSTSavings,
+ UBool inclusive,
+ UDate& result) const {
+ int32_t year, month, dom, dow, doy, mid;
+ Grego::timeToFields(base, year, month, dom, dow, doy, mid);
+ if (year < fStartYear) {
+ return getFirstStart(prevRawOffset, prevDSTSavings, result);
+ }
+ UDate tmp;
+ if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
+ if (tmp < base || (!inclusive && (tmp == base))) {
+ // Return the next one
+ return getStartInYear(year + 1, prevRawOffset, prevDSTSavings, result);
+ } else {
+ result = tmp;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+UBool
+AnnualTimeZoneRule::getPreviousStart(const UDate base,
+ int32_t prevRawOffset,
+ int32_t prevDSTSavings,
+ UBool inclusive,
+ UDate& result) const {
+ int32_t year, month, dom, dow, doy, mid;
+ Grego::timeToFields(base, year, month, dom, dow, doy, mid);
+ if (year > fEndYear) {
+ return getFinalStart(prevRawOffset, prevDSTSavings, result);
+ }
+ UDate tmp;
+ if (getStartInYear(year, prevRawOffset, prevDSTSavings, tmp)) {
+ if (tmp > base || (!inclusive && (tmp == base))) {
+ // Return the previous one
+ return getStartInYear(year - 1, prevRawOffset, prevDSTSavings, result);
+ } else {
+ result = tmp;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeArrayTimeZoneRule)
+
+TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const UnicodeString& name,
+ int32_t rawOffset,
+ int32_t dstSavings,
+ const UDate* startTimes,
+ int32_t numStartTimes,
+ DateTimeRule::TimeRuleType timeRuleType)
+: TimeZoneRule(name, rawOffset, dstSavings), fTimeRuleType(timeRuleType),
+ fStartTimes(NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ initStartTimes(startTimes, numStartTimes, status);
+ //TODO - status?
+}
+
+
+TimeArrayTimeZoneRule::TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source)
+: TimeZoneRule(source), fTimeRuleType(source.fTimeRuleType), fStartTimes(NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ initStartTimes(source.fStartTimes, source.fNumStartTimes, status);
+ //TODO - status?
+}
+
+
+TimeArrayTimeZoneRule::~TimeArrayTimeZoneRule() {
+ if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
+ uprv_free(fStartTimes);
+ }
+}
+
+TimeArrayTimeZoneRule*
+TimeArrayTimeZoneRule::clone(void) const {
+ return new TimeArrayTimeZoneRule(*this);
+}
+
+
+TimeArrayTimeZoneRule&
+TimeArrayTimeZoneRule::operator=(const TimeArrayTimeZoneRule& right) {
+ if (this != &right) {
+ TimeZoneRule::operator=(right);
+ UErrorCode status = U_ZERO_ERROR;
+ initStartTimes(right.fStartTimes, right.fNumStartTimes, status);
+ //TODO - status?
+ fTimeRuleType = right.fTimeRuleType;
+ }
+ return *this;
+}
+
+UBool
+TimeArrayTimeZoneRule::operator==(const TimeZoneRule& that) const {
+ if (this == &that) {
+ return TRUE;
+ }
+ if (getDynamicClassID() != that.getDynamicClassID()
+ || TimeZoneRule::operator==(that) == FALSE) {
+ return FALSE;
+ }
+ TimeArrayTimeZoneRule *tatzr = (TimeArrayTimeZoneRule*)&that;
+ if (fTimeRuleType != tatzr->fTimeRuleType ||
+ fNumStartTimes != tatzr->fNumStartTimes) {
+ return FALSE;
+ }
+ // Compare start times
+ UBool res = TRUE;
+ for (int32_t i = 0; i < fNumStartTimes; i++) {
+ if (fStartTimes[i] != tatzr->fStartTimes[i]) {
+ res = FALSE;
+ break;
+ }
+ }
+ return res;
+}
+
+UBool
+TimeArrayTimeZoneRule::operator!=(const TimeZoneRule& that) const {
+ return !operator==(that);
+}
+
+DateTimeRule::TimeRuleType
+TimeArrayTimeZoneRule::getTimeType(void) const {
+ return fTimeRuleType;
+}
+
+UBool
+TimeArrayTimeZoneRule::getStartTimeAt(int32_t index, UDate& result) const {
+ if (index >= fNumStartTimes || index < 0) {
+ return FALSE;
+ }
+ result = fStartTimes[index];
+ return TRUE;
+}
+
+int32_t
+TimeArrayTimeZoneRule::countStartTimes(void) const {
+ return fNumStartTimes;
+}
+
+UBool
+TimeArrayTimeZoneRule::isEquivalentTo(const TimeZoneRule& other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ if (getDynamicClassID() != other.getDynamicClassID()
+ || TimeZoneRule::isEquivalentTo(other) == FALSE) {
+ return FALSE;
+ }
+ TimeArrayTimeZoneRule* that = (TimeArrayTimeZoneRule*)&other;
+ if (fTimeRuleType != that->fTimeRuleType ||
+ fNumStartTimes != that->fNumStartTimes) {
+ return FALSE;
+ }
+ // Compare start times
+ UBool res = TRUE;
+ for (int32_t i = 0; i < fNumStartTimes; i++) {
+ if (fStartTimes[i] != that->fStartTimes[i]) {
+ res = FALSE;
+ break;
+ }
+ }
+ return res;
+}
+
+UBool
+TimeArrayTimeZoneRule::getFirstStart(int32_t prevRawOffset,
+ int32_t prevDSTSavings,
+ UDate& result) const {
+ if (fNumStartTimes <= 0 || fStartTimes == NULL) {
+ return FALSE;
+ }
+ result = getUTC(fStartTimes[0], prevRawOffset, prevDSTSavings);
+ return TRUE;
+}
+
+UBool
+TimeArrayTimeZoneRule::getFinalStart(int32_t prevRawOffset,
+ int32_t prevDSTSavings,
+ UDate& result) const {
+ if (fNumStartTimes <= 0 || fStartTimes == NULL) {
+ return FALSE;
+ }
+ result = getUTC(fStartTimes[fNumStartTimes - 1], prevRawOffset, prevDSTSavings);
+ return TRUE;
+}
+
+UBool
+TimeArrayTimeZoneRule::getNextStart(const UDate base,
+ int32_t prevRawOffset,
+ int32_t prevDSTSavings,
+ UBool inclusive,
+ UDate& result) const {
+ int32_t i = fNumStartTimes - 1;
+ for (; i >= 0; i--) {
+ UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
+ if (time < base || (!inclusive && time == base)) {
+ break;
+ }
+ result = time;
+ }
+ if (i == fNumStartTimes - 1) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+UBool
+TimeArrayTimeZoneRule::getPreviousStart(const UDate base,
+ int32_t prevRawOffset,
+ int32_t prevDSTSavings,
+ UBool inclusive,
+ UDate& result) const {
+ int32_t i = fNumStartTimes - 1;
+ for (; i >= 0; i--) {
+ UDate time = getUTC(fStartTimes[i], prevRawOffset, prevDSTSavings);
+ if (time < base || (inclusive && time == base)) {
+ result = time;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+// ---- private methods ------
+
+UBool
+TimeArrayTimeZoneRule::initStartTimes(const UDate source[], int32_t size, UErrorCode& status) {
+ // Free old array
+ if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
+ uprv_free(fStartTimes);
+ }
+ // Allocate new one if needed
+ if (size > TIMEARRAY_STACK_BUFFER_SIZE) {
+ fStartTimes = (UDate*)uprv_malloc(sizeof(UDate)*size);
+ if (fStartTimes == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ fNumStartTimes = 0;
+ return FALSE;
+ }
+ } else {
+ fStartTimes = (UDate*)fLocalStartTimes;
+ }
+ uprv_memcpy(fStartTimes, source, sizeof(UDate)*size);
+ fNumStartTimes = size;
+ // Sort dates
+ uprv_sortArray(fStartTimes, fNumStartTimes, (int32_t)sizeof(UDate), compareDates, NULL, TRUE, &status);
+ if (U_FAILURE(status)) {
+ if (fStartTimes != NULL && fStartTimes != fLocalStartTimes) {
+ uprv_free(fStartTimes);
+ }
+ fNumStartTimes = 0;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+UDate
+TimeArrayTimeZoneRule::getUTC(UDate time, int32_t raw, int32_t dst) const {
+ if (fTimeRuleType != DateTimeRule::UTC_TIME) {
+ time -= raw;
+ }
+ if (fTimeRuleType == DateTimeRule::WALL_TIME) {
+ time -= dst;
+ }
+ return time;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/tztrans.cpp b/Build/source/libs/icu/icu-xetex/i18n/tztrans.cpp
new file mode 100644
index 00000000000..32e6ff7ffb9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/tztrans.cpp
@@ -0,0 +1,144 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/tzrule.h"
+#include "unicode/tztrans.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeZoneTransition)
+
+TimeZoneTransition::TimeZoneTransition(UDate time, const TimeZoneRule& from, const TimeZoneRule& to)
+: UObject(), fTime(time), fFrom(from.clone()), fTo(to.clone()) {
+}
+
+TimeZoneTransition::TimeZoneTransition()
+: UObject(), fTime(0), fFrom(NULL), fTo(NULL) {
+}
+
+TimeZoneTransition::TimeZoneTransition(const TimeZoneTransition& source)
+: UObject(), fTime(source.fTime), fFrom(NULL), fTo(NULL) {
+ if (source.fFrom != NULL) {
+ fFrom = source.fFrom->clone();
+ }
+
+ if (source.fTo != NULL) {
+ fTo = source.fTo->clone();
+ }
+}
+
+TimeZoneTransition::~TimeZoneTransition() {
+ if (fFrom != NULL) {
+ delete fFrom;
+ }
+ if (fTo != NULL) {
+ delete fTo;
+ }
+}
+
+TimeZoneTransition*
+TimeZoneTransition::clone(void) const {
+ return new TimeZoneTransition(*this);
+}
+
+TimeZoneTransition&
+TimeZoneTransition::operator=(const TimeZoneTransition& right) {
+ if (this != &right) {
+ fTime = right.fTime;
+ setFrom(*right.fFrom);
+ setTo(*right.fTo);
+ }
+ return *this;
+}
+
+UBool
+TimeZoneTransition::operator==(const TimeZoneTransition& that) const {
+ if (this == &that) {
+ return TRUE;
+ }
+ if (getDynamicClassID() != that.getDynamicClassID()) {
+ return FALSE;
+ }
+ if (fTime != that.fTime) {
+ return FALSE;
+ }
+ if (fFrom == NULL && that.fFrom == NULL
+ || fFrom != NULL && that.fFrom != NULL && *fFrom == *(that.fFrom)) {
+ if (fTo == NULL && that.fTo == NULL
+ || fTo != NULL && that.fTo != NULL && *fTo == *(that.fTo)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+UBool
+TimeZoneTransition::operator!=(const TimeZoneTransition& that) const {
+ return !operator==(that);
+}
+
+void
+TimeZoneTransition::setTime(UDate time) {
+ fTime = time;
+}
+
+void
+TimeZoneTransition::setFrom(const TimeZoneRule& from) {
+ if (fFrom != NULL) {
+ delete fFrom;
+ }
+ fFrom = from.clone();
+}
+
+void
+TimeZoneTransition::adoptFrom(TimeZoneRule* from) {
+ if (fFrom != NULL) {
+ delete fFrom;
+ }
+ fFrom = from;
+}
+
+void
+TimeZoneTransition::setTo(const TimeZoneRule& to) {
+ if (fTo != NULL) {
+ delete fTo;
+ }
+ fTo = to.clone();
+}
+
+void
+TimeZoneTransition::adoptTo(TimeZoneRule* to) {
+ if (fTo != NULL) {
+ delete fTo;
+ }
+ fTo = to;
+}
+
+UDate
+TimeZoneTransition::getTime(void) const {
+ return fTime;
+}
+
+const TimeZoneRule*
+TimeZoneTransition::getTo(void) const {
+ return fTo;
+}
+
+const TimeZoneRule*
+TimeZoneTransition::getFrom(void) const {
+ return fFrom;
+}
+
+U_NAMESPACE_END
+
+#endif
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucal.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucal.cpp
new file mode 100644
index 00000000000..ce9ec5252a8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucal.cpp
@@ -0,0 +1,472 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ucal.h"
+#include "unicode/uloc.h"
+#include "unicode/calendar.h"
+#include "unicode/timezone.h"
+#include "unicode/gregocal.h"
+#include "unicode/simpletz.h"
+#include "unicode/ustring.h"
+#include "unicode/strenum.h"
+#include "cmemory.h"
+#include "ustrenum.h"
+
+U_NAMESPACE_USE
+
+static TimeZone*
+_createTimeZone(const UChar* zoneID, int32_t len, UErrorCode* ec) {
+ TimeZone* zone = NULL;
+ if (ec!=NULL && U_SUCCESS(*ec)) {
+ // Note that if zoneID is invalid, we get back GMT. This odd
+ // behavior is by design and goes back to the JDK. The only
+ // failure we will see is a memory allocation failure.
+ int32_t l = (len<0 ? u_strlen(zoneID) : len);
+ UnicodeString zoneStrID;
+ zoneStrID.setTo((UBool)(len < 0), zoneID, l); /* temporary read-only alias */
+ zone = TimeZone::createTimeZone(zoneStrID);
+ if (zone == NULL) {
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ return zone;
+}
+
+U_CAPI UEnumeration* U_EXPORT2
+ucal_openTimeZones(UErrorCode* ec) {
+ return uenum_openStringEnumeration(TimeZone::createEnumeration(), ec);
+}
+
+U_CAPI UEnumeration* U_EXPORT2
+ucal_openCountryTimeZones(const char* country, UErrorCode* ec) {
+ return uenum_openStringEnumeration(TimeZone::createEnumeration(country), ec);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec) {
+ int32_t len = 0;
+ if (ec!=NULL && U_SUCCESS(*ec)) {
+ TimeZone* zone = TimeZone::createDefault();
+ if (zone == NULL) {
+ *ec = U_MEMORY_ALLOCATION_ERROR;
+ } else {
+ UnicodeString id;
+ zone->getID(id);
+ delete zone;
+ len = id.extract(result, resultCapacity, *ec);
+ }
+ }
+ return len;
+}
+
+U_CAPI void U_EXPORT2
+ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec) {
+ TimeZone* zone = _createTimeZone(zoneID, -1, ec);
+ if (zone != NULL) {
+ TimeZone::adoptDefault(zone);
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec) {
+ int32_t result = 0;
+ TimeZone* zone = _createTimeZone(zoneID, -1, ec);
+ if (U_SUCCESS(*ec)) {
+ if (zone->getDynamicClassID() == SimpleTimeZone::getStaticClassID()) {
+ result = ((SimpleTimeZone*) zone)->getDSTSavings();
+ } else {
+ // Since there is no getDSTSavings on TimeZone, we use a
+ // heuristic: Starting with the current time, march
+ // forwards for one year, looking for DST savings.
+ // Stepping by weeks is sufficient.
+ UDate d = Calendar::getNow();
+ for (int32_t i=0; i<53; ++i, d+=U_MILLIS_PER_DAY*7.0) {
+ int32_t raw, dst;
+ zone->getOffset(d, FALSE, raw, dst, *ec);
+ if (U_FAILURE(*ec)) {
+ break;
+ } else if (dst != 0) {
+ result = dst;
+ break;
+ }
+ }
+ }
+ }
+ delete zone;
+ return result;
+}
+
+U_CAPI UDate U_EXPORT2
+ucal_getNow()
+{
+
+ return Calendar::getNow();
+}
+
+// ignore type until we add more subclasses
+U_CAPI UCalendar* U_EXPORT2
+ucal_open( const UChar* zoneID,
+ int32_t len,
+ const char* locale,
+ UCalendarType /*type*/,
+ UErrorCode* status)
+{
+
+ if(U_FAILURE(*status)) return 0;
+
+ TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
+ : _createTimeZone(zoneID, len, status);
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ return (UCalendar*)Calendar::createInstance(zone, Locale(locale), *status);
+}
+
+U_CAPI void U_EXPORT2
+ucal_close(UCalendar *cal)
+{
+
+ delete (Calendar*) cal;
+}
+
+U_CAPI void U_EXPORT2
+ucal_setTimeZone( UCalendar* cal,
+ const UChar* zoneID,
+ int32_t len,
+ UErrorCode *status)
+{
+
+ if(U_FAILURE(*status))
+ return;
+
+ TimeZone* zone = (zoneID==NULL) ? TimeZone::createDefault()
+ : _createTimeZone(zoneID, len, status);
+
+ if (zone != NULL) {
+ ((Calendar*)cal)->adoptTimeZone(zone);
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getTimeZoneDisplayName(const UCalendar* cal,
+ UCalendarDisplayNameType type,
+ const char *locale,
+ UChar* result,
+ int32_t resultLength,
+ UErrorCode* status)
+{
+
+ if(U_FAILURE(*status)) return -1;
+
+ const TimeZone& tz = ((Calendar*)cal)->getTimeZone();
+ UnicodeString id;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ id.setTo(result, 0, resultLength);
+ }
+
+ switch(type) {
+ case UCAL_STANDARD:
+ tz.getDisplayName(FALSE, TimeZone::LONG, Locale(locale), id);
+ break;
+
+ case UCAL_SHORT_STANDARD:
+ tz.getDisplayName(FALSE, TimeZone::SHORT, Locale(locale), id);
+ break;
+
+ case UCAL_DST:
+ tz.getDisplayName(TRUE, TimeZone::LONG, Locale(locale), id);
+ break;
+
+ case UCAL_SHORT_DST:
+ tz.getDisplayName(TRUE, TimeZone::SHORT, Locale(locale), id);
+ break;
+ }
+
+ return id.extract(result, resultLength, *status);
+}
+
+U_CAPI UBool U_EXPORT2
+ucal_inDaylightTime( const UCalendar* cal,
+ UErrorCode* status )
+{
+
+ if(U_FAILURE(*status)) return (UBool) -1;
+ return ((Calendar*)cal)->inDaylightTime(*status);
+}
+
+U_CAPI void U_EXPORT2
+ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode) {
+ if(U_FAILURE(*pErrorCode)) {
+ return;
+ }
+ Calendar *cpp_cal = (Calendar *)cal;
+ if(cpp_cal->getDynamicClassID() != GregorianCalendar::getStaticClassID()) {
+ *pErrorCode = U_UNSUPPORTED_ERROR;
+ return;
+ }
+ ((GregorianCalendar *)cpp_cal)->setGregorianChange(date, *pErrorCode);
+}
+
+U_CAPI UDate U_EXPORT2
+ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode) {
+ if(U_FAILURE(*pErrorCode)) {
+ return (UDate)0;
+ }
+ Calendar *cpp_cal = (Calendar *)cal;
+ if(cpp_cal->getDynamicClassID() != GregorianCalendar::getStaticClassID()) {
+ *pErrorCode = U_UNSUPPORTED_ERROR;
+ return (UDate)0;
+ }
+ return ((GregorianCalendar *)cpp_cal)->getGregorianChange();
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getAttribute( const UCalendar* cal,
+ UCalendarAttribute attr)
+{
+
+ switch(attr) {
+ case UCAL_LENIENT:
+ return ((Calendar*)cal)->isLenient();
+
+ case UCAL_FIRST_DAY_OF_WEEK:
+ return ((Calendar*)cal)->getFirstDayOfWeek();
+
+ case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
+ return ((Calendar*)cal)->getMinimalDaysInFirstWeek();
+
+ default:
+ break;
+ }
+ return -1;
+}
+
+U_CAPI void U_EXPORT2
+ucal_setAttribute( UCalendar* cal,
+ UCalendarAttribute attr,
+ int32_t newValue)
+{
+
+ switch(attr) {
+ case UCAL_LENIENT:
+ ((Calendar*)cal)->setLenient((UBool)newValue);
+ break;
+
+ case UCAL_FIRST_DAY_OF_WEEK:
+ ((Calendar*)cal)->setFirstDayOfWeek((UCalendarDaysOfWeek)newValue);
+ break;
+
+ case UCAL_MINIMAL_DAYS_IN_FIRST_WEEK:
+ ((Calendar*)cal)->setMinimalDaysInFirstWeek((uint8_t)newValue);
+ break;
+ }
+}
+
+U_CAPI const char* U_EXPORT2
+ucal_getAvailable(int32_t index)
+{
+
+ return uloc_getAvailable(index);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_countAvailable()
+{
+
+ return uloc_countAvailable();
+}
+
+U_CAPI UDate U_EXPORT2
+ucal_getMillis( const UCalendar* cal,
+ UErrorCode* status)
+{
+
+ if(U_FAILURE(*status)) return (UDate) 0;
+
+ return ((Calendar*)cal)->getTime(*status);
+}
+
+U_CAPI void U_EXPORT2
+ucal_setMillis( UCalendar* cal,
+ UDate dateTime,
+ UErrorCode* status )
+{
+ if(U_FAILURE(*status)) return;
+
+ ((Calendar*)cal)->setTime(dateTime, *status);
+}
+
+// TBD: why does this take an UErrorCode?
+U_CAPI void U_EXPORT2
+ucal_setDate( UCalendar* cal,
+ int32_t year,
+ int32_t month,
+ int32_t date,
+ UErrorCode *status)
+{
+
+ if(U_FAILURE(*status)) return;
+
+ ((Calendar*)cal)->set(year, month, date);
+}
+
+// TBD: why does this take an UErrorCode?
+U_CAPI void U_EXPORT2
+ucal_setDateTime( UCalendar* cal,
+ int32_t year,
+ int32_t month,
+ int32_t date,
+ int32_t hour,
+ int32_t minute,
+ int32_t second,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return;
+
+ ((Calendar*)cal)->set(year, month, date, hour, minute, second);
+}
+
+U_CAPI UBool U_EXPORT2
+ucal_equivalentTo( const UCalendar* cal1,
+ const UCalendar* cal2)
+{
+
+ return ((Calendar*)cal1)->isEquivalentTo(*((Calendar*)cal2));
+}
+
+U_CAPI void U_EXPORT2
+ucal_add( UCalendar* cal,
+ UCalendarDateFields field,
+ int32_t amount,
+ UErrorCode* status)
+{
+
+ if(U_FAILURE(*status)) return;
+
+ ((Calendar*)cal)->add(field, amount, *status);
+}
+
+U_CAPI void U_EXPORT2
+ucal_roll( UCalendar* cal,
+ UCalendarDateFields field,
+ int32_t amount,
+ UErrorCode* status)
+{
+
+ if(U_FAILURE(*status)) return;
+
+ ((Calendar*)cal)->roll(field, amount, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_get( const UCalendar* cal,
+ UCalendarDateFields field,
+ UErrorCode* status )
+{
+
+ if(U_FAILURE(*status)) return -1;
+
+ return ((Calendar*)cal)->get(field, *status);
+}
+
+U_CAPI void U_EXPORT2
+ucal_set( UCalendar* cal,
+ UCalendarDateFields field,
+ int32_t value)
+{
+
+ ((Calendar*)cal)->set(field, value);
+}
+
+U_CAPI UBool U_EXPORT2
+ucal_isSet( const UCalendar* cal,
+ UCalendarDateFields field)
+{
+
+ return ((Calendar*)cal)->isSet(field);
+}
+
+U_CAPI void U_EXPORT2
+ucal_clearField( UCalendar* cal,
+ UCalendarDateFields field)
+{
+
+ ((Calendar*)cal)->clear(field);
+}
+
+U_CAPI void U_EXPORT2
+ucal_clear(UCalendar* calendar)
+{
+
+ ((Calendar*)calendar)->clear();
+}
+
+U_CAPI int32_t U_EXPORT2
+ucal_getLimit( const UCalendar* cal,
+ UCalendarDateFields field,
+ UCalendarLimitType type,
+ UErrorCode *status)
+{
+
+ if(status==0 || U_FAILURE(*status)) {
+ return -1;
+ }
+
+ switch(type) {
+ case UCAL_MINIMUM:
+ return ((Calendar*)cal)->getMinimum(field);
+
+ case UCAL_MAXIMUM:
+ return ((Calendar*)cal)->getMaximum(field);
+
+ case UCAL_GREATEST_MINIMUM:
+ return ((Calendar*)cal)->getGreatestMinimum(field);
+
+ case UCAL_LEAST_MAXIMUM:
+ return ((Calendar*)cal)->getLeastMaximum(field);
+
+ case UCAL_ACTUAL_MINIMUM:
+ return ((Calendar*)cal)->getActualMinimum(field,
+ *status);
+
+ case UCAL_ACTUAL_MAXIMUM:
+ return ((Calendar*)cal)->getActualMaximum(field,
+ *status);
+
+ default:
+ break;
+ }
+ return -1;
+}
+
+U_CAPI const char * U_EXPORT2
+ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status)
+{
+ if (cal == NULL) {
+ if (U_SUCCESS(*status)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return NULL;
+ }
+ return ((Calendar*)cal)->getLocaleID(type, *status);
+}
+
+U_CAPI const char * U_EXPORT2
+ucal_getTZDataVersion(UErrorCode* status)
+{
+ return TimeZone::getTZDataVersion(*status);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucln_in.c b/Build/source/libs/icu/icu-xetex/i18n/ucln_in.c
new file mode 100644
index 00000000000..afcf07112fb
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucln_in.c
@@ -0,0 +1,50 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2001-2006, International Business Machines *
+* Corporation and others. All Rights Reserved. *
+* *
+******************************************************************************
+* file name: ucln_in.c
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2001July05
+* created by: George Rhoten
+*/
+
+#include "ucln.h"
+#include "ucln_in.h"
+#include "uassert.h"
+
+/* Leave this copyright notice here! It needs to go somewhere in this library. */
+static const char copyright[] = U_COPYRIGHT_STRING;
+
+static cleanupFunc *gCleanupFunctions[UCLN_I18N_COUNT];
+
+static UBool i18n_cleanup(void)
+{
+ ECleanupI18NType libType = UCLN_I18N_START;
+
+ while (++libType<UCLN_I18N_COUNT) {
+ if (gCleanupFunctions[libType])
+ {
+ gCleanupFunctions[libType]();
+ gCleanupFunctions[libType] = NULL;
+ }
+ }
+ return TRUE;
+}
+
+void ucln_i18n_registerCleanup(ECleanupI18NType type,
+ cleanupFunc *func)
+{
+ U_ASSERT(UCLN_I18N_START < type && type < UCLN_I18N_COUNT);
+ ucln_registerCleanup(UCLN_I18N, i18n_cleanup);
+ if (UCLN_I18N_START < type && type < UCLN_I18N_COUNT)
+ {
+ gCleanupFunctions[type] = func;
+ }
+}
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucln_in.h b/Build/source/libs/icu/icu-xetex/i18n/ucln_in.h
new file mode 100644
index 00000000000..66138191a93
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucln_in.h
@@ -0,0 +1,54 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2001-2006, International Business Machines *
+* Corporation and others. All Rights Reserved. *
+* *
+******************************************************************************
+* file name: ucln_cmn.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2001July05
+* created by: George Rhoten
+*/
+
+#ifndef __UCLN_CMN_H__
+#define __UCLN_CMN_H__
+
+#include "unicode/utypes.h"
+#include "ucln.h"
+
+/*
+Please keep the order of enums declared in same order
+as the functions are suppose to be called. */
+typedef enum ECleanupI18NType {
+ UCLN_I18N_START = -1,
+ UCLN_I18N_TRANSLITERATOR,
+ UCLN_I18N_REGEX,
+ UCLN_I18N_ISLAMIC_CALENDAR,
+ UCLN_I18N_HEBREW_CALENDAR,
+ UCLN_I18N_ASTRO_CALENDAR,
+ UCLN_I18N_CALENDAR,
+ UCLN_I18N_NUMFMT,
+ UCLN_I18N_CURRENCY,
+ UCLN_I18N_TIMEZONE,
+ UCLN_I18N_USEARCH,
+ UCLN_I18N_COLLATOR,
+ UCLN_I18N_UCOL,
+ UCLN_I18N_UCOL_BLD,
+ UCLN_I18N_CSDET,
+ UCLN_I18N_ZONEMETA,
+ UCLN_I18N_ZSFORMAT,
+ UCLN_I18N_COUNT /* This must be last */
+} ECleanupI18NType;
+
+/* Main library cleanup registration function. */
+/* See common/ucln.h for details on adding a cleanup function. */
+U_CFUNC void U_EXPORT2 ucln_i18n_registerCleanup(ECleanupI18NType type,
+ cleanupFunc *func);
+
+U_CFUNC UBool transliterator_cleanup(void);
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucol.cpp
new file mode 100644
index 00000000000..9e4434818cd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol.cpp
@@ -0,0 +1,8378 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: ucol.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 1996-1999 various members of ICU team maintained C API for collation framework
+* 02/16/2001 synwee Added internal method getPrevSpecialCE
+* 03/01/2001 synwee Added maxexpansion functionality.
+* 03/16/2001 weiv Collation framework is rewritten in C and made UCA compliant
+*/
+
+#include "unicode/utypes.h"
+#include "uassert.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coleitr.h"
+#include "unicode/unorm.h"
+#include "unicode/udata.h"
+#include "unicode/ustring.h"
+
+#include "ucol_imp.h"
+#include "ucol_elm.h"
+#include "bocsu.h"
+
+#include "unormimp.h"
+#include "unorm_it.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "ucln_in.h"
+#include "cstring.h"
+#include "utracimp.h"
+#include "putilimp.h"
+
+#ifdef UCOL_DEBUG
+#include <stdio.h>
+#endif
+
+U_NAMESPACE_USE
+
+/* added by synwee for trie manipulation*/
+#define STAGE_1_SHIFT_ 10
+#define STAGE_2_SHIFT_ 4
+#define STAGE_2_MASK_AFTER_SHIFT_ 0x3F
+#define STAGE_3_MASK_ 0xF
+#define LAST_BYTE_MASK_ 0xFF
+#define SECOND_LAST_BYTE_SHIFT_ 8
+
+#define ZERO_CC_LIMIT_ 0xC0
+
+// static UCA. There is only one. Collators don't use it.
+// It is referenced only in ucol_initUCA and ucol_cleanup
+static UCollator* _staticUCA = NULL;
+// static pointer to udata memory. Inited in ucol_initUCA
+// used for cleanup in ucol_cleanup
+static UDataMemory* UCA_DATA_MEM = NULL;
+
+// this is static pointer to the normalizer fcdTrieIndex
+// it is always the same between calls to u_cleanup
+// and therefore writing to it is not synchronized.
+// It is cleaned in ucol_cleanup
+static const uint16_t *fcdTrieIndex=NULL;
+
+// These are values from UCA required for
+// implicit generation and supressing sort key compression
+// they should regularly be in the UCA, but if one
+// is running without UCA, it could be a problem
+static int32_t maxRegularPrimary = 0xA0;
+static int32_t minImplicitPrimary = 0xE0;
+static int32_t maxImplicitPrimary = 0xE4;
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+isAcceptableUCA(void * /*context*/,
+ const char * /*type*/, const char * /*name*/,
+ const UDataInfo *pInfo){
+ /* context, type & name are intentionally not used */
+ if( pInfo->size>=20 &&
+ pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+ pInfo->charsetFamily==U_CHARSET_FAMILY &&
+ pInfo->dataFormat[0]==UCA_DATA_FORMAT_0 && /* dataFormat="UCol" */
+ pInfo->dataFormat[1]==UCA_DATA_FORMAT_1 &&
+ pInfo->dataFormat[2]==UCA_DATA_FORMAT_2 &&
+ pInfo->dataFormat[3]==UCA_DATA_FORMAT_3 &&
+ pInfo->formatVersion[0]==UCA_FORMAT_VERSION_0 &&
+ pInfo->formatVersion[1]>=UCA_FORMAT_VERSION_1// &&
+ //pInfo->formatVersion[1]==UCA_FORMAT_VERSION_1 &&
+ //pInfo->formatVersion[2]==UCA_FORMAT_VERSION_2 && // Too harsh
+ //pInfo->formatVersion[3]==UCA_FORMAT_VERSION_3 && // Too harsh
+ ) {
+ UVersionInfo UCDVersion;
+ u_getUnicodeVersion(UCDVersion);
+ return (UBool)(pInfo->dataVersion[0]==UCDVersion[0]
+ && pInfo->dataVersion[1]==UCDVersion[1]);
+ //&& pInfo->dataVersion[2]==ucaDataInfo.dataVersion[2]
+ //&& pInfo->dataVersion[3]==ucaDataInfo.dataVersion[3]);
+ } else {
+ return FALSE;
+ }
+}
+
+
+static int32_t U_CALLCONV
+_getFoldingOffset(uint32_t data) {
+ return (int32_t)(data&0xFFFFFF);
+}
+
+U_CDECL_END
+
+static
+inline void IInit_collIterate(const UCollator *collator, const UChar *sourceString,
+ int32_t sourceLen, collIterate *s) {
+ (s)->string = (s)->pos = (UChar *)(sourceString);
+ (s)->origFlags = 0;
+ (s)->flags = 0;
+ if (sourceLen >= 0) {
+ s->flags |= UCOL_ITER_HASLEN;
+ (s)->endp = (UChar *)sourceString+sourceLen;
+ }
+ else {
+ /* change to enable easier checking for end of string for fcdpositon */
+ (s)->endp = NULL;
+ }
+ (s)->CEpos = (s)->toReturn = (s)->CEs;
+ (s)->writableBuffer = (s)->stackWritableBuffer;
+ (s)->writableBufSize = UCOL_WRITABLE_BUFFER_SIZE;
+ (s)->coll = (collator);
+ (s)->fcdPosition = 0;
+ if(collator->normalizationMode == UCOL_ON) {
+ (s)->flags |= UCOL_ITER_NORM;
+ }
+ if(collator->hiraganaQ == UCOL_ON && collator->strength >= UCOL_QUATERNARY) {
+ (s)->flags |= UCOL_HIRAGANA_Q;
+ }
+ (s)->iterator = NULL;
+ //(s)->iteratorIndex = 0;
+}
+
+U_CAPI void U_EXPORT2
+uprv_init_collIterate(const UCollator *collator, const UChar *sourceString,
+ int32_t sourceLen, collIterate *s){
+ /* Out-of-line version for use from other files. */
+ IInit_collIterate(collator, sourceString, sourceLen, s);
+}
+
+
+/**
+* Backup the state of the collIterate struct data
+* @param data collIterate to backup
+* @param backup storage
+*/
+static
+inline void backupState(const collIterate *data, collIterateState *backup)
+{
+ backup->fcdPosition = data->fcdPosition;
+ backup->flags = data->flags;
+ backup->origFlags = data->origFlags;
+ backup->pos = data->pos;
+ backup->bufferaddress = data->writableBuffer;
+ backup->buffersize = data->writableBufSize;
+ backup->iteratorMove = 0;
+ backup->iteratorIndex = 0;
+ if(data->iterator != NULL) {
+ //backup->iteratorIndex = data->iterator->getIndex(data->iterator, UITER_CURRENT);
+ backup->iteratorIndex = data->iterator->getState(data->iterator);
+ // no we try to fixup if we're using a normalizing iterator and we get UITER_NO_STATE
+ if(backup->iteratorIndex == UITER_NO_STATE) {
+ while((backup->iteratorIndex = data->iterator->getState(data->iterator)) == UITER_NO_STATE) {
+ backup->iteratorMove++;
+ data->iterator->move(data->iterator, -1, UITER_CURRENT);
+ }
+ data->iterator->move(data->iterator, backup->iteratorMove, UITER_CURRENT);
+ }
+ }
+}
+
+/**
+* Loads the state into the collIterate struct data
+* @param data collIterate to backup
+* @param backup storage
+* @param forwards boolean to indicate if forwards iteration is used,
+* false indicates backwards iteration
+*/
+static
+inline void loadState(collIterate *data, const collIterateState *backup,
+ UBool forwards)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ data->flags = backup->flags;
+ data->origFlags = backup->origFlags;
+ if(data->iterator != NULL) {
+ //data->iterator->move(data->iterator, backup->iteratorIndex, UITER_ZERO);
+ data->iterator->setState(data->iterator, backup->iteratorIndex, &status);
+ if(backup->iteratorMove != 0) {
+ data->iterator->move(data->iterator, backup->iteratorMove, UITER_CURRENT);
+ }
+ }
+ data->pos = backup->pos;
+ if ((data->flags & UCOL_ITER_INNORMBUF) &&
+ data->writableBuffer != backup->bufferaddress) {
+ /*
+ this is when a new buffer has been reallocated and we'll have to
+ calculate the new position.
+ note the new buffer has to contain the contents of the old buffer.
+ */
+ if (forwards) {
+ data->pos = data->writableBuffer +
+ (data->pos - backup->bufferaddress);
+ }
+ else {
+ /* backwards direction */
+ uint32_t temp = backup->buffersize -
+ (data->pos - backup->bufferaddress);
+ data->pos = data->writableBuffer + (data->writableBufSize - temp);
+ }
+ }
+ if ((data->flags & UCOL_ITER_INNORMBUF) == 0) {
+ /*
+ this is alittle tricky.
+ if we are initially not in the normalization buffer, even if we
+ normalize in the later stage, the data in the buffer will be
+ ignored, since we skip back up to the data string.
+ however if we are already in the normalization buffer, any
+ further normalization will pull data into the normalization
+ buffer and modify the fcdPosition.
+ since we are keeping the data in the buffer for use, the
+ fcdPosition can not be reverted back.
+ arrgghh....
+ */
+ data->fcdPosition = backup->fcdPosition;
+ }
+}
+
+
+/*
+* collIter_eos()
+* Checks for a collIterate being positioned at the end of
+* its source string.
+*
+*/
+static
+inline UBool collIter_eos(collIterate *s) {
+ if(s->flags & UCOL_USE_ITERATOR) {
+ return !(s->iterator->hasNext(s->iterator));
+ }
+ if ((s->flags & UCOL_ITER_HASLEN) == 0 && *s->pos != 0) {
+ // Null terminated string, but not at null, so not at end.
+ // Whether in main or normalization buffer doesn't matter.
+ return FALSE;
+ }
+
+ // String with length. Can't be in normalization buffer, which is always
+ // null termintated.
+ if (s->flags & UCOL_ITER_HASLEN) {
+ return (s->pos == s->endp);
+ }
+
+ // We are at a null termination, could be either normalization buffer or main string.
+ if ((s->flags & UCOL_ITER_INNORMBUF) == 0) {
+ // At null at end of main string.
+ return TRUE;
+ }
+
+ // At null at end of normalization buffer. Need to check whether there there are
+ // any characters left in the main buffer.
+ if(s->origFlags & UCOL_USE_ITERATOR) {
+ return !(s->iterator->hasNext(s->iterator));
+ } else if ((s->origFlags & UCOL_ITER_HASLEN) == 0) {
+ // Null terminated main string. fcdPosition is the 'return' position into main buf.
+ return (*s->fcdPosition == 0);
+ }
+ else {
+ // Main string with an end pointer.
+ return s->fcdPosition == s->endp;
+ }
+}
+
+/*
+* collIter_bos()
+* Checks for a collIterate being positioned at the start of
+* its source string.
+*
+*/
+static
+inline UBool collIter_bos(collIterate *source) {
+ // if we're going backwards, we need to know whether there is more in the
+ // iterator, even if we are in the side buffer
+ if(source->flags & UCOL_USE_ITERATOR || source->origFlags & UCOL_USE_ITERATOR) {
+ return !source->iterator->hasPrevious(source->iterator);
+ }
+ if (source->pos <= source->string ||
+ ((source->flags & UCOL_ITER_INNORMBUF) &&
+ *(source->pos - 1) == 0 && source->fcdPosition == NULL)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*static
+inline UBool collIter_SimpleBos(collIterate *source) {
+ // if we're going backwards, we need to know whether there is more in the
+ // iterator, even if we are in the side buffer
+ if(source->flags & UCOL_USE_ITERATOR || source->origFlags & UCOL_USE_ITERATOR) {
+ return !source->iterator->hasPrevious(source->iterator);
+ }
+ if (source->pos == source->string) {
+ return TRUE;
+ }
+ return FALSE;
+}*/
+ //return (data->pos == data->string) ||
+
+
+/**
+* Checks and free writable buffer if it is not the original stack buffer
+* in collIterate. This function does not reassign the writable buffer.
+* @param data collIterate struct to determine and free the writable buffer
+*/
+static
+inline void freeHeapWritableBuffer(collIterate *data)
+{
+ if (data->writableBuffer != data->stackWritableBuffer) {
+ uprv_free(data->writableBuffer);
+ }
+}
+
+
+/****************************************************************************/
+/* Following are the open/close functions */
+/* */
+/****************************************************************************/
+
+static UCollator*
+ucol_initFromBinary(const uint8_t *bin, int32_t length,
+ const UCollator *base,
+ UCollator *fillIn,
+ UErrorCode *status)
+{
+ UCollator *result = fillIn;
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+ /*
+ if(base == NULL) {
+ // we don't support null base yet
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ */
+ // We need these and we could be running without UCA
+ uprv_uca_initImplicitConstants(0, 0, status);
+ UCATableHeader *colData = (UCATableHeader *)bin;
+ // do we want version check here? We're trying to figure out whether collators are compatible
+ if((base && (uprv_memcmp(colData->UCAVersion, base->image->UCAVersion, sizeof(UVersionInfo)) != 0 ||
+ uprv_memcmp(colData->UCDVersion, base->image->UCDVersion, sizeof(UVersionInfo)) != 0)) ||
+ colData->version[0] != UCOL_BUILDER_VERSION)
+ {
+ *status = U_COLLATOR_VERSION_MISMATCH;
+ return NULL;
+ }
+ else {
+ if((uint32_t)length > (paddedsize(sizeof(UCATableHeader)) + paddedsize(sizeof(UColOptionSet)))) {
+ result = ucol_initCollator((const UCATableHeader *)bin, result, base, status);
+ if(U_FAILURE(*status)){
+ return NULL;
+ }
+ result->hasRealData = TRUE;
+ }
+ else {
+ if(base) {
+ result = ucol_initCollator(base->image, result, base, status);
+ ucol_setOptionsFromHeader(result, (UColOptionSet *)(bin+((const UCATableHeader *)bin)->options), status);
+ if(U_FAILURE(*status)){
+ return NULL;
+ }
+ result->hasRealData = FALSE;
+ }
+ else {
+ *status = U_USELESS_COLLATOR_ERROR;
+ return NULL;
+ }
+ }
+ result->freeImageOnClose = FALSE;
+ }
+ result->validLocale = NULL;
+ result->requestedLocale = NULL;
+ result->rules = NULL;
+ result->rulesLength = 0;
+ result->freeRulesOnClose = FALSE;
+ result->rb = NULL;
+ result->elements = NULL;
+ return result;
+}
+
+U_CAPI UCollator* U_EXPORT2
+ucol_openBinary(const uint8_t *bin, int32_t length,
+ const UCollator *base,
+ UErrorCode *status)
+{
+ return ucol_initFromBinary(bin, length, base, NULL, status);
+}
+
+U_CAPI UCollator* U_EXPORT2
+ucol_safeClone(const UCollator *coll, void *stackBuffer, int32_t * pBufferSize, UErrorCode *status)
+{
+ UCollator * localCollator;
+ int32_t bufferSizeNeeded = (int32_t)sizeof(UCollator);
+ char *stackBufferChars = (char *)stackBuffer;
+ int32_t imageSize = 0;
+ int32_t rulesSize = 0;
+ int32_t rulesPadding = 0;
+ uint8_t *image;
+ UChar *rules;
+ UBool colAllocated = FALSE;
+ UBool imageAllocated = FALSE;
+
+ if (status == NULL || U_FAILURE(*status)){
+ return 0;
+ }
+ if ((stackBuffer && !pBufferSize) || !coll){
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ if (coll->rules && coll->freeRulesOnClose) {
+ rulesSize = (int32_t)(coll->rulesLength + 1)*sizeof(UChar);
+ rulesPadding = (int32_t)(bufferSizeNeeded % sizeof(UChar));
+ bufferSizeNeeded += rulesSize + rulesPadding;
+ }
+
+ if (stackBuffer && *pBufferSize <= 0){ /* 'preflighting' request - set needed size into *pBufferSize */
+ *pBufferSize = bufferSizeNeeded;
+ return 0;
+ }
+
+ /* Pointers on 64-bit platforms need to be aligned
+ * on a 64-bit boundry in memory.
+ */
+ if (U_ALIGNMENT_OFFSET(stackBuffer) != 0) {
+ int32_t offsetUp = (int32_t)U_ALIGNMENT_OFFSET_UP(stackBufferChars);
+ if (*pBufferSize > offsetUp) {
+ *pBufferSize -= offsetUp;
+ stackBufferChars += offsetUp;
+ }
+ else {
+ /* prevent using the stack buffer but keep the size > 0 so that we do not just preflight */
+ *pBufferSize = 1;
+ }
+ }
+ stackBuffer = (void *)stackBufferChars;
+
+ if (stackBuffer == NULL || *pBufferSize < bufferSizeNeeded) {
+ /* allocate one here...*/
+ stackBufferChars = (char *)uprv_malloc(bufferSizeNeeded);
+ colAllocated = TRUE;
+ if (U_SUCCESS(*status)) {
+ *status = U_SAFECLONE_ALLOCATED_WARNING;
+ }
+ }
+ localCollator = (UCollator *)stackBufferChars;
+ rules = (UChar *)(stackBufferChars + sizeof(UCollator) + rulesPadding);
+ {
+ UErrorCode tempStatus = U_ZERO_ERROR;
+ imageSize = ucol_cloneBinary(coll, NULL, 0, &tempStatus);
+ }
+ if (coll->freeImageOnClose) {
+ image = (uint8_t *)uprv_malloc(imageSize);
+ ucol_cloneBinary(coll, image, imageSize, status);
+ imageAllocated = TRUE;
+ }
+ else {
+ image = (uint8_t *)coll->image;
+ }
+ localCollator = ucol_initFromBinary(image, imageSize, coll->UCA, localCollator, status);
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ if (coll->rules) {
+ if (coll->freeRulesOnClose) {
+ localCollator->rules = u_strcpy(rules, coll->rules);
+ //bufferEnd += rulesSize;
+ }
+ else {
+ localCollator->rules = coll->rules;
+ }
+ localCollator->freeRulesOnClose = FALSE;
+ localCollator->rulesLength = coll->rulesLength;
+ }
+
+ int32_t i;
+ for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
+ ucol_setAttribute(localCollator, (UColAttribute)i, ucol_getAttribute(coll, (UColAttribute)i, status), status);
+ }
+ localCollator->requestedLocale = NULL; // zero copies of pointers
+ localCollator->validLocale = NULL;
+ localCollator->rb = NULL;
+ localCollator->elements = NULL;
+ localCollator->freeOnClose = colAllocated;
+ localCollator->freeImageOnClose = imageAllocated;
+ return localCollator;
+}
+
+U_CAPI void U_EXPORT2
+ucol_close(UCollator *coll)
+{
+ UTRACE_ENTRY_OC(UTRACE_UCOL_CLOSE);
+ UTRACE_DATA1(UTRACE_INFO, "coll = %p", coll);
+ if(coll != NULL) {
+ // these are always owned by each UCollator struct,
+ // so we always free them
+ if(coll->validLocale != NULL) {
+ uprv_free(coll->validLocale);
+ }
+ if(coll->requestedLocale != NULL) {
+ uprv_free(coll->requestedLocale);
+ }
+ if(coll->resCleaner != NULL) {
+ coll->resCleaner(coll);
+ }
+ if(coll->latinOneCEs != NULL) {
+ uprv_free(coll->latinOneCEs);
+ }
+ if(coll->options != NULL && coll->freeOptionsOnClose) {
+ uprv_free(coll->options);
+ }
+ if(coll->rules != NULL && coll->freeRulesOnClose) {
+ uprv_free((UChar *)coll->rules);
+ }
+ if(coll->image != NULL && coll->freeImageOnClose) {
+ uprv_free((UCATableHeader *)coll->image);
+ }
+
+ /* Here, it would be advisable to close: */
+ /* - UData for UCA (unless we stuff it in the root resb */
+ /* Again, do we need additional housekeeping... HMMM! */
+ UTRACE_DATA1(UTRACE_INFO, "coll->freeOnClose: %d", coll->freeOnClose);
+ if(coll->freeOnClose){
+ /* for safeClone, if freeOnClose is FALSE,
+ don't free the other instance data */
+ uprv_free(coll);
+ }
+ }
+ UTRACE_EXIT();
+}
+
+/* This one is currently used by genrb & tests. After constructing from rules (tailoring),*/
+/* you should be able to get the binary chunk to write out... Doesn't look very full now */
+U_CFUNC uint8_t* U_EXPORT2
+ucol_cloneRuleData(const UCollator *coll, int32_t *length, UErrorCode *status)
+{
+ uint8_t *result = NULL;
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+ if(coll->hasRealData == TRUE) {
+ *length = coll->image->size;
+ result = (uint8_t *)uprv_malloc(*length);
+ /* test for NULL */
+ if (result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(result, coll->image, *length);
+ } else {
+ *length = (int32_t)(paddedsize(sizeof(UCATableHeader))+paddedsize(sizeof(UColOptionSet)));
+ result = (uint8_t *)uprv_malloc(*length);
+ /* test for NULL */
+ if (result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ /* build the UCATableHeader with minimal entries */
+ /* do not copy the header from the UCA file because its values are wrong! */
+ /* uprv_memcpy(result, UCA->image, sizeof(UCATableHeader)); */
+
+ /* reset everything */
+ uprv_memset(result, 0, *length);
+
+ /* set the tailoring-specific values */
+ UCATableHeader *myData = (UCATableHeader *)result;
+ myData->size = *length;
+
+ /* offset for the options, the only part of the data that is present after the header */
+ myData->options = sizeof(UCATableHeader);
+
+ /* need to always set the expansion value for an upper bound of the options */
+ myData->expansion = myData->options + sizeof(UColOptionSet);
+
+ myData->magic = UCOL_HEADER_MAGIC;
+ myData->isBigEndian = U_IS_BIG_ENDIAN;
+ myData->charSetFamily = U_CHARSET_FAMILY;
+
+ /* copy UCA's version; genrb will override all but the builder version with tailoring data */
+ uprv_memcpy(myData->version, coll->image->version, sizeof(UVersionInfo));
+
+ uprv_memcpy(myData->UCAVersion, coll->image->UCAVersion, sizeof(UVersionInfo));
+ uprv_memcpy(myData->UCDVersion, coll->image->UCDVersion, sizeof(UVersionInfo));
+ uprv_memcpy(myData->formatVersion, coll->image->formatVersion, sizeof(UVersionInfo));
+ myData->jamoSpecial = coll->image->jamoSpecial;
+
+ /* copy the collator options */
+ uprv_memcpy(result+paddedsize(sizeof(UCATableHeader)), coll->options, sizeof(UColOptionSet));
+ }
+ return result;
+}
+
+void ucol_setOptionsFromHeader(UCollator* result, UColOptionSet * opts, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return;
+ }
+ result->caseFirst = (UColAttributeValue)opts->caseFirst;
+ result->caseLevel = (UColAttributeValue)opts->caseLevel;
+ result->frenchCollation = (UColAttributeValue)opts->frenchCollation;
+ result->normalizationMode = (UColAttributeValue)opts->normalizationMode;
+ result->strength = (UColAttributeValue)opts->strength;
+ result->variableTopValue = opts->variableTopValue;
+ result->alternateHandling = (UColAttributeValue)opts->alternateHandling;
+ result->hiraganaQ = (UColAttributeValue)opts->hiraganaQ;
+ result->numericCollation = (UColAttributeValue)opts->numericCollation;
+
+ result->caseFirstisDefault = TRUE;
+ result->caseLevelisDefault = TRUE;
+ result->frenchCollationisDefault = TRUE;
+ result->normalizationModeisDefault = TRUE;
+ result->strengthisDefault = TRUE;
+ result->variableTopValueisDefault = TRUE;
+ result->hiraganaQisDefault = TRUE;
+ result->numericCollationisDefault = TRUE;
+
+ ucol_updateInternalState(result, status);
+
+ result->options = opts;
+}
+
+
+/**
+* Approximate determination if a character is at a contraction end.
+* Guaranteed to be TRUE if a character is at the end of a contraction,
+* otherwise it is not deterministic.
+* @param c character to be determined
+* @param coll collator
+*/
+static
+inline UBool ucol_contractionEndCP(UChar c, const UCollator *coll) {
+ if (U16_IS_TRAIL(c)) {
+ return TRUE;
+ }
+
+ if (c < coll->minContrEndCP) {
+ return FALSE;
+ }
+
+ int32_t hash = c;
+ uint8_t htbyte;
+ if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) {
+ hash = (hash & UCOL_UNSAFECP_TABLE_MASK) + 256;
+ }
+ htbyte = coll->contrEndCP[hash>>3];
+ return (((htbyte >> (hash & 7)) & 1) == 1);
+}
+
+
+
+/*
+* i_getCombiningClass()
+* A fast, at least partly inline version of u_getCombiningClass()
+* This is a candidate for further optimization. Used heavily
+* in contraction processing.
+*/
+static
+inline uint8_t i_getCombiningClass(UChar32 c, const UCollator *coll) {
+ uint8_t sCC = 0;
+ if ((c >= 0x300 && ucol_unsafeCP(c, coll)) || c > 0xFFFF) {
+ sCC = u_getCombiningClass(c);
+ }
+ return sCC;
+}
+
+UCollator* ucol_initCollator(const UCATableHeader *image, UCollator *fillIn, const UCollator *UCA, UErrorCode *status) {
+ UChar c;
+ UCollator *result = fillIn;
+ if(U_FAILURE(*status) || image == NULL) {
+ return NULL;
+ }
+
+ if(result == NULL) {
+ result = (UCollator *)uprv_malloc(sizeof(UCollator));
+ if(result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return result;
+ }
+ result->freeOnClose = TRUE;
+ } else {
+ result->freeOnClose = FALSE;
+ }
+
+ result->image = image;
+ result->mapping.getFoldingOffset = _getFoldingOffset;
+ const uint8_t *mapping = (uint8_t*)result->image+result->image->mappingPosition;
+ utrie_unserialize(&result->mapping, mapping, result->image->endExpansionCE - result->image->mappingPosition, status);
+ if(U_FAILURE(*status)) {
+ if(result->freeOnClose == TRUE) {
+ uprv_free(result);
+ result = NULL;
+ }
+ return result;
+ }
+
+ /*result->latinOneMapping = (uint32_t*)((uint8_t*)result->image+result->image->latinOneMapping);*/
+ result->latinOneMapping = UTRIE_GET32_LATIN1(&result->mapping);
+ result->contractionCEs = (uint32_t*)((uint8_t*)result->image+result->image->contractionCEs);
+ result->contractionIndex = (UChar*)((uint8_t*)result->image+result->image->contractionIndex);
+ result->expansion = (uint32_t*)((uint8_t*)result->image+result->image->expansion);
+
+ result->options = (UColOptionSet*)((uint8_t*)result->image+result->image->options);
+ result->freeOptionsOnClose = FALSE;
+
+ /* set attributes */
+ result->caseFirst = (UColAttributeValue)result->options->caseFirst;
+ result->caseLevel = (UColAttributeValue)result->options->caseLevel;
+ result->frenchCollation = (UColAttributeValue)result->options->frenchCollation;
+ result->normalizationMode = (UColAttributeValue)result->options->normalizationMode;
+ result->strength = (UColAttributeValue)result->options->strength;
+ result->variableTopValue = result->options->variableTopValue;
+ result->alternateHandling = (UColAttributeValue)result->options->alternateHandling;
+ result->hiraganaQ = (UColAttributeValue)result->options->hiraganaQ;
+ result->numericCollation = (UColAttributeValue)result->options->numericCollation;
+
+ result->caseFirstisDefault = TRUE;
+ result->caseLevelisDefault = TRUE;
+ result->frenchCollationisDefault = TRUE;
+ result->normalizationModeisDefault = TRUE;
+ result->strengthisDefault = TRUE;
+ result->variableTopValueisDefault = TRUE;
+ result->alternateHandlingisDefault = TRUE;
+ result->hiraganaQisDefault = TRUE;
+ result->numericCollationisDefault = TRUE;
+
+ /*result->scriptOrder = NULL;*/
+
+ result->rules = NULL;
+ result->rulesLength = 0;
+
+ /* get the version info from UCATableHeader and populate the Collator struct*/
+ result->dataVersion[0] = result->image->version[0]; /* UCA Builder version*/
+ result->dataVersion[1] = result->image->version[1]; /* UCA Tailoring rules version*/
+ result->dataVersion[2] = 0;
+ result->dataVersion[3] = 0;
+
+ result->unsafeCP = (uint8_t *)result->image + result->image->unsafeCP;
+ result->minUnsafeCP = 0;
+ for (c=0; c<0x300; c++) { // Find the smallest unsafe char.
+ if (ucol_unsafeCP(c, result)) break;
+ }
+ result->minUnsafeCP = c;
+
+ result->contrEndCP = (uint8_t *)result->image + result->image->contrEndCP;
+ result->minContrEndCP = 0;
+ for (c=0; c<0x300; c++) { // Find the Contraction-ending char.
+ if (ucol_contractionEndCP(c, result)) break;
+ }
+ result->minContrEndCP = c;
+
+ /* max expansion tables */
+ result->endExpansionCE = (uint32_t*)((uint8_t*)result->image +
+ result->image->endExpansionCE);
+ result->lastEndExpansionCE = result->endExpansionCE +
+ result->image->endExpansionCECount - 1;
+ result->expansionCESize = (uint8_t*)result->image +
+ result->image->expansionCESize;
+
+
+ //result->errorCode = *status;
+
+ result->latinOneCEs = NULL;
+
+ result->latinOneRegenTable = FALSE;
+ result->latinOneFailed = FALSE;
+ result->UCA = UCA;
+ result->resCleaner = NULL;
+
+ ucol_updateInternalState(result, status);
+
+ /* Normally these will be set correctly later. This is the default if you use UCA or the default. */
+ result->rb = NULL;
+ result->elements = NULL;
+ result->validLocale = NULL;
+ result->requestedLocale = NULL;
+ result->hasRealData = FALSE; // real data lives in .dat file...
+ result->freeImageOnClose = FALSE;
+
+ return result;
+}
+
+/* new Mark's code */
+
+/**
+ * For generation of Implicit CEs
+ * @author Davis
+ *
+ * Cleaned up so that changes can be made more easily.
+ * Old values:
+# First Implicit: E26A792D
+# Last Implicit: E3DC70C0
+# First CJK: E0030300
+# Last CJK: E0A9DD00
+# First CJK_A: E0A9DF00
+# Last CJK_A: E0DE3100
+ */
+/* Following is a port of Mark's code for new treatment of implicits.
+ * It is positioned here, since ucol_initUCA need to initialize the
+ * variables below according to the data in the fractional UCA.
+ */
+
+/**
+ * Function used to:
+ * a) collapse the 2 different Han ranges from UCA into one (in the right order), and
+ * b) bump any non-CJK characters by 10FFFF.
+ * The relevant blocks are:
+ * A: 4E00..9FFF; CJK Unified Ideographs
+ * F900..FAFF; CJK Compatibility Ideographs
+ * B: 3400..4DBF; CJK Unified Ideographs Extension A
+ * 20000..XX; CJK Unified Ideographs Extension B (and others later on)
+ * As long as
+ * no new B characters are allocated between 4E00 and FAFF, and
+ * no new A characters are outside of this range,
+ * (very high probability) this simple code will work.
+ * The reordered blocks are:
+ * Block1 is CJK
+ * Block2 is CJK_COMPAT_USED
+ * Block3 is CJK_A
+ * (all contiguous)
+ * Any other CJK gets its normal code point
+ * Any non-CJK gets +10FFFF
+ * When we reorder Block1, we make sure that it is at the very start,
+ * so that it will use a 3-byte form.
+ * Warning: the we only pick up the compatibility characters that are
+ * NOT decomposed, so that block is smaller!
+ */
+
+// CONSTANTS
+static const UChar32
+ NON_CJK_OFFSET = 0x110000,
+ UCOL_MAX_INPUT = 0x220001; // 2 * Unicode range + 2
+
+/**
+ * Precomputed by constructor
+ */
+static int32_t
+ final3Multiplier = 0,
+ final4Multiplier = 0,
+ final3Count = 0,
+ final4Count = 0,
+ medialCount = 0,
+ min3Primary = 0,
+ min4Primary = 0,
+ max4Primary = 0,
+ minTrail = 0,
+ maxTrail = 0,
+ max3Trail = 0,
+ max4Trail = 0,
+ min4Boundary = 0;
+
+static const UChar32
+ CJK_BASE = 0x4E00,
+ CJK_LIMIT = 0x9FFF+1,
+ CJK_COMPAT_USED_BASE = 0xFA0E,
+ CJK_COMPAT_USED_LIMIT = 0xFA2F+1,
+ CJK_A_BASE = 0x3400,
+ CJK_A_LIMIT = 0x4DBF+1,
+ CJK_B_BASE = 0x20000,
+ CJK_B_LIMIT = 0x2A6DF+1;
+
+static UChar32 swapCJK(UChar32 i) {
+
+ if (i >= CJK_BASE) {
+ if (i < CJK_LIMIT) return i - CJK_BASE;
+
+ if (i < CJK_COMPAT_USED_BASE) return i + NON_CJK_OFFSET;
+
+ if (i < CJK_COMPAT_USED_LIMIT) return i - CJK_COMPAT_USED_BASE
+ + (CJK_LIMIT - CJK_BASE);
+ if (i < CJK_B_BASE) return i + NON_CJK_OFFSET;
+
+ if (i < CJK_B_LIMIT) return i; // non-BMP-CJK
+
+ return i + NON_CJK_OFFSET; // non-CJK
+ }
+ if (i < CJK_A_BASE) return i + NON_CJK_OFFSET;
+
+ if (i < CJK_A_LIMIT) return i - CJK_A_BASE
+ + (CJK_LIMIT - CJK_BASE)
+ + (CJK_COMPAT_USED_LIMIT - CJK_COMPAT_USED_BASE);
+ return i + NON_CJK_OFFSET; // non-CJK
+}
+
+U_CAPI UChar32 U_EXPORT2
+uprv_uca_getRawFromCodePoint(UChar32 i) {
+ return swapCJK(i)+1;
+}
+
+U_CAPI UChar32 U_EXPORT2
+uprv_uca_getCodePointFromRaw(UChar32 i) {
+ i--;
+ UChar32 result = 0;
+ if(i >= NON_CJK_OFFSET) {
+ result = i - NON_CJK_OFFSET;
+ } else if(i >= CJK_B_BASE) {
+ result = i;
+ } else if(i < CJK_A_LIMIT + (CJK_LIMIT - CJK_BASE) + (CJK_COMPAT_USED_LIMIT - CJK_COMPAT_USED_BASE)) { // rest of CJKs, compacted
+ if(i < CJK_LIMIT - CJK_BASE) {
+ result = i + CJK_BASE;
+ } else if(i < (CJK_LIMIT - CJK_BASE) + (CJK_COMPAT_USED_LIMIT - CJK_COMPAT_USED_BASE)) {
+ result = i + CJK_COMPAT_USED_BASE - (CJK_LIMIT - CJK_BASE);
+ } else {
+ result = i + CJK_A_BASE - (CJK_LIMIT - CJK_BASE) - (CJK_COMPAT_USED_LIMIT - CJK_COMPAT_USED_BASE);
+ }
+ } else {
+ result = -1;
+ }
+ return result;
+}
+
+// GET IMPLICIT PRIMARY WEIGHTS
+// Return value is left justified primary key
+U_CAPI uint32_t U_EXPORT2
+uprv_uca_getImplicitFromRaw(UChar32 cp) {
+ /*
+ if (cp < 0 || cp > UCOL_MAX_INPUT) {
+ throw new IllegalArgumentException("Code point out of range " + Utility.hex(cp));
+ }
+ */
+ int32_t last0 = cp - min4Boundary;
+ if (last0 < 0) {
+ int32_t last1 = cp / final3Count;
+ last0 = cp % final3Count;
+
+ int32_t last2 = last1 / medialCount;
+ last1 %= medialCount;
+
+ last0 = minTrail + last0*final3Multiplier; // spread out, leaving gap at start
+ last1 = minTrail + last1; // offset
+ last2 = min3Primary + last2; // offset
+ /*
+ if (last2 >= min4Primary) {
+ throw new IllegalArgumentException("4-byte out of range: " + Utility.hex(cp) + ", " + Utility.hex(last2));
+ }
+ */
+ return (last2 << 24) + (last1 << 16) + (last0 << 8);
+ } else {
+ int32_t last1 = last0 / final4Count;
+ last0 %= final4Count;
+
+ int32_t last2 = last1 / medialCount;
+ last1 %= medialCount;
+
+ int32_t last3 = last2 / medialCount;
+ last2 %= medialCount;
+
+ last0 = minTrail + last0*final4Multiplier; // spread out, leaving gap at start
+ last1 = minTrail + last1; // offset
+ last2 = minTrail + last2; // offset
+ last3 = min4Primary + last3; // offset
+ /*
+ if (last3 > max4Primary) {
+ throw new IllegalArgumentException("4-byte out of range: " + Utility.hex(cp) + ", " + Utility.hex(last3));
+ }
+ */
+ return (last3 << 24) + (last2 << 16) + (last1 << 8) + last0;
+ }
+}
+
+static uint32_t U_EXPORT2
+uprv_uca_getImplicitPrimary(UChar32 cp) {
+ //if (DEBUG) System.out.println("Incoming: " + Utility.hex(cp));
+
+ cp = swapCJK(cp);
+ cp++;
+ // we now have a range of numbers from 0 to 21FFFF.
+
+ //if (DEBUG) System.out.println("CJK swapped: " + Utility.hex(cp));
+
+ return uprv_uca_getImplicitFromRaw(cp);
+}
+
+/**
+ * Converts implicit CE into raw integer ("code point")
+ * @param implicit
+ * @return -1 if illegal format
+ */
+U_CAPI UChar32 U_EXPORT2
+uprv_uca_getRawFromImplicit(uint32_t implicit) {
+ UChar32 result;
+ UChar32 b3 = implicit & 0xFF;
+ implicit >>= 8;
+ UChar32 b2 = implicit & 0xFF;
+ implicit >>= 8;
+ UChar32 b1 = implicit & 0xFF;
+ implicit >>= 8;
+ UChar32 b0 = implicit & 0xFF;
+
+ // simple parameter checks
+ if (b0 < min3Primary || b0 > max4Primary
+ || b1 < minTrail || b1 > maxTrail) return -1;
+ // normal offsets
+ b1 -= minTrail;
+
+ // take care of the final values, and compose
+ if (b0 < min4Primary) {
+ if (b2 < minTrail || b2 > max3Trail || b3 != 0) return -1;
+ b2 -= minTrail;
+ UChar32 remainder = b2 % final3Multiplier;
+ if (remainder != 0) return -1;
+ b0 -= min3Primary;
+ b2 /= final3Multiplier;
+ result = ((b0 * medialCount) + b1) * final3Count + b2;
+ } else {
+ if (b2 < minTrail || b2 > maxTrail
+ || b3 < minTrail || b3 > max4Trail) return -1;
+ b2 -= minTrail;
+ b3 -= minTrail;
+ UChar32 remainder = b3 % final4Multiplier;
+ if (remainder != 0) return -1;
+ b3 /= final4Multiplier;
+ b0 -= min4Primary;
+ result = (((b0 * medialCount) + b1) * medialCount + b2) * final4Count + b3 + min4Boundary;
+ }
+ // final check
+ if (result < 0 || result > UCOL_MAX_INPUT) return -1;
+ return result;
+}
+
+
+static inline int32_t divideAndRoundUp(int a, int b) {
+ return 1 + (a-1)/b;
+}
+
+/* this function is either called from initUCA or from genUCA before
+ * doing canonical closure for the UCA.
+ */
+
+/**
+ * Set up to generate implicits.
+ * @param minPrimary
+ * @param maxPrimary
+ * @param minTrail final byte
+ * @param maxTrail final byte
+ * @param gap3 the gap we leave for tailoring for 3-byte forms
+ * @param gap4 the gap we leave for tailoring for 4-byte forms
+ */
+static void initImplicitConstants(int minPrimary, int maxPrimary,
+ int minTrailIn, int maxTrailIn,
+ int gap3, int primaries3count,
+ UErrorCode *status) {
+ // some simple parameter checks
+ if (minPrimary < 0 || minPrimary >= maxPrimary || maxPrimary > 0xFF) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ };
+ if (minTrailIn < 0 || minTrailIn >= maxTrailIn || maxTrailIn > 0xFF) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ };
+ if (primaries3count < 1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ };
+
+ minTrail = minTrailIn;
+ maxTrail = maxTrailIn;
+
+ min3Primary = minPrimary;
+ max4Primary = maxPrimary;
+ // compute constants for use later.
+ // number of values we can use in trailing bytes
+ // leave room for empty values between AND above, e.g. if gap = 2
+ // range 3..7 => +3 -4 -5 -6 -7: so 1 value
+ // range 3..8 => +3 -4 -5 +6 -7 -8: so 2 values
+ // range 3..9 => +3 -4 -5 +6 -7 -8 -9: so 2 values
+ final3Multiplier = gap3 + 1;
+ final3Count = (maxTrail - minTrail + 1) / final3Multiplier;
+ max3Trail = minTrail + (final3Count - 1) * final3Multiplier;
+
+ // medials can use full range
+ medialCount = (maxTrail - minTrail + 1);
+ // find out how many values fit in each form
+ int32_t threeByteCount = medialCount * final3Count;
+ // now determine where the 3/4 boundary is.
+ // we use 3 bytes below the boundary, and 4 above
+ int32_t primariesAvailable = maxPrimary - minPrimary + 1;
+ int32_t primaries4count = primariesAvailable - primaries3count;
+
+
+ int32_t min3ByteCoverage = primaries3count * threeByteCount;
+ min4Primary = minPrimary + primaries3count;
+ min4Boundary = min3ByteCoverage;
+ // Now expand out the multiplier for the 4 bytes, and redo.
+
+ int32_t totalNeeded = UCOL_MAX_INPUT - min4Boundary;
+ int32_t neededPerPrimaryByte = divideAndRoundUp(totalNeeded, primaries4count);
+ //if (DEBUG) System.out.println("neededPerPrimaryByte: " + neededPerPrimaryByte);
+ int32_t neededPerFinalByte = divideAndRoundUp(neededPerPrimaryByte, medialCount * medialCount);
+ //if (DEBUG) System.out.println("neededPerFinalByte: " + neededPerFinalByte);
+ int32_t gap4 = (maxTrail - minTrail - 1) / neededPerFinalByte;
+ //if (DEBUG) System.out.println("expandedGap: " + gap4);
+ if (gap4 < 1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ final4Multiplier = gap4 + 1;
+ final4Count = neededPerFinalByte;
+ max4Trail = minTrail + (final4Count - 1) * final4Multiplier;
+ /*
+ if (DEBUG) {
+ System.out.println("final4Count: " + final4Count);
+ for (int counter = 0; counter <= final4Count; ++counter) {
+ int value = minTrail + (1 + counter)*final4Multiplier;
+ System.out.println(counter + "\t" + value + "\t" + Utility.hex(value));
+ }
+ }
+ */
+}
+
+ /**
+ * Supply parameters for generating implicit CEs
+ */
+U_CAPI void U_EXPORT2
+uprv_uca_initImplicitConstants(int32_t, int32_t, UErrorCode *status) {
+ // 13 is the largest 4-byte gap we can use without getting 2 four-byte forms.
+ //initImplicitConstants(minPrimary, maxPrimary, 0x04, 0xFE, 1, 1, status);
+ initImplicitConstants(minImplicitPrimary, maxImplicitPrimary, 0x04, 0xFE, 1, 1, status);
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+ucol_cleanup(void)
+{
+ if (UCA_DATA_MEM) {
+ udata_close(UCA_DATA_MEM);
+ UCA_DATA_MEM = NULL;
+ }
+ if (_staticUCA) {
+ ucol_close(_staticUCA);
+ _staticUCA = NULL;
+ }
+ fcdTrieIndex = NULL;
+ return TRUE;
+}
+U_CDECL_END
+
+/* do not close UCA returned by ucol_initUCA! */
+UCollator *
+ucol_initUCA(UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+ UBool needsInit;
+ UMTX_CHECK(NULL, (_staticUCA == NULL), needsInit);
+
+ if(needsInit) {
+ UCollator *newUCA = NULL;
+ UDataMemory *result = udata_openChoice(NULL, UCA_DATA_TYPE, UCA_DATA_NAME, isAcceptableUCA, NULL, status);
+
+ if(U_FAILURE(*status)) {
+ if (result) {
+ udata_close(result);
+ }
+ uprv_free(newUCA);
+ }
+
+ // init FCD data
+ if (fcdTrieIndex == NULL) {
+ fcdTrieIndex = unorm_getFCDTrie(status);
+ ucln_i18n_registerCleanup(UCLN_I18N_UCOL, ucol_cleanup);
+ }
+
+ if(result != NULL) { /* It looks like sometimes we can fail to find the data file */
+ newUCA = ucol_initCollator((const UCATableHeader *)udata_getMemory(result), newUCA, newUCA, status);
+ if(U_SUCCESS(*status)){
+ umtx_lock(NULL);
+ if(_staticUCA == NULL) {
+ _staticUCA = newUCA;
+ UCA_DATA_MEM = result;
+ result = NULL;
+ newUCA = NULL;
+ }
+ umtx_unlock(NULL);
+
+ if(newUCA != NULL) {
+ udata_close(result);
+ uprv_free(newUCA);
+ }
+ else {
+ ucln_i18n_registerCleanup(UCLN_I18N_UCOL, ucol_cleanup);
+ }
+ // Initalize variables for implicit generation
+ const UCAConstants *UCAconsts = (UCAConstants *)((uint8_t *)_staticUCA->image + _staticUCA->image->UCAConsts);
+ uprv_uca_initImplicitConstants(UCAconsts->UCA_PRIMARY_IMPLICIT_MIN, UCAconsts->UCA_PRIMARY_IMPLICIT_MAX, status);
+ //_staticUCA->mapping.getFoldingOffset = _getFoldingOffset;
+ }else{
+ udata_close(result);
+ uprv_free(newUCA);
+ _staticUCA= NULL;
+ }
+ }
+ }
+ return _staticUCA;
+}
+
+
+/* collIterNormalize Incremental Normalization happens here. */
+/* pick up the range of chars identifed by FCD, */
+/* normalize it into the collIterate's writable buffer, */
+/* switch the collIterate's state to use the writable buffer. */
+/* */
+static
+void collIterNormalize(collIterate *collationSource)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ int32_t normLen;
+ UChar *srcP = collationSource->pos - 1; /* Start of chars to normalize */
+ UChar *endP = collationSource->fcdPosition; /* End of region to normalize+1 */
+
+ normLen = unorm_decompose(collationSource->writableBuffer, (int32_t)collationSource->writableBufSize,
+ srcP, (int32_t)(endP - srcP),
+ FALSE, 0,
+ &status);
+ if(status == U_BUFFER_OVERFLOW_ERROR || status == U_STRING_NOT_TERMINATED_WARNING) {
+ // reallocate and terminate
+ if(!u_growBufferFromStatic(collationSource->stackWritableBuffer,
+ &collationSource->writableBuffer,
+ (int32_t *)&collationSource->writableBufSize, normLen + 1,
+ 0)
+ ) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "collIterNormalize(), out of memory\n");
+#endif
+ return;
+ }
+ status = U_ZERO_ERROR;
+ normLen = unorm_decompose(collationSource->writableBuffer, (int32_t)collationSource->writableBufSize,
+ srcP, (int32_t)(endP - srcP),
+ FALSE, 0,
+ &status);
+ }
+ if (U_FAILURE(status)) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "collIterNormalize(), unorm_decompose() failed, status = %s\n", u_errorName(status));
+#endif
+ return;
+ }
+
+ if(collationSource->writableBuffer != collationSource->stackWritableBuffer) {
+ collationSource->flags |= UCOL_ITER_ALLOCATED;
+ }
+ collationSource->pos = collationSource->writableBuffer;
+ collationSource->origFlags = collationSource->flags;
+ collationSource->flags |= UCOL_ITER_INNORMBUF;
+ collationSource->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN | UCOL_USE_ITERATOR);
+}
+
+
+// This function takes the iterator and extracts normalized stuff up to the next boundary
+// It is similar in the end results to the collIterNormalize, but for the cases when we
+// use an iterator
+/*static
+inline void normalizeIterator(collIterate *collationSource) {
+ UErrorCode status = U_ZERO_ERROR;
+ UBool wasNormalized = FALSE;
+ //int32_t iterIndex = collationSource->iterator->getIndex(collationSource->iterator, UITER_CURRENT);
+ uint32_t iterIndex = collationSource->iterator->getState(collationSource->iterator);
+ int32_t normLen = unorm_next(collationSource->iterator, collationSource->writableBuffer,
+ (int32_t)collationSource->writableBufSize, UNORM_FCD, 0, TRUE, &wasNormalized, &status);
+ if(status == U_BUFFER_OVERFLOW_ERROR || normLen == (int32_t)collationSource->writableBufSize) {
+ // reallocate and terminate
+ if(!u_growBufferFromStatic(collationSource->stackWritableBuffer,
+ &collationSource->writableBuffer,
+ (int32_t *)&collationSource->writableBufSize, normLen + 1,
+ 0)
+ ) {
+ #ifdef UCOL_DEBUG
+ fprintf(stderr, "normalizeIterator(), out of memory\n");
+ #endif
+ return;
+ }
+ status = U_ZERO_ERROR;
+ //collationSource->iterator->move(collationSource->iterator, iterIndex, UITER_ZERO);
+ collationSource->iterator->setState(collationSource->iterator, iterIndex, &status);
+ normLen = unorm_next(collationSource->iterator, collationSource->writableBuffer,
+ (int32_t)collationSource->writableBufSize, UNORM_FCD, 0, TRUE, &wasNormalized, &status);
+ }
+ // Terminate the buffer - we already checked that it is big enough
+ collationSource->writableBuffer[normLen] = 0;
+ if(collationSource->writableBuffer != collationSource->stackWritableBuffer) {
+ collationSource->flags |= UCOL_ITER_ALLOCATED;
+ }
+ collationSource->pos = collationSource->writableBuffer;
+ collationSource->origFlags = collationSource->flags;
+ collationSource->flags |= UCOL_ITER_INNORMBUF;
+ collationSource->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN | UCOL_USE_ITERATOR);
+}*/
+
+
+/* Incremental FCD check and normalize */
+/* Called from getNextCE when normalization state is suspect. */
+/* When entering, the state is known to be this: */
+/* o We are working in the main buffer of the collIterate, not the side */
+/* writable buffer. When in the side buffer, normalization mode is always off, */
+/* so we won't get here. */
+/* o The leading combining class from the current character is 0 or */
+/* the trailing combining class of the previous char was zero. */
+/* True because the previous call to this function will have always exited */
+/* that way, and we get called for every char where cc might be non-zero. */
+static
+inline UBool collIterFCD(collIterate *collationSource) {
+ UChar c, c2;
+ const UChar *srcP, *endP;
+ uint8_t leadingCC;
+ uint8_t prevTrailingCC = 0;
+ uint16_t fcd;
+ UBool needNormalize = FALSE;
+
+ srcP = collationSource->pos-1;
+
+ if (collationSource->flags & UCOL_ITER_HASLEN) {
+ endP = collationSource->endp;
+ } else {
+ endP = NULL;
+ }
+
+ // Get the trailing combining class of the current character. If it's zero,
+ // we are OK.
+ c = *srcP++;
+ /* trie access */
+ fcd = unorm_getFCD16(fcdTrieIndex, c);
+ if (fcd != 0) {
+ if (U16_IS_LEAD(c)) {
+ if ((endP == NULL || srcP != endP) && U16_IS_TRAIL(c2=*srcP)) {
+ ++srcP;
+ fcd = unorm_getFCD16FromSurrogatePair(fcdTrieIndex, fcd, c2);
+ } else {
+ fcd = 0;
+ }
+ }
+
+ prevTrailingCC = (uint8_t)(fcd & LAST_BYTE_MASK_);
+
+ if (prevTrailingCC != 0) {
+ // The current char has a non-zero trailing CC. Scan forward until we find
+ // a char with a leading cc of zero.
+ while (endP == NULL || srcP != endP)
+ {
+ const UChar *savedSrcP = srcP;
+
+ c = *srcP++;
+ /* trie access */
+ fcd = unorm_getFCD16(fcdTrieIndex, c);
+ if (fcd != 0 && U16_IS_LEAD(c)) {
+ if ((endP == NULL || srcP != endP) && U16_IS_TRAIL(c2=*srcP)) {
+ ++srcP;
+ fcd = unorm_getFCD16FromSurrogatePair(fcdTrieIndex, fcd, c2);
+ } else {
+ fcd = 0;
+ }
+ }
+ leadingCC = (uint8_t)(fcd >> SECOND_LAST_BYTE_SHIFT_);
+ if (leadingCC == 0) {
+ srcP = savedSrcP; // Hit char that is not part of combining sequence.
+ // back up over it. (Could be surrogate pair!)
+ break;
+ }
+
+ if (leadingCC < prevTrailingCC) {
+ needNormalize = TRUE;
+ }
+
+ prevTrailingCC = (uint8_t)(fcd & LAST_BYTE_MASK_);
+ }
+ }
+ }
+
+ collationSource->fcdPosition = (UChar *)srcP;
+
+ return needNormalize;
+}
+
+/****************************************************************************/
+/* Following are the CE retrieval functions */
+/* */
+/****************************************************************************/
+
+static uint32_t getImplicit(UChar32 cp, collIterate *collationSource);
+static uint32_t getPrevImplicit(UChar32 cp, collIterate *collationSource);
+
+/* there should be a macro version of this function in the header file */
+/* This is the first function that tries to fetch a collation element */
+/* If it's not succesfull or it encounters a more difficult situation */
+/* some more sofisticated and slower functions are invoked */
+static
+inline uint32_t ucol_IGetNextCE(const UCollator *coll, collIterate *collationSource, UErrorCode *status) {
+ uint32_t order = 0;
+ if (collationSource->CEpos > collationSource->toReturn) { /* Are there any CEs from previous expansions? */
+ order = *(collationSource->toReturn++); /* if so, return them */
+ if(collationSource->CEpos == collationSource->toReturn) {
+ collationSource->CEpos = collationSource->toReturn = collationSource->CEs;
+ }
+ return order;
+ }
+
+ UChar ch = 0;
+
+ for (;;) /* Loop handles case when incremental normalize switches */
+ { /* to or from the side buffer / original string, and we */
+ /* need to start again to get the next character. */
+
+ if ((collationSource->flags & (UCOL_ITER_HASLEN | UCOL_ITER_INNORMBUF | UCOL_ITER_NORM | UCOL_HIRAGANA_Q | UCOL_USE_ITERATOR)) == 0)
+ {
+ // The source string is null terminated and we're not working from the side buffer,
+ // and we're not normalizing. This is the fast path.
+ // (We can be in the side buffer for Thai pre-vowel reordering even when not normalizing.)
+ ch = *collationSource->pos++;
+ if (ch != 0) {
+ break;
+ }
+ else {
+ return UCOL_NO_MORE_CES;
+ }
+ }
+
+ if (collationSource->flags & UCOL_ITER_HASLEN) {
+ // Normal path for strings when length is specified.
+ // (We can't be in side buffer because it is always null terminated.)
+ if (collationSource->pos >= collationSource->endp) {
+ // Ran off of the end of the main source string. We're done.
+ return UCOL_NO_MORE_CES;
+ }
+ ch = *collationSource->pos++;
+ }
+ else if(collationSource->flags & UCOL_USE_ITERATOR) {
+ UChar32 iterCh = collationSource->iterator->next(collationSource->iterator);
+ if(iterCh == U_SENTINEL) {
+ return UCOL_NO_MORE_CES;
+ }
+ ch = (UChar)iterCh;
+ }
+ else
+ {
+ // Null terminated string.
+ ch = *collationSource->pos++;
+ if (ch == 0) {
+ // Ran off end of buffer.
+ if ((collationSource->flags & UCOL_ITER_INNORMBUF) == 0) {
+ // Ran off end of main string. backing up one character.
+ collationSource->pos--;
+ return UCOL_NO_MORE_CES;
+ }
+ else
+ {
+ // Hit null in the normalize side buffer.
+ // Usually this means the end of the normalized data,
+ // except for one odd case: a null followed by combining chars,
+ // which is the case if we are at the start of the buffer.
+ if (collationSource->pos == collationSource->writableBuffer+1) {
+ break;
+ }
+
+ // Null marked end of side buffer.
+ // Revert to the main string and
+ // loop back to top to try again to get a character.
+ collationSource->pos = collationSource->fcdPosition;
+ collationSource->flags = collationSource->origFlags;
+ continue;
+ }
+ }
+ }
+
+ if(collationSource->flags&UCOL_HIRAGANA_Q) {
+ if((ch>=0x3040 && ch<=0x3094) || ch == 0x309d || ch == 0x309e) {
+ collationSource->flags |= UCOL_WAS_HIRAGANA;
+ } else {
+ collationSource->flags &= ~UCOL_WAS_HIRAGANA;
+ }
+ }
+
+ // We've got a character. See if there's any fcd and/or normalization stuff to do.
+ // Note that UCOL_ITER_NORM flag is always zero when we are in the side buffer.
+ if ((collationSource->flags & UCOL_ITER_NORM) == 0) {
+ break;
+ }
+
+ if (collationSource->fcdPosition >= collationSource->pos) {
+ // An earlier FCD check has already covered the current character.
+ // We can go ahead and process this char.
+ break;
+ }
+
+ if (ch < ZERO_CC_LIMIT_ ) {
+ // Fast fcd safe path. Trailing combining class == 0. This char is OK.
+ break;
+ }
+
+ if (ch < NFC_ZERO_CC_BLOCK_LIMIT_) {
+ // We need to peek at the next character in order to tell if we are FCD
+ if ((collationSource->flags & UCOL_ITER_HASLEN) && collationSource->pos >= collationSource->endp) {
+ // We are at the last char of source string.
+ // It is always OK for FCD check.
+ break;
+ }
+
+ // Not at last char of source string (or we'll check against terminating null). Do the FCD fast test
+ if (*collationSource->pos < NFC_ZERO_CC_BLOCK_LIMIT_) {
+ break;
+ }
+ }
+
+
+ // Need a more complete FCD check and possible normalization.
+ if (collIterFCD(collationSource)) {
+ collIterNormalize(collationSource);
+ }
+ if ((collationSource->flags & UCOL_ITER_INNORMBUF) == 0) {
+ // No normalization was needed. Go ahead and process the char we already had.
+ break;
+ }
+
+ // Some normalization happened. Next loop iteration will pick up a char
+ // from the normalization buffer.
+
+ } // end for (;;)
+
+
+ if (ch <= 0xFF) {
+ /* For latin-1 characters we never need to fall back to the UCA table */
+ /* because all of the UCA data is replicated in the latinOneMapping array */
+ order = coll->latinOneMapping[ch];
+ if (order > UCOL_NOT_FOUND) {
+ order = ucol_prv_getSpecialCE(coll, ch, order, collationSource, status);
+ }
+ }
+ else
+ {
+ order = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
+ if(order > UCOL_NOT_FOUND) { /* if a CE is special */
+ order = ucol_prv_getSpecialCE(coll, ch, order, collationSource, status); /* and try to get the special CE */
+ }
+ if(order == UCOL_NOT_FOUND && coll->UCA) { /* We couldn't find a good CE in the tailoring */
+ /* if we got here, the codepoint MUST be over 0xFF - so we look directly in the trie */
+ order = UTRIE_GET32_FROM_LEAD(&coll->UCA->mapping, ch);
+
+ if(order > UCOL_NOT_FOUND) { /* UCA also gives us a special CE */
+ order = ucol_prv_getSpecialCE(coll->UCA, ch, order, collationSource, status);
+ }
+ }
+ }
+ if(order == UCOL_NOT_FOUND) {
+ order = getImplicit(ch, collationSource);
+ }
+ return order; /* return the CE */
+}
+
+/* ucol_getNextCE, out-of-line version for use from other files. */
+U_CAPI uint32_t U_EXPORT2
+ucol_getNextCE(const UCollator *coll, collIterate *collationSource, UErrorCode *status) {
+ return ucol_IGetNextCE(coll, collationSource, status);
+}
+
+
+/**
+* Incremental previous normalization happens here. Pick up the range of chars
+* identifed by FCD, normalize it into the collIterate's writable buffer,
+* switch the collIterate's state to use the writable buffer.
+* @param data collation iterator data
+*/
+static
+void collPrevIterNormalize(collIterate *data)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UChar *pEnd = data->pos; /* End normalize + 1 */
+ UChar *pStart;
+ uint32_t normLen;
+ UChar *pStartNorm;
+
+ /* Start normalize */
+ if (data->fcdPosition == NULL) {
+ pStart = data->string;
+ }
+ else {
+ pStart = data->fcdPosition + 1;
+ }
+
+ normLen = unorm_normalize(pStart, (pEnd - pStart) + 1, UNORM_NFD, 0,
+ data->writableBuffer, 0, &status);
+
+ if (data->writableBufSize <= normLen) {
+ freeHeapWritableBuffer(data);
+ data->writableBuffer = (UChar *)uprv_malloc((normLen + 1) *
+ sizeof(UChar));
+ if(data->writableBuffer == NULL) { // something is wrong here, return
+ return;
+ }
+ data->flags |= UCOL_ITER_ALLOCATED;
+ /* to handle the zero termination */
+ data->writableBufSize = normLen + 1;
+ }
+ status = U_ZERO_ERROR;
+ /*
+ this puts the null termination infront of the normalized string instead
+ of the end
+ */
+ pStartNorm = data->writableBuffer + (data->writableBufSize - normLen);
+ *(pStartNorm - 1) = 0;
+ unorm_normalize(pStart, (pEnd - pStart) + 1, UNORM_NFD, 0, pStartNorm,
+ normLen, &status);
+
+ data->pos = data->writableBuffer + data->writableBufSize;
+ data->origFlags = data->flags;
+ data->flags |= UCOL_ITER_INNORMBUF;
+ data->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+}
+
+
+/**
+* Incremental FCD check for previous iteration and normalize. Called from
+* getPrevCE when normalization state is suspect.
+* When entering, the state is known to be this:
+* o We are working in the main buffer of the collIterate, not the side
+* writable buffer. When in the side buffer, normalization mode is always
+* off, so we won't get here.
+* o The leading combining class from the current character is 0 or the
+* trailing combining class of the previous char was zero.
+* True because the previous call to this function will have always exited
+* that way, and we get called for every char where cc might be non-zero.
+* @param data collation iterate struct
+* @return normalization status, TRUE for normalization to be done, FALSE
+* otherwise
+*/
+static
+inline UBool collPrevIterFCD(collIterate *data)
+{
+ const UChar *src, *start;
+ UChar c, c2;
+ uint8_t leadingCC;
+ uint8_t trailingCC = 0;
+ uint16_t fcd;
+ UBool result = FALSE;
+
+ start = data->string;
+ src = data->pos + 1;
+
+ /* Get the trailing combining class of the current character. */
+ c = *--src;
+ if (!U16_IS_SURROGATE(c)) {
+ fcd = unorm_getFCD16(fcdTrieIndex, c);
+ } else if (U16_IS_TRAIL(c) && start < src && U16_IS_LEAD(c2 = *(src - 1))) {
+ --src;
+ fcd = unorm_getFCD16(fcdTrieIndex, c2);
+ if (fcd != 0) {
+ fcd = unorm_getFCD16FromSurrogatePair(fcdTrieIndex, fcd, c);
+ }
+ } else /* unpaired surrogate */ {
+ fcd = 0;
+ }
+
+ leadingCC = (uint8_t)(fcd >> SECOND_LAST_BYTE_SHIFT_);
+
+ if (leadingCC != 0) {
+ /*
+ The current char has a non-zero leading combining class.
+ Scan backward until we find a char with a trailing cc of zero.
+ */
+ for (;;)
+ {
+ if (start == src) {
+ data->fcdPosition = NULL;
+ return result;
+ }
+
+ c = *--src;
+ if (!U16_IS_SURROGATE(c)) {
+ fcd = unorm_getFCD16(fcdTrieIndex, c);
+ } else if (U16_IS_TRAIL(c) && start < src && U16_IS_LEAD(c2 = *(src - 1))) {
+ --src;
+ fcd = unorm_getFCD16(fcdTrieIndex, c2);
+ if (fcd != 0) {
+ fcd = unorm_getFCD16FromSurrogatePair(fcdTrieIndex, fcd, c);
+ }
+ } else /* unpaired surrogate */ {
+ fcd = 0;
+ }
+
+ trailingCC = (uint8_t)(fcd & LAST_BYTE_MASK_);
+
+ if (trailingCC == 0) {
+ break;
+ }
+
+ if (leadingCC < trailingCC) {
+ result = TRUE;
+ }
+
+ leadingCC = (uint8_t)(fcd >> SECOND_LAST_BYTE_SHIFT_);
+ }
+ }
+
+ data->fcdPosition = (UChar *)src;
+
+ return result;
+}
+
+/** gets a character from the string at a given offset
+ * Handles both normal and iterative cases.
+ * No error checking - caller beware!
+ */
+inline static
+UChar peekCharacter(collIterate *source, int32_t offset) {
+ if(source->pos != NULL) {
+ return *(source->pos + offset);
+ } else if(source->iterator != NULL) {
+ if(offset != 0) {
+ source->iterator->move(source->iterator, offset, UITER_CURRENT);
+ UChar toReturn = (UChar)source->iterator->next(source->iterator);
+ source->iterator->move(source->iterator, -offset-1, UITER_CURRENT);
+ return toReturn;
+ } else {
+ return (UChar)source->iterator->current(source->iterator);
+ }
+ } else {
+ return (UChar)U_SENTINEL;
+ }
+}
+
+/**
+* Determines if we are at the start of the data string in the backwards
+* collation iterator
+* @param data collation iterator
+* @return TRUE if we are at the start
+*/
+static
+inline UBool isAtStartPrevIterate(collIterate *data) {
+ if(data->pos == NULL && data->iterator != NULL) {
+ return !data->iterator->hasPrevious(data->iterator);
+ }
+ //return (collIter_bos(data)) ||
+ return (data->pos == data->string) ||
+ ((data->flags & UCOL_ITER_INNORMBUF) &&
+ *(data->pos - 1) == 0 && data->fcdPosition == NULL);
+}
+
+static
+inline void goBackOne(collIterate *data) {
+# if 0
+ // somehow, it looks like we need to keep iterator synced up
+ // at all times, as above.
+ if(data->pos) {
+ data->pos--;
+ }
+ if(data->iterator) {
+ data->iterator->previous(data->iterator);
+ }
+#endif
+ if(data->iterator && (data->flags & UCOL_USE_ITERATOR)) {
+ data->iterator->previous(data->iterator);
+ }
+ if(data->pos) {
+ data->pos --;
+ }
+}
+
+/**
+* Inline function that gets a simple CE.
+* So what it does is that it will first check the expansion buffer. If the
+* expansion buffer is not empty, ie the end pointer to the expansion buffer
+* is different from the string pointer, we return the collation element at the
+* return pointer and decrement it.
+* For more complicated CEs it resorts to getComplicatedCE.
+* @param coll collator data
+* @param data collation iterator struct
+* @param status error status
+*/
+static
+inline uint32_t ucol_IGetPrevCE(const UCollator *coll, collIterate *data,
+ UErrorCode *status)
+{
+ uint32_t result = (uint32_t)UCOL_NULLORDER;
+ if (data->toReturn > data->CEs) {
+ data->toReturn --;
+ result = *(data->toReturn);
+ if (data->CEs == data->toReturn) {
+ data->CEpos = data->toReturn;
+ }
+ }
+ else {
+ UChar ch = 0;
+ /*
+ Loop handles case when incremental normalize switches to or from the
+ side buffer / original string, and we need to start again to get the
+ next character.
+ */
+ for (;;) {
+ if (data->flags & UCOL_ITER_HASLEN) {
+ /*
+ Normal path for strings when length is specified.
+ Not in side buffer because it is always null terminated.
+ */
+ if (data->pos <= data->string) {
+ /* End of the main source string */
+ return UCOL_NO_MORE_CES;
+ }
+ data->pos --;
+ ch = *data->pos;
+ }
+ // we are using an iterator to go back. Pray for us!
+ else if (data->flags & UCOL_USE_ITERATOR) {
+ UChar32 iterCh = data->iterator->previous(data->iterator);
+ if(iterCh == U_SENTINEL) {
+ return UCOL_NO_MORE_CES;
+ } else {
+ ch = (UChar)iterCh;
+ }
+ }
+ else {
+ data->pos --;
+ ch = *data->pos;
+ /* we are in the side buffer. */
+ if (ch == 0) {
+ /*
+ At the start of the normalize side buffer.
+ Go back to string.
+ Because pointer points to the last accessed character,
+ hence we have to increment it by one here.
+ */
+ if (data->fcdPosition == NULL) {
+ data->pos = data->string;
+ return UCOL_NO_MORE_CES;
+ }
+ else {
+ data->pos = data->fcdPosition + 1;
+ }
+ data->flags = data->origFlags;
+ continue;
+ }
+ }
+
+ if(data->flags&UCOL_HIRAGANA_Q) {
+ if(ch>=0x3040 && ch<=0x309f) {
+ data->flags |= UCOL_WAS_HIRAGANA;
+ } else {
+ data->flags &= ~UCOL_WAS_HIRAGANA;
+ }
+ }
+
+ /*
+ * got a character to determine if there's fcd and/or normalization
+ * stuff to do.
+ * if the current character is not fcd.
+ * if current character is at the start of the string
+ * Trailing combining class == 0.
+ * Note if pos is in the writablebuffer, norm is always 0
+ */
+ if (ch < ZERO_CC_LIMIT_ ||
+ // this should propel us out of the loop in the iterator case
+ (data->flags & UCOL_ITER_NORM) == 0 ||
+ (data->fcdPosition != NULL && data->fcdPosition <= data->pos)
+ || data->string == data->pos) {
+ break;
+ }
+
+ if (ch < NFC_ZERO_CC_BLOCK_LIMIT_) {
+ /* if next character is FCD */
+ if (data->pos == data->string) {
+ /* First char of string is always OK for FCD check */
+ break;
+ }
+
+ /* Not first char of string, do the FCD fast test */
+ if (*(data->pos - 1) < NFC_ZERO_CC_BLOCK_LIMIT_) {
+ break;
+ }
+ }
+
+ /* Need a more complete FCD check and possible normalization. */
+ if (collPrevIterFCD(data)) {
+ collPrevIterNormalize(data);
+ }
+
+ if ((data->flags & UCOL_ITER_INNORMBUF) == 0) {
+ /* No normalization. Go ahead and process the char. */
+ break;
+ }
+
+ /*
+ Some normalization happened.
+ Next loop picks up a char from the normalization buffer.
+ */
+ }
+
+ /* attempt to handle contractions, after removal of the backwards
+ contraction
+ */
+ if (ucol_contractionEndCP(ch, coll) && !isAtStartPrevIterate(data)) {
+ result = ucol_prv_getSpecialPrevCE(coll, ch, UCOL_CONTRACTION, data, status);
+ } else {
+ if (ch <= 0xFF) {
+ result = coll->latinOneMapping[ch];
+ }
+ else {
+ result = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
+ }
+ if (result > UCOL_NOT_FOUND) {
+ result = ucol_prv_getSpecialPrevCE(coll, ch, result, data, status);
+ }
+ if (result == UCOL_NOT_FOUND) { // Not found in master list
+ if (!isAtStartPrevIterate(data) &&
+ ucol_contractionEndCP(ch, data->coll)) {
+ result = UCOL_CONTRACTION;
+ } else {
+ if(coll->UCA) {
+ result = UTRIE_GET32_FROM_LEAD(&coll->UCA->mapping, ch);
+ }
+ }
+
+ if (result > UCOL_NOT_FOUND) {
+ if(coll->UCA) {
+ result = ucol_prv_getSpecialPrevCE(coll->UCA, ch, result, data, status);
+ }
+ }
+ }
+ }
+ if(result == UCOL_NOT_FOUND) {
+ result = getPrevImplicit(ch, data);
+ }
+ }
+ return result;
+}
+
+
+/* ucol_getPrevCE, out-of-line version for use from other files. */
+U_CFUNC uint32_t U_EXPORT2
+ucol_getPrevCE(const UCollator *coll, collIterate *data,
+ UErrorCode *status) {
+ return ucol_IGetPrevCE(coll, data, status);
+}
+
+
+/* this should be connected to special Jamo handling */
+U_CFUNC uint32_t U_EXPORT2
+ucol_getFirstCE(const UCollator *coll, UChar u, UErrorCode *status) {
+ collIterate colIt;
+ uint32_t order;
+ IInit_collIterate(coll, &u, 1, &colIt);
+ order = ucol_IGetNextCE(coll, &colIt, status);
+ /*UCOL_GETNEXTCE(order, coll, colIt, status);*/
+ return order;
+}
+
+/**
+* Inserts the argument character into the end of the buffer pushing back the
+* null terminator.
+* @param data collIterate struct data
+* @param pNull pointer to the null termination
+* @param ch character to be appended
+* @return the position of the new addition
+*/
+static
+inline UChar * insertBufferEnd(collIterate *data, UChar *pNull, UChar ch)
+{
+ uint32_t size = data->writableBufSize;
+ UChar *newbuffer;
+ const uint32_t incsize = 5;
+
+ if ((data->writableBuffer + size) > (pNull + 1)) {
+ *pNull = ch;
+ *(pNull + 1) = 0;
+ return pNull;
+ }
+
+ /*
+ buffer will always be null terminated at the end.
+ giving extra space since it is likely that more characters will be added.
+ */
+ size += incsize;
+ newbuffer = (UChar *)uprv_malloc(sizeof(UChar) * size);
+ if(newbuffer != NULL) { // something wrong, but no status
+ uprv_memcpy(newbuffer, data->writableBuffer,
+ data->writableBufSize * sizeof(UChar));
+
+ freeHeapWritableBuffer(data);
+ data->writableBufSize = size;
+ data->writableBuffer = newbuffer;
+
+ newbuffer = newbuffer + data->writableBufSize;
+ *newbuffer = ch;
+ *(newbuffer + 1) = 0;
+ }
+ return newbuffer;
+}
+
+/**
+* Inserts the argument string into the end of the buffer pushing back the
+* null terminator.
+* @param data collIterate struct data
+* @param pNull pointer to the null termination
+* @param string to be appended
+* @param length of the string to be appended
+* @return the position of the new addition
+*/
+static
+inline UChar * insertBufferEnd(collIterate *data, UChar *pNull, UChar *str,
+ int32_t length)
+{
+ uint32_t size = pNull - data->writableBuffer;
+ UChar *newbuffer;
+
+ if (data->writableBuffer + data->writableBufSize > pNull + length + 1) {
+ uprv_memcpy(pNull, str, length * sizeof(UChar));
+ *(pNull + length) = 0;
+ return pNull;
+ }
+
+ /*
+ buffer will always be null terminated at the end.
+ giving extra space since it is likely that more characters will be added.
+ */
+ newbuffer = (UChar *)uprv_malloc(sizeof(UChar) * (size + length + 1));
+ if(newbuffer != NULL) {
+ uprv_memcpy(newbuffer, data->writableBuffer, size * sizeof(UChar));
+ uprv_memcpy(newbuffer + size, str, length * sizeof(UChar));
+
+ freeHeapWritableBuffer(data);
+ data->writableBufSize = size + length + 1;
+ data->writableBuffer = newbuffer;
+ }
+
+ return newbuffer;
+}
+
+/**
+* Special normalization function for contraction in the forwards iterator.
+* This normalization sequence will place the current character at source->pos
+* and its following normalized sequence into the buffer.
+* The fcd position, pos will be changed.
+* pos will now point to positions in the buffer.
+* Flags will be changed accordingly.
+* @param data collation iterator data
+*/
+static
+inline void normalizeNextContraction(collIterate *data)
+{
+ UChar *buffer = data->writableBuffer;
+ uint32_t buffersize = data->writableBufSize;
+ uint32_t strsize;
+ UErrorCode status = U_ZERO_ERROR;
+ /* because the pointer points to the next character */
+ UChar *pStart = data->pos - 1;
+ UChar *pEnd;
+ uint32_t normLen;
+ UChar *pStartNorm;
+
+ if ((data->flags & UCOL_ITER_INNORMBUF) == 0) {
+ *data->writableBuffer = *(pStart - 1);
+ strsize = 1;
+ }
+ else {
+ strsize = u_strlen(data->writableBuffer);
+ }
+
+ pEnd = data->fcdPosition;
+
+ normLen = unorm_normalize(pStart, pEnd - pStart, UNORM_NFD, 0, buffer, 0,
+ &status);
+
+ if (buffersize <= normLen + strsize) {
+ uint32_t size = strsize + normLen + 1;
+ UChar *temp = (UChar *)uprv_malloc(size * sizeof(UChar));
+ if(temp != NULL) {
+ uprv_memcpy(temp, buffer, sizeof(UChar) * strsize);
+ freeHeapWritableBuffer(data);
+ data->writableBuffer = temp;
+ data->writableBufSize = size;
+ data->flags |= UCOL_ITER_ALLOCATED;
+ }
+ }
+
+ status = U_ZERO_ERROR;
+ pStartNorm = buffer + strsize;
+ /* null-termination will be added here */
+ unorm_normalize(pStart, pEnd - pStart, UNORM_NFD, 0, pStartNorm,
+ normLen + 1, &status);
+
+ data->pos = data->writableBuffer + strsize;
+ data->origFlags = data->flags;
+ data->flags |= UCOL_ITER_INNORMBUF;
+ data->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+}
+
+/**
+* Contraction character management function that returns the next character
+* for the forwards iterator.
+* Does nothing if the next character is in buffer and not the first character
+* in it.
+* Else it checks next character in data string to see if it is normalizable.
+* If it is not, the character is simply copied into the buffer, else
+* the whole normalized substring is copied into the buffer, including the
+* current character.
+* @param data collation element iterator data
+* @return next character
+*/
+static
+inline UChar getNextNormalizedChar(collIterate *data)
+{
+ UChar nextch;
+ UChar ch;
+ // Here we need to add the iterator code. One problem is the way
+ // end of string is handled. If we just return next char, it could
+ // be the sentinel. Most of the cases already check for this, but we
+ // need to be sure.
+ if ((data->flags & (UCOL_ITER_NORM | UCOL_ITER_INNORMBUF)) == 0 ) {
+ /* if no normalization and not in buffer. */
+ if(data->flags & UCOL_USE_ITERATOR) {
+ return (UChar)data->iterator->next(data->iterator);
+ } else {
+ return *(data->pos ++);
+ }
+ }
+
+ //if (data->flags & UCOL_ITER_NORM && data->flags & UCOL_USE_ITERATOR) {
+ //normalizeIterator(data);
+ //}
+
+ UChar *pEndWritableBuffer = NULL;
+ UBool innormbuf = (UBool)(data->flags & UCOL_ITER_INNORMBUF);
+ if ((innormbuf && *data->pos != 0) ||
+ (data->fcdPosition != NULL && !innormbuf &&
+ data->pos < data->fcdPosition)) {
+ /*
+ if next character is in normalized buffer, no further normalization
+ is required
+ */
+ return *(data->pos ++);
+ }
+
+ if (data->flags & UCOL_ITER_HASLEN) {
+ /* in data string */
+ if (data->pos + 1 == data->endp) {
+ return *(data->pos ++);
+ }
+ }
+ else {
+ if (innormbuf) {
+ // inside the normalization buffer, but at the end
+ // (since we encountered zero). This means, in the
+ // case we're using char iterator, that we need to
+ // do another round of normalization.
+ //if(data->origFlags & UCOL_USE_ITERATOR) {
+ // we need to restore original flags,
+ // otherwise, we'll lose them
+ //data->flags = data->origFlags;
+ //normalizeIterator(data);
+ //return *(data->pos++);
+ //} else {
+ /*
+ in writable buffer, at this point fcdPosition can not be
+ pointing to the end of the data string. see contracting tag.
+ */
+ if(data->fcdPosition) {
+ if (*(data->fcdPosition + 1) == 0 ||
+ data->fcdPosition + 1 == data->endp) {
+ /* at the end of the string, dump it into the normalizer */
+ data->pos = insertBufferEnd(data, data->pos,
+ *(data->fcdPosition)) + 1;
+ return *(data->fcdPosition ++);
+ }
+ pEndWritableBuffer = data->pos;
+ data->pos = data->fcdPosition;
+ } else if(data->origFlags & UCOL_USE_ITERATOR) {
+ // if we are here, we're using a normalizing iterator.
+ // we should just continue further.
+ data->flags = data->origFlags;
+ data->pos = NULL;
+ return (UChar)data->iterator->next(data->iterator);
+ }
+ //}
+ }
+ else {
+ if (*(data->pos + 1) == 0) {
+ return *(data->pos ++);
+ }
+ }
+ }
+
+ ch = *data->pos ++;
+ nextch = *data->pos;
+
+ /*
+ * if the current character is not fcd.
+ * Trailing combining class == 0.
+ */
+ if ((data->fcdPosition == NULL || data->fcdPosition < data->pos) &&
+ (nextch >= NFC_ZERO_CC_BLOCK_LIMIT_ ||
+ ch >= NFC_ZERO_CC_BLOCK_LIMIT_)) {
+ /*
+ Need a more complete FCD check and possible normalization.
+ normalize substring will be appended to buffer
+ */
+ if (collIterFCD(data)) {
+ normalizeNextContraction(data);
+ return *(data->pos ++);
+ }
+ else if (innormbuf) {
+ /* fcdposition shifted even when there's no normalization, if we
+ don't input the rest into this, we'll get the wrong position when
+ we reach the end of the writableBuffer */
+ int32_t length = data->fcdPosition - data->pos + 1;
+ data->pos = insertBufferEnd(data, pEndWritableBuffer,
+ data->pos - 1, length);
+ return *(data->pos ++);
+ }
+ }
+
+ if (innormbuf) {
+ /*
+ no normalization is to be done hence only one character will be
+ appended to the buffer.
+ */
+ data->pos = insertBufferEnd(data, pEndWritableBuffer, ch) + 1;
+ }
+
+ /* points back to the pos in string */
+ return ch;
+}
+
+
+
+/**
+* Function to copy the buffer into writableBuffer and sets the fcd position to
+* the correct position
+* @param source data string source
+* @param buffer character buffer
+* @param tempdb current position in buffer that has been used up
+*/
+static
+inline void setDiscontiguosAttribute(collIterate *source, UChar *buffer,
+ UChar *tempdb)
+{
+ /* okay confusing part here. to ensure that the skipped characters are
+ considered later, we need to place it in the appropriate position in the
+ normalization buffer and reassign the pos pointer. simple case if pos
+ reside in string, simply copy to normalization buffer and
+ fcdposition = pos, pos = start of normalization buffer. if pos in
+ normalization buffer, we'll insert the copy infront of pos and point pos
+ to the start of the normalization buffer. why am i doing these copies?
+ well, so that the whole chunk of codes in the getNextCE, ucol_prv_getSpecialCE does
+ not require any changes, which be really painful. */
+ uint32_t length = u_strlen(buffer);;
+ if (source->flags & UCOL_ITER_INNORMBUF) {
+ u_strcpy(tempdb, source->pos);
+ }
+ else {
+ source->fcdPosition = source->pos;
+ source->origFlags = source->flags;
+ source->flags |= UCOL_ITER_INNORMBUF;
+ source->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN | UCOL_USE_ITERATOR);
+ }
+
+ if (length >= source->writableBufSize) {
+ freeHeapWritableBuffer(source);
+ source->writableBuffer =
+ (UChar *)uprv_malloc((length + 1) * sizeof(UChar));
+ if(source->writableBuffer == NULL) {
+ return;
+ }
+ source->writableBufSize = length;
+ }
+
+ u_strcpy(source->writableBuffer, buffer);
+ source->pos = source->writableBuffer;
+}
+
+/**
+* Function to get the discontiguos collation element within the source.
+* Note this function will set the position to the appropriate places.
+* @param coll current collator used
+* @param source data string source
+* @param constart index to the start character in the contraction table
+* @return discontiguos collation element offset
+*/
+static
+uint32_t getDiscontiguous(const UCollator *coll, collIterate *source,
+ const UChar *constart)
+{
+ /* source->pos currently points to the second combining character after
+ the start character */
+ UChar *temppos = source->pos;
+ UChar buffer[4*UCOL_MAX_BUFFER];
+ UChar *tempdb = buffer;
+ const UChar *tempconstart = constart;
+ uint8_t tempflags = source->flags;
+ UBool multicontraction = FALSE;
+ UChar *tempbufferpos = 0;
+ collIterateState discState;
+
+ backupState(source, &discState);
+
+ //*tempdb = *(source->pos - 1);
+ *tempdb = peekCharacter(source, -1);
+ tempdb++;
+ for (;;) {
+ UChar *UCharOffset;
+ UChar schar,
+ tchar;
+ uint32_t result;
+
+ if (((source->flags & UCOL_ITER_HASLEN) && source->pos >= source->endp)
+ || (peekCharacter(source, 0) == 0 &&
+ //|| (*source->pos == 0 &&
+ ((source->flags & UCOL_ITER_INNORMBUF) == 0 ||
+ source->fcdPosition == NULL ||
+ source->fcdPosition == source->endp ||
+ *(source->fcdPosition) == 0 ||
+ u_getCombiningClass(*(source->fcdPosition)) == 0)) ||
+ /* end of string in null terminated string or stopped by a
+ null character, note fcd does not always point to a base
+ character after the discontiguos change */
+ u_getCombiningClass(peekCharacter(source, 0)) == 0) {
+ //u_getCombiningClass(*(source->pos)) == 0) {
+ //constart = (UChar *)coll->image + getContractOffset(CE);
+ if (multicontraction) {
+ *tempbufferpos = 0;
+ source->pos = temppos - 1;
+ setDiscontiguosAttribute(source, buffer, tempdb);
+ return *(coll->contractionCEs +
+ (tempconstart - coll->contractionIndex));
+ }
+ constart = tempconstart;
+ break;
+ }
+
+ UCharOffset = (UChar *)(tempconstart + 1); /* skip the backward offset*/
+ schar = getNextNormalizedChar(source);
+
+ while (schar > (tchar = *UCharOffset)) {
+ UCharOffset++;
+ }
+
+ if (schar != tchar) {
+ /* not the correct codepoint. we stuff the current codepoint into
+ the discontiguos buffer and try the next character */
+ *tempdb = schar;
+ tempdb ++;
+ continue;
+ }
+ else {
+ if (u_getCombiningClass(schar) ==
+ u_getCombiningClass(peekCharacter(source, -2))) {
+ //u_getCombiningClass(*(source->pos - 2))) {
+ *tempdb = schar;
+ tempdb ++;
+ continue;
+ }
+ result = *(coll->contractionCEs +
+ (UCharOffset - coll->contractionIndex));
+ }
+ *tempdb = 0;
+
+ if (result == UCOL_NOT_FOUND) {
+ break;
+ } else if (isContraction(result)) {
+ /* this is a multi-contraction*/
+ tempconstart = (UChar *)coll->image + getContractOffset(result);
+ if (*(coll->contractionCEs + (constart - coll->contractionIndex))
+ != UCOL_NOT_FOUND) {
+ multicontraction = TRUE;
+ temppos = source->pos + 1;
+ tempbufferpos = buffer + u_strlen(buffer);
+ }
+ } else {
+ setDiscontiguosAttribute(source, buffer, tempdb);
+ return result;
+ }
+ }
+
+ /* no problems simply reverting just like that,
+ if we are in string before getting into this function, points back to
+ string hence no problem.
+ if we are in normalization buffer before getting into this function,
+ since we'll never use another normalization within this function, we
+ know that fcdposition points to a base character. the normalization buffer
+ never change, hence this revert works. */
+ loadState(source, &discState, TRUE);
+ goBackOne(source);
+
+ //source->pos = temppos - 1;
+ source->flags = tempflags;
+ return *(coll->contractionCEs + (constart - coll->contractionIndex));
+}
+
+static
+inline UBool isNonChar(UChar32 cp) {
+ if ((cp & 0xFFFE) == 0xFFFE || (0xFDD0 <= cp && cp <= 0xFDEF) || (0xD800 <= cp && cp <= 0xDFFF)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* now uses Mark's getImplicitPrimary code */
+static
+inline uint32_t getImplicit(UChar32 cp, collIterate *collationSource) {
+ if(isNonChar(cp)) {
+ return 0;
+ }
+ uint32_t r = uprv_uca_getImplicitPrimary(cp);
+ *(collationSource->CEpos++) = ((r & 0x0000FFFF)<<16) | 0x000000C0;
+ return (r & UCOL_PRIMARYMASK) | 0x00000505; // This was 'order'
+}
+
+/**
+* Inserts the argument character into the front of the buffer replacing the
+* front null terminator.
+* @param data collation element iterator data
+* @param pNull pointer to the null terminator
+* @param ch character to be appended
+* @return positon of added character
+*/
+static
+inline UChar * insertBufferFront(collIterate *data, UChar *pNull, UChar ch)
+{
+ uint32_t size = data->writableBufSize;
+ UChar *end;
+ UChar *newbuffer;
+ const uint32_t incsize = 5;
+
+ if (pNull > data->writableBuffer + 1) {
+ *pNull = ch;
+ *(pNull - 1) = 0;
+ return pNull;
+ }
+
+ /*
+ buffer will always be null terminated infront.
+ giving extra space since it is likely that more characters will be added.
+ */
+ size += incsize;
+ newbuffer = (UChar *)uprv_malloc(sizeof(UChar) * size);
+ if(newbuffer == NULL) {
+ return NULL;
+ }
+ end = newbuffer + incsize;
+ uprv_memcpy(end, data->writableBuffer,
+ data->writableBufSize * sizeof(UChar));
+ *end = ch;
+ *(end - 1) = 0;
+
+ freeHeapWritableBuffer(data);
+
+ data->writableBufSize = size;
+ data->writableBuffer = newbuffer;
+ return end;
+}
+
+/**
+* Special normalization function for contraction in the previous iterator.
+* This normalization sequence will place the current character at source->pos
+* and its following normalized sequence into the buffer.
+* The fcd position, pos will be changed.
+* pos will now point to positions in the buffer.
+* Flags will be changed accordingly.
+* @param data collation iterator data
+*/
+static
+inline void normalizePrevContraction(collIterate *data, UErrorCode *status)
+{
+ UChar *buffer = data->writableBuffer;
+ uint32_t buffersize = data->writableBufSize;
+ uint32_t nulltermsize;
+ UErrorCode localstatus = U_ZERO_ERROR;
+ UChar *pEnd = data->pos + 1; /* End normalize + 1 */
+ UChar *pStart;
+ uint32_t normLen;
+ UChar *pStartNorm;
+
+ if (data->flags & UCOL_ITER_HASLEN) {
+ /*
+ normalization buffer not used yet, we'll pull down the next
+ character into the end of the buffer
+ */
+ *(buffer + (buffersize - 1)) = *(data->pos + 1);
+ nulltermsize = buffersize - 1;
+ }
+ else {
+ nulltermsize = buffersize;
+ UChar *temp = buffer + (nulltermsize - 1);
+ while (*(temp --) != 0) {
+ nulltermsize --;
+ }
+ }
+
+ /* Start normalize */
+ if (data->fcdPosition == NULL) {
+ pStart = data->string;
+ }
+ else {
+ pStart = data->fcdPosition + 1;
+ }
+
+ normLen = unorm_normalize(pStart, pEnd - pStart, UNORM_NFD, 0, buffer, 0,
+ &localstatus);
+
+ if (nulltermsize <= normLen) {
+ uint32_t size = buffersize - nulltermsize + normLen + 1;
+ UChar *temp = (UChar *)uprv_malloc(size * sizeof(UChar));
+ if (temp == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ nulltermsize = normLen + 1;
+ uprv_memcpy(temp + normLen, buffer,
+ sizeof(UChar) * (buffersize - nulltermsize));
+ freeHeapWritableBuffer(data);
+ data->writableBuffer = temp;
+ data->writableBufSize = size;
+ }
+
+ /*
+ this puts the null termination infront of the normalized string instead
+ of the end
+ */
+ pStartNorm = buffer + (nulltermsize - normLen);
+ *(pStartNorm - 1) = 0;
+ unorm_normalize(pStart, pEnd - pStart, UNORM_NFD, 0, pStartNorm, normLen,
+ status);
+
+ data->pos = data->writableBuffer + nulltermsize;
+ data->origFlags = data->flags;
+ data->flags |= UCOL_ITER_INNORMBUF;
+ data->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+}
+
+/**
+* Contraction character management function that returns the previous character
+* for the backwards iterator.
+* Does nothing if the previous character is in buffer and not the first
+* character in it.
+* Else it checks previous character in data string to see if it is
+* normalizable.
+* If it is not, the character is simply copied into the buffer, else
+* the whole normalized substring is copied into the buffer, including the
+* current character.
+* @param data collation element iterator data
+* @return previous character
+*/
+static
+inline UChar getPrevNormalizedChar(collIterate *data, UErrorCode *status)
+{
+ UChar prevch;
+ UChar ch;
+ UChar *start;
+ UBool innormbuf = (UBool)(data->flags & UCOL_ITER_INNORMBUF);
+ UChar *pNull = NULL;
+ if ((data->flags & (UCOL_ITER_NORM | UCOL_ITER_INNORMBUF)) == 0 ||
+ (innormbuf && *(data->pos - 1) != 0)) {
+ /*
+ if no normalization.
+ if previous character is in normalized buffer, no further normalization
+ is required
+ */
+ if(data->flags & UCOL_USE_ITERATOR) {
+ data->iterator->move(data->iterator, -1, UITER_CURRENT);
+ return (UChar)data->iterator->next(data->iterator);
+ } else {
+ return *(data->pos - 1);
+ }
+ }
+
+ start = data->pos;
+ if (data->flags & UCOL_ITER_HASLEN) {
+ /* in data string */
+ if ((start - 1) == data->string) {
+ return *(start - 1);
+ }
+ start --;
+ ch = *start;
+ prevch = *(start - 1);
+ }
+ else {
+ /*
+ in writable buffer, at this point fcdPosition can not be NULL.
+ see contracting tag.
+ */
+ if (data->fcdPosition == data->string) {
+ /* at the start of the string, just dump it into the normalizer */
+ insertBufferFront(data, data->pos - 1, *(data->fcdPosition));
+ data->fcdPosition = NULL;
+ return *(data->pos - 1);
+ }
+ pNull = data->pos - 1;
+ start = data->fcdPosition;
+ ch = *start;
+ prevch = *(start - 1);
+ }
+ /*
+ * if the current character is not fcd.
+ * Trailing combining class == 0.
+ */
+ if (data->fcdPosition > start &&
+ (ch >= NFC_ZERO_CC_BLOCK_LIMIT_ || prevch >= NFC_ZERO_CC_BLOCK_LIMIT_))
+ {
+ /*
+ Need a more complete FCD check and possible normalization.
+ normalize substring will be appended to buffer
+ */
+ UChar *backuppos = data->pos;
+ data->pos = start;
+ if (collPrevIterFCD(data)) {
+ normalizePrevContraction(data, status);
+ return *(data->pos - 1);
+ }
+ data->pos = backuppos;
+ data->fcdPosition ++;
+ }
+
+ if (innormbuf) {
+ /*
+ no normalization is to be done hence only one character will be
+ appended to the buffer.
+ */
+ insertBufferFront(data, pNull, ch);
+ data->fcdPosition --;
+ }
+
+ return ch;
+}
+
+/* This function handles the special CEs like contractions, expansions, surrogates, Thai */
+/* It is called by getNextCE */
+
+uint32_t ucol_prv_getSpecialCE(const UCollator *coll, UChar ch, uint32_t CE, collIterate *source, UErrorCode *status) {
+ collIterateState entryState;
+ backupState(source, &entryState);
+ UChar32 cp = ch;
+
+ for (;;) {
+ // This loop will repeat only in the case of contractions, and only when a contraction
+ // is found and the first CE resulting from that contraction is itself a special
+ // (an expansion, for example.) All other special CE types are fully handled the
+ // first time through, and the loop exits.
+
+ const uint32_t *CEOffset = NULL;
+ switch(getCETag(CE)) {
+ case NOT_FOUND_TAG:
+ /* This one is not found, and we'll let somebody else bother about it... no more games */
+ return CE;
+ case SURROGATE_TAG:
+ /* we encountered a leading surrogate. We shall get the CE by using the following code unit */
+ /* two things can happen here: next code point can be a trailing surrogate - we will use it */
+ /* to retrieve the CE, or it is not a trailing surrogate (or the string is done). In that case */
+ /* we return 0 (completely ignorable - per UCA specification */
+ {
+ UChar trail;
+ collIterateState state;
+ backupState(source, &state);
+ if (collIter_eos(source) || !(U16_IS_TRAIL((trail = getNextNormalizedChar(source))))) {
+ // we chould have stepped one char forward and it might have turned that it
+ // was not a trail surrogate. In that case, we have to backup.
+ loadState(source, &state, TRUE);
+ return 0;
+ } else {
+ /* TODO: CE contain the data from the previous CE + the mask. It should at least be unmasked */
+ CE = UTRIE_GET32_FROM_OFFSET_TRAIL(&coll->mapping, CE&0xFFFFFF, trail);
+ if(CE == UCOL_NOT_FOUND) { // there are tailored surrogates in this block, but not this one.
+ // We need to backup
+ loadState(source, &state, TRUE);
+ return CE;
+ }
+ // calculate the supplementary code point value, if surrogate was not tailored
+ cp = ((((uint32_t)ch)<<10UL)+(trail)-(((uint32_t)0xd800<<10UL)+0xdc00-0x10000));
+ }
+ }
+ break;
+ case SPEC_PROC_TAG:
+ {
+ // Special processing is getting a CE that is preceded by a certain prefix
+ // Currently this is only needed for optimizing Japanese length and iteration marks.
+ // When we encouter a special processing tag, we go backwards and try to see if
+ // we have a match.
+ // Contraction tables are used - so the whole process is not unlike contraction.
+ // prefix data is stored backwards in the table.
+ const UChar *UCharOffset;
+ UChar schar, tchar;
+ collIterateState prefixState;
+ backupState(source, &prefixState);
+ loadState(source, &entryState, TRUE);
+ goBackOne(source); // We want to look at the point where we entered - actually one
+ // before that...
+
+ for(;;) {
+ // This loop will run once per source string character, for as long as we
+ // are matching a potential contraction sequence
+
+ // First we position ourselves at the begining of contraction sequence
+ const UChar *ContractionStart = UCharOffset = (UChar *)coll->image+getContractOffset(CE);
+ if (collIter_bos(source)) {
+ CE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
+ break;
+ }
+ schar = getPrevNormalizedChar(source, status);
+ goBackOne(source);
+
+ while(schar > (tchar = *UCharOffset)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
+ UCharOffset++;
+ }
+
+ if (schar == tchar) {
+ // Found the source string char in the table.
+ // Pick up the corresponding CE from the table.
+ CE = *(coll->contractionCEs +
+ (UCharOffset - coll->contractionIndex));
+ }
+ else
+ {
+ // Source string char was not in the table.
+ // We have not found the prefix.
+ CE = *(coll->contractionCEs +
+ (ContractionStart - coll->contractionIndex));
+ }
+
+ if(!isPrefix(CE)) {
+ // The source string char was in the contraction table, and the corresponding
+ // CE is not a prefix CE. We found the prefix, break
+ // out of loop, this CE will end up being returned. This is the normal
+ // way out of prefix handling when the source actually contained
+ // the prefix.
+ break;
+ }
+ }
+ if(CE != UCOL_NOT_FOUND) { // we found something and we can merilly continue
+ loadState(source, &prefixState, TRUE);
+ if(source->origFlags & UCOL_USE_ITERATOR) {
+ source->flags = source->origFlags;
+ }
+ } else { // prefix search was a failure, we have to backup all the way to the start
+ loadState(source, &entryState, TRUE);
+ }
+ break;
+ }
+ case CONTRACTION_TAG:
+ {
+ /* This should handle contractions */
+ collIterateState state;
+ backupState(source, &state);
+ uint32_t firstCE = *(coll->contractionCEs + ((UChar *)coll->image+getContractOffset(CE) - coll->contractionIndex)); //UCOL_NOT_FOUND;
+ const UChar *UCharOffset;
+ UChar schar, tchar;
+
+ for (;;) {
+ /* This loop will run once per source string character, for as long as we */
+ /* are matching a potential contraction sequence */
+
+ /* First we position ourselves at the begining of contraction sequence */
+ const UChar *ContractionStart = UCharOffset = (UChar *)coll->image+getContractOffset(CE);
+
+ if (collIter_eos(source)) {
+ // Ran off the end of the source string.
+ CE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
+ // So we'll pick whatever we have at the point...
+ if (CE == UCOL_NOT_FOUND) {
+ // back up the source over all the chars we scanned going into this contraction.
+ CE = firstCE;
+ loadState(source, &state, TRUE);
+ if(source->origFlags & UCOL_USE_ITERATOR) {
+ source->flags = source->origFlags;
+ }
+ }
+ break;
+ }
+
+ uint8_t maxCC = (uint8_t)(*(UCharOffset)&0xFF); /*get the discontiguos stuff */ /* skip the backward offset, see above */
+ uint8_t allSame = (uint8_t)(*(UCharOffset++)>>8);
+
+ schar = getNextNormalizedChar(source);
+ while(schar > (tchar = *UCharOffset)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
+ UCharOffset++;
+ }
+
+ if (schar == tchar) {
+ // Found the source string char in the contraction table.
+ // Pick up the corresponding CE from the table.
+ CE = *(coll->contractionCEs +
+ (UCharOffset - coll->contractionIndex));
+ }
+ else
+ {
+ // Source string char was not in contraction table.
+ // Unless we have a discontiguous contraction, we have finished
+ // with this contraction.
+ UChar32 miss = schar;
+ if(U16_IS_LEAD(schar)) { // in order to do the proper detection, we
+ // need to see if we're dealing with a supplementary
+ miss = U16_GET_SUPPLEMENTARY(schar, getNextNormalizedChar(source));
+ }
+
+ uint8_t sCC;
+ if (miss < 0x300 ||
+ maxCC == 0 ||
+ (sCC = i_getCombiningClass(miss, coll)) == 0 ||
+ sCC>maxCC ||
+ (allSame != 0 && sCC == maxCC) ||
+ collIter_eos(source)) {
+ // Contraction can not be discontiguous.
+ goBackOne(source); // back up the source string by one,
+ // because the character we just looked at was
+ // not part of the contraction. */
+ if(U_IS_SUPPLEMENTARY(miss)) {
+ goBackOne(source);
+ }
+ CE = *(coll->contractionCEs +
+ (ContractionStart - coll->contractionIndex));
+ } else {
+ //
+ // Contraction is possibly discontiguous.
+ // Scan more of source string looking for a match
+ //
+ UChar tempchar;
+ /* find the next character if schar is not a base character
+ and we are not yet at the end of the string */
+ tempchar = getNextNormalizedChar(source);
+ // probably need another supplementary thingie here
+ goBackOne(source);
+ if (i_getCombiningClass(tempchar, coll) == 0) {
+ goBackOne(source);
+ if(U_IS_SUPPLEMENTARY(miss)) {
+ goBackOne(source);
+ }
+ /* Spit out the last char of the string, wasn't tasty enough */
+ CE = *(coll->contractionCEs +
+ (ContractionStart - coll->contractionIndex));
+ } else {
+ CE = getDiscontiguous(coll, source, ContractionStart);
+ }
+ }
+ } // else after if(schar == tchar)
+
+ if(CE == UCOL_NOT_FOUND) {
+ /* The Source string did not match the contraction that we were checking. */
+ /* Back up the source position to undo the effects of having partially */
+ /* scanned through what ultimately proved to not be a contraction. */
+ loadState(source, &state, TRUE);
+ CE = firstCE;
+ break;
+ }
+
+ if(!isContraction(CE)) {
+ // The source string char was in the contraction table, and the corresponding
+ // CE is not a contraction CE. We completed the contraction, break
+ // out of loop, this CE will end up being returned. This is the normal
+ // way out of contraction handling when the source actually contained
+ // the contraction.
+ break;
+ }
+
+
+ // The source string char was in the contraction table, and the corresponding
+ // CE is IS a contraction CE. We will continue looping to check the source
+ // string for the remaining chars in the contraction.
+ uint32_t tempCE = *(coll->contractionCEs + (ContractionStart - coll->contractionIndex));
+ if(tempCE != UCOL_NOT_FOUND) {
+ // We have scanned a a section of source string for which there is a
+ // CE from the contraction table. Remember the CE and scan position, so
+ // that we can return to this point if further scanning fails to
+ // match a longer contraction sequence.
+ firstCE = tempCE;
+
+ goBackOne(source);
+ backupState(source, &state);
+ getNextNormalizedChar(source);
+
+ // Another way to do this is:
+ //collIterateState tempState;
+ //backupState(source, &tempState);
+ //goBackOne(source);
+ //backupState(source, &state);
+ //loadState(source, &tempState, TRUE);
+
+ // The problem is that for incomplete contractions we have to remember the previous
+ // position. Before, the only thing I needed to do was state.pos--;
+ // After iterator introduction and especially after introduction of normalizing
+ // iterators, it became much more difficult to decrease the saved state.
+ // I'm not yet sure which of the two methods above is faster.
+ }
+ } // for(;;)
+ break;
+ } // case CONTRACTION_TAG:
+ case LONG_PRIMARY_TAG:
+ {
+ *(source->CEpos++) = ((CE & 0xFF)<<24)|UCOL_CONTINUATION_MARKER;
+ CE = ((CE & 0xFFFF00) << 8) | (UCOL_BYTE_COMMON << 8) | UCOL_BYTE_COMMON;
+ return CE;
+ }
+ case EXPANSION_TAG:
+ {
+ /* This should handle expansion. */
+ /* NOTE: we can encounter both continuations and expansions in an expansion! */
+ /* I have to decide where continuations are going to be dealt with */
+ uint32_t size;
+ uint32_t i; /* general counter */
+ CEOffset = (uint32_t *)coll->image+getExpansionOffset(CE); /* find the offset to expansion table */
+ size = getExpansionCount(CE);
+ CE = *CEOffset++;
+ if(size != 0) { /* if there are less than 16 elements in expansion, we don't terminate */
+ for(i = 1; i<size; i++) {
+ *(source->CEpos++) = *CEOffset++;
+ }
+ } else { /* else, we do */
+ while(*CEOffset != 0) {
+ *(source->CEpos++) = *CEOffset++;
+ }
+ }
+ return CE;
+ }
+ case DIGIT_TAG:
+ {
+ /*
+ We do a check to see if we want to collate digits as numbers; if so we generate
+ a custom collation key. Otherwise we pull out the value stored in the expansion table.
+ */
+ //uint32_t size;
+ uint32_t i; /* general counter */
+
+ if (source->coll->numericCollation == UCOL_ON){
+ collIterateState digitState = {0,0,0,0,0,0,0,0};
+ UChar32 char32 = 0;
+
+ uint32_t digIndx = 0;
+ uint32_t endIndex = 0;
+ uint32_t trailingZeroIndex = 0;
+
+ uint32_t primWeight = 0;
+
+ int32_t digVal = 0;
+ uint8_t collateVal = 0;
+
+ UBool nonZeroValReached = FALSE;
+
+ uint8_t *numTempBuf;
+ uint8_t stackNumTempBuf[UCOL_MAX_BUFFER]; // I just need a temporary place to store my generated CEs.
+ uint32_t numTempBufSize = UCOL_MAX_BUFFER;
+
+ numTempBuf = stackNumTempBuf;
+ /*
+ We parse the source string until we hit a char that's NOT a digit.
+ Use this u_charDigitValue. This might be slow because we have to
+ handle surrogates...
+ */
+/*
+ if (U16_IS_LEAD(ch)){
+ if (!collIter_eos(source)) {
+ backupState(source, &digitState);
+ UChar trail = getNextNormalizedChar(source);
+ if(U16_IS_TRAIL(trail)) {
+ char32 = U16_GET_SUPPLEMENTARY(ch, trail);
+ } else {
+ loadState(source, &digitState, TRUE);
+ char32 = ch;
+ }
+ } else {
+ char32 = ch;
+ }
+ } else {
+ char32 = ch;
+ }
+ digVal = u_charDigitValue(char32);
+*/
+ digVal = u_charDigitValue(cp); // if we have arrived here, we have
+ // already processed possible supplementaries that trigered the digit tag -
+ // all supplementaries are marked in the UCA.
+ /*
+ We pad a zero in front of the first element anyways. This takes
+ care of the (probably) most common case where people are sorting things followed
+ by a single digit
+ */
+ digIndx++;
+ for(;;){
+ // Make sure we have enough space.
+ if (digIndx >= ((numTempBufSize - 2) * 2) + 1)
+ {
+ numTempBufSize *= 2;
+ if (numTempBuf == stackNumTempBuf){
+ numTempBuf = (uint8_t *)uprv_malloc(sizeof(uint8_t) * numTempBufSize);
+ uprv_memcpy(numTempBuf, stackNumTempBuf, UCOL_MAX_BUFFER);
+ } else {
+ uprv_realloc(numTempBuf, numTempBufSize);
+ }
+ }
+
+ // Skipping over leading zeroes.
+ if (digVal != 0) {
+ nonZeroValReached = TRUE;
+ }
+ if (nonZeroValReached) {
+ /*
+ We parse the digit string into base 100 numbers (this fits into a byte).
+ We only add to the buffer in twos, thus if we are parsing an odd character,
+ that serves as the 'tens' digit while the if we are parsing an even one, that
+ is the 'ones' digit. We dumped the parsed base 100 value (collateVal) into
+ a buffer. We multiply each collateVal by 2 (to give us room) and add 5 (to avoid
+ overlapping magic CE byte values). The last byte we subtract 1 to ensure it is less
+ than all the other bytes.
+ */
+
+ if (digIndx % 2 == 1){
+ collateVal += (uint8_t)digVal;
+
+ // We don't enter the low-order-digit case unless we've already seen
+ // the high order, or for the first digit, which is always non-zero.
+ if (collateVal != 0)
+ trailingZeroIndex = 0;
+
+ numTempBuf[(digIndx/2) + 2] = collateVal*2 + 6;
+ collateVal = 0;
+ }
+ else{
+ // We drop the collation value into the buffer so if we need to do
+ // a "front patch" we don't have to check to see if we're hitting the
+ // last element.
+ collateVal = (uint8_t)(digVal * 10);
+
+ // Check for trailing zeroes.
+ if (collateVal == 0)
+ {
+ if (!trailingZeroIndex)
+ trailingZeroIndex = (digIndx/2) + 2;
+ }
+ else
+ trailingZeroIndex = 0;
+
+ numTempBuf[(digIndx/2) + 2] = collateVal*2 + 6;
+ }
+ digIndx++;
+ }
+
+ // Get next character.
+ if (!collIter_eos(source)){
+ ch = getNextNormalizedChar(source);
+ if (U16_IS_LEAD(ch)){
+ if (!collIter_eos(source)) {
+ backupState(source, &digitState);
+ UChar trail = getNextNormalizedChar(source);
+ if(U16_IS_TRAIL(trail)) {
+ char32 = U16_GET_SUPPLEMENTARY(ch, trail);
+ } else {
+ loadState(source, &digitState, TRUE);
+ char32 = ch;
+ }
+ }
+ } else {
+ char32 = ch;
+ }
+
+ if ((digVal = u_charDigitValue(char32)) == -1){
+ // Resetting position to point to the next unprocessed char. We
+ // overshot it when doing our test/set for numbers.
+ if (char32 > 0xFFFF) { // For surrogates.
+ loadState(source, &digitState, TRUE);
+ //goBackOne(source);
+ }
+ goBackOne(source);
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (nonZeroValReached == FALSE){
+ digIndx = 2;
+ numTempBuf[2] = 6;
+ }
+
+ endIndex = trailingZeroIndex ? trailingZeroIndex : ((digIndx/2) + 2) ;
+ if (digIndx % 2 != 0){
+ /*
+ We missed a value. Since digIndx isn't even, stuck too many values into the buffer (this is what
+ we get for padding the first byte with a zero). "Front-patch" now by pushing all nybbles forward.
+ Doing it this way ensures that at least 50% of the time (statistically speaking) we'll only be doing a
+ single pass and optimizes for strings with single digits. I'm just assuming that's the more common case.
+ */
+
+ for(i = 2; i < endIndex; i++){
+ numTempBuf[i] = (((((numTempBuf[i] - 6)/2) % 10) * 10) +
+ (((numTempBuf[i+1])-6)/2) / 10) * 2 + 6;
+ }
+ --digIndx;
+ }
+
+ // Subtract one off of the last byte.
+ numTempBuf[endIndex-1] -= 1;
+
+ /*
+ We want to skip over the first two slots in the buffer. The first slot
+ is reserved for the header byte UCOL_CODAN_PLACEHOLDER. The second slot is for the
+ sign/exponent byte: 0x80 + (decimalPos/2) & 7f.
+ */
+ numTempBuf[0] = UCOL_CODAN_PLACEHOLDER;
+ numTempBuf[1] = (uint8_t)(0x80 + ((digIndx/2) & 0x7F));
+
+ // Now transfer the collation key to our collIterate struct.
+ // The total size for our collation key is endIndx bumped up to the next largest even value divided by two.
+ //size = ((endIndex+1) & ~1)/2;
+ CE = (((numTempBuf[0] << 8) | numTempBuf[1]) << UCOL_PRIMARYORDERSHIFT) | //Primary weight
+ (UCOL_BYTE_COMMON << UCOL_SECONDARYORDERSHIFT) | // Secondary weight
+ UCOL_BYTE_COMMON; // Tertiary weight.
+ i = 2; // Reset the index into the buffer.
+ while(i < endIndex)
+ {
+ primWeight = numTempBuf[i++] << 8;
+ if ( i < endIndex)
+ primWeight |= numTempBuf[i++];
+ *(source->CEpos++) = (primWeight << UCOL_PRIMARYORDERSHIFT) | UCOL_CONTINUATION_MARKER;
+ }
+
+ if (numTempBuf != stackNumTempBuf)
+ uprv_free(numTempBuf);
+ } else {
+ // no numeric mode, we'll just switch to whatever we stashed and continue
+ CEOffset = (uint32_t *)coll->image+getExpansionOffset(CE); /* find the offset to expansion table */
+ CE = *CEOffset++;
+ break;
+ }
+ return CE;
+ }
+ /* various implicits optimization */
+ // TODO: remove CJK_IMPLICIT_TAG completely - handled by the getImplicit
+ case CJK_IMPLICIT_TAG: /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
+ //return getImplicit(cp, source, 0x04000000);
+ return getImplicit(cp, source);
+ case IMPLICIT_TAG: /* everything that is not defined otherwise */
+ /* UCA is filled with these. Tailorings are NOT_FOUND */
+ //return getImplicit(cp, source, 0);
+ return getImplicit(cp, source);
+ case TRAIL_SURROGATE_TAG: /* DC00-DFFF*/
+ return 0; /* broken surrogate sequence */
+ case LEAD_SURROGATE_TAG: /* D800-DBFF*/
+ UChar nextChar;
+ if( source->flags & UCOL_USE_ITERATOR) {
+ if(U_IS_TRAIL(nextChar = (UChar)source->iterator->current(source->iterator))) {
+ cp = U16_GET_SUPPLEMENTARY(ch, nextChar);
+ source->iterator->next(source->iterator);
+ return getImplicit(cp, source);
+ } else {
+ return 0;
+ }
+ } else if((((source->flags & UCOL_ITER_HASLEN) == 0 ) || (source->pos<source->endp)) &&
+ U_IS_TRAIL((nextChar=*source->pos))) {
+ cp = U16_GET_SUPPLEMENTARY(ch, nextChar);
+ source->pos++;
+ return getImplicit(cp, source);
+ } else {
+ return 0; /* completely ignorable */
+ }
+ case HANGUL_SYLLABLE_TAG: /* AC00-D7AF*/
+ {
+ const uint32_t
+ SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7;
+ //const uint32_t LCount = 19;
+ const uint32_t VCount = 21;
+ const uint32_t TCount = 28;
+ //const uint32_t NCount = VCount * TCount; // 588
+ //const uint32_t SCount = LCount * NCount; // 11172
+ uint32_t L = ch - SBase;
+
+ // divide into pieces
+
+ uint32_t T = L % TCount; // we do it in this order since some compilers can do % and / in one operation
+ L /= TCount;
+ uint32_t V = L % VCount;
+ L /= VCount;
+
+ // offset them
+
+ L += LBase;
+ V += VBase;
+ T += TBase;
+
+ // return the first CE, but first put the rest into the expansion buffer
+ if (!source->coll->image->jamoSpecial) { // FAST PATH
+
+ *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, V);
+ if (T != TBase) {
+ *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, T);
+ }
+
+ return UTRIE_GET32_FROM_LEAD(&coll->mapping, L);
+
+ } else { // Jamo is Special
+ // Since Hanguls pass the FCD check, it is
+ // guaranteed that we won't be in
+ // the normalization buffer if something like this happens
+ // However, if we are using a uchar iterator and normalization
+ // is ON, the Hangul that lead us here is going to be in that
+ // normalization buffer. Here we want to restore the uchar
+ // iterator state and pull out of the normalization buffer
+ if(source->iterator != NULL && source->flags & UCOL_ITER_INNORMBUF) {
+ source->flags = source->origFlags; // restore the iterator
+ source->pos = NULL;
+ }
+ // Move Jamos into normalization buffer
+ source->writableBuffer[0] = (UChar)L;
+ source->writableBuffer[1] = (UChar)V;
+ if (T != TBase) {
+ source->writableBuffer[2] = (UChar)T;
+ source->writableBuffer[3] = 0;
+ } else {
+ source->writableBuffer[2] = 0;
+ }
+
+ source->fcdPosition = source->pos; // Indicate where to continue in main input string
+ // after exhausting the writableBuffer
+ source->pos = source->writableBuffer;
+ source->origFlags = source->flags;
+ source->flags |= UCOL_ITER_INNORMBUF;
+ source->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+
+ return(UCOL_IGNORABLE);
+ }
+ }
+ case CHARSET_TAG:
+ /* not yet implemented */
+ /* probably after 1.8 */
+ return UCOL_NOT_FOUND;
+ default:
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ CE=0;
+ break;
+ }
+ if (CE <= UCOL_NOT_FOUND) break;
+ }
+ return CE;
+}
+
+
+/* now uses Mark's getImplicitPrimary code */
+static
+inline uint32_t getPrevImplicit(UChar32 cp, collIterate *collationSource) {
+ if(isNonChar(cp)) {
+ return 0;
+ }
+
+ uint32_t r = uprv_uca_getImplicitPrimary(cp);
+
+ *(collationSource->CEpos++) = (r & UCOL_PRIMARYMASK) | 0x00000505;
+ collationSource->toReturn = collationSource->CEpos;
+ return ((r & 0x0000FFFF)<<16) | 0x000000C0;
+}
+
+/**
+ * This function handles the special CEs like contractions, expansions,
+ * surrogates, Thai.
+ * It is called by both getPrevCE
+ */
+uint32_t ucol_prv_getSpecialPrevCE(const UCollator *coll, UChar ch, uint32_t CE,
+ collIterate *source,
+ UErrorCode *status)
+{
+ const uint32_t *CEOffset = NULL;
+ UChar *UCharOffset = NULL;
+ UChar schar;
+ const UChar *constart = NULL;
+ uint32_t size;
+ UChar buffer[UCOL_MAX_BUFFER];
+ uint32_t *endCEBuffer;
+ UChar *strbuffer;
+ int32_t noChars = 0;
+
+ for(;;)
+ {
+ /* the only ces that loops are thai and contractions */
+ switch (getCETag(CE))
+ {
+ case NOT_FOUND_TAG: /* this tag always returns */
+ return CE;
+ case SURROGATE_TAG: /* This is a surrogate pair */
+ /* essentialy an engaged lead surrogate. */
+ /* if you have encountered it here, it means that a */
+ /* broken sequence was encountered and this is an error */
+ return 0;
+ case SPEC_PROC_TAG:
+ {
+ // Special processing is getting a CE that is preceded by a certain prefix
+ // Currently this is only needed for optimizing Japanese length and iteration marks.
+ // When we encouter a special processing tag, we go backwards and try to see if
+ // we have a match.
+ // Contraction tables are used - so the whole process is not unlike contraction.
+ // prefix data is stored backwards in the table.
+ const UChar *UCharOffset;
+ UChar schar, tchar;
+ collIterateState prefixState;
+ backupState(source, &prefixState);
+ for(;;) {
+ // This loop will run once per source string character, for as long as we
+ // are matching a potential contraction sequence
+
+ // First we position ourselves at the begining of contraction sequence
+ const UChar *ContractionStart = UCharOffset = (UChar *)coll->image+getContractOffset(CE);
+
+ if (collIter_bos(source)) {
+ CE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
+ break;
+ }
+ schar = getPrevNormalizedChar(source, status);
+ goBackOne(source);
+
+ while(schar > (tchar = *UCharOffset)) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
+ UCharOffset++;
+ }
+
+ if (schar == tchar) {
+ // Found the source string char in the table.
+ // Pick up the corresponding CE from the table.
+ CE = *(coll->contractionCEs +
+ (UCharOffset - coll->contractionIndex));
+ }
+ else
+ {
+ // if there is a completely ignorable code point in the middle of
+ // a prefix, we need to act as if it's not there
+ // assumption: 'real' noncharacters (*fffe, *ffff, fdd0-fdef are set to zero)
+ // lone surrogates cannot be set to zero as it would break other processing
+ uint32_t isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, schar);
+ // it's easy for BMP code points
+ if(isZeroCE == 0) {
+ continue;
+ } else if(U16_IS_TRAIL(schar) || U16_IS_LEAD(schar)) {
+ // for supplementary code points, we have to check the next one
+ // situations where we are going to ignore
+ // 1. beginning of the string: schar is a lone surrogate
+ // 2. schar is a lone surrogate
+ // 3. schar is a trail surrogate in a valid surrogate sequence
+ // that is explicitly set to zero.
+ if (!collIter_bos(source)) {
+ UChar lead;
+ if(U16_IS_LEAD(lead = getPrevNormalizedChar(source, status))) {
+ isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, lead);
+ if(getCETag(isZeroCE) == SURROGATE_TAG) {
+ uint32_t finalCE = UTRIE_GET32_FROM_OFFSET_TRAIL(&coll->mapping, isZeroCE&0xFFFFFF, schar);
+ if(finalCE == 0) {
+ // this is a real, assigned completely ignorable code point
+ goBackOne(source);
+ continue;
+ }
+ }
+ } else {
+ // lone surrogate, completely ignorable
+ continue;
+ }
+ } else {
+ // lone surrogate at the beggining, completely ignorable
+ continue;
+ }
+ }
+ // Source string char was not in the table.
+ // We have not found the prefix.
+ CE = *(coll->contractionCEs +
+ (ContractionStart - coll->contractionIndex));
+ }
+
+ if(!isPrefix(CE)) {
+ // The source string char was in the contraction table, and the corresponding
+ // CE is not a prefix CE. We found the prefix, break
+ // out of loop, this CE will end up being returned. This is the normal
+ // way out of prefix handling when the source actually contained
+ // the prefix.
+ break;
+ }
+ }
+ loadState(source, &prefixState, TRUE);
+ break;
+ }
+
+ case CONTRACTION_TAG:
+ /* to ensure that the backwards and forwards iteration matches, we
+ take the current region of most possible match and pass it through
+ the forward iteration. this will ensure that the obstinate problem of
+ overlapping contractions will not occur.
+ */
+ schar = peekCharacter(source, 0);
+ constart = (UChar *)coll->image + getContractOffset(CE);
+ if (isAtStartPrevIterate(source)
+ /* commented away contraction end checks after adding the checks
+ in getPrevCE */) {
+ /* start of string or this is not the end of any contraction */
+ CE = *(coll->contractionCEs +
+ (constart - coll->contractionIndex));
+ break;
+ }
+ strbuffer = buffer;
+ UCharOffset = strbuffer + (UCOL_MAX_BUFFER - 1);
+ *(UCharOffset --) = 0;
+ noChars = 0;
+ // have to swap thai characters
+ while (ucol_unsafeCP(schar, coll)) {
+ *(UCharOffset) = schar;
+ noChars++;
+ UCharOffset --;
+ schar = getPrevNormalizedChar(source, status);
+ goBackOne(source);
+ // TODO: when we exhaust the contraction buffer,
+ // it needs to get reallocated. The problem is
+ // that the size depends on the string which is
+ // not iterated over. However, since we're travelling
+ // backwards, we already had to set the iterator at
+ // the end - so we might as well know where we are?
+ if (UCharOffset + 1 == buffer) {
+ /* we have exhausted the buffer */
+ int32_t newsize = 0;
+ if(source->pos) { // actually dealing with a position
+ newsize = source->pos - source->string + 1;
+ } else { // iterator
+ newsize = 4 * UCOL_MAX_BUFFER;
+ }
+ strbuffer = (UChar *)uprv_malloc(sizeof(UChar) *
+ (newsize + UCOL_MAX_BUFFER));
+ /* test for NULL */
+ if (strbuffer == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return UCOL_NO_MORE_CES;
+ }
+ UCharOffset = strbuffer + newsize;
+ uprv_memcpy(UCharOffset, buffer,
+ UCOL_MAX_BUFFER * sizeof(UChar));
+ UCharOffset --;
+ }
+ if ((source->pos && (source->pos == source->string ||
+ ((source->flags & UCOL_ITER_INNORMBUF) &&
+ *(source->pos - 1) == 0 && source->fcdPosition == NULL)))
+ || (source->iterator && !source->iterator->hasPrevious(source->iterator))) {
+ break;
+ }
+ }
+ /* adds the initial base character to the string */
+ *(UCharOffset) = schar;
+ noChars++;
+
+ /* a new collIterate is used to simplify things, since using the current
+ collIterate will mean that the forward and backwards iteration will
+ share and change the same buffers. we don't want to get into that. */
+ collIterate temp;
+ //IInit_collIterate(coll, UCharOffset, -1, &temp);
+ IInit_collIterate(coll, UCharOffset, noChars, &temp);
+ temp.flags &= ~UCOL_ITER_NORM;
+
+ CE = ucol_IGetNextCE(coll, &temp, status);
+ endCEBuffer = source->CEs + UCOL_EXPAND_CE_BUFFER_SIZE;
+ while (CE != UCOL_NO_MORE_CES) {
+ *(source->CEpos ++) = CE;
+ if (source->CEpos == endCEBuffer) {
+ /* ran out of CE space, bail.
+ there's no guarantee of the right character position after
+ this bail*/
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ source->CEpos = source->CEs;
+ freeHeapWritableBuffer(&temp);
+ if (strbuffer != buffer) {
+ uprv_free(strbuffer);
+ }
+ return (uint32_t)UCOL_NULLORDER;
+ }
+ CE = ucol_IGetNextCE(coll, &temp, status);
+ }
+ freeHeapWritableBuffer(&temp);
+ if (strbuffer != buffer) {
+ uprv_free(strbuffer);
+ }
+ source->toReturn = source->CEpos - 1;
+ if (source->toReturn == source->CEs) {
+ source->CEpos = source->CEs;
+ }
+ return *(source->toReturn);
+ case LONG_PRIMARY_TAG:
+ {
+ *(source->CEpos++) = ((CE & 0xFFFF00) << 8) | (UCOL_BYTE_COMMON << 8) | UCOL_BYTE_COMMON;
+ *(source->CEpos++) = ((CE & 0xFF)<<24)|UCOL_CONTINUATION_MARKER;
+ source->toReturn = source->CEpos - 1;
+ return *(source->toReturn);
+ }
+ case EXPANSION_TAG: /* this tag always returns */
+ /*
+ This should handle expansion.
+ NOTE: we can encounter both continuations and expansions in an expansion!
+ I have to decide where continuations are going to be dealt with
+ */
+ /* find the offset to expansion table */
+ CEOffset = (uint32_t *)coll->image + getExpansionOffset(CE);
+ size = getExpansionCount(CE);
+ if (size != 0) {
+ /*
+ if there are less than 16 elements in expansion, we don't terminate
+ */
+ uint32_t count;
+ for (count = 0; count < size; count++) {
+ *(source->CEpos ++) = *CEOffset++;
+ }
+ }
+ else {
+ /* else, we do */
+ while (*CEOffset != 0) {
+ *(source->CEpos ++) = *CEOffset ++;
+ }
+ }
+ source->toReturn = source->CEpos - 1;
+ // in case of one element expansion, we
+ // want to immediately return CEpos
+ if(source->toReturn == source->CEs) {
+ source->CEpos = source->CEs;
+ }
+ return *(source->toReturn);
+ case DIGIT_TAG:
+ {
+ /*
+ We do a check to see if we want to collate digits as numbers; if so we generate
+ a custom collation key. Otherwise we pull out the value stored in the expansion table.
+ */
+ //uint32_t size;
+ uint32_t i; /* general counter */
+
+ if (source->coll->numericCollation == UCOL_ON){
+ collIterateState state = {0,0,0,0,0,0,0,0};
+ UChar32 char32 = 0;
+
+ uint32_t digIndx = 0;
+ uint32_t endIndex = 0;
+ uint32_t leadingZeroIndex = 0;
+ uint32_t trailingZeroCount = 0;
+
+ uint32_t primWeight = 0;
+
+ int32_t digVal = 0;
+ uint8_t collateVal = 0;
+
+ UBool nonZeroValReached = FALSE;
+
+ uint8_t *numTempBuf;
+ uint8_t stackNumTempBuf[UCOL_MAX_BUFFER]; // I just need a temporary place to store my generated CEs.
+ uint32_t numTempBufSize = UCOL_MAX_BUFFER;
+
+ numTempBuf = stackNumTempBuf;
+ /*
+ We parse the source string until we hit a char that's NOT a digit.
+ Use this u_charDigitValue. This might be slow because we have to
+ handle surrogates...
+ */
+
+ if (U16_IS_TRAIL (ch)){
+ if (!collIter_bos(source)){
+ UChar lead = getPrevNormalizedChar(source, status);
+ if(U16_IS_LEAD(lead)) {
+ char32 = U16_GET_SUPPLEMENTARY(lead,ch);
+ goBackOne(source);
+ } else {
+ char32 = ch;
+ }
+ } else {
+ char32 = ch;
+ }
+ } else {
+ char32 = ch;
+ }
+ digVal = u_charDigitValue(char32);
+
+ for(;;){
+ // Make sure we have enough space.
+ if (digIndx >= ((numTempBufSize - 2) * 2) + 1)
+ {
+ numTempBufSize *= 2;
+ if (numTempBuf == stackNumTempBuf){
+ numTempBuf = (uint8_t *)uprv_malloc(sizeof(uint8_t) * numTempBufSize);
+ uprv_memcpy(numTempBuf, stackNumTempBuf, UCOL_MAX_BUFFER);
+ }else
+ uprv_realloc(numTempBuf, numTempBufSize);
+ }
+
+ // Skip over trailing zeroes, and keep a count of them.
+ if (digVal != 0)
+ nonZeroValReached = TRUE;
+ if (nonZeroValReached){
+ /*
+ We parse the digit string into base 100 numbers (this fits into a byte).
+ We only add to the buffer in twos, thus if we are parsing an odd character,
+ that serves as the 'tens' digit while the if we are parsing an even one, that
+ is the 'ones' digit. We dumped the parsed base 100 value (collateVal) into
+ a buffer. We multiply each collateVal by 2 (to give us room) and add 5 (to avoid
+ overlapping magic CE byte values). The last byte we subtract 1 to ensure it is less
+ than all the other bytes.
+
+ Since we're doing in this reverse we want to put the first digit encountered into the
+ ones place and the second digit encountered into the tens place.
+ */
+
+ if ((digIndx + trailingZeroCount) % 2 == 1){
+ // High-order digit case (tens place)
+ collateVal += (uint8_t)(digVal * 10);
+
+ // We cannot set leadingZeroIndex unless it has been set for the
+ // low-order digit. Therefore, all we can do for the high-order
+ // digit is turn it off, never on.
+ // The only time we will have a high digit without a low is for
+ // the very first non-zero digit, so no zero check is necessary.
+ if (collateVal != 0)
+ leadingZeroIndex = 0;
+
+ numTempBuf[(digIndx/2) + 2] = collateVal*2 + 6;
+ collateVal = 0;
+ }
+ else{
+ // Low-order digit case (ones place)
+ collateVal = (uint8_t)digVal;
+
+ // Check for leading zeroes.
+ if (collateVal == 0)
+ {
+ if (!leadingZeroIndex)
+ leadingZeroIndex = (digIndx/2) + 2;
+ }
+ else
+ leadingZeroIndex = 0;
+
+ // No need to write to buffer; the case of a last odd digit
+ // is handled below.
+ }
+ ++digIndx;
+ }
+ else
+ ++trailingZeroCount;
+
+ if (!collIter_bos(source)){
+ ch = getPrevNormalizedChar(source, status);
+ //goBackOne(source);
+ if (U16_IS_TRAIL(ch)){
+ backupState(source, &state);
+ if (!collIter_bos(source))
+ {
+ goBackOne(source);
+ UChar lead = getPrevNormalizedChar(source, status);
+ if(U16_IS_LEAD(lead)) {
+ char32 = U16_GET_SUPPLEMENTARY(lead,ch);
+ } else {
+ loadState(source, &state, FALSE);
+ char32 = ch;
+ }
+ }
+ }
+ else
+ char32 = ch;
+
+ if ((digVal = u_charDigitValue(char32)) == -1){
+ if (char32 > 0xFFFF) {// For surrogates.
+ loadState(source, &state, FALSE);
+ }
+ // Don't need to "reverse" the goBackOne call,
+ // as this points to the next position to process..
+ //if (char32 > 0xFFFF) // For surrogates.
+ //getNextNormalizedChar(source);
+ break;
+ }
+ goBackOne(source);
+ }else
+ break;
+ }
+
+ if (nonZeroValReached == FALSE){
+ digIndx = 2;
+ trailingZeroCount = 0;
+ numTempBuf[2] = 6;
+ }
+
+ if ((digIndx + trailingZeroCount) % 2 != 0){
+ numTempBuf[((digIndx)/2) + 2] = collateVal*2 + 6;
+ digIndx += 1; // The implicit leading zero
+ }
+ if (trailingZeroCount % 2 != 0){
+ // We had to consume one trailing zero for the low digit
+ // of the least significant byte
+ digIndx += 1; // The trailing zero not in the exponent
+ trailingZeroCount -= 1;
+ }
+
+ endIndex = leadingZeroIndex ? leadingZeroIndex : ((digIndx/2) + 2) ;
+
+ // Subtract one off of the last byte. Really the first byte here, but it's reversed...
+ numTempBuf[2] -= 1;
+
+ /*
+ We want to skip over the first two slots in the buffer. The first slot
+ is reserved for the header byte UCOL_CODAN_PLACEHOLDER. The second slot is for the
+ sign/exponent byte: 0x80 + (decimalPos/2) & 7f.
+ The exponent must be adjusted by the number of leading zeroes, and the number of
+ trailing zeroes.
+ */
+ numTempBuf[0] = UCOL_CODAN_PLACEHOLDER;
+ uint32_t exponent = (digIndx+trailingZeroCount)/2;
+ if (leadingZeroIndex)
+ exponent -= ((digIndx/2) + 2 - leadingZeroIndex);
+ numTempBuf[1] = (uint8_t)(0x80 + (exponent & 0x7F));
+
+ // Now transfer the collation key to our collIterate struct.
+ // The total size for our collation key is endIndx bumped up to the next largest even value divided by two.
+ //size = ((endIndex+1) & ~1)/2;
+ *(source->CEpos++) = (((numTempBuf[0] << 8) | numTempBuf[1]) << UCOL_PRIMARYORDERSHIFT) | //Primary weight
+ (UCOL_BYTE_COMMON << UCOL_SECONDARYORDERSHIFT) | // Secondary weight
+ UCOL_BYTE_COMMON; // Tertiary weight.
+ i = endIndex - 1; // Reset the index into the buffer.
+ while(i >= 2)
+ {
+ primWeight = numTempBuf[i--] << 8;
+ if ( i >= 2)
+ primWeight |= numTempBuf[i--];
+ *(source->CEpos++) = (primWeight << UCOL_PRIMARYORDERSHIFT) | UCOL_CONTINUATION_MARKER;
+ }
+ if (numTempBuf != stackNumTempBuf)
+ uprv_free(numTempBuf);
+
+ source->toReturn = source->CEpos -1;
+ return *(source->toReturn);
+ }
+ else {
+ CEOffset = (uint32_t *)coll->image + getExpansionOffset(CE);
+ CE = *(CEOffset++);
+ break;
+ }
+ }
+ case HANGUL_SYLLABLE_TAG: /* AC00-D7AF*/
+ {
+ const uint32_t
+ SBase = 0xAC00, LBase = 0x1100, VBase = 0x1161, TBase = 0x11A7;
+ //const uint32_t LCount = 19;
+ const uint32_t VCount = 21;
+ const uint32_t TCount = 28;
+ //const uint32_t NCount = VCount * TCount; /* 588 */
+ //const uint32_t SCount = LCount * NCount; /* 11172 */
+
+ uint32_t L = ch - SBase;
+ /*
+ divide into pieces.
+ we do it in this order since some compilers can do % and / in one
+ operation
+ */
+ uint32_t T = L % TCount;
+ L /= TCount;
+ uint32_t V = L % VCount;
+ L /= VCount;
+
+ /* offset them */
+ L += LBase;
+ V += VBase;
+ T += TBase;
+
+ /*
+ return the first CE, but first put the rest into the expansion buffer
+ */
+ if (!source->coll->image->jamoSpecial)
+ {
+ *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, L);
+ *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, V);
+ if (T != TBase)
+ *(source->CEpos++) = UTRIE_GET32_FROM_LEAD(&coll->mapping, T);
+
+ source->toReturn = source->CEpos - 1;
+ return *(source->toReturn);
+ } else {
+ // Since Hanguls pass the FCD check, it is
+ // guaranteed that we won't be in
+ // the normalization buffer if something like this happens
+ // Move Jamos into normalization buffer
+ /*
+ Move the Jamos into the
+ normalization buffer
+ */
+ UChar *tempbuffer = source->writableBuffer +
+ (source->writableBufSize - 1);
+ *(tempbuffer) = 0;
+ if (T != TBase) {
+ *(tempbuffer - 1) = (UChar)T;
+ *(tempbuffer - 2) = (UChar)V;
+ *(tempbuffer - 3) = (UChar)L;
+ *(tempbuffer - 4) = 0;
+ } else {
+ *(tempbuffer - 1) = (UChar)V;
+ *(tempbuffer - 2) = (UChar)L;
+ *(tempbuffer - 3) = 0;
+ }
+
+ /*
+ Indicate where to continue in main input string after exhausting
+ the writableBuffer
+ */
+ if (source->pos == source->string) {
+ source->fcdPosition = NULL;
+ } else {
+ source->fcdPosition = source->pos-1;
+ }
+
+ source->pos = tempbuffer;
+ source->origFlags = source->flags;
+ source->flags |= UCOL_ITER_INNORMBUF;
+ source->flags &= ~(UCOL_ITER_NORM | UCOL_ITER_HASLEN);
+
+ return(UCOL_IGNORABLE);
+ }
+ }
+ case LEAD_SURROGATE_TAG: /* D800-DBFF*/
+ return 0; /* broken surrogate sequence */
+ case TRAIL_SURROGATE_TAG: /* DC00-DFFF*/
+ {
+ UChar32 cp = 0;
+ UChar prevChar;
+ UChar *prev;
+ if (isAtStartPrevIterate(source)) {
+ /* we are at the start of the string, wrong place to be at */
+ return 0;
+ }
+ if (source->pos != source->writableBuffer) {
+ prev = source->pos - 1;
+ } else {
+ prev = source->fcdPosition;
+ }
+ prevChar = *prev;
+
+ /* Handles Han and Supplementary characters here.*/
+ if (U16_IS_LEAD(prevChar)) {
+ cp = ((((uint32_t)prevChar)<<10UL)+(ch)-(((uint32_t)0xd800<<10UL)+0xdc00-0x10000));
+ source->pos = prev;
+ } else {
+ return 0; /* completely ignorable */
+ }
+ return getPrevImplicit(cp, source);
+ }
+ // TODO: Remove CJK implicits as they are handled by the getImplicitPrimary function
+ case CJK_IMPLICIT_TAG: /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
+ return getPrevImplicit(ch, source);
+ case IMPLICIT_TAG: /* everything that is not defined otherwise */
+ return getPrevImplicit(ch, source);
+ /* UCA is filled with these. Tailorings are NOT_FOUND */
+ /* not yet implemented */
+ case CHARSET_TAG: /* this tag always returns */
+ /* probably after 1.8 */
+ return UCOL_NOT_FOUND;
+ default: /* this tag always returns */
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ CE=0;
+ break;
+ }
+ if (CE <= UCOL_NOT_FOUND) {
+ break;
+ }
+ }
+ return CE;
+}
+
+/* This should really be a macro */
+/* However, it is used only when stack buffers are not sufficiently big, and then we're messed up performance wise */
+/* anyway */
+static
+uint8_t *reallocateBuffer(uint8_t **secondaries, uint8_t *secStart, uint8_t *second, uint32_t *secSize, uint32_t newSize, UErrorCode *status) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, ".");
+#endif
+ uint8_t *newStart = NULL;
+ uint32_t offset = *secondaries-secStart;
+
+ if(secStart==second) {
+ newStart=(uint8_t*)uprv_malloc(newSize);
+ if(newStart==NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(newStart, secStart, *secondaries-secStart);
+ } else {
+ newStart=(uint8_t*)uprv_realloc(secStart, newSize);
+ if(newStart==NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ }
+ *secondaries=newStart+offset;
+ *secSize=newSize;
+ return newStart;
+}
+
+
+/* This should really be a macro */
+/* This function is used to reverse parts of a buffer. We need this operation when doing continuation */
+/* secondaries in French */
+/*
+void uprv_ucol_reverse_buffer(uint8_t *start, uint8_t *end) {
+ uint8_t temp;
+ while(start<end) {
+ temp = *start;
+ *start++ = *end;
+ *end-- = temp;
+ }
+}
+*/
+
+#define uprv_ucol_reverse_buffer(TYPE, start, end) { \
+ TYPE tempA; \
+while((start)<(end)) { \
+ tempA = *(start); \
+ *(start)++ = *(end); \
+ *(end)-- = tempA; \
+} \
+}
+
+/****************************************************************************/
+/* Following are the sortkey generation functions */
+/* */
+/****************************************************************************/
+
+/**
+ * Merge two sort keys.
+ * This is useful, for example, to combine sort keys from first and last names
+ * to sort such pairs.
+ * Merged sort keys consider on each collation level the first part first entirely,
+ * then the second one.
+ * It is possible to merge multiple sort keys by consecutively merging
+ * another one with the intermediate result.
+ *
+ * The length of the merge result is the sum of the lengths of the input sort keys
+ * minus 1.
+ *
+ * @param src1 the first sort key
+ * @param src1Length the length of the first sort key, including the zero byte at the end;
+ * can be -1 if the function is to find the length
+ * @param src2 the second sort key
+ * @param src2Length the length of the second sort key, including the zero byte at the end;
+ * can be -1 if the function is to find the length
+ * @param dest the buffer where the merged sort key is written,
+ * can be NULL if destCapacity==0
+ * @param destCapacity the number of bytes in the dest buffer
+ * @return the length of the merged sort key, src1Length+src2Length-1;
+ * can be larger than destCapacity, or 0 if an error occurs (only for illegal arguments),
+ * in which cases the contents of dest is undefined
+ *
+ * @draft
+ */
+U_CAPI int32_t U_EXPORT2
+ucol_mergeSortkeys(const uint8_t *src1, int32_t src1Length,
+ const uint8_t *src2, int32_t src2Length,
+ uint8_t *dest, int32_t destCapacity) {
+ int32_t destLength;
+ uint8_t b;
+
+ /* check arguments */
+ if( src1==NULL || src1Length<-2 || src1Length==0 || (src1Length>0 && src1[src1Length-1]!=0) ||
+ src2==NULL || src2Length<-2 || src2Length==0 || (src2Length>0 && src2[src2Length-1]!=0) ||
+ destCapacity<0 || (destCapacity>0 && dest==NULL)
+ ) {
+ /* error, attempt to write a zero byte and return 0 */
+ if(dest!=NULL && destCapacity>0) {
+ *dest=0;
+ }
+ return 0;
+ }
+
+ /* check lengths and capacity */
+ if(src1Length<0) {
+ src1Length=(int32_t)uprv_strlen((const char *)src1)+1;
+ }
+ if(src2Length<0) {
+ src2Length=(int32_t)uprv_strlen((const char *)src2)+1;
+ }
+
+ destLength=src1Length+src2Length-1;
+ if(destLength>destCapacity) {
+ /* the merged sort key does not fit into the destination */
+ return destLength;
+ }
+
+ /* merge the sort keys with the same number of levels */
+ while(*src1!=0 && *src2!=0) { /* while both have another level */
+ /* copy level from src1 not including 00 or 01 */
+ while((b=*src1)>=2) {
+ ++src1;
+ *dest++=b;
+ }
+
+ /* add a 02 merge separator */
+ *dest++=2;
+
+ /* copy level from src2 not including 00 or 01 */
+ while((b=*src2)>=2) {
+ ++src2;
+ *dest++=b;
+ }
+
+ /* if both sort keys have another level, then add a 01 level separator and continue */
+ if(*src1==1 && *src2==1) {
+ ++src1;
+ ++src2;
+ *dest++=1;
+ }
+ }
+
+ /*
+ * here, at least one sort key is finished now, but the other one
+ * might have some contents left from containing more levels;
+ * that contents is just appended to the result
+ */
+ if(*src1!=0) {
+ /* src1 is not finished, therefore *src2==0, and src1 is appended */
+ src2=src1;
+ }
+ /* append src2, "the other, unfinished sort key" */
+ uprv_strcpy((char *)dest, (const char *)src2);
+
+ /* trust that neither sort key contained illegally embedded zero bytes */
+ return destLength;
+}
+
+/* sortkey API */
+U_CAPI int32_t U_EXPORT2
+ucol_getSortKey(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t *result,
+ int32_t resultLength)
+{
+ UTRACE_ENTRY(UTRACE_UCOL_GET_SORTKEY);
+ if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
+ UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source string = %vh ", coll, source,
+ ((sourceLength==-1 && source!=NULL) ? u_strlen(source) : sourceLength));
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t keySize = 0;
+
+ if(source != NULL) {
+ // source == NULL is actually an error situation, but we would need to
+ // have an error code to return it. Until we introduce a new
+ // API, it stays like this
+
+ /* this uses the function pointer that is set in updateinternalstate */
+ /* currently, there are two funcs: */
+ /*ucol_calcSortKey(...);*/
+ /*ucol_calcSortKeySimpleTertiary(...);*/
+
+ keySize = coll->sortKeyGen(coll, source, sourceLength, &result, resultLength, FALSE, &status);
+ //((UCollator *)coll)->errorCode = status; /*semantically const */
+ }
+ UTRACE_DATA2(UTRACE_VERBOSE, "Sort Key = %vb", result, keySize);
+ UTRACE_EXIT_STATUS(status);
+ return keySize;
+}
+
+/* this function is called by the C++ API for sortkey generation */
+U_CFUNC int32_t
+ucol_getSortKeyWithAllocation(const UCollator *coll,
+ const UChar *source, int32_t sourceLength,
+ uint8_t **pResult,
+ UErrorCode *pErrorCode) {
+ *pResult = 0;
+ return coll->sortKeyGen(coll, source, sourceLength, pResult, 0, TRUE, pErrorCode);
+}
+
+#define UCOL_FSEC_BUF_SIZE 256
+
+/* This function tries to get the size of a sortkey. It will be invoked if the size of resulting buffer is 0 */
+/* or if we run out of space while making a sortkey and want to return ASAP */
+int32_t ucol_getSortKeySize(const UCollator *coll, collIterate *s, int32_t currentSize, UColAttributeValue strength, int32_t len) {
+ UErrorCode status = U_ZERO_ERROR;
+ //const UCAConstants *UCAconsts = (UCAConstants *)((uint8_t *)coll->UCA->image + coll->image->UCAConsts);
+ uint8_t compareSec = (uint8_t)((strength >= UCOL_SECONDARY)?0:0xFF);
+ uint8_t compareTer = (uint8_t)((strength >= UCOL_TERTIARY)?0:0xFF);
+ uint8_t compareQuad = (uint8_t)((strength >= UCOL_QUATERNARY)?0:0xFF);
+ UBool compareIdent = (strength == UCOL_IDENTICAL);
+ UBool doCase = (coll->caseLevel == UCOL_ON);
+ UBool shifted = (coll->alternateHandling == UCOL_SHIFTED);
+ //UBool qShifted = shifted && (compareQuad == 0);
+ UBool doHiragana = (coll->hiraganaQ == UCOL_ON) && (compareQuad == 0);
+ UBool isFrenchSec = (coll->frenchCollation == UCOL_ON) && (compareSec == 0);
+ uint8_t fSecsBuff[UCOL_FSEC_BUF_SIZE];
+ uint8_t *fSecs = fSecsBuff;
+ uint32_t fSecsLen = 0, fSecsMaxLen = UCOL_FSEC_BUF_SIZE;
+ uint8_t *frenchStartPtr = NULL, *frenchEndPtr = NULL;
+
+ uint32_t variableTopValue = coll->variableTopValue;
+ uint8_t UCOL_COMMON_BOT4 = (uint8_t)((coll->variableTopValue>>8)+1);
+ if(doHiragana) {
+ UCOL_COMMON_BOT4++;
+ /* allocate one more space for hiragana */
+ }
+ uint8_t UCOL_BOT_COUNT4 = (uint8_t)(0xFF - UCOL_COMMON_BOT4);
+
+ uint32_t order = UCOL_NO_MORE_CES;
+ uint8_t primary1 = 0;
+ uint8_t primary2 = 0;
+ uint8_t secondary = 0;
+ uint8_t tertiary = 0;
+ int32_t caseShift = 0;
+ uint32_t c2 = 0, c3 = 0, c4 = 0; /* variables for compression */
+
+ uint8_t caseSwitch = coll->caseSwitch;
+ uint8_t tertiaryMask = coll->tertiaryMask;
+ uint8_t tertiaryCommon = coll->tertiaryCommon;
+
+ UBool wasShifted = FALSE;
+ UBool notIsContinuation = FALSE;
+ uint8_t leadPrimary = 0;
+
+
+ for(;;) {
+ order = ucol_IGetNextCE(coll, s, &status);
+ if(order == UCOL_NO_MORE_CES) {
+ break;
+ }
+
+ if(order == 0) {
+ continue;
+ }
+
+ notIsContinuation = !isContinuation(order);
+
+
+ if(notIsContinuation) {
+ tertiary = (uint8_t)((order & UCOL_BYTE_SIZE_MASK));
+ } else {
+ tertiary = (uint8_t)((order & UCOL_REMOVE_CONTINUATION));
+ }
+ secondary = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary2 = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary1 = (uint8_t)(order >> 8);
+
+
+ if(shifted && ((notIsContinuation && order <= variableTopValue && primary1 > 0)
+ || (!notIsContinuation && wasShifted))
+ || (wasShifted && primary1 == 0)) { /* amendment to the UCA says that primary ignorables */
+ /* and other ignorables should be removed if following a shifted code point */
+ if(primary1 == 0) { /* if we were shifted and we got an ignorable code point */
+ /* we should just completely ignore it */
+ continue;
+ }
+ if(compareQuad == 0) {
+ if(c4 > 0) {
+ currentSize += (c2/UCOL_BOT_COUNT4)+1;
+ c4 = 0;
+ }
+ currentSize++;
+ if(primary2 != 0) {
+ currentSize++;
+ }
+ }
+ wasShifted = TRUE;
+ } else {
+ wasShifted = FALSE;
+ /* Note: This code assumes that the table is well built i.e. not having 0 bytes where they are not supposed to be. */
+ /* Usually, we'll have non-zero primary1 & primary2, except in cases of LatinOne and friends, when primary2 will */
+ /* calculate sortkey size */
+ if(primary1 != UCOL_IGNORABLE) {
+ if(notIsContinuation) {
+ if(leadPrimary == primary1) {
+ currentSize++;
+ } else {
+ if(leadPrimary != 0) {
+ currentSize++;
+ }
+ if(primary2 == UCOL_IGNORABLE) {
+ /* one byter, not compressed */
+ currentSize++;
+ leadPrimary = 0;
+ } else if(primary1<UCOL_BYTE_FIRST_NON_LATIN_PRIMARY ||
+ //(primary1 > (UCOL_RESET_TOP_VALUE>>24) && primary1 < (UCOL_NEXT_TOP_VALUE>>24))) {
+ //(primary1 > (*UCAconsts->UCA_LAST_NON_VARIABLE>>24) && primary1 < (*UCAconsts->UCA_FIRST_IMPLICIT>>24))) {
+ (primary1 > maxRegularPrimary && primary1 < minImplicitPrimary)) {
+ /* not compressible */
+ leadPrimary = 0;
+ currentSize+=2;
+ } else { /* compress */
+ leadPrimary = primary1;
+ currentSize+=2;
+ }
+ }
+ } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
+ currentSize++;
+ if(primary2 != UCOL_IGNORABLE) {
+ currentSize++;
+ }
+ }
+ }
+
+ if(secondary > compareSec) { /* I think that != 0 test should be != IGNORABLE */
+ if(!isFrenchSec){
+ if (secondary == UCOL_COMMON2 && notIsContinuation) {
+ c2++;
+ } else {
+ if(c2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ currentSize += (c2/(uint32_t)UCOL_TOP_COUNT2)+1;
+ } else {
+ currentSize += (c2/(uint32_t)UCOL_BOT_COUNT2)+1;
+ }
+ c2 = 0;
+ }
+ currentSize++;
+ }
+ } else {
+ fSecs[fSecsLen++] = secondary;
+ if(fSecsLen == fSecsMaxLen) {
+ if(fSecs == fSecsBuff) {
+ fSecs = (uint8_t *)uprv_malloc(2*fSecsLen);
+ } else {
+ fSecs = (uint8_t *)uprv_realloc(fSecs, 2*fSecsLen);
+ }
+ if(fSecs == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return -1;
+ }
+ fSecsMaxLen *= 2;
+ }
+ if(notIsContinuation) {
+ if (frenchStartPtr != NULL) {
+ /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ frenchStartPtr = NULL;
+ }
+ } else {
+ if (frenchStartPtr == NULL) {
+ frenchStartPtr = fSecs+fSecsLen-2;
+ }
+ frenchEndPtr = fSecs+fSecsLen-1;
+ }
+ }
+ }
+
+ if(doCase && (primary1 > 0 || strength >= UCOL_SECONDARY)) {
+ // do the case level if we need to do it. We don't want to calculate
+ // case level for primary ignorables if we have only primary strength and case level
+ // otherwise we would break well formedness of CEs
+ if (caseShift == 0) {
+ currentSize++;
+ caseShift = UCOL_CASE_SHIFT_START;
+ }
+ if((tertiary&0x3F) > 0 && notIsContinuation) {
+ caseShift--;
+ if((tertiary &0xC0) != 0) {
+ if (caseShift == 0) {
+ currentSize++;
+ caseShift = UCOL_CASE_SHIFT_START;
+ }
+ caseShift--;
+ }
+ }
+ } else {
+ if(notIsContinuation) {
+ tertiary ^= caseSwitch;
+ }
+ }
+
+ tertiary &= tertiaryMask;
+ if(tertiary > compareTer) { /* I think that != 0 test should be != IGNORABLE */
+ if (tertiary == tertiaryCommon && notIsContinuation) {
+ c3++;
+ } else {
+ if(c3 > 0) {
+ if((tertiary > tertiaryCommon && tertiaryCommon == UCOL_COMMON3_NORMAL)
+ || (tertiary <= tertiaryCommon && tertiaryCommon == UCOL_COMMON3_UPPERFIRST)) {
+ currentSize += (c3/(uint32_t)coll->tertiaryTopCount)+1;
+ } else {
+ currentSize += (c3/(uint32_t)coll->tertiaryBottomCount)+1;
+ }
+ c3 = 0;
+ }
+ currentSize++;
+ }
+ }
+
+ if(/*qShifted*/(compareQuad==0) && notIsContinuation) {
+ if(s->flags & UCOL_WAS_HIRAGANA) { // This was Hiragana and we need to note it
+ if(c4>0) { // Close this part
+ currentSize += (c4/UCOL_BOT_COUNT4)+1;
+ c4 = 0;
+ }
+ currentSize++; // Add the Hiragana
+ } else { // This wasn't Hiragana, so we can continue adding stuff
+ c4++;
+ }
+ }
+
+ }
+ }
+
+ if(!isFrenchSec){
+ if(c2 > 0) {
+ currentSize += (c2/(uint32_t)UCOL_BOT_COUNT2)+((c2%(uint32_t)UCOL_BOT_COUNT2 != 0)?1:0);
+ }
+ } else {
+ uint32_t i = 0;
+ if(frenchStartPtr != NULL) {
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ }
+ for(i = 0; i<fSecsLen; i++) {
+ secondary = *(fSecs+fSecsLen-i-1);
+ /* This is compression code. */
+ if (secondary == UCOL_COMMON2) {
+ ++c2;
+ } else {
+ if(c2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ currentSize += (c2/(uint32_t)UCOL_TOP_COUNT2)+((c2%(uint32_t)UCOL_TOP_COUNT2 != 0)?1:0);
+ } else {
+ currentSize += (c2/(uint32_t)UCOL_BOT_COUNT2)+((c2%(uint32_t)UCOL_BOT_COUNT2 != 0)?1:0);
+ }
+ c2 = 0;
+ }
+ currentSize++;
+ }
+ }
+ if(c2 > 0) {
+ currentSize += (c2/(uint32_t)UCOL_BOT_COUNT2)+((c2%(uint32_t)UCOL_BOT_COUNT2 != 0)?1:0);
+ }
+ if(fSecs != fSecsBuff) {
+ uprv_free(fSecs);
+ }
+ }
+
+ if(c3 > 0) {
+ currentSize += (c3/(uint32_t)coll->tertiaryBottomCount) + ((c3%(uint32_t)coll->tertiaryBottomCount != 0)?1:0);
+ }
+
+ if(c4 > 0 && compareQuad == 0) {
+ currentSize += (c4/(uint32_t)UCOL_BOT_COUNT4)+((c4%(uint32_t)UCOL_BOT_COUNT4 != 0)?1:0);
+ }
+
+ if(compareIdent) {
+ currentSize += u_lengthOfIdenticalLevelRun(s->string, len);
+ }
+ return currentSize;
+
+}
+
+static
+inline void doCaseShift(uint8_t **cases, uint32_t &caseShift) {
+ if (caseShift == 0) {
+ *(*cases)++ = UCOL_CASE_BYTE_START;
+ caseShift = UCOL_CASE_SHIFT_START;
+ }
+}
+
+// Adds a value to the buffer if it's safe to add. Increments the number of added values, so that we
+// know how many values we wanted to add, even if we didn't add them all
+static
+inline void addWithIncrement(uint8_t *&primaries, uint8_t *limit, uint32_t &size, const uint8_t value) {
+ size++;
+ if(primaries < limit) {
+ *(primaries)++ = value;
+ }
+}
+
+// Packs the secondary buffer when processing French locale. Adds the terminator.
+static
+inline uint8_t *packFrench(uint8_t *primaries, uint8_t *primEnd, uint8_t *secondaries, uint32_t *secsize, uint8_t *frenchStartPtr, uint8_t *frenchEndPtr) {
+ uint8_t secondary;
+ int32_t count2 = 0;
+ uint32_t i = 0, size = 0;
+ // we use i here since the key size already accounts for terminators, so we'll discard the increment
+ addWithIncrement(primaries, primEnd, i, UCOL_LEVELTERMINATOR);
+ /* If there are any unresolved continuation secondaries, reverse them here so that we can reverse the whole secondary thing */
+ if(frenchStartPtr != NULL) {
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ }
+ for(i = 0; i<*secsize; i++) {
+ secondary = *(secondaries-i-1);
+ /* This is compression code. */
+ if (secondary == UCOL_COMMON2) {
+ ++count2;
+ } else {
+ if (count2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ while (count2 > UCOL_TOP_COUNT2) {
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2));
+ count2 -= (uint32_t)UCOL_TOP_COUNT2;
+ }
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_TOP2 - (count2-1)));
+ } else {
+ while (count2 > UCOL_BOT_COUNT2) {
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+ count2 = 0;
+ }
+ addWithIncrement(primaries, primEnd, size, secondary);
+ }
+ }
+ if (count2 > 0) {
+ while (count2 > UCOL_BOT_COUNT2) {
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2));
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ addWithIncrement(primaries, primEnd, size, (uint8_t)(UCOL_COMMON_BOT2 + (count2-1)));
+ }
+ *secsize = size;
+ return primaries;
+}
+
+/* This is the sortkey work horse function */
+U_CFUNC int32_t U_CALLCONV
+ucol_calcSortKey(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocateSKBuffer,
+ UErrorCode *status)
+{
+ //const UCAConstants *UCAconsts = (UCAConstants *)((uint8_t *)coll->UCA->image + coll->image->UCAConsts);
+
+ uint32_t i = 0; /* general purpose counter */
+
+ /* Stack allocated buffers for buffers we use */
+ uint8_t prim[UCOL_PRIMARY_MAX_BUFFER], second[UCOL_SECONDARY_MAX_BUFFER], tert[UCOL_TERTIARY_MAX_BUFFER], caseB[UCOL_CASE_MAX_BUFFER], quad[UCOL_QUAD_MAX_BUFFER];
+
+ uint8_t *primaries = *result, *secondaries = second, *tertiaries = tert, *cases = caseB, *quads = quad;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if(primaries == NULL && allocateSKBuffer == TRUE) {
+ primaries = *result = prim;
+ resultLength = UCOL_PRIMARY_MAX_BUFFER;
+ }
+
+ uint32_t secSize = UCOL_SECONDARY_MAX_BUFFER, terSize = UCOL_TERTIARY_MAX_BUFFER,
+ caseSize = UCOL_CASE_MAX_BUFFER, quadSize = UCOL_QUAD_MAX_BUFFER;
+
+ uint32_t sortKeySize = 1; /* it is always \0 terminated */
+
+ UChar normBuffer[UCOL_NORMALIZATION_MAX_BUFFER];
+ UChar *normSource = normBuffer;
+ int32_t normSourceLen = UCOL_NORMALIZATION_MAX_BUFFER;
+
+ int32_t len = (sourceLength == -1 ? u_strlen(source) : sourceLength);
+
+ UColAttributeValue strength = coll->strength;
+
+ uint8_t compareSec = (uint8_t)((strength >= UCOL_SECONDARY)?0:0xFF);
+ uint8_t compareTer = (uint8_t)((strength >= UCOL_TERTIARY)?0:0xFF);
+ uint8_t compareQuad = (uint8_t)((strength >= UCOL_QUATERNARY)?0:0xFF);
+ UBool compareIdent = (strength == UCOL_IDENTICAL);
+ UBool doCase = (coll->caseLevel == UCOL_ON);
+ UBool isFrenchSec = (coll->frenchCollation == UCOL_ON) && (compareSec == 0);
+ UBool shifted = (coll->alternateHandling == UCOL_SHIFTED);
+ //UBool qShifted = shifted && (compareQuad == 0);
+ UBool doHiragana = (coll->hiraganaQ == UCOL_ON) && (compareQuad == 0);
+ /*const uint8_t *scriptOrder = coll->scriptOrder;*/
+
+ uint32_t variableTopValue = coll->variableTopValue;
+ // TODO: UCOL_COMMON_BOT4 should be a function of qShifted. If we have no
+ // qShifted, we don't need to set UCOL_COMMON_BOT4 so high.
+ uint8_t UCOL_COMMON_BOT4 = (uint8_t)((coll->variableTopValue>>8)+1);
+ uint8_t UCOL_HIRAGANA_QUAD = 0;
+ if(doHiragana) {
+ UCOL_HIRAGANA_QUAD=UCOL_COMMON_BOT4++;
+ /* allocate one more space for hiragana, value for hiragana */
+ }
+ uint8_t UCOL_BOT_COUNT4 = (uint8_t)(0xFF - UCOL_COMMON_BOT4);
+
+ /* support for special features like caselevel and funky secondaries */
+ uint8_t *frenchStartPtr = NULL;
+ uint8_t *frenchEndPtr = NULL;
+ uint32_t caseShift = 0;
+
+ sortKeySize += ((compareSec?0:1) + (compareTer?0:1) + (doCase?1:0) + /*(qShifted?1:0)*/(compareQuad?0:1) + (compareIdent?1:0));
+
+ /* If we need to normalize, we'll do it all at once at the beginning! */
+ UNormalizationMode normMode;
+ if(compareIdent) {
+ normMode = UNORM_NFD;
+ } else if(coll->normalizationMode != UCOL_OFF) {
+ normMode = UNORM_FCD;
+ } else {
+ normMode = UNORM_NONE;
+ }
+
+ if(normMode != UNORM_NONE && UNORM_YES != unorm_quickCheck(source, len, normMode, status)) {
+ len = unorm_internalNormalize(normSource, normSourceLen,
+ source, len,
+ normMode, FALSE,
+ status);
+ if(*status == U_BUFFER_OVERFLOW_ERROR) {
+ normSourceLen = len;
+ normSource = (UChar *)uprv_malloc(len*U_SIZEOF_UCHAR);
+ if(normSource == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ *status = U_ZERO_ERROR;
+ len = unorm_internalNormalize(normSource, normSourceLen,
+ source, len,
+ normMode, FALSE,
+ status);
+ }
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ source = normSource;
+ }
+
+ collIterate s;
+ IInit_collIterate(coll, (UChar *)source, len, &s);
+ if(source == normSource) {
+ s.flags &= ~UCOL_ITER_NORM;
+ }
+
+ if(resultLength == 0 || primaries == NULL) {
+ int32_t keyLen = ucol_getSortKeySize(coll, &s, sortKeySize, strength, len);
+ if(normSource != normBuffer) {
+ uprv_free(normSource);
+ }
+ return keyLen;
+ }
+ uint8_t *primarySafeEnd = primaries + resultLength - 1;
+ if(strength > UCOL_PRIMARY) {
+ primarySafeEnd--;
+ }
+
+ uint32_t minBufferSize = UCOL_MAX_BUFFER;
+
+ uint8_t *primStart = primaries;
+ uint8_t *secStart = secondaries;
+ uint8_t *terStart = tertiaries;
+ uint8_t *caseStart = cases;
+ uint8_t *quadStart = quads;
+
+ uint32_t order = 0;
+
+ uint8_t primary1 = 0;
+ uint8_t primary2 = 0;
+ uint8_t secondary = 0;
+ uint8_t tertiary = 0;
+ uint8_t caseSwitch = coll->caseSwitch;
+ uint8_t tertiaryMask = coll->tertiaryMask;
+ int8_t tertiaryAddition = (int8_t)coll->tertiaryAddition;
+ uint8_t tertiaryTop = coll->tertiaryTop;
+ uint8_t tertiaryBottom = coll->tertiaryBottom;
+ uint8_t tertiaryCommon = coll->tertiaryCommon;
+ uint8_t caseBits = 0;
+
+ UBool finished = FALSE;
+ UBool wasShifted = FALSE;
+ UBool notIsContinuation = FALSE;
+
+ uint32_t prevBuffSize = 0;
+
+ uint32_t count2 = 0, count3 = 0, count4 = 0;
+ uint8_t leadPrimary = 0;
+
+ for(;;) {
+ for(i=prevBuffSize; i<minBufferSize; ++i) {
+
+ order = ucol_IGetNextCE(coll, &s, status);
+ if(order == UCOL_NO_MORE_CES) {
+ finished = TRUE;
+ break;
+ }
+
+ if(order == 0) {
+ continue;
+ }
+
+ notIsContinuation = !isContinuation(order);
+
+ if(notIsContinuation) {
+ tertiary = (uint8_t)(order & UCOL_BYTE_SIZE_MASK);
+ } else {
+ tertiary = (uint8_t)((order & UCOL_REMOVE_CONTINUATION));
+ }
+
+ secondary = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary2 = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary1 = (uint8_t)(order >> 8);
+
+ /*if(notIsContinuation && scriptOrder != NULL) {
+ primary1 = scriptOrder[primary1];
+ }*/
+
+ if(shifted && ((notIsContinuation && order <= variableTopValue && primary1 > 0)
+ || (!notIsContinuation && wasShifted))
+ || (wasShifted && primary1 == 0)) { /* amendment to the UCA says that primary ignorables */
+ /* and other ignorables should be removed if following a shifted code point */
+ if(primary1 == 0) { /* if we were shifted and we got an ignorable code point */
+ /* we should just completely ignore it */
+ continue;
+ }
+ if(compareQuad == 0) {
+ if(count4 > 0) {
+ while (count4 > UCOL_BOT_COUNT4) {
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4);
+ count4 -= UCOL_BOT_COUNT4;
+ }
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + (count4-1));
+ count4 = 0;
+ }
+ /* We are dealing with a variable and we're treating them as shifted */
+ /* This is a shifted ignorable */
+ if(primary1 != 0) { /* we need to check this since we could be in continuation */
+ *quads++ = primary1;
+ }
+ if(primary2 != 0) {
+ *quads++ = primary2;
+ }
+ }
+ wasShifted = TRUE;
+ } else {
+ wasShifted = FALSE;
+ /* Note: This code assumes that the table is well built i.e. not having 0 bytes where they are not supposed to be. */
+ /* Usually, we'll have non-zero primary1 & primary2, except in cases of LatinOne and friends, when primary2 will */
+ /* regular and simple sortkey calc */
+ if(primary1 != UCOL_IGNORABLE) {
+ if(notIsContinuation) {
+ if(leadPrimary == primary1) {
+ *primaries++ = primary2;
+ } else {
+ if(leadPrimary != 0) {
+ *primaries++ = (uint8_t)((primary1 > leadPrimary) ? UCOL_BYTE_UNSHIFTED_MAX : UCOL_BYTE_UNSHIFTED_MIN);
+ }
+ if(primary2 == UCOL_IGNORABLE) {
+ /* one byter, not compressed */
+ *primaries++ = primary1;
+ leadPrimary = 0;
+ } else if(primary1<UCOL_BYTE_FIRST_NON_LATIN_PRIMARY ||
+ //(primary1 > (*UCAconsts->UCA_LAST_NON_VARIABLE>>24) && primary1 < (*UCAconsts->UCA_FIRST_IMPLICIT>>24))) {
+ (primary1 > maxRegularPrimary && primary1 < minImplicitPrimary)) {
+ /* not compressible */
+ leadPrimary = 0;
+ *primaries++ = primary1;
+ *primaries++ = primary2;
+ } else { /* compress */
+ *primaries++ = leadPrimary = primary1;
+ *primaries++ = primary2;
+ }
+ }
+ } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
+ *primaries++ = primary1;
+ if(primary2 != UCOL_IGNORABLE) {
+ *primaries++ = primary2; /* second part */
+ }
+ }
+ }
+
+ if(secondary > compareSec) {
+ if(!isFrenchSec) {
+ /* This is compression code. */
+ if (secondary == UCOL_COMMON2 && notIsContinuation) {
+ ++count2;
+ } else {
+ if (count2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ while (count2 > UCOL_TOP_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2);
+ count2 -= (uint32_t)UCOL_TOP_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_TOP2 - (count2-1));
+ } else {
+ while (count2 > UCOL_BOT_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + (count2-1));
+ }
+ count2 = 0;
+ }
+ *secondaries++ = secondary;
+ }
+ } else {
+ *secondaries++ = secondary;
+ /* Do the special handling for French secondaries */
+ /* We need to get continuation elements and do intermediate restore */
+ /* abc1c2c3de with french secondaries need to be edc1c2c3ba NOT edc3c2c1ba */
+ if(notIsContinuation) {
+ if (frenchStartPtr != NULL) {
+ /* reverse secondaries from frenchStartPtr up to frenchEndPtr */
+ uprv_ucol_reverse_buffer(uint8_t, frenchStartPtr, frenchEndPtr);
+ frenchStartPtr = NULL;
+ }
+ } else {
+ if (frenchStartPtr == NULL) {
+ frenchStartPtr = secondaries - 2;
+ }
+ frenchEndPtr = secondaries-1;
+ }
+ }
+ }
+
+ if(doCase && (primary1 > 0 || strength >= UCOL_SECONDARY)) {
+ // do the case level if we need to do it. We don't want to calculate
+ // case level for primary ignorables if we have only primary strength and case level
+ // otherwise we would break well formedness of CEs
+ doCaseShift(&cases, caseShift);
+ if(notIsContinuation) {
+ caseBits = (uint8_t)(tertiary & 0xC0);
+
+ if(tertiary != 0) {
+ if(coll->caseFirst == UCOL_UPPER_FIRST) {
+ if((caseBits & 0xC0) == 0) {
+ *(cases-1) |= 1 << (--caseShift);
+ } else {
+ *(cases-1) |= 0 << (--caseShift);
+ /* second bit */
+ doCaseShift(&cases, caseShift);
+ *(cases-1) |= ((caseBits>>6)&1) << (--caseShift);
+ }
+ } else {
+ if((caseBits & 0xC0) == 0) {
+ *(cases-1) |= 0 << (--caseShift);
+ } else {
+ *(cases-1) |= 1 << (--caseShift);
+ /* second bit */
+ doCaseShift(&cases, caseShift);
+ *(cases-1) |= ((caseBits>>7)&1) << (--caseShift);
+ }
+ }
+ }
+
+ }
+ } else {
+ if(notIsContinuation) {
+ tertiary ^= caseSwitch;
+ }
+ }
+
+ tertiary &= tertiaryMask;
+ if(tertiary > compareTer) {
+ /* This is compression code. */
+ /* sequence size check is included in the if clause */
+ if (tertiary == tertiaryCommon && notIsContinuation) {
+ ++count3;
+ } else {
+ if(tertiary > tertiaryCommon && tertiaryCommon == UCOL_COMMON3_NORMAL) {
+ tertiary += tertiaryAddition;
+ } else if(tertiary <= tertiaryCommon && tertiaryCommon == UCOL_COMMON3_UPPERFIRST) {
+ tertiary -= tertiaryAddition;
+ }
+ if (count3 > 0) {
+ if ((tertiary > tertiaryCommon)) {
+ while (count3 > coll->tertiaryTopCount) {
+ *tertiaries++ = (uint8_t)(tertiaryTop - coll->tertiaryTopCount);
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryTop - (count3-1));
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ *tertiaries++ = (uint8_t)(tertiaryBottom + coll->tertiaryBottomCount);
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryBottom + (count3-1));
+ }
+ count3 = 0;
+ }
+ *tertiaries++ = tertiary;
+ }
+ }
+
+ if(/*qShifted*/(compareQuad==0) && notIsContinuation) {
+ if(s.flags & UCOL_WAS_HIRAGANA) { // This was Hiragana and we need to note it
+ if(count4>0) { // Close this part
+ while (count4 > UCOL_BOT_COUNT4) {
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4);
+ count4 -= UCOL_BOT_COUNT4;
+ }
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + (count4-1));
+ count4 = 0;
+ }
+ *quads++ = UCOL_HIRAGANA_QUAD; // Add the Hiragana
+ } else { // This wasn't Hiragana, so we can continue adding stuff
+ count4++;
+ }
+ }
+ }
+
+ if(primaries > primarySafeEnd) { /* We have stepped over the primary buffer */
+ if(allocateSKBuffer == FALSE) { /* need to save our butts if we cannot reallocate */
+ IInit_collIterate(coll, (UChar *)source, len, &s);
+ if(source == normSource) {
+ s.flags &= ~UCOL_ITER_NORM;
+ }
+ sortKeySize = ucol_getSortKeySize(coll, &s, sortKeySize, strength, len);
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ finished = TRUE;
+ break;
+ } else { /* It's much nicer if we can actually reallocate */
+ int32_t sks = sortKeySize+(primaries - primStart)+(secondaries - secStart)+(tertiaries - terStart)+(cases-caseStart)+(quads-quadStart);
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sks, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ primarySafeEnd = primStart + resultLength - 1;
+ if(strength > UCOL_PRIMARY) {
+ primarySafeEnd--;
+ }
+ } else {
+ IInit_collIterate(coll, (UChar *)source, len, &s);
+ if(source == normSource) {
+ s.flags &= ~UCOL_ITER_NORM;
+ }
+ sortKeySize = ucol_getSortKeySize(coll, &s, sortKeySize, strength, len);
+ finished = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ if(finished) {
+ break;
+ } else {
+ prevBuffSize = minBufferSize;
+
+ uint32_t frenchStartOffset = 0, frenchEndOffset = 0;
+ if (frenchStartPtr != NULL) {
+ frenchStartOffset = frenchStartPtr - secStart;
+ frenchEndOffset = frenchEndPtr - secStart;
+ }
+ secStart = reallocateBuffer(&secondaries, secStart, second, &secSize, 2*secSize, status);
+ if (frenchStartPtr != NULL) {
+ frenchStartPtr = secStart + frenchStartOffset;
+ frenchEndPtr = secStart + frenchEndOffset;
+ }
+
+ terStart = reallocateBuffer(&tertiaries, terStart, tert, &terSize, 2*terSize, status);
+ caseStart = reallocateBuffer(&cases, caseStart, caseB, &caseSize, 2*caseSize, status);
+ quadStart = reallocateBuffer(&quads, quadStart, quad, &quadSize, 2*quadSize, status);
+ minBufferSize *= 2;
+ if(U_FAILURE(*status)) { // if we cannot reallocate buffers, we can at least give the sortkey size
+ IInit_collIterate(coll, (UChar *)source, len, &s);
+ if(source == normSource) {
+ s.flags &= ~UCOL_ITER_NORM;
+ }
+ sortKeySize = ucol_getSortKeySize(coll, &s, sortKeySize, strength, len);
+ break;
+ }
+ }
+ }
+
+ /* Here, we are generally done with processing */
+ /* bailing out would not be too productive */
+
+ if(U_SUCCESS(*status)) {
+ sortKeySize += (primaries - primStart);
+ /* we have done all the CE's, now let's put them together to form a key */
+ if(compareSec == 0) {
+ if (count2 > 0) {
+ while (count2 > UCOL_BOT_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + (count2-1));
+ }
+ uint32_t secsize = secondaries-secStart;
+ if(!isFrenchSec) { // Regular situation, we know the length of secondaries
+ sortKeySize += secsize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, secStart, secsize);
+ primaries += secsize;
+ } else {
+ if(allocateSKBuffer == TRUE) { /* need to save our butts if we cannot reallocate */
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, secStart, secsize);
+ primaries += secsize;
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ } else { // French secondary is on. We will need to pack French. packFrench will add the level terminator
+ uint8_t *newPrim = packFrench(primaries, primStart+resultLength, secondaries, &secsize, frenchStartPtr, frenchEndPtr);
+ sortKeySize += secsize;
+ if(sortKeySize <= resultLength) { // if we managed to pack fine
+ primaries = newPrim; // update the primary pointer
+ } else { // overflow, need to reallocate and redo
+ if(allocateSKBuffer == TRUE) { /* need to save our butts if we cannot reallocate */
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ primaries = packFrench(primaries, primStart+resultLength, secondaries, &secsize, frenchStartPtr, frenchEndPtr);
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ }
+ }
+
+ if(doCase) {
+ uint32_t casesize = cases - caseStart;
+ sortKeySize += casesize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, caseStart, casesize);
+ primaries += casesize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, caseStart, casesize);
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ }
+
+ if(compareTer == 0) {
+ if (count3 > 0) {
+ if (coll->tertiaryCommon != UCOL_COMMON_BOT3) {
+ while (count3 >= coll->tertiaryTopCount) {
+ *tertiaries++ = (uint8_t)(tertiaryTop - coll->tertiaryTopCount);
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryTop - count3);
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ *tertiaries++ = (uint8_t)(tertiaryBottom + coll->tertiaryBottomCount);
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryBottom + (count3-1));
+ }
+ }
+ uint32_t tersize = tertiaries - terStart;
+ sortKeySize += tersize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, terStart, tersize);
+ primaries += tersize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, terStart, tersize);
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+
+ if(compareQuad == 0/*qShifted == TRUE*/) {
+ if(count4 > 0) {
+ while (count4 > UCOL_BOT_COUNT4) {
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + UCOL_BOT_COUNT4);
+ count4 -= UCOL_BOT_COUNT4;
+ }
+ *quads++ = (uint8_t)(UCOL_COMMON_BOT4 + (count4-1));
+ }
+ uint32_t quadsize = quads - quadStart;
+ sortKeySize += quadsize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, quadStart, quadsize);
+ primaries += quadsize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, quadStart, quadsize);
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ }
+
+ if(compareIdent) {
+ sortKeySize += u_lengthOfIdenticalLevelRun(s.string, len);
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ primaries += u_writeIdenticalLevelRun(s.string, len, primaries);
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ u_writeIdenticalLevelRun(s.string, len, primaries);
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ }
+ }
+ *(primaries++) = '\0';
+ }
+
+ if(terStart != tert) {
+ uprv_free(terStart);
+ uprv_free(secStart);
+ uprv_free(caseStart);
+ uprv_free(quadStart);
+ }
+
+ if(normSource != normBuffer) {
+ uprv_free(normSource);
+ }
+
+ if(allocateSKBuffer == TRUE) {
+ *result = (uint8_t*)uprv_malloc(sortKeySize);
+ /* test for NULL */
+ if (*result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return sortKeySize;
+ }
+ uprv_memcpy(*result, primStart, sortKeySize);
+ if(primStart != prim) {
+ uprv_free(primStart);
+ }
+ }
+
+ return sortKeySize;
+}
+
+
+U_CFUNC int32_t U_CALLCONV
+ucol_calcSortKeySimpleTertiary(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocateSKBuffer,
+ UErrorCode *status)
+{
+ U_ALIGN_CODE(16);
+
+ //const UCAConstants *UCAconsts = (UCAConstants *)((uint8_t *)coll->UCA->image + coll->image->UCAConsts);
+ uint32_t i = 0; /* general purpose counter */
+
+ /* Stack allocated buffers for buffers we use */
+ uint8_t prim[UCOL_PRIMARY_MAX_BUFFER], second[UCOL_SECONDARY_MAX_BUFFER], tert[UCOL_TERTIARY_MAX_BUFFER];
+
+ uint8_t *primaries = *result, *secondaries = second, *tertiaries = tert;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if(primaries == NULL && allocateSKBuffer == TRUE) {
+ primaries = *result = prim;
+ resultLength = UCOL_PRIMARY_MAX_BUFFER;
+ }
+
+ uint32_t secSize = UCOL_SECONDARY_MAX_BUFFER, terSize = UCOL_TERTIARY_MAX_BUFFER;
+
+ uint32_t sortKeySize = 3; /* it is always \0 terminated plus separators for secondary and tertiary */
+
+ UChar normBuffer[UCOL_NORMALIZATION_MAX_BUFFER];
+ UChar *normSource = normBuffer;
+ int32_t normSourceLen = UCOL_NORMALIZATION_MAX_BUFFER;
+
+ int32_t len = sourceLength;
+
+ /* If we need to normalize, we'll do it all at once at the beginning! */
+ if(coll->normalizationMode != UCOL_OFF && UNORM_YES != unorm_quickCheck(source, len, UNORM_FCD, status)) {
+ len = unorm_internalNormalize(normSource, normSourceLen,
+ source, len,
+ UNORM_FCD, FALSE,
+ status);
+ if(*status == U_BUFFER_OVERFLOW_ERROR) {
+ normSourceLen = len;
+ normSource = (UChar *)uprv_malloc(len*U_SIZEOF_UCHAR);
+ if(normSource == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ *status = U_ZERO_ERROR;
+ len = unorm_internalNormalize(normSource, normSourceLen,
+ source, len,
+ UNORM_FCD, FALSE,
+ status);
+ }
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ source = normSource;
+ }
+
+ collIterate s;
+ IInit_collIterate(coll, (UChar *)source, len, &s);
+ if(source == normSource) {
+ s.flags &= ~UCOL_ITER_NORM;
+ }
+
+ if(resultLength == 0 || primaries == NULL) {
+ int32_t t = ucol_getSortKeySize(coll, &s, sortKeySize, coll->strength, len);
+ if(normSource != normBuffer) {
+ uprv_free(normSource);
+ }
+ return t;
+ }
+
+ uint8_t *primarySafeEnd = primaries + resultLength - 2;
+
+ uint32_t minBufferSize = UCOL_MAX_BUFFER;
+
+ uint8_t *primStart = primaries;
+ uint8_t *secStart = secondaries;
+ uint8_t *terStart = tertiaries;
+
+ uint32_t order = 0;
+
+ uint8_t primary1 = 0;
+ uint8_t primary2 = 0;
+ uint8_t secondary = 0;
+ uint8_t tertiary = 0;
+ uint8_t caseSwitch = coll->caseSwitch;
+ uint8_t tertiaryMask = coll->tertiaryMask;
+ int8_t tertiaryAddition = (int8_t)coll->tertiaryAddition;
+ uint8_t tertiaryTop = coll->tertiaryTop;
+ uint8_t tertiaryBottom = coll->tertiaryBottom;
+ uint8_t tertiaryCommon = coll->tertiaryCommon;
+
+ uint32_t prevBuffSize = 0;
+
+ UBool finished = FALSE;
+ UBool notIsContinuation = FALSE;
+
+ uint32_t count2 = 0, count3 = 0;
+ uint8_t leadPrimary = 0;
+
+ for(;;) {
+ for(i=prevBuffSize; i<minBufferSize; ++i) {
+
+ order = ucol_IGetNextCE(coll, &s, status);
+
+ if(order == 0) {
+ continue;
+ }
+
+ if(order == UCOL_NO_MORE_CES) {
+ finished = TRUE;
+ break;
+ }
+
+ notIsContinuation = !isContinuation(order);
+
+ if(notIsContinuation) {
+ tertiary = (uint8_t)((order & tertiaryMask));
+ } else {
+ tertiary = (uint8_t)((order & UCOL_REMOVE_CONTINUATION));
+ }
+ secondary = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary2 = (uint8_t)((order >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary1 = (uint8_t)(order >> 8);
+
+ /* Note: This code assumes that the table is well built i.e. not having 0 bytes where they are not supposed to be. */
+ /* Usually, we'll have non-zero primary1 & primary2, except in cases of LatinOne and friends, when primary2 will */
+ /* be zero with non zero primary1. primary3 is different than 0 only for long primaries - see above. */
+ /* regular and simple sortkey calc */
+ if(primary1 != UCOL_IGNORABLE) {
+ if(notIsContinuation) {
+ if(leadPrimary == primary1) {
+ *primaries++ = primary2;
+ } else {
+ if(leadPrimary != 0) {
+ *primaries++ = (uint8_t)((primary1 > leadPrimary) ? UCOL_BYTE_UNSHIFTED_MAX : UCOL_BYTE_UNSHIFTED_MIN);
+ }
+ if(primary2 == UCOL_IGNORABLE) {
+ /* one byter, not compressed */
+ *primaries++ = primary1;
+ leadPrimary = 0;
+ } else if(primary1<UCOL_BYTE_FIRST_NON_LATIN_PRIMARY ||
+ //(primary1 > (UCOL_RESET_TOP_VALUE>>24) && primary1 < (UCOL_NEXT_TOP_VALUE>>24)))
+ //(primary1 > (*UCAconsts->UCA_LAST_NON_VARIABLE>>24) && primary1 < (*UCAconsts->UCA_FIRST_IMPLICIT>>24))) {
+ (primary1 > maxRegularPrimary && primary1 < minImplicitPrimary)) {
+ /* not compressible */
+ leadPrimary = 0;
+ *primaries++ = primary1;
+ *primaries++ = primary2;
+ } else { /* compress */
+ *primaries++ = leadPrimary = primary1;
+ *primaries++ = primary2;
+ }
+ }
+ } else { /* we are in continuation, so we're gonna add primary to the key don't care about compression */
+ *primaries++ = primary1;
+ if(primary2 != UCOL_IGNORABLE) {
+ *primaries++ = primary2; /* second part */
+ }
+ }
+ }
+
+ if(secondary > 0) { /* I think that != 0 test should be != IGNORABLE */
+ /* This is compression code. */
+ if (secondary == UCOL_COMMON2 && notIsContinuation) {
+ ++count2;
+ } else {
+ if (count2 > 0) {
+ if (secondary > UCOL_COMMON2) { // not necessary for 4th level.
+ while (count2 > UCOL_TOP_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_TOP2 - UCOL_TOP_COUNT2);
+ count2 -= (uint32_t)UCOL_TOP_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_TOP2 - (count2-1));
+ } else {
+ while (count2 > UCOL_BOT_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + (count2-1));
+ }
+ count2 = 0;
+ }
+ *secondaries++ = secondary;
+ }
+ }
+
+ if(notIsContinuation) {
+ tertiary ^= caseSwitch;
+ }
+
+ if(tertiary > 0) {
+ /* This is compression code. */
+ /* sequence size check is included in the if clause */
+ if (tertiary == tertiaryCommon && notIsContinuation) {
+ ++count3;
+ } else {
+ if(tertiary > tertiaryCommon && tertiaryCommon == UCOL_COMMON3_NORMAL) {
+ tertiary += tertiaryAddition;
+ } else if (tertiary <= tertiaryCommon && tertiaryCommon == UCOL_COMMON3_UPPERFIRST) {
+ tertiary -= tertiaryAddition;
+ }
+ if (count3 > 0) {
+ if ((tertiary > tertiaryCommon)) {
+ while (count3 > coll->tertiaryTopCount) {
+ *tertiaries++ = (uint8_t)(tertiaryTop - coll->tertiaryTopCount);
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryTop - (count3-1));
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ *tertiaries++ = (uint8_t)(tertiaryBottom + coll->tertiaryBottomCount);
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryBottom + (count3-1));
+ }
+ count3 = 0;
+ }
+ *tertiaries++ = tertiary;
+ }
+ }
+
+ if(primaries > primarySafeEnd) { /* We have stepped over the primary buffer */
+ if(allocateSKBuffer == FALSE) { /* need to save our butts if we cannot reallocate */
+ IInit_collIterate(coll, (UChar *)source, len, &s);
+ if(source == normSource) {
+ s.flags &= ~UCOL_ITER_NORM;
+ }
+ sortKeySize = ucol_getSortKeySize(coll, &s, sortKeySize, coll->strength, len);
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ finished = TRUE;
+ break;
+ } else { /* It's much nicer if we can actually reallocate */
+ int32_t sks = sortKeySize+(primaries - primStart)+(secondaries - secStart)+(tertiaries - terStart);
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sks, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ primarySafeEnd = primStart + resultLength - 2;
+ } else {
+ IInit_collIterate(coll, (UChar *)source, len, &s);
+ if(source == normSource) {
+ s.flags &= ~UCOL_ITER_NORM;
+ }
+ sortKeySize = ucol_getSortKeySize(coll, &s, sortKeySize, coll->strength, len);
+ finished = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ if(finished) {
+ break;
+ } else {
+ prevBuffSize = minBufferSize;
+ secStart = reallocateBuffer(&secondaries, secStart, second, &secSize, 2*secSize, status);
+ terStart = reallocateBuffer(&tertiaries, terStart, tert, &terSize, 2*terSize, status);
+ minBufferSize *= 2;
+ if(U_FAILURE(*status)) { // if we cannot reallocate buffers, we can at least give the sortkey size
+ IInit_collIterate(coll, (UChar *)source, len, &s);
+ if(source == normSource) {
+ s.flags &= ~UCOL_ITER_NORM;
+ }
+ sortKeySize = ucol_getSortKeySize(coll, &s, sortKeySize, coll->strength, len);
+ break;
+ }
+ }
+ }
+
+ if(U_SUCCESS(*status)) {
+ sortKeySize += (primaries - primStart);
+ /* we have done all the CE's, now let's put them together to form a key */
+ if (count2 > 0) {
+ while (count2 > UCOL_BOT_COUNT2) {
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + UCOL_BOT_COUNT2);
+ count2 -= (uint32_t)UCOL_BOT_COUNT2;
+ }
+ *secondaries++ = (uint8_t)(UCOL_COMMON_BOT2 + (count2-1));
+ }
+ uint32_t secsize = secondaries-secStart;
+ sortKeySize += secsize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, secStart, secsize);
+ primaries += secsize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ *result = primStart;
+ uprv_memcpy(primaries, secStart, secsize);
+ }
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+
+ if (count3 > 0) {
+ if (coll->tertiaryCommon != UCOL_COMMON3_NORMAL) {
+ while (count3 >= coll->tertiaryTopCount) {
+ *tertiaries++ = (uint8_t)(tertiaryTop - coll->tertiaryTopCount);
+ count3 -= (uint32_t)coll->tertiaryTopCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryTop - count3);
+ } else {
+ while (count3 > coll->tertiaryBottomCount) {
+ *tertiaries++ = (uint8_t)(tertiaryBottom + coll->tertiaryBottomCount);
+ count3 -= (uint32_t)coll->tertiaryBottomCount;
+ }
+ *tertiaries++ = (uint8_t)(tertiaryBottom + (count3-1));
+ }
+ }
+ uint32_t tersize = tertiaries - terStart;
+ sortKeySize += tersize;
+ if(sortKeySize <= resultLength) {
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, terStart, tersize);
+ primaries += tersize;
+ } else {
+ if(allocateSKBuffer == TRUE) {
+ primStart = reallocateBuffer(&primaries, *result, prim, &resultLength, 2*sortKeySize, status);
+ if(U_SUCCESS(*status)) {
+ *result = primStart;
+ *(primaries++) = UCOL_LEVELTERMINATOR;
+ uprv_memcpy(primaries, terStart, tersize);
+ }
+ } else {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+
+ *(primaries++) = '\0';
+ }
+
+ if(terStart != tert) {
+ uprv_free(terStart);
+ uprv_free(secStart);
+ }
+
+ if(normSource != normBuffer) {
+ uprv_free(normSource);
+ }
+
+ if(allocateSKBuffer == TRUE) {
+ *result = (uint8_t*)uprv_malloc(sortKeySize);
+ /* test for NULL */
+ if (*result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return sortKeySize;
+ }
+ uprv_memcpy(*result, primStart, sortKeySize);
+ if(primStart != prim) {
+ uprv_free(primStart);
+ }
+ }
+
+ return sortKeySize;
+}
+
+static inline
+UBool isShiftedCE(uint32_t CE, uint32_t LVT, UBool *wasShifted) {
+ UBool notIsContinuation = !isContinuation(CE);
+ uint8_t primary1 = (uint8_t)((CE >> 24) & 0xFF);
+ if(LVT && ((notIsContinuation && (CE & 0xFFFF0000)<= LVT && primary1 > 0)
+ || (!notIsContinuation && *wasShifted))
+ || (*wasShifted && primary1 == 0)) { /* amendment to the UCA says that primary ignorables */
+ // The stuff below should probably be in the sortkey code... maybe not...
+ if(primary1 != 0) { /* if we were shifted and we got an ignorable code point */
+ /* we should just completely ignore it */
+ *wasShifted = TRUE;
+ //continue;
+ }
+ //*wasShifted = TRUE;
+ return TRUE;
+ } else {
+ *wasShifted = FALSE;
+ return FALSE;
+ }
+}
+static inline
+void terminatePSKLevel(int32_t level, int32_t maxLevel, int32_t &i, uint8_t *dest) {
+ if(level < maxLevel) {
+ dest[i++] = UCOL_LEVELTERMINATOR;
+ } else {
+ dest[i++] = 0;
+ }
+}
+
+/** enumeration of level identifiers for partial sort key generation */
+enum {
+ UCOL_PSK_PRIMARY = 0,
+ UCOL_PSK_SECONDARY = 1,
+ UCOL_PSK_CASE = 2,
+ UCOL_PSK_TERTIARY = 3,
+ UCOL_PSK_QUATERNARY = 4,
+ UCOL_PSK_QUIN = 5, /** This is an extra level, not used - but we have three bits to blow */
+ UCOL_PSK_IDENTICAL = 6,
+ UCOL_PSK_NULL = 7, /** level for the end of sort key. Will just produce zeros */
+ UCOL_PSK_LIMIT
+};
+
+/** collation state enum. *_SHIFT value is how much to shift right
+ * to get the state piece to the right. *_MASK value should be
+ * ANDed with the shifted state. This data is stored in state[1]
+ * field.
+ */
+enum {
+ UCOL_PSK_LEVEL_SHIFT = 0, /** level identificator. stores an enum value from above */
+ UCOL_PSK_LEVEL_MASK = 7, /** three bits */
+ UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT = 3, /** number of bytes of primary or quaternary already written */
+ UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK = 1,
+ /** can be only 0 or 1, since we get up to two bytes from primary or quaternary
+ * This field is also used to denote that the French secondary level is finished
+ */
+ UCOL_PSK_WAS_SHIFTED_SHIFT = 4,/** was the last value shifted */
+ UCOL_PSK_WAS_SHIFTED_MASK = 1, /** can be 0 or 1 (Boolean) */
+ UCOL_PSK_USED_FRENCH_SHIFT = 5,/** how many French bytes have we already written */
+ UCOL_PSK_USED_FRENCH_MASK = 3, /** up to 4 bytes. See comment just below */
+ /** When we do French we need to reverse secondary values. However, continuations
+ * need to stay the same. So if you had abc1c2c3de, you need to have edc1c2c3ba
+ */
+ UCOL_PSK_BOCSU_BYTES_SHIFT = 7,
+ UCOL_PSK_BOCSU_BYTES_MASK = 3,
+ UCOL_PSK_CONSUMED_CES_SHIFT = 9,
+ UCOL_PSK_CONSUMED_CES_MASK = 0x7FFFF
+};
+
+// macro calculating the number of expansion CEs available
+#define uprv_numAvailableExpCEs(s) (s).CEpos - (s).toReturn
+
+
+/** main sortkey part procedure. On the first call,
+ * you should pass in a collator, an iterator, empty state
+ * state[0] == state[1] == 0, a buffer to hold results
+ * number of bytes you need and an error code pointer.
+ * Make sure your buffer is big enough to hold the wanted
+ * number of sortkey bytes. I don't check.
+ * The only meaningful status you can get back is
+ * U_BUFFER_OVERFLOW_ERROR, which basically means that you
+ * have been dealt a raw deal and that you probably won't
+ * be able to use partial sortkey generation for this
+ * particular combination of string and collator. This
+ * is highly unlikely, but you should still check the error code.
+ * Any other status means that you're not in a sane situation
+ * anymore. After the first call, preserve state values and
+ * use them on subsequent calls to obtain more bytes of a sortkey.
+ * Use until the number of bytes written is smaller than the requested
+ * number of bytes. Generated sortkey is not compatible with the
+ * one generated by ucol_getSortKey, as we don't do any compression.
+ * However, levels are still terminated by a 1 (one) and the sortkey
+ * is terminated by a 0 (zero). Identical level is the same as in the
+ * regular sortkey - internal bocu-1 implementation is used.
+ * For curious, although you cannot do much about this, here is
+ * the structure of state words.
+ * state[0] - iterator state. Depends on the iterator implementation,
+ * but allows the iterator to continue where it stopped in
+ * the last iteration.
+ * state[1] - collation processing state. Here is the distribution
+ * of the bits:
+ * 0, 1, 2 - level of the sortkey - primary, secondary, case, tertiary
+ * quaternary, quin (we don't use this one), identical and
+ * null (producing only zeroes - first one to terminate the
+ * sortkey and subsequent to fill the buffer).
+ * 3 - byte count. Number of bytes written on the primary level.
+ * 4 - was shifted. Whether the previous iteration finished in the
+ * shifted state.
+ * 5, 6 - French continuation bytes written. See the comment in the enum
+ * 7,8 - Bocsu bytes used. Number of bytes from a bocu sequence on
+ * the identical level.
+ * 9..31 - CEs consumed. Number of getCE or next32 operations performed
+ * since thes last successful update of the iterator state.
+ */
+U_CAPI int32_t U_EXPORT2
+ucol_nextSortKeyPart(const UCollator *coll,
+ UCharIterator *iter,
+ uint32_t state[2],
+ uint8_t *dest, int32_t count,
+ UErrorCode *status) {
+ /* error checking */
+ if(status==NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+ UTRACE_ENTRY(UTRACE_UCOL_NEXTSORTKEYPART);
+ if( coll==NULL || iter==NULL ||
+ state==NULL ||
+ count<0 || (count>0 && dest==NULL)
+ ) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ UTRACE_EXIT_STATUS(status);
+ return 0;
+ }
+
+ UTRACE_DATA6(UTRACE_VERBOSE, "coll=%p, iter=%p, state=%d %d, dest=%p, count=%d",
+ coll, iter, state[0], state[1], dest, count);
+
+ if(count==0) {
+ /* nothing to do */
+ UTRACE_EXIT_VALUE(0);
+ return 0;
+ }
+ /** Setting up situation according to the state we got from the previous iteration */
+ // The state of the iterator from the previous invocation
+ uint32_t iterState = state[0];
+ // Has the last iteration ended in the shifted state
+ UBool wasShifted = ((state[1] >> UCOL_PSK_WAS_SHIFTED_SHIFT) & UCOL_PSK_WAS_SHIFTED_MASK)?TRUE:FALSE;
+ // What is the current level of the sortkey?
+ int32_t level= (state[1] >> UCOL_PSK_LEVEL_SHIFT) & UCOL_PSK_LEVEL_MASK;
+ // Have we written only one byte from a two byte primary in the previous iteration?
+ // Also on secondary level - have we finished with the French secondary?
+ int32_t byteCountOrFrenchDone = (state[1] >> UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT) & UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK;
+ // number of bytes in the continuation buffer for French
+ int32_t usedFrench = (state[1] >> UCOL_PSK_USED_FRENCH_SHIFT) & UCOL_PSK_USED_FRENCH_MASK;
+ // Number of bytes already written from a bocsu sequence. Since
+ // the longes bocsu sequence is 4 long, this can be up to 3.
+ int32_t bocsuBytesUsed = (state[1] >> UCOL_PSK_BOCSU_BYTES_SHIFT) & UCOL_PSK_BOCSU_BYTES_MASK;
+ // Number of elements that need to be consumed in this iteration because
+ // the iterator returned UITER_NO_STATE at the end of the last iteration,
+ // so we had to save the last valid state.
+ int32_t cces = (state[1] >> UCOL_PSK_CONSUMED_CES_SHIFT) & UCOL_PSK_CONSUMED_CES_MASK;
+
+ /** values that depend on the collator attributes */
+ // strength of the collator.
+ int32_t strength = ucol_getAttribute(coll, UCOL_STRENGTH, status);
+ // maximal level of the partial sortkey. Need to take whether case level is done
+ int32_t maxLevel = 0;
+ if(strength < UCOL_TERTIARY) {
+ if(ucol_getAttribute(coll, UCOL_CASE_LEVEL, status) == UCOL_ON) {
+ maxLevel = UCOL_PSK_CASE;
+ } else {
+ maxLevel = strength;
+ }
+ } else {
+ if(strength == UCOL_TERTIARY) {
+ maxLevel = UCOL_PSK_TERTIARY;
+ } else if(strength == UCOL_QUATERNARY) {
+ maxLevel = UCOL_PSK_QUATERNARY;
+ } else { // identical
+ maxLevel = UCOL_IDENTICAL;
+ }
+ }
+ // value for the quaternary level if Hiragana is encountered. Used for JIS X 4061 collation
+ uint8_t UCOL_HIRAGANA_QUAD =
+ (ucol_getAttribute(coll, UCOL_HIRAGANA_QUATERNARY_MODE, status) == UCOL_ON)?0xFE:0xFF;
+ // Boundary value that decides whether a CE is shifted or not
+ uint32_t LVT = (coll->alternateHandling == UCOL_SHIFTED)?(coll->variableTopValue<<16):0;
+ // Are we doing French collation?
+ UBool doingFrench = (ucol_getAttribute(coll, UCOL_FRENCH_COLLATION, status) == UCOL_ON);
+
+ /** initializing the collation state */
+ UBool notIsContinuation = FALSE;
+ uint32_t CE = UCOL_NO_MORE_CES;
+
+ collIterate s;
+ IInit_collIterate(coll, NULL, -1, &s);
+ s.iterator = iter;
+ s.flags |= UCOL_USE_ITERATOR;
+ // This variable tells us whether we have produced some other levels in this iteration
+ // before we moved to the identical level. In that case, we need to switch the
+ // type of the iterator.
+ UBool doingIdenticalFromStart = FALSE;
+ // Normalizing iterator
+ // The division for the array length may truncate the array size to
+ // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
+ // for all platforms anyway.
+ UAlignedMemory stackNormIter[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
+ UNormIterator *normIter = NULL;
+ // If the normalization is turned on for the collator and we are below identical level
+ // we will use a FCD normalizing iterator
+ if(ucol_getAttribute(coll, UCOL_NORMALIZATION_MODE, status) == UCOL_ON && level < UCOL_PSK_IDENTICAL) {
+ normIter = unorm_openIter(stackNormIter, sizeof(stackNormIter), status);
+ s.iterator = unorm_setIter(normIter, iter, UNORM_FCD, status);
+ s.flags &= ~UCOL_ITER_NORM;
+ if(U_FAILURE(*status)) {
+ UTRACE_EXIT_STATUS(*status);
+ return 0;
+ }
+ } else if(level == UCOL_PSK_IDENTICAL) {
+ // for identical level, we need a NFD iterator. We need to instantiate it here, since we
+ // will be updating the state - and this cannot be done on an ordinary iterator.
+ normIter = unorm_openIter(stackNormIter, sizeof(stackNormIter), status);
+ s.iterator = unorm_setIter(normIter, iter, UNORM_NFD, status);
+ s.flags &= ~UCOL_ITER_NORM;
+ if(U_FAILURE(*status)) {
+ UTRACE_EXIT_STATUS(*status);
+ return 0;
+ }
+ doingIdenticalFromStart = TRUE;
+ }
+
+ // This is the tentative new state of the iterator. The problem
+ // is that the iterator might return an undefined state, in
+ // which case we should save the last valid state and increase
+ // the iterator skip value.
+ uint32_t newState = 0;
+
+ // First, we set the iterator to the last valid position
+ // from the last iteration. This was saved in state[0].
+ if(iterState == 0) {
+ /* initial state */
+ if(level == UCOL_PSK_SECONDARY && doingFrench && !byteCountOrFrenchDone) {
+ s.iterator->move(s.iterator, 0, UITER_LIMIT);
+ } else {
+ s.iterator->move(s.iterator, 0, UITER_START);
+ }
+ } else {
+ /* reset to previous state */
+ s.iterator->setState(s.iterator, iterState, status);
+ if(U_FAILURE(*status)) {
+ UTRACE_EXIT_STATUS(*status);
+ return 0;
+ }
+ }
+
+
+
+ // This variable tells us whether we can attempt to update the state
+ // of iterator. Situations where we don't want to update iterator state
+ // are the existence of expansion CEs that are not yet processed, and
+ // finishing the case level without enough space in the buffer to insert
+ // a level terminator.
+ UBool canUpdateState = TRUE;
+
+ // Consume all the CEs that were consumed at the end of the previous
+ // iteration without updating the iterator state. On identical level,
+ // consume the code points.
+ int32_t counter = cces;
+ if(level < UCOL_PSK_IDENTICAL) {
+ while(counter-->0) {
+ // If we're doing French and we are on the secondary level,
+ // we go backwards.
+ if(level == UCOL_PSK_SECONDARY && doingFrench) {
+ CE = ucol_IGetPrevCE(coll, &s, status);
+ } else {
+ CE = ucol_IGetNextCE(coll, &s, status);
+ }
+ if(CE==UCOL_NO_MORE_CES) {
+ /* should not happen */
+ *status=U_INTERNAL_PROGRAM_ERROR;
+ UTRACE_EXIT_STATUS(*status);
+ return 0;
+ }
+ if(uprv_numAvailableExpCEs(s)) {
+ canUpdateState = FALSE;
+ }
+ }
+ } else {
+ while(counter-->0) {
+ uiter_next32(s.iterator);
+ }
+ }
+
+ // French secondary needs to know whether the iterator state of zero came from previous level OR
+ // from a new invocation...
+ UBool wasDoingPrimary = FALSE;
+ // destination buffer byte counter. When this guy
+ // gets to count, we're done with the iteration
+ int32_t i = 0;
+ // used to count the zero bytes written after we
+ // have finished with the sort key
+ int32_t j = 0;
+
+
+ // Hm.... I think we're ready to plunge in. Basic story is as following:
+ // we have a fall through case based on level. This is used for initial
+ // positioning on iteration start. Every level processor contains a
+ // for(;;) which will be broken when we exhaust all the CEs. Other
+ // way to exit is a goto saveState, which happens when we have filled
+ // out our buffer.
+ switch(level) {
+ case UCOL_PSK_PRIMARY:
+ wasDoingPrimary = TRUE;
+ for(;;) {
+ if(i==count) {
+ goto saveState;
+ }
+ // We should save the state only if we
+ // are sure that we are done with the
+ // previous iterator state
+ if(canUpdateState && byteCountOrFrenchDone == 0) {
+ newState = s.iterator->getState(s.iterator);
+ if(newState != UITER_NO_STATE) {
+ iterState = newState;
+ cces = 0;
+ }
+ }
+ CE = ucol_IGetNextCE(coll, &s, status);
+ cces++;
+ if(CE==UCOL_NO_MORE_CES) {
+ // Add the level separator
+ terminatePSKLevel(level, maxLevel, i, dest);
+ byteCountOrFrenchDone=0;
+ // Restart the iteration an move to the
+ // second level
+ s.iterator->move(s.iterator, 0, UITER_START);
+ cces = 0;
+ level = UCOL_PSK_SECONDARY;
+ break;
+ }
+ if(!isShiftedCE(CE, LVT, &wasShifted)) {
+ CE >>= UCOL_PRIMARYORDERSHIFT; /* get primary */
+ if(CE != 0) {
+ if(byteCountOrFrenchDone == 0) {
+ // get the second byte of primary
+ dest[i++]=(uint8_t)(CE >> 8);
+ } else {
+ byteCountOrFrenchDone = 0;
+ }
+ if((CE &=0xff)!=0) {
+ if(i==count) {
+ /* overflow */
+ byteCountOrFrenchDone = 1;
+ cces--;
+ goto saveState;
+ }
+ dest[i++]=(uint8_t)CE;
+ }
+ }
+ }
+ if(uprv_numAvailableExpCEs(s)) {
+ canUpdateState = FALSE;
+ } else {
+ canUpdateState = TRUE;
+ }
+ }
+ /* fall through to next level */
+ case UCOL_PSK_SECONDARY:
+ if(strength >= UCOL_SECONDARY) {
+ if(!doingFrench) {
+ for(;;) {
+ if(i == count) {
+ goto saveState;
+ }
+ // We should save the state only if we
+ // are sure that we are done with the
+ // previous iterator state
+ if(canUpdateState) {
+ newState = s.iterator->getState(s.iterator);
+ if(newState != UITER_NO_STATE) {
+ iterState = newState;
+ cces = 0;
+ }
+ }
+ CE = ucol_IGetNextCE(coll, &s, status);
+ cces++;
+ if(CE==UCOL_NO_MORE_CES) {
+ // Add the level separator
+ terminatePSKLevel(level, maxLevel, i, dest);
+ byteCountOrFrenchDone = 0;
+ // Restart the iteration an move to the
+ // second level
+ s.iterator->move(s.iterator, 0, UITER_START);
+ cces = 0;
+ level = UCOL_PSK_CASE;
+ break;
+ }
+ if(!isShiftedCE(CE, LVT, &wasShifted)) {
+ CE >>= 8; /* get secondary */
+ if(CE != 0) {
+ dest[i++]=(uint8_t)CE;
+ }
+ }
+ if(uprv_numAvailableExpCEs(s)) {
+ canUpdateState = FALSE;
+ } else {
+ canUpdateState = TRUE;
+ }
+ }
+ } else { // French secondary processing
+ uint8_t frenchBuff[UCOL_MAX_BUFFER];
+ int32_t frenchIndex = 0;
+ // Here we are going backwards.
+ // If the iterator is at the beggining, it should be
+ // moved to end.
+ if(wasDoingPrimary) {
+ s.iterator->move(s.iterator, 0, UITER_LIMIT);
+ cces = 0;
+ }
+ for(;;) {
+ if(i == count) {
+ goto saveState;
+ }
+ if(canUpdateState) {
+ newState = s.iterator->getState(s.iterator);
+ if(newState != UITER_NO_STATE) {
+ iterState = newState;
+ cces = 0;
+ }
+ }
+ CE = ucol_IGetPrevCE(coll, &s, status);
+ cces++;
+ if(CE==UCOL_NO_MORE_CES) {
+ // Add the level separator
+ terminatePSKLevel(level, maxLevel, i, dest);
+ byteCountOrFrenchDone = 0;
+ // Restart the iteration an move to the next level
+ s.iterator->move(s.iterator, 0, UITER_START);
+ level = UCOL_PSK_CASE;
+ break;
+ }
+ if(isContinuation(CE)) { // if it's a continuation, we want to save it and
+ // reverse when we get a first non-continuation CE.
+ CE >>= 8;
+ frenchBuff[frenchIndex++] = (uint8_t)CE;
+ } else if(!isShiftedCE(CE, LVT, &wasShifted)) {
+ CE >>= 8; /* get secondary */
+ if(!frenchIndex) {
+ if(CE != 0) {
+ dest[i++]=(uint8_t)CE;
+ }
+ } else {
+ frenchBuff[frenchIndex++] = (uint8_t)CE;
+ frenchIndex -= usedFrench;
+ usedFrench = 0;
+ while(i < count && frenchIndex) {
+ dest[i++] = frenchBuff[--frenchIndex];
+ usedFrench++;
+ }
+ }
+ }
+ if(uprv_numAvailableExpCEs(s)) {
+ canUpdateState = FALSE;
+ } else {
+ canUpdateState = TRUE;
+ }
+ }
+ }
+ } else {
+ level = UCOL_PSK_CASE;
+ }
+ /* fall through to next level */
+ case UCOL_PSK_CASE:
+ if(ucol_getAttribute(coll, UCOL_CASE_LEVEL, status) == UCOL_ON) {
+ uint32_t caseShift = UCOL_CASE_SHIFT_START;
+ uint8_t caseByte = UCOL_CASE_BYTE_START;
+ uint8_t caseBits = 0;
+
+ for(;;) {
+ if(i == count) {
+ goto saveState;
+ }
+ // We should save the state only if we
+ // are sure that we are done with the
+ // previous iterator state
+ if(canUpdateState) {
+ newState = s.iterator->getState(s.iterator);
+ if(newState != UITER_NO_STATE) {
+ iterState = newState;
+ cces = 0;
+ }
+ }
+ CE = ucol_IGetNextCE(coll, &s, status);
+ cces++;
+ if(CE==UCOL_NO_MORE_CES) {
+ // On the case level we might have an unfinished
+ // case byte. Add one if it's started.
+ if(caseShift != UCOL_CASE_SHIFT_START) {
+ dest[i++] = caseByte;
+ }
+ cces = 0;
+ // We have finished processing CEs on this level.
+ // However, we don't know if we have enough space
+ // to add a case level terminator.
+ if(i < count) {
+ // Add the level separator
+ terminatePSKLevel(level, maxLevel, i, dest);
+ // Restart the iteration and move to the
+ // next level
+ s.iterator->move(s.iterator, 0, UITER_START);
+ level = UCOL_PSK_TERTIARY;
+ } else {
+ canUpdateState = FALSE;
+ }
+ break;
+ }
+
+ if(!isShiftedCE(CE, LVT, &wasShifted)) {
+ if(!isContinuation(CE) && ((CE & UCOL_PRIMARYMASK) != 0 || strength > UCOL_PRIMARY)) {
+ // do the case level if we need to do it. We don't want to calculate
+ // case level for primary ignorables if we have only primary strength and case level
+ // otherwise we would break well formedness of CEs
+ CE = (uint8_t)(CE & UCOL_BYTE_SIZE_MASK);
+ caseBits = (uint8_t)(CE & 0xC0);
+ // this copies the case level logic from the
+ // sort key generation code
+ if(CE != 0) {
+ if(coll->caseFirst == UCOL_UPPER_FIRST) {
+ if((caseBits & 0xC0) == 0) {
+ caseByte |= 1 << (--caseShift);
+ } else {
+ caseByte |= 0 << (--caseShift);
+ /* second bit */
+ if(caseShift == 0) {
+ dest[i++] = caseByte;
+ caseShift = UCOL_CASE_SHIFT_START;
+ caseByte = UCOL_CASE_BYTE_START;
+ }
+ caseByte |= ((caseBits>>6)&1) << (--caseShift);
+ }
+ } else {
+ if((caseBits & 0xC0) == 0) {
+ caseByte |= 0 << (--caseShift);
+ } else {
+ caseByte |= 1 << (--caseShift);
+ /* second bit */
+ if(caseShift == 0) {
+ dest[i++] = caseByte;
+ caseShift = UCOL_CASE_SHIFT_START;
+ caseByte = UCOL_CASE_BYTE_START;
+ }
+ caseByte |= ((caseBits>>7)&1) << (--caseShift);
+ }
+ }
+ }
+
+ }
+ }
+ // Not sure this is correct for the case level - revisit
+ if(uprv_numAvailableExpCEs(s)) {
+ canUpdateState = FALSE;
+ } else {
+ canUpdateState = TRUE;
+ }
+ }
+ } else {
+ level = UCOL_PSK_TERTIARY;
+ }
+ /* fall through to next level */
+ case UCOL_PSK_TERTIARY:
+ if(strength >= UCOL_TERTIARY) {
+ for(;;) {
+ if(i == count) {
+ goto saveState;
+ }
+ // We should save the state only if we
+ // are sure that we are done with the
+ // previous iterator state
+ if(canUpdateState) {
+ newState = s.iterator->getState(s.iterator);
+ if(newState != UITER_NO_STATE) {
+ iterState = newState;
+ cces = 0;
+ }
+ }
+ CE = ucol_IGetNextCE(coll, &s, status);
+ cces++;
+ if(CE==UCOL_NO_MORE_CES) {
+ // Add the level separator
+ terminatePSKLevel(level, maxLevel, i, dest);
+ byteCountOrFrenchDone = 0;
+ // Restart the iteration an move to the
+ // second level
+ s.iterator->move(s.iterator, 0, UITER_START);
+ cces = 0;
+ level = UCOL_PSK_QUATERNARY;
+ break;
+ }
+ if(!isShiftedCE(CE, LVT, &wasShifted)) {
+ notIsContinuation = !isContinuation(CE);
+
+ if(notIsContinuation) {
+ CE = (uint8_t)(CE & UCOL_BYTE_SIZE_MASK);
+ CE ^= coll->caseSwitch;
+ CE &= coll->tertiaryMask;
+ } else {
+ CE = (uint8_t)((CE & UCOL_REMOVE_CONTINUATION));
+ }
+
+ if(CE != 0) {
+ dest[i++]=(uint8_t)CE;
+ }
+ }
+ if(uprv_numAvailableExpCEs(s)) {
+ canUpdateState = FALSE;
+ } else {
+ canUpdateState = TRUE;
+ }
+ }
+ } else {
+ // if we're not doing tertiary
+ // skip to the end
+ level = UCOL_PSK_NULL;
+ }
+ /* fall through to next level */
+ case UCOL_PSK_QUATERNARY:
+ if(strength >= UCOL_QUATERNARY) {
+ for(;;) {
+ if(i == count) {
+ goto saveState;
+ }
+ // We should save the state only if we
+ // are sure that we are done with the
+ // previous iterator state
+ if(canUpdateState) {
+ newState = s.iterator->getState(s.iterator);
+ if(newState != UITER_NO_STATE) {
+ iterState = newState;
+ cces = 0;
+ }
+ }
+ CE = ucol_IGetNextCE(coll, &s, status);
+ cces++;
+ if(CE==UCOL_NO_MORE_CES) {
+ // Add the level separator
+ terminatePSKLevel(level, maxLevel, i, dest);
+ //dest[i++] = UCOL_LEVELTERMINATOR;
+ byteCountOrFrenchDone = 0;
+ // Restart the iteration an move to the
+ // second level
+ s.iterator->move(s.iterator, 0, UITER_START);
+ cces = 0;
+ level = UCOL_PSK_QUIN;
+ break;
+ }
+ if(CE==0)
+ continue;
+ if(isShiftedCE(CE, LVT, &wasShifted)) {
+ CE >>= 16; /* get primary */
+ if(CE != 0) {
+ if(byteCountOrFrenchDone == 0) {
+ dest[i++]=(uint8_t)(CE >> 8);
+ } else {
+ byteCountOrFrenchDone = 0;
+ }
+ if((CE &=0xff)!=0) {
+ if(i==count) {
+ /* overflow */
+ byteCountOrFrenchDone = 1;
+ goto saveState;
+ }
+ dest[i++]=(uint8_t)CE;
+ }
+ }
+ } else {
+ notIsContinuation = !isContinuation(CE);
+ if(notIsContinuation) {
+ if(s.flags & UCOL_WAS_HIRAGANA) { // This was Hiragana and we need to note it
+ dest[i++] = UCOL_HIRAGANA_QUAD;
+ } else {
+ dest[i++] = 0xFF;
+ }
+ }
+ }
+ if(uprv_numAvailableExpCEs(s)) {
+ canUpdateState = FALSE;
+ } else {
+ canUpdateState = TRUE;
+ }
+ }
+ } else {
+ // if we're not doing quaternary
+ // skip to the end
+ level = UCOL_PSK_NULL;
+ }
+ /* fall through to next level */
+ case UCOL_PSK_QUIN:
+ level = UCOL_PSK_IDENTICAL;
+ /* fall through to next level */
+ case UCOL_PSK_IDENTICAL:
+ if(strength >= UCOL_IDENTICAL) {
+ UChar32 first, second;
+ int32_t bocsuBytesWritten = 0;
+ // We always need to do identical on
+ // the NFD form of the string.
+ if(normIter == NULL) {
+ // we arrived from the level below and
+ // normalization was not turned on.
+ // therefore, we need to make a fresh NFD iterator
+ normIter = unorm_openIter(stackNormIter, sizeof(stackNormIter), status);
+ s.iterator = unorm_setIter(normIter, iter, UNORM_NFD, status);
+ } else if(!doingIdenticalFromStart) {
+ // there is an iterator, but we did some other levels.
+ // therefore, we have a FCD iterator - need to make
+ // a NFD one.
+ // normIter being at the beginning does not guarantee
+ // that the underlying iterator is at the beginning
+ iter->move(iter, 0, UITER_START);
+ s.iterator = unorm_setIter(normIter, iter, UNORM_NFD, status);
+ }
+ // At this point we have a NFD iterator that is positioned
+ // in the right place
+ if(U_FAILURE(*status)) {
+ UTRACE_EXIT_STATUS(*status);
+ return 0;
+ }
+ first = uiter_previous32(s.iterator);
+ // maybe we're at the start of the string
+ if(first == U_SENTINEL) {
+ first = 0;
+ } else {
+ uiter_next32(s.iterator);
+ }
+
+ j = 0;
+ for(;;) {
+ if(i == count) {
+ if(j+1 < bocsuBytesWritten) {
+ bocsuBytesUsed = j+1;
+ }
+ goto saveState;
+ }
+
+ // On identical level, we will always save
+ // the state if we reach this point, since
+ // we don't depend on getNextCE for content
+ // all the content is in our buffer and we
+ // already either stored the full buffer OR
+ // otherwise we won't arrive here.
+ newState = s.iterator->getState(s.iterator);
+ if(newState != UITER_NO_STATE) {
+ iterState = newState;
+ cces = 0;
+ }
+
+ uint8_t buff[4];
+ second = uiter_next32(s.iterator);
+ cces++;
+
+ // end condition for identical level
+ if(second == U_SENTINEL) {
+ terminatePSKLevel(level, maxLevel, i, dest);
+ level = UCOL_PSK_NULL;
+ break;
+ }
+ bocsuBytesWritten = u_writeIdenticalLevelRunTwoChars(first, second, buff);
+ first = second;
+
+ j = 0;
+ if(bocsuBytesUsed != 0) {
+ while(bocsuBytesUsed-->0) {
+ j++;
+ }
+ }
+
+ while(i < count && j < bocsuBytesWritten) {
+ dest[i++] = buff[j++];
+ }
+ }
+
+ } else {
+ level = UCOL_PSK_NULL;
+ }
+ /* fall through to next level */
+ case UCOL_PSK_NULL:
+ j = i;
+ while(j<count) {
+ dest[j++]=0;
+ }
+ break;
+ default:
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ UTRACE_EXIT_STATUS(*status);
+ return 0;
+ }
+
+saveState:
+ // Now we need to return stuff. First we want to see whether we have
+ // done everything for the current state of iterator.
+ if(byteCountOrFrenchDone
+ || canUpdateState == FALSE
+ || (newState = s.iterator->getState(s.iterator)) == UITER_NO_STATE) {
+ // Any of above mean that the previous transaction
+ // wasn't finished and that we should store the
+ // previous iterator state.
+ state[0] = iterState;
+ } else {
+ // The transaction is complete. We will continue in the next iteration.
+ state[0] = s.iterator->getState(s.iterator);
+ cces = 0;
+ }
+ // Store the number of bocsu bytes written.
+ if((bocsuBytesUsed & UCOL_PSK_BOCSU_BYTES_MASK) != bocsuBytesUsed) {
+ *status = U_INDEX_OUTOFBOUNDS_ERROR;
+ }
+ state[1] = (bocsuBytesUsed & UCOL_PSK_BOCSU_BYTES_MASK) << UCOL_PSK_BOCSU_BYTES_SHIFT;
+
+ // Next we put in the level of comparison
+ state[1] |= ((level & UCOL_PSK_LEVEL_MASK) << UCOL_PSK_LEVEL_SHIFT);
+
+ // If we are doing French, we need to store whether we have just finished the French level
+ if(level == UCOL_PSK_SECONDARY && doingFrench) {
+ state[1] |= (((state[0] == 0) & UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK) << UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT);
+ } else {
+ state[1] |= ((byteCountOrFrenchDone & UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_MASK) << UCOL_PSK_BYTE_COUNT_OR_FRENCH_DONE_SHIFT);
+ }
+
+ // Was the latest CE shifted
+ if(wasShifted) {
+ state[1] |= 1 << UCOL_PSK_WAS_SHIFTED_SHIFT;
+ }
+ // Check for cces overflow
+ if((cces & UCOL_PSK_CONSUMED_CES_MASK) != cces) {
+ *status = U_INDEX_OUTOFBOUNDS_ERROR;
+ }
+ // Store cces
+ state[1] |= ((cces & UCOL_PSK_CONSUMED_CES_MASK) << UCOL_PSK_CONSUMED_CES_SHIFT);
+
+ // Check for French overflow
+ if((usedFrench & UCOL_PSK_USED_FRENCH_MASK) != usedFrench) {
+ *status = U_INDEX_OUTOFBOUNDS_ERROR;
+ }
+ // Store number of bytes written in the French secondary continuation sequence
+ state[1] |= ((usedFrench & UCOL_PSK_USED_FRENCH_MASK) << UCOL_PSK_USED_FRENCH_SHIFT);
+
+
+ // If we have used normalizing iterator, get rid of it
+ if(normIter != NULL) {
+ unorm_closeIter(normIter);
+ }
+
+ // Return number of meaningful sortkey bytes.
+ UTRACE_DATA4(UTRACE_VERBOSE, "dest = %vb, state=%d %d",
+ dest,i, state[0], state[1]);
+ UTRACE_EXIT_VALUE(i);
+ return i;
+}
+
+/**
+ * Produce a bound for a given sortkey and a number of levels.
+ */
+U_CAPI int32_t U_EXPORT2
+ucol_getBound(const uint8_t *source,
+ int32_t sourceLength,
+ UColBoundMode boundType,
+ uint32_t noOfLevels,
+ uint8_t *result,
+ int32_t resultLength,
+ UErrorCode *status) {
+ // consistency checks
+ if(status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+ if(source == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ int32_t sourceIndex = 0;
+ // Scan the string until we skip enough of the key OR reach the end of the key
+ do {
+ sourceIndex++;
+ if(source[sourceIndex] == UCOL_LEVELTERMINATOR) {
+ noOfLevels--;
+ }
+ } while (noOfLevels > 0
+ && (source[sourceIndex] != 0 || sourceIndex < sourceLength));
+
+ if((source[sourceIndex] == 0 || sourceIndex == sourceLength)
+ && noOfLevels > 0) {
+ *status = U_SORT_KEY_TOO_SHORT_WARNING;
+ }
+
+
+ // READ ME: this code assumes that the values for boundType
+ // enum will not changes. They are set so that the enum value
+ // corresponds to the number of extra bytes each bound type
+ // needs.
+ if(result != NULL && resultLength >= sourceIndex+boundType) {
+ uprv_memcpy(result, source, sourceIndex);
+ switch(boundType) {
+ // Lower bound just gets terminated. No extra bytes
+ case UCOL_BOUND_LOWER: // = 0
+ break;
+ // Upper bound needs one extra byte
+ case UCOL_BOUND_UPPER: // = 1
+ result[sourceIndex++] = 2;
+ break;
+ // Upper long bound needs two extra bytes
+ case UCOL_BOUND_UPPER_LONG: // = 2
+ result[sourceIndex++] = 0xFF;
+ result[sourceIndex++] = 0xFF;
+ break;
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ result[sourceIndex++] = 0;
+
+ return sourceIndex;
+ } else {
+ return sourceIndex+boundType+1;
+ }
+}
+
+/****************************************************************************/
+/* Following are the functions that deal with the properties of a collator */
+/* there are new APIs and some compatibility APIs */
+/****************************************************************************/
+
+static inline void
+ucol_addLatinOneEntry(UCollator *coll, UChar ch, uint32_t CE,
+ int32_t *primShift, int32_t *secShift, int32_t *terShift) {
+ uint8_t primary1 = 0, primary2 = 0, secondary = 0, tertiary = 0;
+ UBool reverseSecondary = FALSE;
+ if(!isContinuation(CE)) {
+ tertiary = (uint8_t)((CE & coll->tertiaryMask));
+ tertiary ^= coll->caseSwitch;
+ reverseSecondary = TRUE;
+ } else {
+ tertiary = (uint8_t)((CE & UCOL_REMOVE_CONTINUATION));
+ tertiary &= UCOL_REMOVE_CASE;
+ reverseSecondary = FALSE;
+ }
+
+ secondary = (uint8_t)((CE >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary2 = (uint8_t)((CE >>= 8) & UCOL_BYTE_SIZE_MASK);
+ primary1 = (uint8_t)(CE >> 8);
+
+ if(primary1 != 0) {
+ coll->latinOneCEs[ch] |= (primary1 << *primShift);
+ *primShift -= 8;
+ }
+ if(primary2 != 0) {
+ if(*primShift < 0) {
+ coll->latinOneCEs[ch] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[coll->latinOneTableLen+ch] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[2*coll->latinOneTableLen+ch] = UCOL_BAIL_OUT_CE;
+ return;
+ }
+ coll->latinOneCEs[ch] |= (primary2 << *primShift);
+ *primShift -= 8;
+ }
+ if(secondary != 0) {
+ if(reverseSecondary && coll->frenchCollation == UCOL_ON) { // reverse secondary
+ coll->latinOneCEs[coll->latinOneTableLen+ch] >>= 8; // make space for secondary
+ coll->latinOneCEs[coll->latinOneTableLen+ch] |= (secondary << 24);
+ } else { // normal case
+ coll->latinOneCEs[coll->latinOneTableLen+ch] |= (secondary << *secShift);
+ }
+ *secShift -= 8;
+ }
+ if(tertiary != 0) {
+ coll->latinOneCEs[2*coll->latinOneTableLen+ch] |= (tertiary << *terShift);
+ *terShift -= 8;
+ }
+}
+
+static inline UBool
+ucol_resizeLatinOneTable(UCollator *coll, int32_t size, UErrorCode *status) {
+ uint32_t *newTable = (uint32_t *)uprv_malloc(size*sizeof(uint32_t)*3);
+ if(newTable == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ coll->latinOneFailed = TRUE;
+ return FALSE;
+ }
+ int32_t sizeToCopy = ((size<coll->latinOneTableLen)?size:coll->latinOneTableLen)*sizeof(uint32_t);
+ uprv_memset(newTable, 0, size*sizeof(uint32_t)*3);
+ uprv_memcpy(newTable, coll->latinOneCEs, sizeToCopy);
+ uprv_memcpy(newTable+size, coll->latinOneCEs+coll->latinOneTableLen, sizeToCopy);
+ uprv_memcpy(newTable+2*size, coll->latinOneCEs+2*coll->latinOneTableLen, sizeToCopy);
+ coll->latinOneTableLen = size;
+ uprv_free(coll->latinOneCEs);
+ coll->latinOneCEs = newTable;
+ return TRUE;
+}
+
+static UBool
+ucol_setUpLatinOne(UCollator *coll, UErrorCode *status) {
+ UBool result = TRUE;
+ if(coll->latinOneCEs == NULL) {
+ coll->latinOneCEs = (uint32_t *)uprv_malloc(sizeof(uint32_t)*UCOL_LATINONETABLELEN*3);
+ if(coll->latinOneCEs == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return FALSE;
+ }
+ coll->latinOneTableLen = UCOL_LATINONETABLELEN;
+ }
+ UChar ch = 0;
+ UCollationElements *it = ucol_openElements(coll, &ch, 1, status);
+ uprv_memset(coll->latinOneCEs, 0, sizeof(uint32_t)*coll->latinOneTableLen*3);
+
+ int32_t primShift = 24, secShift = 24, terShift = 24;
+ uint32_t CE = 0;
+ int32_t contractionOffset = UCOL_ENDOFLATINONERANGE+1;
+
+ // TODO: make safe if you get more than you wanted...
+ for(ch = 0; ch <= UCOL_ENDOFLATINONERANGE; ch++) {
+ primShift = 24; secShift = 24; terShift = 24;
+ if(ch < 0x100) {
+ CE = coll->latinOneMapping[ch];
+ } else {
+ CE = UTRIE_GET32_FROM_LEAD(&coll->mapping, ch);
+ if(CE == UCOL_NOT_FOUND && coll->UCA) {
+ CE = UTRIE_GET32_FROM_LEAD(&coll->UCA->mapping, ch);
+ }
+ }
+ if(CE < UCOL_NOT_FOUND) {
+ ucol_addLatinOneEntry(coll, ch, CE, &primShift, &secShift, &terShift);
+ } else {
+ switch (getCETag(CE)) {
+ case EXPANSION_TAG:
+ case DIGIT_TAG:
+ ucol_setText(it, &ch, 1, status);
+ while((int32_t)(CE = ucol_next(it, status)) != UCOL_NULLORDER) {
+ if(primShift < 0 || secShift < 0 || terShift < 0) {
+ coll->latinOneCEs[ch] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[coll->latinOneTableLen+ch] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[2*coll->latinOneTableLen+ch] = UCOL_BAIL_OUT_CE;
+ break;
+ }
+ ucol_addLatinOneEntry(coll, ch, CE, &primShift, &secShift, &terShift);
+ }
+ break;
+ case CONTRACTION_TAG:
+ // here is the trick
+ // F2 is contraction. We do something very similar to contractions
+ // but have two indices, one in the real contraction table and the
+ // other to where we stuffed things. This hopes that we don't have
+ // many contractions (this should work for latin-1 tables).
+ {
+ if((CE & 0x00FFF000) != 0) {
+ *status = U_UNSUPPORTED_ERROR;
+ goto cleanup_after_failure;
+ }
+
+ const UChar *UCharOffset = (UChar *)coll->image+getContractOffset(CE);
+
+ CE |= (contractionOffset & 0xFFF) << 12; // insert the offset in latin-1 table
+
+ coll->latinOneCEs[ch] = CE;
+ coll->latinOneCEs[coll->latinOneTableLen+ch] = CE;
+ coll->latinOneCEs[2*coll->latinOneTableLen+ch] = CE;
+
+ // We're going to jump into contraction table, pick the elements
+ // and use them
+ do {
+ CE = *(coll->contractionCEs +
+ (UCharOffset - coll->contractionIndex));
+ if(CE > UCOL_NOT_FOUND && getCETag(CE) == EXPANSION_TAG) {
+ uint32_t size;
+ uint32_t i; /* general counter */
+ uint32_t *CEOffset = (uint32_t *)coll->image+getExpansionOffset(CE); /* find the offset to expansion table */
+ size = getExpansionCount(CE);
+ //CE = *CEOffset++;
+ if(size != 0) { /* if there are less than 16 elements in expansion, we don't terminate */
+ for(i = 0; i<size; i++) {
+ if(primShift < 0 || secShift < 0 || terShift < 0) {
+ coll->latinOneCEs[(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[2*coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
+ break;
+ }
+ ucol_addLatinOneEntry(coll, (UChar)contractionOffset, *CEOffset++, &primShift, &secShift, &terShift);
+ }
+ } else { /* else, we do */
+ while(*CEOffset != 0) {
+ if(primShift < 0 || secShift < 0 || terShift < 0) {
+ coll->latinOneCEs[(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[2*coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
+ break;
+ }
+ ucol_addLatinOneEntry(coll, (UChar)contractionOffset, *CEOffset++, &primShift, &secShift, &terShift);
+ }
+ }
+ contractionOffset++;
+ } else if(CE < UCOL_NOT_FOUND) {
+ ucol_addLatinOneEntry(coll, (UChar)contractionOffset++, CE, &primShift, &secShift, &terShift);
+ } else {
+ coll->latinOneCEs[(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
+ coll->latinOneCEs[2*coll->latinOneTableLen+(UChar)contractionOffset] = UCOL_BAIL_OUT_CE;
+ contractionOffset++;
+ }
+ UCharOffset++;
+ primShift = 24; secShift = 24; terShift = 24;
+ if(contractionOffset == coll->latinOneTableLen) { // we need to reallocate
+ if(!ucol_resizeLatinOneTable(coll, 2*coll->latinOneTableLen, status)) {
+ goto cleanup_after_failure;
+ }
+ }
+ } while(*UCharOffset != 0xFFFF);
+ }
+ break;
+ default:
+ goto cleanup_after_failure;
+ }
+ }
+ }
+ // compact table
+ if(contractionOffset < coll->latinOneTableLen) {
+ if(!ucol_resizeLatinOneTable(coll, contractionOffset, status)) {
+ goto cleanup_after_failure;
+ }
+ }
+ ucol_closeElements(it);
+ return result;
+
+cleanup_after_failure:
+ // status should already be set before arriving here.
+ coll->latinOneFailed = TRUE;
+ ucol_closeElements(it);
+ return FALSE;
+}
+
+void ucol_updateInternalState(UCollator *coll, UErrorCode *status) {
+ if(U_SUCCESS(*status)) {
+ if(coll->caseFirst == UCOL_UPPER_FIRST) {
+ coll->caseSwitch = UCOL_CASE_SWITCH;
+ } else {
+ coll->caseSwitch = UCOL_NO_CASE_SWITCH;
+ }
+
+ if(coll->caseLevel == UCOL_ON || coll->caseFirst == UCOL_OFF) {
+ coll->tertiaryMask = UCOL_REMOVE_CASE;
+ coll->tertiaryCommon = UCOL_COMMON3_NORMAL;
+ coll->tertiaryAddition = UCOL_FLAG_BIT_MASK_CASE_SW_OFF;
+ coll->tertiaryTop = UCOL_COMMON_TOP3_CASE_SW_OFF;
+ coll->tertiaryBottom = UCOL_COMMON_BOT3;
+ } else {
+ coll->tertiaryMask = UCOL_KEEP_CASE;
+ coll->tertiaryAddition = UCOL_FLAG_BIT_MASK_CASE_SW_ON;
+ if(coll->caseFirst == UCOL_UPPER_FIRST) {
+ coll->tertiaryCommon = UCOL_COMMON3_UPPERFIRST;
+ coll->tertiaryTop = UCOL_COMMON_TOP3_CASE_SW_UPPER;
+ coll->tertiaryBottom = UCOL_COMMON_BOTTOM3_CASE_SW_UPPER;
+ } else {
+ coll->tertiaryCommon = UCOL_COMMON3_NORMAL;
+ coll->tertiaryTop = UCOL_COMMON_TOP3_CASE_SW_LOWER;
+ coll->tertiaryBottom = UCOL_COMMON_BOTTOM3_CASE_SW_LOWER;
+ }
+ }
+
+ /* Set the compression values */
+ uint8_t tertiaryTotal = (uint8_t)(coll->tertiaryTop - UCOL_COMMON_BOT3-1);
+ coll->tertiaryTopCount = (uint8_t)(UCOL_PROPORTION3*tertiaryTotal); /* we multilply double with int, but need only int */
+ coll->tertiaryBottomCount = (uint8_t)(tertiaryTotal - coll->tertiaryTopCount);
+
+ if(coll->caseLevel == UCOL_OFF && coll->strength == UCOL_TERTIARY
+ && coll->frenchCollation == UCOL_OFF && coll->alternateHandling == UCOL_NON_IGNORABLE) {
+ coll->sortKeyGen = ucol_calcSortKeySimpleTertiary;
+ } else {
+ coll->sortKeyGen = ucol_calcSortKey;
+ }
+ if(coll->caseLevel == UCOL_OFF && coll->strength <= UCOL_TERTIARY && coll->numericCollation == UCOL_OFF
+ && coll->alternateHandling == UCOL_NON_IGNORABLE && !coll->latinOneFailed) {
+ if(coll->latinOneCEs == NULL || coll->latinOneRegenTable) {
+ if(ucol_setUpLatinOne(coll, status)) { // if we succeed in building latin1 table, we'll use it
+ //fprintf(stderr, "F");
+ coll->latinOneUse = TRUE;
+ } else {
+ coll->latinOneUse = FALSE;
+ }
+ if(*status == U_UNSUPPORTED_ERROR) {
+ *status = U_ZERO_ERROR;
+ }
+ } else { // latin1Table exists and it doesn't need to be regenerated, just use it
+ coll->latinOneUse = TRUE;
+ }
+ } else {
+ coll->latinOneUse = FALSE;
+ }
+ }
+}
+
+U_CAPI uint32_t U_EXPORT2
+ucol_setVariableTop(UCollator *coll, const UChar *varTop, int32_t len, UErrorCode *status) {
+ if(U_FAILURE(*status) || coll == NULL) {
+ return 0;
+ }
+ if(len == -1) {
+ len = u_strlen(varTop);
+ }
+ if(len == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ collIterate s;
+ IInit_collIterate(coll, varTop, len, &s);
+
+ uint32_t CE = ucol_IGetNextCE(coll, &s, status);
+
+ /* here we check if we have consumed all characters */
+ /* you can put in either one character or a contraction */
+ /* you shouldn't put more... */
+ if(s.pos != s.endp || CE == UCOL_NO_MORE_CES) {
+ *status = U_CE_NOT_FOUND_ERROR;
+ return 0;
+ }
+
+ uint32_t nextCE = ucol_IGetNextCE(coll, &s, status);
+
+ if(isContinuation(nextCE) && (nextCE & UCOL_PRIMARYMASK) != 0) {
+ *status = U_PRIMARY_TOO_LONG_ERROR;
+ return 0;
+ }
+ if(coll->variableTopValue != (CE & UCOL_PRIMARYMASK)>>16) {
+ coll->variableTopValueisDefault = FALSE;
+ coll->variableTopValue = (CE & UCOL_PRIMARYMASK)>>16;
+ }
+
+ return CE & UCOL_PRIMARYMASK;
+}
+
+U_CAPI uint32_t U_EXPORT2 ucol_getVariableTop(const UCollator *coll, UErrorCode *status) {
+ if(U_FAILURE(*status) || coll == NULL) {
+ return 0;
+ }
+ return coll->variableTopValue<<16;
+}
+
+U_CAPI void U_EXPORT2
+ucol_restoreVariableTop(UCollator *coll, const uint32_t varTop, UErrorCode *status) {
+ if(U_FAILURE(*status) || coll == NULL) {
+ return;
+ }
+
+ if(coll->variableTopValue != (varTop & UCOL_PRIMARYMASK)>>16) {
+ coll->variableTopValueisDefault = FALSE;
+ coll->variableTopValue = (varTop & UCOL_PRIMARYMASK)>>16;
+ }
+}
+/* Attribute setter API */
+U_CAPI void U_EXPORT2
+ucol_setAttribute(UCollator *coll, UColAttribute attr, UColAttributeValue value, UErrorCode *status) {
+ if(U_FAILURE(*status) || coll == NULL) {
+ return;
+ }
+ UColAttributeValue oldFrench = coll->frenchCollation;
+ UColAttributeValue oldCaseFirst = coll->caseFirst;
+ switch(attr) {
+ case UCOL_NUMERIC_COLLATION: /* sort substrings of digits as numbers */
+ if(value == UCOL_ON) {
+ coll->numericCollation = UCOL_ON;
+ coll->numericCollationisDefault = FALSE;
+ } else if (value == UCOL_OFF) {
+ coll->numericCollation = UCOL_OFF;
+ coll->numericCollationisDefault = FALSE;
+ } else if (value == UCOL_DEFAULT) {
+ coll->numericCollationisDefault = TRUE;
+ coll->numericCollation = (UColAttributeValue)coll->options->numericCollation;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+ case UCOL_HIRAGANA_QUATERNARY_MODE: /* special quaternary values for Hiragana */
+ if(value == UCOL_ON) {
+ coll->hiraganaQ = UCOL_ON;
+ coll->hiraganaQisDefault = FALSE;
+ } else if (value == UCOL_OFF) {
+ coll->hiraganaQ = UCOL_OFF;
+ coll->hiraganaQisDefault = FALSE;
+ } else if (value == UCOL_DEFAULT) {
+ coll->hiraganaQisDefault = TRUE;
+ coll->hiraganaQ = (UColAttributeValue)coll->options->hiraganaQ;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+ case UCOL_FRENCH_COLLATION: /* attribute for direction of secondary weights*/
+ if(value == UCOL_ON) {
+ coll->frenchCollation = UCOL_ON;
+ coll->frenchCollationisDefault = FALSE;
+ } else if (value == UCOL_OFF) {
+ coll->frenchCollation = UCOL_OFF;
+ coll->frenchCollationisDefault = FALSE;
+ } else if (value == UCOL_DEFAULT) {
+ coll->frenchCollationisDefault = TRUE;
+ coll->frenchCollation = (UColAttributeValue)coll->options->frenchCollation;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR ;
+ }
+ break;
+ case UCOL_ALTERNATE_HANDLING: /* attribute for handling variable elements*/
+ if(value == UCOL_SHIFTED) {
+ coll->alternateHandling = UCOL_SHIFTED;
+ coll->alternateHandlingisDefault = FALSE;
+ } else if (value == UCOL_NON_IGNORABLE) {
+ coll->alternateHandling = UCOL_NON_IGNORABLE;
+ coll->alternateHandlingisDefault = FALSE;
+ } else if (value == UCOL_DEFAULT) {
+ coll->alternateHandlingisDefault = TRUE;
+ coll->alternateHandling = (UColAttributeValue)coll->options->alternateHandling ;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR ;
+ }
+ break;
+ case UCOL_CASE_FIRST: /* who goes first, lower case or uppercase */
+ if(value == UCOL_LOWER_FIRST) {
+ coll->caseFirst = UCOL_LOWER_FIRST;
+ coll->caseFirstisDefault = FALSE;
+ } else if (value == UCOL_UPPER_FIRST) {
+ coll->caseFirst = UCOL_UPPER_FIRST;
+ coll->caseFirstisDefault = FALSE;
+ } else if (value == UCOL_OFF) {
+ coll->caseFirst = UCOL_OFF;
+ coll->caseFirstisDefault = FALSE;
+ } else if (value == UCOL_DEFAULT) {
+ coll->caseFirst = (UColAttributeValue)coll->options->caseFirst;
+ coll->caseFirstisDefault = TRUE;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR ;
+ }
+ break;
+ case UCOL_CASE_LEVEL: /* do we have an extra case level */
+ if(value == UCOL_ON) {
+ coll->caseLevel = UCOL_ON;
+ coll->caseLevelisDefault = FALSE;
+ } else if (value == UCOL_OFF) {
+ coll->caseLevel = UCOL_OFF;
+ coll->caseLevelisDefault = FALSE;
+ } else if (value == UCOL_DEFAULT) {
+ coll->caseLevel = (UColAttributeValue)coll->options->caseLevel;
+ coll->caseLevelisDefault = TRUE;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR ;
+ }
+ break;
+ case UCOL_NORMALIZATION_MODE: /* attribute for normalization */
+ if(value == UCOL_ON) {
+ coll->normalizationMode = UCOL_ON;
+ coll->normalizationModeisDefault = FALSE;
+ } else if (value == UCOL_OFF) {
+ coll->normalizationMode = UCOL_OFF;
+ coll->normalizationModeisDefault = FALSE;
+ } else if (value == UCOL_DEFAULT) {
+ coll->normalizationModeisDefault = TRUE;
+ coll->normalizationMode = (UColAttributeValue)coll->options->normalizationMode;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR ;
+ }
+ break;
+ case UCOL_STRENGTH: /* attribute for strength */
+ if (value == UCOL_DEFAULT) {
+ coll->strengthisDefault = TRUE;
+ coll->strength = (UColAttributeValue)coll->options->strength;
+ } else if (value <= UCOL_IDENTICAL) {
+ coll->strengthisDefault = FALSE;
+ coll->strength = value;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR ;
+ }
+ break;
+ case UCOL_ATTRIBUTE_COUNT:
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ break;
+ }
+ if(oldFrench != coll->frenchCollation || oldCaseFirst != coll->caseFirst) {
+ coll->latinOneRegenTable = TRUE;
+ } else {
+ coll->latinOneRegenTable = FALSE;
+ }
+ ucol_updateInternalState(coll, status);
+}
+
+U_CAPI UColAttributeValue U_EXPORT2
+ucol_getAttribute(const UCollator *coll, UColAttribute attr, UErrorCode *status) {
+ if(U_FAILURE(*status) || coll == NULL) {
+ return UCOL_DEFAULT;
+ }
+ switch(attr) {
+ case UCOL_NUMERIC_COLLATION:
+ return coll->numericCollation;
+ case UCOL_HIRAGANA_QUATERNARY_MODE:
+ return coll->hiraganaQ;
+ case UCOL_FRENCH_COLLATION: /* attribute for direction of secondary weights*/
+ return coll->frenchCollation;
+ case UCOL_ALTERNATE_HANDLING: /* attribute for handling variable elements*/
+ return coll->alternateHandling;
+ case UCOL_CASE_FIRST: /* who goes first, lower case or uppercase */
+ return coll->caseFirst;
+ case UCOL_CASE_LEVEL: /* do we have an extra case level */
+ return coll->caseLevel;
+ case UCOL_NORMALIZATION_MODE: /* attribute for normalization */
+ return coll->normalizationMode;
+ case UCOL_STRENGTH: /* attribute for strength */
+ return coll->strength;
+ case UCOL_ATTRIBUTE_COUNT:
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ break;
+ }
+ return UCOL_DEFAULT;
+}
+
+U_CAPI void U_EXPORT2
+ucol_setStrength( UCollator *coll,
+ UCollationStrength strength)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ ucol_setAttribute(coll, UCOL_STRENGTH, strength, &status);
+}
+
+U_CAPI UCollationStrength U_EXPORT2
+ucol_getStrength(const UCollator *coll)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ return ucol_getAttribute(coll, UCOL_STRENGTH, &status);
+}
+
+/****************************************************************************/
+/* Following are misc functions */
+/* there are new APIs and some compatibility APIs */
+/****************************************************************************/
+
+U_CAPI void U_EXPORT2
+ucol_getVersion(const UCollator* coll,
+ UVersionInfo versionInfo)
+{
+ /* RunTime version */
+ uint8_t rtVersion = UCOL_RUNTIME_VERSION;
+ /* Builder version*/
+ uint8_t bdVersion = coll->image->version[0];
+
+ /* Charset Version. Need to get the version from cnv files
+ * makeconv should populate cnv files with version and
+ * an api has to be provided in ucnv.h to obtain this version
+ */
+ uint8_t csVersion = 0;
+
+ /* combine the version info */
+ uint16_t cmbVersion = (uint16_t)((rtVersion<<11) | (bdVersion<<6) | (csVersion));
+
+ /* Tailoring rules */
+ versionInfo[0] = (uint8_t)(cmbVersion>>8);
+ versionInfo[1] = (uint8_t)cmbVersion;
+ versionInfo[2] = coll->image->version[1];
+ if(coll->UCA) {
+ versionInfo[3] = coll->UCA->image->UCAVersion[0];
+ } else {
+ versionInfo[3] = 0;
+ }
+}
+
+
+/* This internal API checks whether a character is tailored or not */
+U_CAPI UBool U_EXPORT2
+ucol_isTailored(const UCollator *coll, const UChar u, UErrorCode *status) {
+ if(U_FAILURE(*status) || coll == NULL || coll == coll->UCA) {
+ return FALSE;
+ }
+
+ uint32_t CE = UCOL_NOT_FOUND;
+ const UChar *ContractionStart = NULL;
+ if(u < 0x100) { /* latin-1 */
+ CE = coll->latinOneMapping[u];
+ if(coll->UCA && CE == coll->UCA->latinOneMapping[u]) {
+ return FALSE;
+ }
+ } else { /* regular */
+ CE = UTRIE_GET32_FROM_LEAD(&coll->mapping, u);
+ }
+
+ if(isContraction(CE)) {
+ ContractionStart = (UChar *)coll->image+getContractOffset(CE);
+ CE = *(coll->contractionCEs + (ContractionStart- coll->contractionIndex));
+ }
+
+ return (UBool)(CE != UCOL_NOT_FOUND);
+}
+
+
+/****************************************************************************/
+/* Following are the string compare functions */
+/* */
+/****************************************************************************/
+
+
+/* ucol_checkIdent internal function. Does byte level string compare. */
+/* Used by strcoll if strength == identical and strings */
+/* are otherwise equal. Moved out-of-line because this */
+/* is a rare case. */
+/* */
+/* Comparison must be done on NFD normalized strings. */
+/* FCD is not good enough. */
+/* */
+/* TODO: make an incremental NFD Comparison function, which could */
+/* be of general use */
+
+static
+UCollationResult ucol_checkIdent(collIterate *sColl, collIterate *tColl, UBool normalize, UErrorCode *status)
+{
+
+ // TODO: When we have an UChar iterator, we need to access the whole string. One
+ // useful modification would be a UChar iterator extract API, since reset next next...
+ // is not optimal.
+ // TODO: Handle long strings. Do the same in compareUsingSortKeys.
+
+ // When we arrive here, we can have normal strings or UCharIterators. Currently they are both
+ // of same type, but that doesn't really mean that it will stay that way.
+
+ // The division for the array length may truncate the array size to
+ // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
+ // for all platforms anyway.
+ UAlignedMemory stackNormIter1[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
+ UAlignedMemory stackNormIter2[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
+ //UChar sStackBuf[256], tStackBuf[256];
+ //int32_t sBufSize = 256, tBufSize = 256;
+ int32_t comparison;
+ int32_t sLen = 0;
+ UChar *sBuf = NULL;
+ int32_t tLen = 0;
+ UChar *tBuf = NULL;
+ UBool freeSBuf = FALSE, freeTBuf = FALSE;
+
+ if (sColl->flags & UCOL_USE_ITERATOR) {
+ UNormIterator *sNIt = NULL, *tNIt = NULL;
+ sNIt = unorm_openIter(stackNormIter1, sizeof(stackNormIter1), status);
+ tNIt = unorm_openIter(stackNormIter2, sizeof(stackNormIter2), status);
+ sColl->iterator->move(sColl->iterator, 0, UITER_START);
+ tColl->iterator->move(tColl->iterator, 0, UITER_START);
+ UCharIterator *sIt = unorm_setIter(sNIt, sColl->iterator, UNORM_NFD, status);
+ UCharIterator *tIt = unorm_setIter(tNIt, tColl->iterator, UNORM_NFD, status);
+ comparison = u_strCompareIter(sIt, tIt, TRUE);
+ unorm_closeIter(sNIt);
+ unorm_closeIter(tNIt);
+ } else {
+ sLen = (sColl->flags & UCOL_ITER_HASLEN) ? sColl->endp - sColl->string : -1;
+ sBuf = sColl->string;
+ tLen = (tColl->flags & UCOL_ITER_HASLEN) ? tColl->endp - tColl->string : -1;
+ tBuf = tColl->string;
+
+ if (normalize) {
+ *status = U_ZERO_ERROR;
+ if (unorm_quickCheck(sBuf, sLen, UNORM_NFD, status) != UNORM_YES) {
+ sLen = unorm_decompose(sColl->writableBuffer, (int32_t)sColl->writableBufSize,
+ sBuf, sLen,
+ FALSE, 0,
+ status);
+ if(*status == U_BUFFER_OVERFLOW_ERROR) {
+ if(!u_growBufferFromStatic(sColl->stackWritableBuffer,
+ &sColl->writableBuffer,
+ (int32_t *)&sColl->writableBufSize, sLen,
+ 0)
+ ) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return UCOL_LESS; /* TODO set *status = U_MEMORY_ALLOCATION_ERROR; */
+ }
+ *status = U_ZERO_ERROR;
+ sLen = unorm_decompose(sColl->writableBuffer, (int32_t)sColl->writableBufSize,
+ sBuf, sLen,
+ FALSE, 0,
+ status);
+ }
+ if(freeSBuf) {
+ uprv_free(sBuf);
+ freeSBuf = FALSE;
+ }
+ sBuf = sColl->writableBuffer;
+ if (sBuf != sColl->stackWritableBuffer) {
+ sColl->flags |= UCOL_ITER_ALLOCATED;
+ }
+ }
+
+ *status = U_ZERO_ERROR;
+ if (unorm_quickCheck(tBuf, tLen, UNORM_NFD, status) != UNORM_YES) {
+ tLen = unorm_decompose(tColl->writableBuffer, (int32_t)tColl->writableBufSize,
+ tBuf, tLen,
+ FALSE, 0,
+ status);
+ if(*status == U_BUFFER_OVERFLOW_ERROR) {
+ if(!u_growBufferFromStatic(tColl->stackWritableBuffer,
+ &tColl->writableBuffer,
+ (int32_t *)&tColl->writableBufSize, tLen,
+ 0)
+ ) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return UCOL_LESS; /* TODO set *status = U_MEMORY_ALLOCATION_ERROR; */
+ }
+ *status = U_ZERO_ERROR;
+ tLen = unorm_decompose(tColl->writableBuffer, (int32_t)tColl->writableBufSize,
+ tBuf, tLen,
+ FALSE, 0,
+ status);
+ }
+ if(freeTBuf) {
+ uprv_free(tBuf);
+ freeTBuf = FALSE;
+ }
+ tBuf = tColl->writableBuffer;
+ if (tBuf != tColl->stackWritableBuffer) {
+ tColl->flags |= UCOL_ITER_ALLOCATED;
+ }
+ }
+ }
+
+ if (sLen == -1 && tLen == -1) {
+ comparison = u_strcmpCodePointOrder(sBuf, tBuf);
+ } else {
+ if (sLen == -1) {
+ sLen = u_strlen(sBuf);
+ }
+ if (tLen == -1) {
+ tLen = u_strlen(tBuf);
+ }
+ comparison = u_memcmpCodePointOrder(sBuf, tBuf, uprv_min(sLen, tLen));
+ if (comparison == 0) {
+ comparison = sLen - tLen;
+ }
+ }
+ }
+
+ if (comparison < 0) {
+ return UCOL_LESS;
+ } else if (comparison == 0) {
+ return UCOL_EQUAL;
+ } else /* comparison > 0 */ {
+ return UCOL_GREATER;
+ }
+}
+
+/* CEBuf - A struct and some inline functions to handle the saving */
+/* of CEs in a buffer within ucol_strcoll */
+
+#define UCOL_CEBUF_SIZE 512
+typedef struct ucol_CEBuf {
+ uint32_t *buf;
+ uint32_t *endp;
+ uint32_t *pos;
+ uint32_t localArray[UCOL_CEBUF_SIZE];
+} ucol_CEBuf;
+
+
+static
+inline void UCOL_INIT_CEBUF(ucol_CEBuf *b) {
+ (b)->buf = (b)->pos = (b)->localArray;
+ (b)->endp = (b)->buf + UCOL_CEBUF_SIZE;
+}
+
+static
+void ucol_CEBuf_Expand(ucol_CEBuf *b, collIterate *ci) {
+ uint32_t oldSize;
+ uint32_t newSize;
+ uint32_t *newBuf;
+
+ ci->flags |= UCOL_ITER_ALLOCATED;
+ oldSize = b->pos - b->buf;
+ newSize = oldSize * 2;
+ newBuf = (uint32_t *)uprv_malloc(newSize * sizeof(uint32_t));
+ if(newBuf != NULL) {
+ uprv_memcpy(newBuf, b->buf, oldSize * sizeof(uint32_t));
+ if (b->buf != b->localArray) {
+ uprv_free(b->buf);
+ }
+ b->buf = newBuf;
+ b->endp = b->buf + newSize;
+ b->pos = b->buf + oldSize;
+ }
+}
+
+static
+inline void UCOL_CEBUF_PUT(ucol_CEBuf *b, uint32_t ce, collIterate *ci) {
+ if (b->pos == b->endp) {
+ ucol_CEBuf_Expand(b, ci);
+}
+ *(b)->pos++ = ce;
+}
+
+/* This is a trick string compare function that goes in and uses sortkeys to compare */
+/* It is used when compare gets in trouble and needs to bail out */
+static UCollationResult ucol_compareUsingSortKeys(collIterate *sColl,
+ collIterate *tColl,
+ UErrorCode *status)
+{
+ uint8_t sourceKey[UCOL_MAX_BUFFER], targetKey[UCOL_MAX_BUFFER];
+ uint8_t *sourceKeyP = sourceKey;
+ uint8_t *targetKeyP = targetKey;
+ int32_t sourceKeyLen = UCOL_MAX_BUFFER, targetKeyLen = UCOL_MAX_BUFFER;
+ const UCollator *coll = sColl->coll;
+ UChar *source = NULL;
+ UChar *target = NULL;
+ int32_t result = UCOL_EQUAL;
+ UChar sStackBuf[256], tStackBuf[256];
+ int32_t sourceLength = (sColl->flags&UCOL_ITER_HASLEN)?(sColl->endp-sColl->string):-1;
+ int32_t targetLength = (tColl->flags&UCOL_ITER_HASLEN)?(tColl->endp-tColl->string):-1;
+
+ // TODO: Handle long strings. Do the same in ucol_checkIdent.
+ if(sColl->flags & UCOL_USE_ITERATOR) {
+ sColl->iterator->move(sColl->iterator, 0, UITER_START);
+ tColl->iterator->move(tColl->iterator, 0, UITER_START);
+ source = sStackBuf;
+ UChar *sBufp = source;
+ target = tStackBuf;
+ UChar *tBufp = target;
+ while(sColl->iterator->hasNext(sColl->iterator)) {
+ *sBufp++ = (UChar)sColl->iterator->next(sColl->iterator);
+ }
+ while(tColl->iterator->hasNext(tColl->iterator)) {
+ *tBufp++ = (UChar)tColl->iterator->next(tColl->iterator);
+ }
+ sourceLength = sBufp - source;
+ targetLength = tBufp - target;
+ } else { // no iterators
+ sourceLength = (sColl->flags&UCOL_ITER_HASLEN)?(sColl->endp-sColl->string):-1;
+ targetLength = (tColl->flags&UCOL_ITER_HASLEN)?(tColl->endp-tColl->string):-1;
+ source = sColl->string;
+ target = tColl->string;
+ }
+
+
+
+ sourceKeyLen = ucol_getSortKey(coll, source, sourceLength, sourceKeyP, sourceKeyLen);
+ if(sourceKeyLen > UCOL_MAX_BUFFER) {
+ sourceKeyP = (uint8_t*)uprv_malloc(sourceKeyLen*sizeof(uint8_t));
+ if(sourceKeyP == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup_and_do_compare;
+ }
+ sourceKeyLen = ucol_getSortKey(coll, source, sourceLength, sourceKeyP, sourceKeyLen);
+ }
+
+ targetKeyLen = ucol_getSortKey(coll, target, targetLength, targetKeyP, targetKeyLen);
+ if(targetKeyLen > UCOL_MAX_BUFFER) {
+ targetKeyP = (uint8_t*)uprv_malloc(targetKeyLen*sizeof(uint8_t));
+ if(targetKeyP == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup_and_do_compare;
+ }
+ targetKeyLen = ucol_getSortKey(coll, target, targetLength, targetKeyP, targetKeyLen);
+ }
+
+ result = uprv_strcmp((const char*)sourceKeyP, (const char*)targetKeyP);
+
+cleanup_and_do_compare:
+ if(sourceKeyP != NULL && sourceKeyP != sourceKey) {
+ uprv_free(sourceKeyP);
+ }
+
+ if(targetKeyP != NULL && targetKeyP != targetKey) {
+ uprv_free(targetKeyP);
+ }
+
+ if(result<0) {
+ return UCOL_LESS;
+ } else if(result>0) {
+ return UCOL_GREATER;
+ } else {
+ return UCOL_EQUAL;
+ }
+}
+
+
+static inline UCollationResult
+ucol_strcollRegular( collIterate *sColl, collIterate *tColl,
+// const UCollator *coll,
+// const UChar *source,
+// int32_t sourceLength,
+// const UChar *target,
+// int32_t targetLength,
+ UErrorCode *status)
+{
+ U_ALIGN_CODE(16);
+
+ const UCollator *coll = sColl->coll;
+
+
+ // setting up the collator parameters
+ UColAttributeValue strength = coll->strength;
+ UBool initialCheckSecTer = (strength >= UCOL_SECONDARY);
+
+ UBool checkSecTer = initialCheckSecTer;
+ UBool checkTertiary = (strength >= UCOL_TERTIARY);
+ UBool checkQuad = (strength >= UCOL_QUATERNARY);
+ UBool checkIdent = (strength == UCOL_IDENTICAL);
+ UBool checkCase = (coll->caseLevel == UCOL_ON);
+ UBool isFrenchSec = (coll->frenchCollation == UCOL_ON) && checkSecTer;
+ UBool shifted = (coll->alternateHandling == UCOL_SHIFTED);
+ UBool qShifted = shifted && checkQuad;
+ UBool doHiragana = (coll->hiraganaQ == UCOL_ON) && checkQuad;
+
+ if(doHiragana && shifted) {
+ return (ucol_compareUsingSortKeys(sColl, tColl, status));
+ }
+ uint8_t caseSwitch = coll->caseSwitch;
+ uint8_t tertiaryMask = coll->tertiaryMask;
+
+ // This is the lowest primary value that will not be ignored if shifted
+ uint32_t LVT = (shifted)?(coll->variableTopValue<<16):0;
+
+ UCollationResult result = UCOL_EQUAL;
+ UCollationResult hirResult = UCOL_EQUAL;
+
+ // Preparing the CE buffers. They will be filled during the primary phase
+ ucol_CEBuf sCEs;
+ ucol_CEBuf tCEs;
+ UCOL_INIT_CEBUF(&sCEs);
+ UCOL_INIT_CEBUF(&tCEs);
+
+ uint32_t secS = 0, secT = 0;
+ uint32_t sOrder=0, tOrder=0;
+
+ // Non shifted primary processing is quite simple
+ if(!shifted) {
+ for(;;) {
+
+ // We fetch CEs until we hit a non ignorable primary or end.
+ do {
+ // We get the next CE
+ sOrder = ucol_IGetNextCE(coll, sColl, status);
+ // Stuff it in the buffer
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl);
+ // And keep just the primary part.
+ sOrder &= UCOL_PRIMARYMASK;
+ } while(sOrder == 0);
+
+ // see the comments on the above block
+ do {
+ tOrder = ucol_IGetNextCE(coll, tColl, status);
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl);
+ tOrder &= UCOL_PRIMARYMASK;
+ } while(tOrder == 0);
+
+ // if both primaries are the same
+ if(sOrder == tOrder) {
+ // and there are no more CEs, we advance to the next level
+ if(sOrder == UCOL_NO_MORE_CES_PRIMARY) {
+ break;
+ }
+ if(doHiragana && hirResult == UCOL_EQUAL) {
+ if((sColl->flags & UCOL_WAS_HIRAGANA) != (tColl->flags & UCOL_WAS_HIRAGANA)) {
+ hirResult = ((sColl->flags & UCOL_WAS_HIRAGANA) > (tColl->flags & UCOL_WAS_HIRAGANA))
+ ? UCOL_LESS:UCOL_GREATER;
+ }
+ }
+ } else {
+ // if two primaries are different, we are done
+ result = (sOrder < tOrder) ? UCOL_LESS: UCOL_GREATER;
+ goto commonReturn;
+ }
+ } // no primary difference... do the rest from the buffers
+ } else { // shifted - do a slightly more complicated processing :)
+ for(;;) {
+ UBool sInShifted = FALSE;
+ UBool tInShifted = FALSE;
+ // This version of code can be refactored. However, it seems easier to understand this way.
+ // Source loop. Sam as the target loop.
+ for(;;) {
+ sOrder = ucol_IGetNextCE(coll, sColl, status);
+ if(sOrder == UCOL_NO_MORE_CES) {
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl);
+ break;
+ } else if(sOrder == 0
+ || (sInShifted && (sOrder & UCOL_PRIMARYMASK) == 0)) {
+ /* UCA amendment - ignore ignorables that follow shifted code points */
+ continue;
+ } else if(isContinuation(sOrder)) {
+ if((sOrder & UCOL_PRIMARYMASK) > 0) { /* There is primary value */
+ if(sInShifted) {
+ sOrder = (sOrder & UCOL_PRIMARYMASK) | 0xC0; /* preserve interesting continuation */
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl);
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl);
+ break;
+ }
+ } else { /* Just lower level values */
+ if(sInShifted) {
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl);
+ continue;
+ }
+ }
+ } else { /* regular */
+ if((sOrder & UCOL_PRIMARYMASK) > LVT) {
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl);
+ break;
+ } else {
+ if((sOrder & UCOL_PRIMARYMASK) > 0) {
+ sInShifted = TRUE;
+ sOrder &= UCOL_PRIMARYMASK;
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl);
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&sCEs, sOrder, sColl);
+ sInShifted = FALSE;
+ continue;
+ }
+ }
+ }
+ }
+ sOrder &= UCOL_PRIMARYMASK;
+ sInShifted = FALSE;
+
+ for(;;) {
+ tOrder = ucol_IGetNextCE(coll, tColl, status);
+ if(tOrder == UCOL_NO_MORE_CES) {
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl);
+ break;
+ } else if(tOrder == 0
+ || (tInShifted && (tOrder & UCOL_PRIMARYMASK) == 0)) {
+ /* UCA amendment - ignore ignorables that follow shifted code points */
+ continue;
+ } else if(isContinuation(tOrder)) {
+ if((tOrder & UCOL_PRIMARYMASK) > 0) { /* There is primary value */
+ if(tInShifted) {
+ tOrder = (tOrder & UCOL_PRIMARYMASK) | 0xC0; /* preserve interesting continuation */
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl);
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl);
+ break;
+ }
+ } else { /* Just lower level values */
+ if(tInShifted) {
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl);
+ continue;
+ }
+ }
+ } else { /* regular */
+ if((tOrder & UCOL_PRIMARYMASK) > LVT) {
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl);
+ break;
+ } else {
+ if((tOrder & UCOL_PRIMARYMASK) > 0) {
+ tInShifted = TRUE;
+ tOrder &= UCOL_PRIMARYMASK;
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl);
+ continue;
+ } else {
+ UCOL_CEBUF_PUT(&tCEs, tOrder, tColl);
+ tInShifted = FALSE;
+ continue;
+ }
+ }
+ }
+ }
+ tOrder &= UCOL_PRIMARYMASK;
+ tInShifted = FALSE;
+
+ if(sOrder == tOrder) {
+ /*
+ if(doHiragana && hirResult == UCOL_EQUAL) {
+ if((sColl.flags & UCOL_WAS_HIRAGANA) != (tColl.flags & UCOL_WAS_HIRAGANA)) {
+ hirResult = ((sColl.flags & UCOL_WAS_HIRAGANA) > (tColl.flags & UCOL_WAS_HIRAGANA))
+ ? UCOL_LESS:UCOL_GREATER;
+ }
+ }
+ */
+ if(sOrder == UCOL_NO_MORE_CES_PRIMARY) {
+ break;
+ } else {
+ sOrder = 0; tOrder = 0;
+ continue;
+ }
+ } else {
+ result = (sOrder < tOrder) ? UCOL_LESS : UCOL_GREATER;
+ goto commonReturn;
+ }
+ } /* no primary difference... do the rest from the buffers */
+ }
+
+ /* now, we're gonna reexamine collected CEs */
+ uint32_t *sCE;
+ uint32_t *tCE;
+
+ /* This is the secondary level of comparison */
+ if(checkSecTer) {
+ if(!isFrenchSec) { /* normal */
+ sCE = sCEs.buf;
+ tCE = tCEs.buf;
+ for(;;) {
+ while (secS == 0) {
+ secS = *(sCE++) & UCOL_SECONDARYMASK;
+ }
+
+ while(secT == 0) {
+ secT = *(tCE++) & UCOL_SECONDARYMASK;
+ }
+
+ if(secS == secT) {
+ if(secS == UCOL_NO_MORE_CES_SECONDARY) {
+ break;
+ } else {
+ secS = 0; secT = 0;
+ continue;
+ }
+ } else {
+ result = (secS < secT) ? UCOL_LESS : UCOL_GREATER;
+ goto commonReturn;
+ }
+ }
+ } else { /* do the French */
+ uint32_t *sCESave = NULL;
+ uint32_t *tCESave = NULL;
+ sCE = sCEs.pos-2; /* this could also be sCEs-- if needs to be optimized */
+ tCE = tCEs.pos-2;
+ for(;;) {
+ while (secS == 0 && sCE >= sCEs.buf) {
+ if(sCESave == 0) {
+ secS = *(sCE--);
+ if(isContinuation(secS)) {
+ while(isContinuation(secS = *(sCE--)));
+ /* after this, secS has the start of continuation, and sCEs points before that */
+ sCESave = sCE; /* we save it, so that we know where to come back AND that we need to go forward */
+ sCE+=2; /* need to point to the first continuation CP */
+ /* However, now you can just continue doing stuff */
+ }
+ } else {
+ secS = *(sCE++);
+ if(!isContinuation(secS)) { /* This means we have finished with this cont */
+ sCE = sCESave; /* reset the pointer to before continuation */
+ sCESave = 0;
+ continue;
+ }
+ }
+ secS &= UCOL_SECONDARYMASK; /* remove the continuation bit */
+ }
+
+ while(secT == 0 && tCE >= tCEs.buf) {
+ if(tCESave == 0) {
+ secT = *(tCE--);
+ if(isContinuation(secT)) {
+ while(isContinuation(secT = *(tCE--)));
+ /* after this, secS has the start of continuation, and sCEs points before that */
+ tCESave = tCE; /* we save it, so that we know where to come back AND that we need to go forward */
+ tCE+=2; /* need to point to the first continuation CP */
+ /* However, now you can just continue doing stuff */
+ }
+ } else {
+ secT = *(tCE++);
+ if(!isContinuation(secT)) { /* This means we have finished with this cont */
+ tCE = tCESave; /* reset the pointer to before continuation */
+ tCESave = 0;
+ continue;
+ }
+ }
+ secT &= UCOL_SECONDARYMASK; /* remove the continuation bit */
+ }
+
+ if(secS == secT) {
+ if(secS == UCOL_NO_MORE_CES_SECONDARY || (sCE < sCEs.buf && tCE < tCEs.buf)) {
+ break;
+ } else {
+ secS = 0; secT = 0;
+ continue;
+ }
+ } else {
+ result = (secS < secT) ? UCOL_LESS : UCOL_GREATER;
+ goto commonReturn;
+ }
+ }
+ }
+ }
+
+ /* doing the case bit */
+ if(checkCase) {
+ sCE = sCEs.buf;
+ tCE = tCEs.buf;
+ for(;;) {
+ while((secS & UCOL_REMOVE_CASE) == 0) {
+ if(!isContinuation(*sCE++)) {
+ secS =*(sCE-1);
+ if(((secS & UCOL_PRIMARYMASK) != 0) || strength > UCOL_PRIMARY) {
+ // primary ignorables should not be considered on the case level when the strength is primary
+ // otherwise, the CEs stop being well-formed
+ secS &= UCOL_TERT_CASE_MASK;
+ secS ^= caseSwitch;
+ } else {
+ secS = 0;
+ }
+ } else {
+ secS = 0;
+ }
+ }
+
+ while((secT & UCOL_REMOVE_CASE) == 0) {
+ if(!isContinuation(*tCE++)) {
+ secT = *(tCE-1);
+ if(((secT & UCOL_PRIMARYMASK) != 0) || strength > UCOL_PRIMARY) {
+ // primary ignorables should not be considered on the case level when the strength is primary
+ // otherwise, the CEs stop being well-formed
+ secT &= UCOL_TERT_CASE_MASK;
+ secT ^= caseSwitch;
+ } else {
+ secT = 0;
+ }
+ } else {
+ secT = 0;
+ }
+ }
+
+ if((secS & UCOL_CASE_BIT_MASK) < (secT & UCOL_CASE_BIT_MASK)) {
+ result = UCOL_LESS;
+ goto commonReturn;
+ } else if((secS & UCOL_CASE_BIT_MASK) > (secT & UCOL_CASE_BIT_MASK)) {
+ result = UCOL_GREATER;
+ goto commonReturn;
+ }
+
+ if((secS & UCOL_REMOVE_CASE) == UCOL_NO_MORE_CES_TERTIARY || (secT & UCOL_REMOVE_CASE) == UCOL_NO_MORE_CES_TERTIARY ) {
+ break;
+ } else {
+ secS = 0;
+ secT = 0;
+ }
+ }
+ }
+
+ /* Tertiary level */
+ if(checkTertiary) {
+ secS = 0;
+ secT = 0;
+ sCE = sCEs.buf;
+ tCE = tCEs.buf;
+ for(;;) {
+ while((secS & UCOL_REMOVE_CASE) == 0) {
+ secS = *(sCE++) & tertiaryMask;
+ if(!isContinuation(secS)) {
+ secS ^= caseSwitch;
+ } else {
+ secS &= UCOL_REMOVE_CASE;
+ }
+ }
+
+ while((secT & UCOL_REMOVE_CASE) == 0) {
+ secT = *(tCE++) & tertiaryMask;
+ if(!isContinuation(secT)) {
+ secT ^= caseSwitch;
+ } else {
+ secT &= UCOL_REMOVE_CASE;
+ }
+ }
+
+ if(secS == secT) {
+ if((secS & UCOL_REMOVE_CASE) == 1) {
+ break;
+ } else {
+ secS = 0; secT = 0;
+ continue;
+ }
+ } else {
+ result = (secS < secT) ? UCOL_LESS : UCOL_GREATER;
+ goto commonReturn;
+ }
+ }
+ }
+
+
+ if(qShifted /*checkQuad*/) {
+ UBool sInShifted = TRUE;
+ UBool tInShifted = TRUE;
+ secS = 0;
+ secT = 0;
+ sCE = sCEs.buf;
+ tCE = tCEs.buf;
+ for(;;) {
+ while(secS == 0 && secS != UCOL_NO_MORE_CES || (isContinuation(secS) && !sInShifted)) {
+ secS = *(sCE++);
+ if(isContinuation(secS)) {
+ if(!sInShifted) {
+ continue;
+ }
+ } else if(secS > LVT || (secS & UCOL_PRIMARYMASK) == 0) { /* non continuation */
+ secS = UCOL_PRIMARYMASK;
+ sInShifted = FALSE;
+ } else {
+ sInShifted = TRUE;
+ }
+ }
+ secS &= UCOL_PRIMARYMASK;
+
+
+ while(secT == 0 && secT != UCOL_NO_MORE_CES || (isContinuation(secT) && !tInShifted)) {
+ secT = *(tCE++);
+ if(isContinuation(secT)) {
+ if(!tInShifted) {
+ continue;
+ }
+ } else if(secT > LVT || (secT & UCOL_PRIMARYMASK) == 0) {
+ secT = UCOL_PRIMARYMASK;
+ tInShifted = FALSE;
+ } else {
+ tInShifted = TRUE;
+ }
+ }
+ secT &= UCOL_PRIMARYMASK;
+
+ if(secS == secT) {
+ if(secS == UCOL_NO_MORE_CES_PRIMARY) {
+ break;
+ } else {
+ secS = 0; secT = 0;
+ continue;
+ }
+ } else {
+ result = (secS < secT) ? UCOL_LESS : UCOL_GREATER;
+ goto commonReturn;
+ }
+ }
+ } else if(doHiragana && hirResult != UCOL_EQUAL) {
+ // If we're fine on quaternaries, we might be different
+ // on Hiragana. This, however, might fail us in shifted.
+ result = hirResult;
+ goto commonReturn;
+ }
+
+ /* For IDENTICAL comparisons, we use a bitwise character comparison */
+ /* as a tiebreaker if all else is equal. */
+ /* Getting here should be quite rare - strings are not identical - */
+ /* that is checked first, but compared == through all other checks. */
+ if(checkIdent)
+ {
+ //result = ucol_checkIdent(&sColl, &tColl, coll->normalizationMode == UCOL_ON);
+ result = ucol_checkIdent(sColl, tColl, TRUE, status);
+ }
+
+commonReturn:
+ if ((sColl->flags | tColl->flags) & UCOL_ITER_ALLOCATED) {
+ freeHeapWritableBuffer(sColl);
+ freeHeapWritableBuffer(tColl);
+
+ if (sCEs.buf != sCEs.localArray ) {
+ uprv_free(sCEs.buf);
+ }
+ if (tCEs.buf != tCEs.localArray ) {
+ uprv_free(tCEs.buf);
+ }
+ }
+
+ return result;
+}
+
+
+static inline uint32_t
+ucol_getLatinOneContraction(const UCollator *coll, int32_t strength,
+ uint32_t CE, const UChar *s, int32_t *index, int32_t len) {
+ const UChar *UCharOffset = (UChar *)coll->image+getContractOffset(CE&0xFFF);
+ int32_t latinOneOffset = (CE & 0x00FFF000) >> 12;
+ int32_t offset = 1;
+ UChar schar = 0, tchar = 0;
+
+ for(;;) {
+ if(len == -1) {
+ if(s[*index] == 0) { // end of string
+ return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset]);
+ } else {
+ schar = s[*index];
+ }
+ } else {
+ if(*index == len) {
+ return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset]);
+ } else {
+ schar = s[*index];
+ }
+ }
+
+ while(schar > (tchar = *(UCharOffset+offset))) { /* since the contraction codepoints should be ordered, we skip all that are smaller */
+ offset++;
+ }
+
+ if (schar == tchar) {
+ (*index)++;
+ return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset+offset]);
+ }
+ else
+ {
+ if(schar & 0xFF00 /*> UCOL_ENDOFLATIN1RANGE*/) {
+ return UCOL_BAIL_OUT_CE;
+ }
+ // skip completely ignorables
+ uint32_t isZeroCE = UTRIE_GET32_FROM_LEAD(&coll->mapping, schar);
+ if(isZeroCE == 0) { // we have to ignore completely ignorables
+ (*index)++;
+ continue;
+ }
+
+ return(coll->latinOneCEs[strength*coll->latinOneTableLen+latinOneOffset]);
+ }
+ }
+}
+
+
+/**
+ * This is a fast strcoll, geared towards text in Latin-1.
+ * It supports contractions of size two, French secondaries
+ * and case switching. You can use it with strengths primary
+ * to tertiary. It does not support shifted and case level.
+ * It relies on the table build by setupLatin1Table. If it
+ * doesn't understand something, it will go to the regular
+ * strcoll.
+ */
+static inline UCollationResult
+ucol_strcollUseLatin1( const UCollator *coll,
+ const UChar *source,
+ int32_t sLen,
+ const UChar *target,
+ int32_t tLen,
+ UErrorCode *status)
+{
+ U_ALIGN_CODE(16);
+ int32_t strength = coll->strength;
+
+ int32_t sIndex = 0, tIndex = 0;
+ UChar sChar = 0, tChar = 0;
+ uint32_t sOrder=0, tOrder=0;
+
+ UBool endOfSource = FALSE;
+
+ uint32_t *elements = coll->latinOneCEs;
+
+ UBool haveContractions = FALSE; // if we have contractions in our string
+ // we cannot do French secondary
+
+ // Do the primary level
+ for(;;) {
+ while(sOrder==0) { // this loop skips primary ignorables
+ // sOrder=getNextlatinOneCE(source);
+ if(sLen==-1) { // handling zero terminated strings
+ sChar=source[sIndex++];
+ if(sChar==0) {
+ endOfSource = TRUE;
+ break;
+ }
+ } else { // handling strings with known length
+ if(sIndex==sLen) {
+ endOfSource = TRUE;
+ break;
+ }
+ sChar=source[sIndex++];
+ }
+ if(sChar&0xFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
+ //fprintf(stderr, "R");
+ goto returnRegular;
+ //return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
+ }
+ sOrder = elements[sChar];
+ if(sOrder >= UCOL_NOT_FOUND) { // if we got a special
+ // specials can basically be either contractions or bail-out signs. If we get anything
+ // else, we'll bail out anywasy
+ if(getCETag(sOrder) == CONTRACTION_TAG) {
+ sOrder = ucol_getLatinOneContraction(coll, UCOL_PRIMARY, sOrder, source, &sIndex, sLen);
+ haveContractions = TRUE; // if there are contractions, we cannot do French secondary
+ // However, if there are contractions in the table, but we always use just one char,
+ // we might be able to do French. This should be checked out.
+ }
+ if(sOrder >= UCOL_NOT_FOUND /*== UCOL_BAIL_OUT_CE*/) {
+ //fprintf(stderr, "S");
+ goto returnRegular;
+ //return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
+ }
+ }
+ }
+
+ while(tOrder==0) { // this loop skips primary ignorables
+ // tOrder=getNextlatinOneCE(target);
+ if(tLen==-1) { // handling zero terminated strings
+ tChar=target[tIndex++];
+ if(tChar==0) {
+ if(endOfSource) { // this is different than source loop,
+ // as we already know that source loop is done here,
+ // so we can either finish the primary loop if both
+ // strings are done or anounce the result if only
+ // target is done. Same below.
+ goto endOfPrimLoop;
+ } else {
+ return UCOL_GREATER;
+ }
+ }
+ } else { // handling strings with known length
+ if(tIndex==tLen) {
+ if(endOfSource) {
+ goto endOfPrimLoop;
+ } else {
+ return UCOL_GREATER;
+ }
+ }
+ tChar=target[tIndex++];
+ }
+ if(tChar&0xFF00) { // if we encounter non-latin-1, we bail out (sChar > 0xFF, but this is faster on win32)
+ //fprintf(stderr, "R");
+ goto returnRegular;
+ //return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
+ }
+ tOrder = elements[tChar];
+ if(tOrder >= UCOL_NOT_FOUND) {
+ // Handling specials, see the comments for source
+ if(getCETag(tOrder) == CONTRACTION_TAG) {
+ tOrder = ucol_getLatinOneContraction(coll, UCOL_PRIMARY, tOrder, target, &tIndex, tLen);
+ haveContractions = TRUE;
+ }
+ if(tOrder >= UCOL_NOT_FOUND /*== UCOL_BAIL_OUT_CE*/) {
+ //fprintf(stderr, "S");
+ goto returnRegular;
+ //return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
+ }
+ }
+ }
+ if(endOfSource) { // source is finished, but target is not, say the result.
+ return UCOL_LESS;
+ }
+
+ if(sOrder == tOrder) { // if we have same CEs, we continue the loop
+ sOrder = 0; tOrder = 0;
+ continue;
+ } else {
+ // compare current top bytes
+ if(((sOrder^tOrder)&0xFF000000)!=0) {
+ // top bytes differ, return difference
+ if(sOrder < tOrder) {
+ return UCOL_LESS;
+ } else if(sOrder > tOrder) {
+ return UCOL_GREATER;
+ }
+ // instead of return (int32_t)(sOrder>>24)-(int32_t)(tOrder>>24);
+ // since we must return enum value
+ }
+
+ // top bytes match, continue with following bytes
+ sOrder<<=8;
+ tOrder<<=8;
+ }
+ }
+
+endOfPrimLoop:
+ // after primary loop, we definitely know the sizes of strings,
+ // so we set it and use simpler loop for secondaries and tertiaries
+ sLen = sIndex; tLen = tIndex;
+ if(strength >= UCOL_SECONDARY) {
+ // adjust the table beggining
+ elements += coll->latinOneTableLen;
+ endOfSource = FALSE;
+
+ if(coll->frenchCollation == UCOL_OFF) { // non French
+ // This loop is a simplified copy of primary loop
+ // at this point we know that whole strings are latin-1, so we don't
+ // check for that. We also know that we only have contractions as
+ // specials.
+ sIndex = 0; tIndex = 0;
+ for(;;) {
+ while(sOrder==0) {
+ if(sIndex==sLen) {
+ endOfSource = TRUE;
+ break;
+ }
+ sChar=source[sIndex++];
+ sOrder = elements[sChar];
+ if(sOrder > UCOL_NOT_FOUND) {
+ sOrder = ucol_getLatinOneContraction(coll, UCOL_SECONDARY, sOrder, source, &sIndex, sLen);
+ }
+ }
+
+ while(tOrder==0) {
+ if(tIndex==tLen) {
+ if(endOfSource) {
+ goto endOfSecLoop;
+ } else {
+ return UCOL_GREATER;
+ }
+ }
+ tChar=target[tIndex++];
+ tOrder = elements[tChar];
+ if(tOrder > UCOL_NOT_FOUND) {
+ tOrder = ucol_getLatinOneContraction(coll, UCOL_SECONDARY, tOrder, target, &tIndex, tLen);
+ }
+ }
+ if(endOfSource) {
+ return UCOL_LESS;
+ }
+
+ if(sOrder == tOrder) {
+ sOrder = 0; tOrder = 0;
+ continue;
+ } else {
+ // see primary loop for comments on this
+ if(((sOrder^tOrder)&0xFF000000)!=0) {
+ if(sOrder < tOrder) {
+ return UCOL_LESS;
+ } else if(sOrder > tOrder) {
+ return UCOL_GREATER;
+ }
+ }
+ sOrder<<=8;
+ tOrder<<=8;
+ }
+ }
+ } else { // French
+ if(haveContractions) { // if we have contractions, we have to bail out
+ // since we don't really know how to handle them here
+ goto returnRegular;
+ //return ucol_strcollRegular(coll, source, sLen, target, tLen, status);
+ }
+ // For French, we go backwards
+ sIndex = sLen; tIndex = tLen;
+ for(;;) {
+ while(sOrder==0) {
+ if(sIndex==0) {
+ endOfSource = TRUE;
+ break;
+ }
+ sChar=source[--sIndex];
+ sOrder = elements[sChar];
+ // don't even look for contractions
+ }
+
+ while(tOrder==0) {
+ if(tIndex==0) {
+ if(endOfSource) {
+ goto endOfSecLoop;
+ } else {
+ return UCOL_GREATER;
+ }
+ }
+ tChar=target[--tIndex];
+ tOrder = elements[tChar];
+ // don't even look for contractions
+ }
+ if(endOfSource) {
+ return UCOL_LESS;
+ }
+
+ if(sOrder == tOrder) {
+ sOrder = 0; tOrder = 0;
+ continue;
+ } else {
+ // see the primary loop for comments
+ if(((sOrder^tOrder)&0xFF000000)!=0) {
+ if(sOrder < tOrder) {
+ return UCOL_LESS;
+ } else if(sOrder > tOrder) {
+ return UCOL_GREATER;
+ }
+ }
+ sOrder<<=8;
+ tOrder<<=8;
+ }
+ }
+ }
+ }
+
+endOfSecLoop:
+ if(strength >= UCOL_TERTIARY) {
+ // tertiary loop is the same as secondary (except no French)
+ elements += coll->latinOneTableLen;
+ sIndex = 0; tIndex = 0;
+ endOfSource = FALSE;
+ for(;;) {
+ while(sOrder==0) {
+ if(sIndex==sLen) {
+ endOfSource = TRUE;
+ break;
+ }
+ sChar=source[sIndex++];
+ sOrder = elements[sChar];
+ if(sOrder > UCOL_NOT_FOUND) {
+ sOrder = ucol_getLatinOneContraction(coll, UCOL_TERTIARY, sOrder, source, &sIndex, sLen);
+ }
+ }
+ while(tOrder==0) {
+ if(tIndex==tLen) {
+ if(endOfSource) {
+ return UCOL_EQUAL; // if both strings are at the end, they are equal
+ } else {
+ return UCOL_GREATER;
+ }
+ }
+ tChar=target[tIndex++];
+ tOrder = elements[tChar];
+ if(tOrder > UCOL_NOT_FOUND) {
+ tOrder = ucol_getLatinOneContraction(coll, UCOL_TERTIARY, tOrder, target, &tIndex, tLen);
+ }
+ }
+ if(endOfSource) {
+ return UCOL_LESS;
+ }
+ if(sOrder == tOrder) {
+ sOrder = 0; tOrder = 0;
+ continue;
+ } else {
+ if(((sOrder^tOrder)&0xff000000)!=0) {
+ if(sOrder < tOrder) {
+ return UCOL_LESS;
+ } else if(sOrder > tOrder) {
+ return UCOL_GREATER;
+ }
+ }
+ sOrder<<=8;
+ tOrder<<=8;
+ }
+ }
+ }
+ return UCOL_EQUAL;
+
+returnRegular:
+ // Preparing the context objects for iterating over strings
+ collIterate sColl, tColl;
+
+ IInit_collIterate(coll, source, sLen, &sColl);
+ IInit_collIterate(coll, target, tLen, &tColl);
+ return ucol_strcollRegular(&sColl, &tColl, status);
+}
+
+
+U_CAPI UCollationResult U_EXPORT2
+ucol_strcollIter( const UCollator *coll,
+ UCharIterator *sIter,
+ UCharIterator *tIter,
+ UErrorCode *status) {
+ if(!status || U_FAILURE(*status)) {
+ return UCOL_EQUAL;
+ }
+
+ UTRACE_ENTRY(UTRACE_UCOL_STRCOLLITER);
+ UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, sIter=%p, tIter=%p", coll, sIter, tIter);
+
+ if (sIter == tIter) {
+ UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status)
+ return UCOL_EQUAL;
+ }
+ if(sIter == NULL || tIter == NULL || coll == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ UTRACE_EXIT_VALUE_STATUS(UCOL_EQUAL, *status)
+ return UCOL_EQUAL;
+ }
+
+ UCollationResult result = UCOL_EQUAL;
+
+ // Preparing the context objects for iterating over strings
+ collIterate sColl, tColl;
+ // The division for the array length may truncate the array size to
+ // a little less than UNORM_ITER_SIZE, but that size is dimensioned too high
+ // for all platforms anyway.
+ UAlignedMemory stackNormIter1[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
+ UAlignedMemory stackNormIter2[UNORM_ITER_SIZE/sizeof(UAlignedMemory)];
+ UNormIterator *sNormIter = NULL, *tNormIter = NULL;
+
+ IInit_collIterate(coll, NULL, -1, &sColl);
+ sColl.iterator = sIter;
+ sColl.flags |= UCOL_USE_ITERATOR;
+ IInit_collIterate(coll, NULL, -1, &tColl);
+ tColl.flags |= UCOL_USE_ITERATOR;
+ tColl.iterator = tIter;
+
+ if(ucol_getAttribute(coll, UCOL_NORMALIZATION_MODE, status) == UCOL_ON) {
+ sNormIter = unorm_openIter(stackNormIter1, sizeof(stackNormIter1), status);
+ sColl.iterator = unorm_setIter(sNormIter, sIter, UNORM_FCD, status);
+ sColl.flags &= ~UCOL_ITER_NORM;
+
+ tNormIter = unorm_openIter(stackNormIter2, sizeof(stackNormIter2), status);
+ tColl.iterator = unorm_setIter(tNormIter, tIter, UNORM_FCD, status);
+ tColl.flags &= ~UCOL_ITER_NORM;
+ }
+
+ UChar32 sChar = U_SENTINEL, tChar = U_SENTINEL;
+
+ while((sChar = sColl.iterator->next(sColl.iterator)) ==
+ (tChar = tColl.iterator->next(tColl.iterator))) {
+ if(sChar == U_SENTINEL) {
+ result = UCOL_EQUAL;
+ goto end_compare;
+ }
+ }
+
+ if(sChar == U_SENTINEL) {
+ tChar = tColl.iterator->previous(tColl.iterator);
+ }
+
+ if(tChar == U_SENTINEL) {
+ sChar = sColl.iterator->previous(sColl.iterator);
+ }
+
+ sChar = sColl.iterator->previous(sColl.iterator);
+ tChar = tColl.iterator->previous(tColl.iterator);
+
+ if (ucol_unsafeCP((UChar)sChar, coll) || ucol_unsafeCP((UChar)tChar, coll))
+ {
+ // We are stopped in the middle of a contraction.
+ // Scan backwards through the == part of the string looking for the start of the contraction.
+ // It doesn't matter which string we scan, since they are the same in this region.
+ do
+ {
+ sChar = sColl.iterator->previous(sColl.iterator);
+ tChar = tColl.iterator->previous(tColl.iterator);
+ }
+ while (sChar != U_SENTINEL && ucol_unsafeCP((UChar)sChar, coll));
+ }
+
+
+ if(U_SUCCESS(*status)) {
+ result = ucol_strcollRegular(&sColl, &tColl, status);
+ }
+
+end_compare:
+ if(sNormIter || tNormIter) {
+ unorm_closeIter(sNormIter);
+ unorm_closeIter(tNormIter);
+ }
+
+ UTRACE_EXIT_VALUE_STATUS(result, *status)
+ return result;
+}
+
+
+
+/* */
+/* ucol_strcoll Main public API string comparison function */
+/* */
+U_CAPI UCollationResult U_EXPORT2
+ucol_strcoll( const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ const UChar *target,
+ int32_t targetLength) {
+ U_ALIGN_CODE(16);
+
+ UTRACE_ENTRY(UTRACE_UCOL_STRCOLL);
+ if (UTRACE_LEVEL(UTRACE_VERBOSE)) {
+ UTRACE_DATA3(UTRACE_VERBOSE, "coll=%p, source=%p, target=%p", coll, source, target);
+ UTRACE_DATA2(UTRACE_VERBOSE, "source string = %vh ", source, sourceLength);
+ UTRACE_DATA2(UTRACE_VERBOSE, "target string = %vh ", target, targetLength);
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ if(source == NULL || target == NULL) {
+ // do not crash, but return. Should have
+ // status argument to return error.
+ UTRACE_EXIT_VALUE(UTRACE_UCOL_STRCOLL);
+ return UCOL_EQUAL;
+ }
+ collIterate sColl, tColl;
+
+ /* Scan the strings. Find: */
+ /* The length of any leading portion that is equal */
+ /* Whether they are exactly equal. (in which case we just return) */
+ const UChar *pSrc = source;
+ const UChar *pTarg = target;
+ int32_t equalLength;
+
+ if (sourceLength == -1 && targetLength == -1) {
+ // Both strings are null terminated.
+ // Check for them being the same string, and scan through
+ // any leading equal portion.
+ if (source==target) {
+ UTRACE_EXIT_VALUE(UCOL_EQUAL);
+ return UCOL_EQUAL;
+ }
+
+ for (;;) {
+ if ( *pSrc != *pTarg || *pSrc == 0) {
+ break;
+ }
+ pSrc++;
+ pTarg++;
+ }
+ if (*pSrc == 0 && *pTarg == 0) {
+ UTRACE_EXIT_VALUE(UCOL_EQUAL);
+ return UCOL_EQUAL;
+ }
+ equalLength = pSrc - source;
+ }
+ else
+ {
+ // One or both strings has an explicit length.
+ /* check if source and target are same strings */
+
+ if (source==target && sourceLength==targetLength) {
+ UTRACE_EXIT_VALUE(UCOL_EQUAL);
+ return UCOL_EQUAL;
+ }
+ const UChar *pSrcEnd = source + sourceLength;
+ const UChar *pTargEnd = target + targetLength;
+
+
+ // Scan while the strings are bitwise ==, or until one is exhausted.
+ for (;;) {
+ if (pSrc == pSrcEnd || pTarg == pTargEnd) {
+ break;
+ }
+ if ((*pSrc == 0 && sourceLength == -1) || (*pTarg == 0 && targetLength == -1)) {
+ break;
+ }
+ if (*pSrc != *pTarg) {
+ break;
+ }
+ pSrc++;
+ pTarg++;
+ }
+ equalLength = pSrc - source;
+
+ // If we made it all the way through both strings, we are done. They are ==
+ if ((pSrc ==pSrcEnd || (pSrcEnd <pSrc && *pSrc==0)) && /* At end of src string, however it was specified. */
+ (pTarg==pTargEnd || (pTargEnd<pTarg && *pTarg==0))) { /* and also at end of dest string */
+ UTRACE_EXIT_VALUE(UCOL_EQUAL);
+ return UCOL_EQUAL;
+ }
+ }
+ if (equalLength > 0) {
+ /* There is an identical portion at the beginning of the two strings. */
+ /* If the identical portion ends within a contraction or a comibining */
+ /* character sequence, back up to the start of that sequence. */
+ pSrc = source + equalLength; /* point to the first differing chars */
+ pTarg = target + equalLength;
+ if (pSrc != source+sourceLength && ucol_unsafeCP(*pSrc, coll) ||
+ pTarg != target+targetLength && ucol_unsafeCP(*pTarg, coll))
+ {
+ // We are stopped in the middle of a contraction.
+ // Scan backwards through the == part of the string looking for the start of the contraction.
+ // It doesn't matter which string we scan, since they are the same in this region.
+ do
+ {
+ equalLength--;
+ pSrc--;
+ }
+ while (equalLength>0 && ucol_unsafeCP(*pSrc, coll));
+ }
+
+ source += equalLength;
+ target += equalLength;
+ if (sourceLength > 0) {
+ sourceLength -= equalLength;
+ }
+ if (targetLength > 0) {
+ targetLength -= equalLength;
+ }
+ }
+
+ UCollationResult returnVal;
+ if(!coll->latinOneUse || (sourceLength > 0 && *source&0xff00) || (targetLength > 0 && *target&0xff00)) {
+ // Preparing the context objects for iterating over strings
+ IInit_collIterate(coll, source, sourceLength, &sColl);
+ IInit_collIterate(coll, target, targetLength, &tColl);
+ returnVal = ucol_strcollRegular(&sColl, &tColl, &status);
+ } else {
+ returnVal = ucol_strcollUseLatin1(coll, source, sourceLength, target, targetLength, &status);
+ }
+ UTRACE_EXIT_VALUE(returnVal);
+ return returnVal;
+}
+
+/* convenience function for comparing strings */
+U_CAPI UBool U_EXPORT2
+ucol_greater( const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ const UChar *target,
+ int32_t targetLength)
+{
+ return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
+ == UCOL_GREATER);
+}
+
+/* convenience function for comparing strings */
+U_CAPI UBool U_EXPORT2
+ucol_greaterOrEqual( const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ const UChar *target,
+ int32_t targetLength)
+{
+ return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
+ != UCOL_LESS);
+}
+
+/* convenience function for comparing strings */
+U_CAPI UBool U_EXPORT2
+ucol_equal( const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ const UChar *target,
+ int32_t targetLength)
+{
+ return (ucol_strcoll(coll, source, sourceLength, target, targetLength)
+ == UCOL_EQUAL);
+}
+
+U_CAPI void U_EXPORT2
+ucol_getUCAVersion(const UCollator* coll, UVersionInfo info) {
+ if(coll && coll->UCA) {
+ uprv_memcpy(info, coll->UCA->image->UCAVersion, sizeof(UVersionInfo));
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_cloneBinary(const UCollator *coll,
+ uint8_t *buffer, int32_t capacity,
+ UErrorCode *status)
+{
+ int32_t length = 0;
+ if(U_FAILURE(*status)) {
+ return length;
+ }
+ if(capacity < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return length;
+ }
+ if(coll->hasRealData == TRUE) {
+ length = coll->image->size;
+ if(length <= capacity) {
+ uprv_memcpy(buffer, coll->image, length);
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ } else {
+ length = (int32_t)(paddedsize(sizeof(UCATableHeader))+paddedsize(sizeof(UColOptionSet)));
+ if(length <= capacity) {
+ /* build the UCATableHeader with minimal entries */
+ /* do not copy the header from the UCA file because its values are wrong! */
+ /* uprv_memcpy(result, UCA->image, sizeof(UCATableHeader)); */
+
+ /* reset everything */
+ uprv_memset(buffer, 0, length);
+
+ /* set the tailoring-specific values */
+ UCATableHeader *myData = (UCATableHeader *)buffer;
+ myData->size = length;
+
+ /* offset for the options, the only part of the data that is present after the header */
+ myData->options = sizeof(UCATableHeader);
+
+ /* need to always set the expansion value for an upper bound of the options */
+ myData->expansion = myData->options + sizeof(UColOptionSet);
+
+ myData->magic = UCOL_HEADER_MAGIC;
+ myData->isBigEndian = U_IS_BIG_ENDIAN;
+ myData->charSetFamily = U_CHARSET_FAMILY;
+
+ /* copy UCA's version; genrb will override all but the builder version with tailoring data */
+ uprv_memcpy(myData->version, coll->image->version, sizeof(UVersionInfo));
+
+ uprv_memcpy(myData->UCAVersion, coll->image->UCAVersion, sizeof(UVersionInfo));
+ uprv_memcpy(myData->UCDVersion, coll->image->UCDVersion, sizeof(UVersionInfo));
+ uprv_memcpy(myData->formatVersion, coll->image->formatVersion, sizeof(UVersionInfo));
+ myData->jamoSpecial = coll->image->jamoSpecial;
+
+ /* copy the collator options */
+ uprv_memcpy(buffer+paddedsize(sizeof(UCATableHeader)), coll->options, sizeof(UColOptionSet));
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ }
+ return length;
+}
+
+U_CAPI void U_EXPORT2
+ucol_forgetUCA(void)
+{
+ _staticUCA = NULL;
+ UCA_DATA_MEM = NULL;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_bld.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucol_bld.cpp
new file mode 100644
index 00000000000..83f33f49e55
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_bld.cpp
@@ -0,0 +1,1312 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: ucol_bld.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created 02/22/2001
+* created by: Vladimir Weinstein
+*
+* This module builds a collator based on the rule set.
+*
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/ucoleitr.h"
+#include "unicode/uchar.h"
+#include "ucol_bld.h"
+#include "ucln_in.h"
+#include "umutex.h"
+#include "unicode/uniset.h"
+#include "unormimp.h"
+
+static const InverseUCATableHeader* _staticInvUCA = NULL;
+static UDataMemory* invUCA_DATA_MEM = NULL;
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+isAcceptableInvUCA(void * /*context*/,
+ const char * /*type*/, const char * /*name*/,
+ const UDataInfo *pInfo)
+{
+ /* context, type & name are intentionally not used */
+ if( pInfo->size>=20 &&
+ pInfo->isBigEndian==U_IS_BIG_ENDIAN &&
+ pInfo->charsetFamily==U_CHARSET_FAMILY &&
+ pInfo->dataFormat[0]==INVUCA_DATA_FORMAT_0 && /* dataFormat="InvC" */
+ pInfo->dataFormat[1]==INVUCA_DATA_FORMAT_1 &&
+ pInfo->dataFormat[2]==INVUCA_DATA_FORMAT_2 &&
+ pInfo->dataFormat[3]==INVUCA_DATA_FORMAT_3 &&
+ pInfo->formatVersion[0]==INVUCA_FORMAT_VERSION_0 &&
+ pInfo->formatVersion[1]>=INVUCA_FORMAT_VERSION_1 //&&
+ //pInfo->formatVersion[1]==INVUCA_FORMAT_VERSION_1 &&
+ //pInfo->formatVersion[2]==INVUCA_FORMAT_VERSION_2 &&
+ //pInfo->formatVersion[3]==INVUCA_FORMAT_VERSION_3 &&
+ ) {
+ UVersionInfo UCDVersion;
+ u_getUnicodeVersion(UCDVersion);
+ if(pInfo->dataVersion[0]==UCDVersion[0] &&
+ pInfo->dataVersion[1]==UCDVersion[1]) {
+ //pInfo->dataVersion[1]==invUcaDataInfo.dataVersion[1] &&
+ //pInfo->dataVersion[2]==invUcaDataInfo.dataVersion[2] &&
+ //pInfo->dataVersion[3]==invUcaDataInfo.dataVersion[3]) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+}
+U_CDECL_END
+
+/*
+* Takes two CEs (lead and continuation) and
+* compares them as CEs should be compared:
+* primary vs. primary, secondary vs. secondary
+* tertiary vs. tertiary
+*/
+static int32_t compareCEs(uint32_t source0, uint32_t source1, uint32_t target0, uint32_t target1) {
+ uint32_t s1 = source0, s2, t1 = target0, t2;
+ if(isContinuation(source1)) {
+ s2 = source1;
+ } else {
+ s2 = 0;
+ }
+ if(isContinuation(target1)) {
+ t2 = target1;
+ } else {
+ t2 = 0;
+ }
+
+ uint32_t s = 0, t = 0;
+ if(s1 == t1 && s2 == t2) {
+ return 0;
+ }
+ s = (s1 & 0xFFFF0000)|((s2 & 0xFFFF0000)>>16);
+ t = (t1 & 0xFFFF0000)|((t2 & 0xFFFF0000)>>16);
+ if(s < t) {
+ return -1;
+ } else if(s > t) {
+ return 1;
+ } else {
+ s = (s1 & 0x0000FF00) | (s2 & 0x0000FF00)>>8;
+ t = (t1 & 0x0000FF00) | (t2 & 0x0000FF00)>>8;
+ if(s < t) {
+ return -1;
+ } else if(s > t) {
+ return 1;
+ } else {
+ s = (s1 & 0x000000FF)<<8 | (s2 & 0x000000FF);
+ t = (t1 & 0x000000FF)<<8 | (t2 & 0x000000FF);
+ if(s < t) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ }
+}
+
+static
+int32_t ucol_inv_findCE(const UColTokenParser *src, uint32_t CE, uint32_t SecondCE) {
+ uint32_t bottom = 0, top = src->invUCA->tableSize;
+ uint32_t i = 0;
+ uint32_t first = 0, second = 0;
+ uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+ int32_t res = 0;
+
+ while(bottom < top-1) {
+ i = (top+bottom)/2;
+ first = *(CETable+3*i);
+ second = *(CETable+3*i+1);
+ res = compareCEs(first, second, CE, SecondCE);
+ if(res > 0) {
+ top = i;
+ } else if(res < 0) {
+ bottom = i;
+ } else {
+ break;
+ }
+ }
+
+ /* weiv: */
+ /* in searching for elements, I have removed the failure */
+ /* The reason for this is that the builder does not rely */
+ /* on search mechanism telling it that it didn't find an */
+ /* element. However, indirect positioning relies on being */
+ /* able to find the elements around any CE, even if it is */
+ /* not defined in the UCA. */
+ return i;
+ /*
+ if((first == CE && second == SecondCE)) {
+ return i;
+ } else {
+ return -1;
+ }
+ */
+}
+
+static const uint32_t strengthMask[UCOL_CE_STRENGTH_LIMIT] = {
+ 0xFFFF0000,
+ 0xFFFFFF00,
+ 0xFFFFFFFF
+};
+
+U_CAPI int32_t U_EXPORT2 ucol_inv_getNextCE(const UColTokenParser *src,
+ uint32_t CE, uint32_t contCE,
+ uint32_t *nextCE, uint32_t *nextContCE,
+ uint32_t strength)
+{
+ uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+ int32_t iCE;
+
+ iCE = ucol_inv_findCE(src, CE, contCE);
+
+ if(iCE<0) {
+ *nextCE = UCOL_NOT_FOUND;
+ return -1;
+ }
+
+ CE &= strengthMask[strength];
+ contCE &= strengthMask[strength];
+
+ *nextCE = CE;
+ *nextContCE = contCE;
+
+ while((*nextCE & strengthMask[strength]) == CE
+ && (*nextContCE & strengthMask[strength]) == contCE) {
+ *nextCE = (*(CETable+3*(++iCE)));
+ *nextContCE = (*(CETable+3*(iCE)+1));
+ }
+
+ return iCE;
+}
+
+U_CFUNC int32_t U_EXPORT2 ucol_inv_getPrevCE(const UColTokenParser *src,
+ uint32_t CE, uint32_t contCE,
+ uint32_t *prevCE, uint32_t *prevContCE,
+ uint32_t strength)
+{
+ uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+ int32_t iCE;
+
+ iCE = ucol_inv_findCE(src, CE, contCE);
+
+ if(iCE<0) {
+ *prevCE = UCOL_NOT_FOUND;
+ return -1;
+ }
+
+ CE &= strengthMask[strength];
+ contCE &= strengthMask[strength];
+
+ *prevCE = CE;
+ *prevContCE = contCE;
+
+ while((*prevCE & strengthMask[strength]) == CE
+ && (*prevContCE & strengthMask[strength])== contCE
+ && iCE > 0) { /* this condition should prevent falling off the edge of the world */
+ /* here, we end up in a singularity - zero */
+ *prevCE = (*(CETable+3*(--iCE)));
+ *prevContCE = (*(CETable+3*(iCE)+1));
+ }
+
+ return iCE;
+}
+
+U_CFUNC uint32_t U_EXPORT2 ucol_getCEStrengthDifference(uint32_t CE, uint32_t contCE,
+ uint32_t prevCE, uint32_t prevContCE)
+{
+ if(prevCE == CE && prevContCE == contCE) {
+ return UCOL_IDENTICAL;
+ }
+ if((prevCE & strengthMask[UCOL_PRIMARY]) != (CE & strengthMask[UCOL_PRIMARY])
+ || (prevContCE & strengthMask[UCOL_PRIMARY]) != (contCE & strengthMask[UCOL_PRIMARY])) {
+ return UCOL_PRIMARY;
+ }
+ if((prevCE & strengthMask[UCOL_SECONDARY]) != (CE & strengthMask[UCOL_SECONDARY])
+ || (prevContCE & strengthMask[UCOL_SECONDARY]) != (contCE & strengthMask[UCOL_SECONDARY])) {
+ return UCOL_SECONDARY;
+ }
+ return UCOL_TERTIARY;
+}
+
+
+/*static
+inline int32_t ucol_inv_getPrevious(UColTokenParser *src, UColTokListHeader *lh, uint32_t strength) {
+
+ uint32_t CE = lh->baseCE;
+ uint32_t SecondCE = lh->baseContCE;
+
+ uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+ uint32_t previousCE, previousContCE;
+ int32_t iCE;
+
+ iCE = ucol_inv_findCE(src, CE, SecondCE);
+
+ if(iCE<0) {
+ return -1;
+ }
+
+ CE &= strengthMask[strength];
+ SecondCE &= strengthMask[strength];
+
+ previousCE = CE;
+ previousContCE = SecondCE;
+
+ while((previousCE & strengthMask[strength]) == CE && (previousContCE & strengthMask[strength])== SecondCE) {
+ previousCE = (*(CETable+3*(--iCE)));
+ previousContCE = (*(CETable+3*(iCE)+1));
+ }
+ lh->previousCE = previousCE;
+ lh->previousContCE = previousContCE;
+
+ return iCE;
+}*/
+
+static
+inline int32_t ucol_inv_getNext(UColTokenParser *src, UColTokListHeader *lh, uint32_t strength) {
+ uint32_t CE = lh->baseCE;
+ uint32_t SecondCE = lh->baseContCE;
+
+ uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+ uint32_t nextCE, nextContCE;
+ int32_t iCE;
+
+ iCE = ucol_inv_findCE(src, CE, SecondCE);
+
+ if(iCE<0) {
+ return -1;
+ }
+
+ CE &= strengthMask[strength];
+ SecondCE &= strengthMask[strength];
+
+ nextCE = CE;
+ nextContCE = SecondCE;
+
+ while((nextCE & strengthMask[strength]) == CE
+ && (nextContCE & strengthMask[strength]) == SecondCE) {
+ nextCE = (*(CETable+3*(++iCE)));
+ nextContCE = (*(CETable+3*(iCE)+1));
+ }
+
+ lh->nextCE = nextCE;
+ lh->nextContCE = nextContCE;
+
+ return iCE;
+}
+
+U_CFUNC void ucol_inv_getGapPositions(UColTokenParser *src, UColTokListHeader *lh, UErrorCode *status) {
+ /* reset all the gaps */
+ int32_t i = 0;
+ uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+ uint32_t st = 0;
+ uint32_t t1, t2;
+ int32_t pos;
+
+ UColToken *tok = lh->first;
+ uint32_t tokStrength = tok->strength;
+
+ for(i = 0; i<3; i++) {
+ lh->gapsHi[3*i] = 0;
+ lh->gapsHi[3*i+1] = 0;
+ lh->gapsHi[3*i+2] = 0;
+ lh->gapsLo[3*i] = 0;
+ lh->gapsLo[3*i+1] = 0;
+ lh->gapsLo[3*i+2] = 0;
+ lh->numStr[i] = 0;
+ lh->fStrToken[i] = NULL;
+ lh->lStrToken[i] = NULL;
+ lh->pos[i] = -1;
+ }
+
+ UCAConstants *consts = (UCAConstants *)((uint8_t *)src->UCA->image + src->UCA->image->UCAConsts);
+
+ if((lh->baseCE & 0xFF000000)>= (consts->UCA_PRIMARY_IMPLICIT_MIN<<24) && (lh->baseCE & 0xFF000000) <= (consts->UCA_PRIMARY_IMPLICIT_MAX<<24) ) { /* implicits - */
+ //if(lh->baseCE >= PRIMARY_IMPLICIT_MIN && lh->baseCE < PRIMARY_IMPLICIT_MAX ) { /* implicits - */
+ lh->pos[0] = 0;
+ t1 = lh->baseCE;
+ t2 = lh->baseContCE & UCOL_REMOVE_CONTINUATION;
+ lh->gapsLo[0] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+ lh->gapsLo[1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+ lh->gapsLo[2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+ uint32_t primaryCE = t1 & UCOL_PRIMARYMASK | (t2 & UCOL_PRIMARYMASK) >> 16;
+ primaryCE = uprv_uca_getImplicitFromRaw(uprv_uca_getRawFromImplicit(primaryCE)+1);
+
+ t1 = primaryCE & UCOL_PRIMARYMASK | 0x0505;
+ t2 = (primaryCE << 16) & UCOL_PRIMARYMASK; // | UCOL_CONTINUATION_MARKER;
+
+ lh->gapsHi[0] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+ lh->gapsHi[1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+ lh->gapsHi[2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+ } else if(lh->indirect == TRUE && lh->nextCE != 0) {
+ //} else if(lh->baseCE == UCOL_RESET_TOP_VALUE && lh->baseContCE == 0) {
+ lh->pos[0] = 0;
+ t1 = lh->baseCE;
+ t2 = lh->baseContCE&UCOL_REMOVE_CONTINUATION;
+ lh->gapsLo[0] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+ lh->gapsLo[1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+ lh->gapsLo[2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+ t1 = lh->nextCE;
+ t2 = lh->nextContCE&UCOL_REMOVE_CONTINUATION;
+ lh->gapsHi[0] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+ lh->gapsHi[1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+ lh->gapsHi[2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+ } else {
+ for(;;) {
+ if(tokStrength < UCOL_CE_STRENGTH_LIMIT) {
+ if((lh->pos[tokStrength] = ucol_inv_getNext(src, lh, tokStrength)) >= 0) {
+ lh->fStrToken[tokStrength] = tok;
+ } else { /* The CE must be implicit, since it's not in the table */
+ /* Error */
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ }
+ }
+
+ while(tok != NULL && tok->strength >= tokStrength) {
+ if(tokStrength < UCOL_CE_STRENGTH_LIMIT) {
+ lh->lStrToken[tokStrength] = tok;
+ }
+ tok = tok->next;
+ }
+ if(tokStrength < UCOL_CE_STRENGTH_LIMIT-1) {
+ /* check if previous interval is the same and merge the intervals if it is so */
+ if(lh->pos[tokStrength] == lh->pos[tokStrength+1]) {
+ lh->fStrToken[tokStrength] = lh->fStrToken[tokStrength+1];
+ lh->fStrToken[tokStrength+1] = NULL;
+ lh->lStrToken[tokStrength+1] = NULL;
+ lh->pos[tokStrength+1] = -1;
+ }
+ }
+ if(tok != NULL) {
+ tokStrength = tok->strength;
+ } else {
+ break;
+ }
+ }
+ for(st = 0; st < 3; st++) {
+ if((pos = lh->pos[st]) >= 0) {
+ t1 = *(CETable+3*(pos));
+ t2 = *(CETable+3*(pos)+1);
+ lh->gapsHi[3*st] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+ lh->gapsHi[3*st+1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+ //lh->gapsHi[3*st+2] = (UCOL_TERTIARYORDER(t1)) << 24 | (UCOL_TERTIARYORDER(t2)) << 16;
+ lh->gapsHi[3*st+2] = (t1&0x3f) << 24 | (t2&0x3f) << 16;
+ //pos--;
+ //t1 = *(CETable+3*(pos));
+ //t2 = *(CETable+3*(pos)+1);
+ t1 = lh->baseCE;
+ t2 = lh->baseContCE;
+ lh->gapsLo[3*st] = (t1 & UCOL_PRIMARYMASK) | (t2 & UCOL_PRIMARYMASK) >> 16;
+ lh->gapsLo[3*st+1] = (t1 & UCOL_SECONDARYMASK) << 16 | (t2 & UCOL_SECONDARYMASK) << 8;
+ lh->gapsLo[3*st+2] = (t1&0x3f) << 24 | (t2&0x3f) << 16;
+ }
+ }
+ }
+}
+
+
+#define ucol_countBytes(value, noOfBytes) \
+{ \
+ uint32_t mask = 0xFFFFFFFF; \
+ (noOfBytes) = 0; \
+ while(mask != 0) { \
+ if(((value) & mask) != 0) { \
+ (noOfBytes)++; \
+ } \
+ mask >>= 8; \
+ } \
+}
+
+U_CFUNC uint32_t ucol_getNextGenerated(ucolCEGenerator *g, UErrorCode *status) {
+ if(U_SUCCESS(*status)) {
+ g->current = ucol_nextWeight(g->ranges, &g->noOfRanges);
+ }
+ return g->current;
+}
+
+U_CFUNC uint32_t ucol_getSimpleCEGenerator(ucolCEGenerator *g, UColToken *tok, uint32_t strength, UErrorCode *status) {
+ /* TODO: rename to enum names */
+ uint32_t high, low, count=1;
+ uint32_t maxByte = (strength == UCOL_TERTIARY)?0x3F:0xFF;
+
+ if(strength == UCOL_SECONDARY) {
+ low = UCOL_COMMON_TOP2<<24;
+ high = 0xFFFFFFFF;
+ count = 0xFF - UCOL_COMMON_TOP2;
+ } else {
+ low = UCOL_BYTE_COMMON << 24; //0x05000000;
+ high = 0x40000000;
+ count = 0x40 - UCOL_BYTE_COMMON;
+ }
+
+ if(tok->next != NULL && tok->next->strength == strength) {
+ count = tok->next->toInsert;
+ }
+
+ g->noOfRanges = ucol_allocWeights(low, high, count, maxByte, g->ranges);
+ g->current = UCOL_BYTE_COMMON<<24;
+
+ if(g->noOfRanges == 0) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ }
+ return g->current;
+}
+
+U_CFUNC uint32_t ucol_getCEGenerator(ucolCEGenerator *g, uint32_t* lows, uint32_t* highs, UColToken *tok, uint32_t fStrength, UErrorCode *status) {
+ uint32_t strength = tok->strength;
+ uint32_t low = lows[fStrength*3+strength];
+ uint32_t high = highs[fStrength*3+strength];
+ uint32_t maxByte = 0;
+ if(strength == UCOL_TERTIARY) {
+ maxByte = 0x3F;
+ } else if(strength == UCOL_PRIMARY) {
+ maxByte = 0xFE;
+ } else {
+ maxByte = 0xFF;
+ }
+
+ uint32_t count = tok->toInsert;
+
+ if(low >= high && strength > UCOL_PRIMARY) {
+ int32_t s = strength;
+ for(;;) {
+ s--;
+ if(lows[fStrength*3+s] != highs[fStrength*3+s]) {
+ if(strength == UCOL_SECONDARY) {
+ low = UCOL_COMMON_TOP2<<24;
+ high = 0xFFFFFFFF;
+ } else {
+ //low = 0x02000000; // This needs to be checked - what if low is
+ // not good...
+ high = 0x40000000;
+ }
+ break;
+ }
+ if(s<0) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ return 0;
+ }
+ }
+ }
+
+ if(low == 0) {
+ low = 0x01000000;
+ }
+
+ if(strength == UCOL_SECONDARY) { /* similar as simple */
+ if(low >= (UCOL_COMMON_BOT2<<24) && low < (uint32_t)(UCOL_COMMON_TOP2<<24)) {
+ low = UCOL_COMMON_TOP2<<24;
+ }
+ if(high > (UCOL_COMMON_BOT2<<24) && high < (uint32_t)(UCOL_COMMON_TOP2<<24)) {
+ high = UCOL_COMMON_TOP2<<24;
+ }
+ if(low < (UCOL_COMMON_BOT2<<24)) {
+ g->noOfRanges = ucol_allocWeights(UCOL_BYTE_UNSHIFTED_MIN<<24, high, count, maxByte, g->ranges);
+ g->current = ucol_nextWeight(g->ranges, &g->noOfRanges);
+ //g->current = UCOL_COMMON_BOT2<<24;
+ return g->current;
+ }
+ }
+
+ g->noOfRanges = ucol_allocWeights(low, high, count, maxByte, g->ranges);
+ if(g->noOfRanges == 0) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ }
+ g->current = ucol_nextWeight(g->ranges, &g->noOfRanges);
+ return g->current;
+}
+
+static
+uint32_t u_toLargeKana(const UChar *source, const uint32_t sourceLen, UChar *resBuf, const uint32_t resLen, UErrorCode *status) {
+ uint32_t i = 0;
+ UChar c;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if(sourceLen > resLen) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ for(i = 0; i < sourceLen; i++) {
+ c = source[i];
+ if(0x3042 < c && c < 0x30ef) { /* Kana range */
+ switch(c - 0x3000) {
+ case 0x41: case 0x43: case 0x45: case 0x47: case 0x49: case 0x63: case 0x83: case 0x85: case 0x8E:
+ case 0xA1: case 0xA3: case 0xA5: case 0xA7: case 0xA9: case 0xC3: case 0xE3: case 0xE5: case 0xEE:
+ c++;
+ break;
+ case 0xF5:
+ c = 0x30AB;
+ break;
+ case 0xF6:
+ c = 0x30B1;
+ break;
+ }
+ }
+ resBuf[i] = c;
+ }
+ return sourceLen;
+}
+
+static
+uint32_t u_toSmallKana(const UChar *source, const uint32_t sourceLen, UChar *resBuf, const uint32_t resLen, UErrorCode *status) {
+ uint32_t i = 0;
+ UChar c;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if(sourceLen > resLen) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ for(i = 0; i < sourceLen; i++) {
+ c = source[i];
+ if(0x3042 < c && c < 0x30ef) { /* Kana range */
+ switch(c - 0x3000) {
+ case 0x42: case 0x44: case 0x46: case 0x48: case 0x4A: case 0x64: case 0x84: case 0x86: case 0x8F:
+ case 0xA2: case 0xA4: case 0xA6: case 0xA8: case 0xAA: case 0xC4: case 0xE4: case 0xE6: case 0xEF:
+ c--;
+ break;
+ case 0xAB:
+ c = 0x30F5;
+ break;
+ case 0xB1:
+ c = 0x30F6;
+ break;
+ }
+ }
+ resBuf[i] = c;
+ }
+ return sourceLen;
+}
+
+static
+uint8_t ucol_uprv_getCaseBits(const UCollator *UCA, const UChar *src, uint32_t len, UErrorCode *status) {
+ uint32_t i = 0;
+ UChar n[128];
+ uint32_t nLen = 0;
+ uint32_t uCount = 0, lCount = 0;
+
+ collIterate s;
+ uint32_t order = 0;
+
+ if(U_FAILURE(*status)) {
+ return UCOL_LOWER_CASE;
+ }
+
+ nLen = unorm_normalize(src, len, UNORM_NFKD, 0, n, 128, status);
+ if(U_SUCCESS(*status)) {
+ for(i = 0; i < nLen; i++) {
+ uprv_init_collIterate(UCA, &n[i], 1, &s);
+ order = ucol_getNextCE(UCA, &s, status);
+ if(isContinuation(order)) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ return UCOL_LOWER_CASE;
+ }
+ if((order&UCOL_CASE_BIT_MASK)== UCOL_UPPER_CASE) {
+ uCount++;
+ } else {
+ if(u_islower(n[i])) {
+ lCount++;
+ } else {
+ UChar sk[1], lk[1];
+ u_toSmallKana(&n[i], 1, sk, 1, status);
+ u_toLargeKana(&n[i], 1, lk, 1, status);
+ if(sk[0] == n[i] && lk[0] != n[i]) {
+ lCount++;
+ }
+ }
+ }
+ }
+ }
+
+ if(uCount != 0 && lCount != 0) {
+ return UCOL_MIXED_CASE;
+ } else if(uCount != 0) {
+ return UCOL_UPPER_CASE;
+ } else {
+ return UCOL_LOWER_CASE;
+ }
+}
+
+
+U_CFUNC void ucol_doCE(UColTokenParser *src, uint32_t *CEparts, UColToken *tok, UErrorCode *status) {
+ /* this one makes the table and stuff */
+ uint32_t noOfBytes[3];
+ uint32_t i;
+
+ for(i = 0; i<3; i++) {
+ ucol_countBytes(CEparts[i], noOfBytes[i]);
+ }
+
+ /* Here we have to pack CEs from parts */
+
+ uint32_t CEi = 0;
+ uint32_t value = 0;
+
+ while(2*CEi<noOfBytes[0] || CEi<noOfBytes[1] || CEi<noOfBytes[2]) {
+ if(CEi > 0) {
+ value = UCOL_CONTINUATION_MARKER; /* Continuation marker */
+ } else {
+ value = 0;
+ }
+
+ if(2*CEi<noOfBytes[0]) {
+ value |= ((CEparts[0]>>(32-16*(CEi+1))) & 0xFFFF) << 16;
+ }
+ if(CEi<noOfBytes[1]) {
+ value |= ((CEparts[1]>>(32-8*(CEi+1))) & 0xFF) << 8;
+ }
+ if(CEi<noOfBytes[2]) {
+ value |= ((CEparts[2]>>(32-8*(CEi+1))) & 0x3F);
+ }
+ tok->CEs[CEi] = value;
+ CEi++;
+ }
+ if(CEi == 0) { /* totally ignorable */
+ tok->noOfCEs = 1;
+ tok->CEs[0] = 0;
+ } else { /* there is at least something */
+ tok->noOfCEs = CEi;
+ }
+
+
+ // we want to set case bits here and now, not later.
+ // Case bits handling
+ if(tok->CEs[0] != 0) { // case bits should be set only for non-ignorables
+ tok->CEs[0] &= 0xFFFFFF3F; // Clean the case bits field
+ int32_t cSize = (tok->source & 0xFF000000) >> 24;
+ UChar *cPoints = (tok->source & 0x00FFFFFF) + src->source;
+
+ if(cSize > 1) {
+ // Do it manually
+ tok->CEs[0] |= ucol_uprv_getCaseBits(src->UCA, cPoints, cSize, status);
+ } else {
+ // Copy it from the UCA
+ uint32_t caseCE = ucol_getFirstCE(src->UCA, cPoints[0], status);
+ tok->CEs[0] |= (caseCE & 0xC0);
+ }
+ }
+
+#if UCOL_DEBUG==2
+ fprintf(stderr, "%04X str: %i, [%08X, %08X, %08X]: tok: ", tok->debugSource, tok->strength, CEparts[0] >> (32-8*noOfBytes[0]), CEparts[1] >> (32-8*noOfBytes[1]), CEparts[2]>> (32-8*noOfBytes[2]));
+ for(i = 0; i<tok->noOfCEs; i++) {
+ fprintf(stderr, "%08X ", tok->CEs[i]);
+ }
+ fprintf(stderr, "\n");
+#endif
+}
+
+U_CFUNC void ucol_initBuffers(UColTokenParser *src, UColTokListHeader *lh, UErrorCode *status) {
+ ucolCEGenerator Gens[UCOL_CE_STRENGTH_LIMIT];
+ uint32_t CEparts[UCOL_CE_STRENGTH_LIMIT];
+
+ UColToken *tok = lh->last;
+ uint32_t t[UCOL_STRENGTH_LIMIT];
+
+ uprv_memset(t, 0, UCOL_STRENGTH_LIMIT*sizeof(uint32_t));
+
+ tok->toInsert = 1;
+ t[tok->strength] = 1;
+
+ while(tok->previous != NULL) {
+ if(tok->previous->strength < tok->strength) { /* going up */
+ t[tok->strength] = 0;
+ t[tok->previous->strength]++;
+ } else if(tok->previous->strength > tok->strength) { /* going down */
+ t[tok->previous->strength] = 1;
+ } else {
+ t[tok->strength]++;
+ }
+ tok=tok->previous;
+ tok->toInsert = t[tok->strength];
+ }
+
+ tok->toInsert = t[tok->strength];
+ ucol_inv_getGapPositions(src, lh, status);
+
+#if UCOL_DEBUG
+ fprintf(stderr, "BaseCE: %08X %08X\n", lh->baseCE, lh->baseContCE);
+ int32_t j = 2;
+ for(j = 2; j >= 0; j--) {
+ fprintf(stderr, "gapsLo[%i] [%08X %08X %08X]\n", j, lh->gapsLo[j*3], lh->gapsLo[j*3+1], lh->gapsLo[j*3+2]);
+ fprintf(stderr, "gapsHi[%i] [%08X %08X %08X]\n", j, lh->gapsHi[j*3], lh->gapsHi[j*3+1], lh->gapsHi[j*3+2]);
+ }
+ tok=lh->first[UCOL_TOK_POLARITY_POSITIVE];
+
+ do {
+ fprintf(stderr,"%i", tok->strength);
+ tok = tok->next;
+ } while(tok != NULL);
+ fprintf(stderr, "\n");
+
+ tok=lh->first[UCOL_TOK_POLARITY_POSITIVE];
+
+ do {
+ fprintf(stderr,"%i", tok->toInsert);
+ tok = tok->next;
+ } while(tok != NULL);
+#endif
+
+ tok = lh->first;
+ uint32_t fStrength = UCOL_IDENTICAL;
+ uint32_t initStrength = UCOL_IDENTICAL;
+
+
+ CEparts[UCOL_PRIMARY] = (lh->baseCE & UCOL_PRIMARYMASK) | (lh->baseContCE & UCOL_PRIMARYMASK) >> 16;
+ CEparts[UCOL_SECONDARY] = (lh->baseCE & UCOL_SECONDARYMASK) << 16 | (lh->baseContCE & UCOL_SECONDARYMASK) << 8;
+ CEparts[UCOL_TERTIARY] = (UCOL_TERTIARYORDER(lh->baseCE)) << 24 | (UCOL_TERTIARYORDER(lh->baseContCE)) << 16;
+
+ while (tok != NULL && U_SUCCESS(*status)) {
+ fStrength = tok->strength;
+ if(fStrength < initStrength) {
+ initStrength = fStrength;
+ if(lh->pos[fStrength] == -1) {
+ while(lh->pos[fStrength] == -1 && fStrength > 0) {
+ fStrength--;
+ }
+ if(lh->pos[fStrength] == -1) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ }
+ if(initStrength == UCOL_TERTIARY) { /* starting with tertiary */
+ CEparts[UCOL_PRIMARY] = lh->gapsLo[fStrength*3];
+ CEparts[UCOL_SECONDARY] = lh->gapsLo[fStrength*3+1];
+ /*CEparts[UCOL_TERTIARY] = ucol_getCEGenerator(&Gens[2], lh->gapsLo[fStrength*3+2], lh->gapsHi[fStrength*3+2], tok, UCOL_TERTIARY); */
+ CEparts[UCOL_TERTIARY] = ucol_getCEGenerator(&Gens[UCOL_TERTIARY], lh->gapsLo, lh->gapsHi, tok, fStrength, status);
+ } else if(initStrength == UCOL_SECONDARY) { /* secondaries */
+ CEparts[UCOL_PRIMARY] = lh->gapsLo[fStrength*3];
+ /*CEparts[1] = ucol_getCEGenerator(&Gens[1], lh->gapsLo[fStrength*3+1], lh->gapsHi[fStrength*3+1], tok, 1);*/
+ CEparts[UCOL_SECONDARY] = ucol_getCEGenerator(&Gens[UCOL_SECONDARY], lh->gapsLo, lh->gapsHi, tok, fStrength, status);
+ CEparts[UCOL_TERTIARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_TERTIARY], tok, UCOL_TERTIARY, status);
+ } else { /* primaries */
+ /*CEparts[UCOL_PRIMARY] = ucol_getCEGenerator(&Gens[0], lh->gapsLo[0], lh->gapsHi[0], tok, UCOL_PRIMARY);*/
+ CEparts[UCOL_PRIMARY] = ucol_getCEGenerator(&Gens[UCOL_PRIMARY], lh->gapsLo, lh->gapsHi, tok, fStrength, status);
+ CEparts[UCOL_SECONDARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_SECONDARY], tok, UCOL_SECONDARY, status);
+ CEparts[UCOL_TERTIARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_TERTIARY], tok, UCOL_TERTIARY, status);
+ }
+ } else {
+ if(tok->strength == UCOL_TERTIARY) {
+ CEparts[UCOL_TERTIARY] = ucol_getNextGenerated(&Gens[UCOL_TERTIARY], status);
+ } else if(tok->strength == UCOL_SECONDARY) {
+ CEparts[UCOL_SECONDARY] = ucol_getNextGenerated(&Gens[UCOL_SECONDARY], status);
+ CEparts[UCOL_TERTIARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_TERTIARY], tok, UCOL_TERTIARY, status);
+ } else if(tok->strength == UCOL_PRIMARY) {
+ CEparts[UCOL_PRIMARY] = ucol_getNextGenerated(&Gens[UCOL_PRIMARY], status);
+ CEparts[UCOL_SECONDARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_SECONDARY], tok, UCOL_SECONDARY, status);
+ CEparts[UCOL_TERTIARY] = ucol_getSimpleCEGenerator(&Gens[UCOL_TERTIARY], tok, UCOL_TERTIARY, status);
+ }
+ }
+ ucol_doCE(src, CEparts, tok, status);
+ tok = tok->next;
+ }
+}
+
+U_CFUNC void ucol_createElements(UColTokenParser *src, tempUCATable *t, UColTokListHeader *lh, UErrorCode *status) {
+ UCAElements el;
+ UColToken *tok = lh->first;
+ UColToken *expt = NULL;
+ uint32_t i = 0, j = 0;
+ const uint16_t *fcdTrieData = unorm_getFCDTrie(status);
+
+ while(tok != NULL && U_SUCCESS(*status)) {
+ /* first, check if there are any expansions */
+ /* if there are expansions, we need to do a little bit more processing */
+ /* since parts of expansion can be tailored, while others are not */
+ if(tok->expansion != 0) {
+ uint32_t len = tok->expansion >> 24;
+ uint32_t currentSequenceLen = len;
+ uint32_t expOffset = tok->expansion & 0x00FFFFFF;
+ //uint32_t exp = currentSequenceLen | expOffset;
+ UColToken exp;
+ exp.source = currentSequenceLen | expOffset;
+ exp.rulesToParse = src->source;
+
+ while(len > 0) {
+ currentSequenceLen = len;
+ while(currentSequenceLen > 0) {
+ exp.source = (currentSequenceLen << 24) | expOffset;
+ if((expt = (UColToken *)uhash_get(src->tailored, &exp)) != NULL && expt->strength != UCOL_TOK_RESET) { /* expansion is tailored */
+ uint32_t noOfCEsToCopy = expt->noOfCEs;
+ for(j = 0; j<noOfCEsToCopy; j++) {
+ tok->expCEs[tok->noOfExpCEs + j] = expt->CEs[j];
+ }
+ tok->noOfExpCEs += noOfCEsToCopy;
+ // Smart people never try to add codepoints and CEs.
+ // For some odd reason, it won't work.
+ expOffset += currentSequenceLen; //noOfCEsToCopy;
+ len -= currentSequenceLen; //noOfCEsToCopy;
+ break;
+ } else {
+ currentSequenceLen--;
+ }
+ }
+ if(currentSequenceLen == 0) { /* couldn't find any tailored subsequence */
+ /* will have to get one from UCA */
+ /* first, get the UChars from the rules */
+ /* then pick CEs out until there is no more and stuff them into expansion */
+ collIterate s;
+ uint32_t order = 0;
+ uprv_init_collIterate(src->UCA, expOffset + src->source, 1, &s);
+
+ for(;;) {
+ order = ucol_getNextCE(src->UCA, &s, status);
+ if(order == UCOL_NO_MORE_CES) {
+ break;
+ }
+ tok->expCEs[tok->noOfExpCEs++] = order;
+ }
+ expOffset++;
+ len--;
+ }
+ }
+ } else {
+ tok->noOfExpCEs = 0;
+ }
+
+ /* set the ucaelement with obtained values */
+ el.noOfCEs = tok->noOfCEs + tok->noOfExpCEs;
+ /* copy CEs */
+ for(i = 0; i<tok->noOfCEs; i++) {
+ el.CEs[i] = tok->CEs[i];
+ }
+ for(i = 0; i<tok->noOfExpCEs; i++) {
+ el.CEs[i+tok->noOfCEs] = tok->expCEs[i];
+ }
+
+ /* copy UChars */
+ // We kept prefix and source kind of together, as it is a kind of a contraction.
+ // However, now we have to slice the prefix off the main thing -
+ el.prefix = el.prefixChars;
+ el.cPoints = el.uchars;
+ if(tok->prefix != 0) { // we will just copy the prefix here, and adjust accordingly in the
+ // addPrefix function in ucol_elm. The reason is that we need to add both composed AND
+ // decomposed elements to the unsaf table.
+ el.prefixSize = tok->prefix>>24;
+ uprv_memcpy(el.prefix, src->source + (tok->prefix & 0x00FFFFFF), el.prefixSize*sizeof(UChar));
+
+ el.cSize = (tok->source >> 24)-(tok->prefix>>24);
+ uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF)+(tok->prefix>>24) + src->source, el.cSize*sizeof(UChar));
+ } else {
+ el.prefixSize = 0;
+ *el.prefix = 0;
+
+ el.cSize = (tok->source >> 24);
+ uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF) + src->source, el.cSize*sizeof(UChar));
+ }
+ if(src->UCA != NULL) {
+ UBool containCombinMarks = FALSE;
+ for(i = 0; i<el.cSize; i++) {
+ if(UCOL_ISJAMO(el.cPoints[i])) {
+ t->image->jamoSpecial = TRUE;
+ }
+ if ( !src->buildCCTabFlag ) {
+ // check combining class
+ int16_t fcd = unorm_getFCD16(fcdTrieData, el.cPoints[i]);
+ if ( (fcd && 0xff) == 0 ) {
+ // reset flag when current char is not combining mark.
+ containCombinMarks = FALSE;
+ }
+ else {
+ containCombinMarks = TRUE;
+ }
+ }
+ }
+ if ( !src->buildCCTabFlag && containCombinMarks ) {
+ src->buildCCTabFlag = TRUE;
+ }
+ }
+
+ /* and then, add it */
+#if UCOL_DEBUG==2
+ fprintf(stderr, "Adding: %04X with %08X\n", el.cPoints[0], el.CEs[0]);
+#endif
+ uprv_uca_addAnElement(t, &el, status);
+
+#if UCOL_DEBUG_DUPLICATES
+ if(*status != U_ZERO_ERROR) {
+ fprintf(stderr, "replaced CE for %04X with CE for %04X\n", el.cPoints[0], tok->debugSource);
+ *status = U_ZERO_ERROR;
+ }
+#endif
+
+ tok = tok->next;
+ }
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+_processUCACompleteIgnorables(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
+ UErrorCode status = U_ZERO_ERROR;
+ tempUCATable *t = (tempUCATable *)context;
+ if(value == 0) {
+ while(start < limit) {
+ uint32_t CE = utrie_get32(t->mapping, start, NULL);
+ if(CE == UCOL_NOT_FOUND) {
+ UCAElements el;
+ el.isThai = FALSE;
+ el.prefixSize = 0;
+ el.prefixChars[0] = 0;
+ el.prefix = el.prefixChars;
+ el.cPoints = el.uchars;
+
+ el.cSize = 0;
+ UTF_APPEND_CHAR(el.uchars, el.cSize, 1024, start);
+
+ el.noOfCEs = 1;
+ el.CEs[0] = 0;
+ uprv_uca_addAnElement(t, &el, &status);
+
+ }
+ start++;
+ }
+ }
+ if(U_FAILURE(status)) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+U_CDECL_END
+
+static void
+ucol_uprv_bld_copyRangeFromUCA(UColTokenParser *src, tempUCATable *t,
+ UChar32 start, UChar32 end,
+ UErrorCode *status)
+{
+ //UChar decomp[256];
+ uint32_t CE = UCOL_NOT_FOUND;
+ UChar32 u = 0;
+ UCAElements el;
+ el.isThai = FALSE;
+ el.prefixSize = 0;
+ el.prefixChars[0] = 0;
+ collIterate colIt;
+
+ if(U_SUCCESS(*status)) {
+ for(u = start; u<=end; u++) {
+ if((CE = utrie_get32(t->mapping, u, NULL)) == UCOL_NOT_FOUND
+ /* this test is for contractions that are missing the starting element. */
+ || ((isCntTableElement(CE)) &&
+ (uprv_cnttab_getCE(t->contractions, CE, 0, status) == UCOL_NOT_FOUND))
+ ) {
+ el.cSize = 0;
+ U16_APPEND_UNSAFE(el.uchars, el.cSize, u);
+ //decomp[0] = (UChar)u;
+ //el.uchars[0] = (UChar)u;
+ el.cPoints = el.uchars;
+ //el.cSize = 1;
+ el.noOfCEs = 0;
+ el.prefix = el.prefixChars;
+ el.prefixSize = 0;
+ //uprv_init_collIterate(src->UCA, decomp, 1, &colIt);
+ // We actually want to check whether this element is a special
+ // If it is an implicit element (hangul, CJK - we want to copy the
+ // special, not the resolved CEs) - for hangul, copying resolved
+ // would just make things the same (there is an expansion and it
+ // takes approximately the same amount of time to resolve as
+ // falling back to the UCA).
+ /*
+ UTRIE_GET32(src->UCA->mapping, u, CE);
+ tag = getCETag(CE);
+ if(tag == HANGUL_SYLLABLE_TAG || tag == CJK_IMPLICIT_TAG
+ || tag == IMPLICIT_TAG || tag == TRAIL_SURROGATE_TAG
+ || tag == LEAD_SURROGATE_TAG) {
+ el.CEs[el.noOfCEs++] = CE;
+ } else {
+ */
+ // It turns out that it does not make sense to keep implicits
+ // unresolved. The cost of resolving them is big enough so that
+ // it doesn't make any difference whether we have to go to the UCA
+ // or not.
+ {
+ uprv_init_collIterate(src->UCA, el.uchars, el.cSize, &colIt);
+ while(CE != UCOL_NO_MORE_CES) {
+ CE = ucol_getNextCE(src->UCA, &colIt, status);
+ if(CE != UCOL_NO_MORE_CES) {
+ el.CEs[el.noOfCEs++] = CE;
+ }
+ }
+ }
+ uprv_uca_addAnElement(t, &el, status);
+ }
+ }
+ }
+}
+
+UCATableHeader *ucol_assembleTailoringTable(UColTokenParser *src, UErrorCode *status) {
+ U_NAMESPACE_USE
+
+ uint32_t i = 0;
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+ /*
+ 2. Eliminate the negative lists by doing the following for each non-null negative list:
+ o if previousCE(baseCE, strongestN) != some ListHeader X's baseCE,
+ create new ListHeader X
+ o reverse the list, add to the end of X's positive list. Reset the strength of the
+ first item you add, based on the stronger strength levels of the two lists.
+ */
+ /*
+ 3. For each ListHeader with a non-null positive list:
+ */
+ /*
+ o Find all character strings with CEs between the baseCE and the
+ next/previous CE, at the strength of the first token. Add these to the
+ tailoring.
+ ? That is, if UCA has ... x <<< X << x' <<< X' < y ..., and the
+ tailoring has & x < z...
+ ? Then we change the tailoring to & x <<< X << x' <<< X' < z ...
+ */
+ /* It is possible that this part should be done even while constructing list */
+ /* The problem is that it is unknown what is going to be the strongest weight */
+ /* So we might as well do it here */
+
+ /*
+ o Allocate CEs for each token in the list, based on the total number N of the
+ largest level difference, and the gap G between baseCE and nextCE at that
+ level. The relation * between the last item and nextCE is the same as the
+ strongest strength.
+ o Example: baseCE < a << b <<< q << c < d < e * nextCE(X,1)
+ ? There are 3 primary items: a, d, e. Fit them into the primary gap.
+ Then fit b and c into the secondary gap between a and d, then fit q
+ into the tertiary gap between b and c.
+
+ o Example: baseCE << b <<< q << c * nextCE(X,2)
+ ? There are 2 secondary items: b, c. Fit them into the secondary gap.
+ Then fit q into the tertiary gap between b and c.
+ o When incrementing primary values, we will not cross high byte
+ boundaries except where there is only a single-byte primary. That is to
+ ensure that the script reordering will continue to work.
+ */
+ UCATableHeader *image = (UCATableHeader *)uprv_malloc(sizeof(UCATableHeader));
+ /* test for NULL */
+ if (image == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(image, src->UCA->image, sizeof(UCATableHeader));
+
+ for(i = 0; i<src->resultLen; i++) {
+ /* now we need to generate the CEs */
+ /* We stuff the initial value in the buffers, and increase the appropriate buffer */
+ /* According to strength */
+ if(U_SUCCESS(*status)) {
+ if(src->lh[i].first) { // if there are any elements
+ // due to the way parser works, subsequent tailorings
+ // may remove all the elements from a sequence, therefore
+ // leaving an empty tailoring sequence.
+ ucol_initBuffers(src, &src->lh[i], status);
+ }
+ }
+ if(U_FAILURE(*status)) {
+ uprv_free(image);
+ return NULL;
+ }
+ }
+
+ if(src->varTop != NULL) { /* stuff the variable top value */
+ src->opts->variableTopValue = (*(src->varTop->CEs))>>16;
+ /* remove it from the list */
+ if(src->varTop->listHeader->first == src->varTop) { /* first in list */
+ src->varTop->listHeader->first = src->varTop->next;
+ }
+ if(src->varTop->listHeader->last == src->varTop) { /* first in list */
+ src->varTop->listHeader->last = src->varTop->previous;
+ }
+ if(src->varTop->next != NULL) {
+ src->varTop->next->previous = src->varTop->previous;
+ }
+ if(src->varTop->previous != NULL) {
+ src->varTop->previous->next = src->varTop->next;
+ }
+ }
+
+
+ tempUCATable *t = uprv_uca_initTempTable(image, src->opts, src->UCA, NOT_FOUND_TAG, NOT_FOUND_TAG, status);
+ if(U_FAILURE(*status)) {
+ uprv_free(image);
+ return NULL;
+ }
+
+
+ /* After this, we have assigned CE values to all regular CEs */
+ /* now we will go through list once more and resolve expansions, */
+ /* make UCAElements structs and add them to table */
+ for(i = 0; i<src->resultLen; i++) {
+ /* now we need to generate the CEs */
+ /* We stuff the initial value in the buffers, and increase the appropriate buffer */
+ /* According to strength */
+ if(U_SUCCESS(*status)) {
+ ucol_createElements(src, t, &src->lh[i], status);
+ }
+ }
+
+ UCAElements el;
+ el.isThai = FALSE;
+ el.prefixSize = 0;
+ el.prefixChars[0] = 0;
+
+ /* add latin-1 stuff */
+ ucol_uprv_bld_copyRangeFromUCA(src, t, 0, 0xFF, status);
+
+ /* add stuff for copying */
+ if(src->copySet != NULL) {
+ int32_t i = 0;
+ UnicodeSet *set = (UnicodeSet *)src->copySet;
+ for(i = 0; i < set->getRangeCount(); i++) {
+ ucol_uprv_bld_copyRangeFromUCA(src, t, set->getRangeStart(i), set->getRangeEnd(i), status);
+ }
+ }
+
+ if(U_SUCCESS(*status)) {
+ /* copy contractions from the UCA - this is felt mostly for cyrillic*/
+
+ uint32_t tailoredCE = UCOL_NOT_FOUND;
+ //UChar *conts = (UChar *)((uint8_t *)src->UCA->image + src->UCA->image->UCAConsts+sizeof(UCAConstants));
+ UChar *conts = (UChar *)((uint8_t *)src->UCA->image + src->UCA->image->contractionUCACombos);
+ UCollationElements *ucaEl = ucol_openElements(src->UCA, NULL, 0, status);
+ while(*conts != 0) {
+ /*tailoredCE = ucmpe32_get(t->mapping, *conts);*/
+ tailoredCE = utrie_get32(t->mapping, *conts, NULL);
+ if(tailoredCE != UCOL_NOT_FOUND) {
+ UBool needToAdd = TRUE;
+ if(isCntTableElement(tailoredCE)) {
+ if(uprv_cnttab_isTailored(t->contractions, tailoredCE, conts+1, status) == TRUE) {
+ needToAdd = FALSE;
+ }
+ }
+ if(src->removeSet != NULL && uset_contains(src->removeSet, *conts)) {
+ needToAdd = FALSE;
+ }
+
+ if(needToAdd == TRUE) { // we need to add if this contraction is not tailored.
+ el.prefix = el.prefixChars;
+ el.prefixSize = 0;
+ el.cPoints = el.uchars;
+ el.noOfCEs = 0;
+ el.uchars[0] = *conts;
+ el.uchars[1] = *(conts+1);
+ if(*(conts+2)!=0) {
+ el.uchars[2] = *(conts+2);
+ el.cSize = 3;
+ } else {
+ el.cSize = 2;
+ }
+ ucol_setText(ucaEl, el.uchars, el.cSize, status);
+ while ((int32_t)(el.CEs[el.noOfCEs] = ucol_next(ucaEl, status)) != UCOL_NULLORDER) {
+ el.noOfCEs++;
+ }
+ uprv_uca_addAnElement(t, &el, status);
+ }
+
+ } else if(src->removeSet != NULL && uset_contains(src->removeSet, *conts)) {
+ ucol_uprv_bld_copyRangeFromUCA(src, t, *conts, *conts, status);
+ }
+ conts+=3;
+ }
+ ucol_closeElements(ucaEl);
+ }
+
+ // Add completely ignorable elements
+ utrie_enum(&t->UCA->mapping, NULL, _processUCACompleteIgnorables, t);
+
+ // add tailoring characters related canonical closures
+ uprv_uca_canonicalClosure(t, src, status);
+
+ /* still need to produce compatibility closure */
+
+ UCATableHeader *myData = uprv_uca_assembleTable(t, status);
+
+ uprv_uca_closeTempTable(t);
+ uprv_free(image);
+
+ return myData;
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+ucol_bld_cleanup(void)
+{
+ udata_close(invUCA_DATA_MEM);
+ invUCA_DATA_MEM = NULL;
+ _staticInvUCA = NULL;
+ return TRUE;
+}
+U_CDECL_END
+
+U_CAPI const InverseUCATableHeader * U_EXPORT2
+ucol_initInverseUCA(UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return NULL;
+
+ UBool needsInit;
+ UMTX_CHECK(NULL, (_staticInvUCA == NULL), needsInit);
+
+ if(needsInit) {
+ InverseUCATableHeader *newInvUCA = NULL;
+ UDataMemory *result = udata_openChoice(NULL, INVC_DATA_TYPE, INVC_DATA_NAME, isAcceptableInvUCA, NULL, status);
+
+ if(U_FAILURE(*status)) {
+ if (result) {
+ udata_close(result);
+ }
+ // This is not needed, as we are talking about
+ // memory we got from UData
+ //uprv_free(newInvUCA);
+ }
+
+ if(result != NULL) { /* It looks like sometimes we can fail to find the data file */
+ newInvUCA = (InverseUCATableHeader *)udata_getMemory(result);
+ UCollator *UCA = ucol_initUCA(status);
+ // UCA versions of UCA and inverse UCA should match
+ if(uprv_memcmp(newInvUCA->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0) {
+ *status = U_INVALID_FORMAT_ERROR;
+ udata_close(result);
+ return NULL;
+ }
+
+ umtx_lock(NULL);
+ if(_staticInvUCA == NULL) {
+ _staticInvUCA = newInvUCA;
+ invUCA_DATA_MEM = result;
+ result = NULL;
+ newInvUCA = NULL;
+ }
+ umtx_unlock(NULL);
+
+ if(newInvUCA != NULL) {
+ udata_close(result);
+ // This is not needed, as we are talking about
+ // memory we got from UData
+ //uprv_free(newInvUCA);
+ }
+ else {
+ ucln_i18n_registerCleanup(UCLN_I18N_UCOL_BLD, ucol_bld_cleanup);
+ }
+ }
+ }
+ return _staticInvUCA;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_bld.h b/Build/source/libs/icu/icu-xetex/i18n/ucol_bld.h
new file mode 100644
index 00000000000..67a28a36a50
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_bld.h
@@ -0,0 +1,62 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: ucol_tok.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created 02/22/2001
+* created by: Vladimir Weinstein
+*
+* This module builds a collator based on the rule set.
+*
+*/
+
+#ifndef UCOL_BLD_H
+#define UCOL_BLD_H
+
+#ifdef UCOL_DEBUG
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+#if !UCONFIG_NO_COLLATION_BUILDER
+
+#include "ucol_imp.h"
+#include "ucol_tok.h"
+#include "ucol_elm.h"
+#include "ucol_wgt.h"
+
+#include "uhash.h"
+#include "cpputils.h"
+
+#include "unicode/ustring.h"
+#include "unicode/unistr.h"
+#include "unicode/normlzr.h"
+
+U_CFUNC
+UCATableHeader *ucol_assembleTailoringTable(UColTokenParser *src, UErrorCode *status);
+
+typedef struct {
+ WeightRange ranges[7];
+ int32_t noOfRanges;
+ uint32_t byteSize; uint32_t start; uint32_t limit;
+ int32_t maxCount;
+ int32_t count;
+ uint32_t current;
+ uint32_t fLow; /*forbidden Low */
+ uint32_t fHigh; /*forbidden High */
+} ucolCEGenerator;
+
+#endif /* #if !UCONFIG_NO_COLLATION_BUILDER */
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_cnt.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucol_cnt.cpp
new file mode 100644
index 00000000000..368197c4bc5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_cnt.cpp
@@ -0,0 +1,577 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2001-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: ucol_cnt.cpp
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created 02/22/2001
+ * created by: Vladimir Weinstein
+ *
+ * This module maintains a contraction table structure in expanded form
+ * and provides means to flatten this structure
+ *
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uchar.h"
+#include "ucol_cnt.h"
+#include "cmemory.h"
+
+static void uprv_growTable(ContractionTable *tbl, UErrorCode *status) {
+ if(tbl->position == tbl->size) {
+ uint32_t *newData = (uint32_t *)uprv_realloc(tbl->CEs, 2*tbl->size*sizeof(uint32_t));
+ if(newData == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ UChar *newCPs = (UChar *)uprv_realloc(tbl->codePoints, 2*tbl->size*sizeof(UChar));
+ if(newCPs == NULL) {
+ uprv_free(newData);
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ tbl->CEs = newData;
+ tbl->codePoints = newCPs;
+ tbl->size *= 2;
+ }
+}
+
+U_CAPI CntTable* U_EXPORT2
+/*uprv_cnttab_open(CompactEIntArray *mapping, UErrorCode *status) {*/
+uprv_cnttab_open(UNewTrie *mapping, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ CntTable *tbl = (CntTable *)uprv_malloc(sizeof(CntTable));
+ if(tbl == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ tbl->mapping = mapping;
+ tbl->elements = (ContractionTable **)uprv_malloc(INIT_EXP_TABLE_SIZE*sizeof(ContractionTable *));
+ if(tbl->elements == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(tbl);
+ return NULL;
+ }
+ tbl->capacity = INIT_EXP_TABLE_SIZE;
+ uprv_memset(tbl->elements, 0, INIT_EXP_TABLE_SIZE*sizeof(ContractionTable *));
+ tbl->size = 0;
+ tbl->position = 0;
+ tbl->CEs = NULL;
+ tbl->codePoints = NULL;
+ tbl->offsets = NULL;
+ tbl->currentTag = NOT_FOUND_TAG;
+ return tbl;
+}
+
+static ContractionTable *addATableElement(CntTable *table, uint32_t *key, UErrorCode *status) {
+ ContractionTable *el = (ContractionTable *)uprv_malloc(sizeof(ContractionTable));
+ if(el == NULL) {
+ goto outOfMemory;
+ }
+ el->CEs = (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE*sizeof(uint32_t));
+ if(el->CEs == NULL) {
+ goto outOfMemory;
+ }
+
+ el->codePoints = (UChar *)uprv_malloc(INIT_EXP_TABLE_SIZE*sizeof(UChar));
+ if(el->codePoints == NULL) {
+ uprv_free(el->CEs);
+ goto outOfMemory;
+ }
+
+ el->position = 0;
+ el->size = INIT_EXP_TABLE_SIZE;
+ uprv_memset(el->CEs, 0, INIT_EXP_TABLE_SIZE*sizeof(uint32_t));
+ uprv_memset(el->codePoints, 0, INIT_EXP_TABLE_SIZE*sizeof(UChar));
+
+ table->elements[table->size] = el;
+
+ //uhash_put(table->elements, (void *)table->size, el, status);
+
+ *key = table->size++;
+
+ if(table->size == table->capacity) {
+ ContractionTable **newElements = (ContractionTable **)uprv_malloc(table->capacity*2*sizeof(ContractionTable *));
+ // do realloc
+ /* table->elements = (ContractionTable **)realloc(table->elements, table->capacity*2*sizeof(ContractionTable *));*/
+ if(newElements == NULL) {
+ uprv_free(el->codePoints);
+ uprv_free(el->CEs);
+ goto outOfMemory;
+ }
+ ContractionTable **oldElements = table->elements;
+ uprv_memcpy(newElements, oldElements, table->capacity*sizeof(ContractionTable *));
+ uprv_memset(newElements+table->capacity, 0, table->capacity*sizeof(ContractionTable *));
+ table->capacity *= 2;
+ table->elements = newElements;
+ uprv_free(oldElements);
+ }
+
+ return el;
+
+outOfMemory:
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ if (el) uprv_free(el);
+ return NULL;
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_cnttab_constructTable(CntTable *table, uint32_t mainOffset, UErrorCode *status) {
+ int32_t i = 0, j = 0;
+ if(U_FAILURE(*status) || table->size == 0) {
+ return 0;
+ }
+
+ table->position = 0;
+
+ if(table->offsets != NULL) {
+ uprv_free(table->offsets);
+ }
+ table->offsets = (int32_t *)uprv_malloc(table->size*sizeof(int32_t));
+ if(table->offsets == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+
+ /* See how much memory we need */
+ for(i = 0; i<table->size; i++) {
+ table->offsets[i] = table->position+mainOffset;
+ table->position += table->elements[i]->position;
+ }
+
+ /* Allocate it */
+ if(table->CEs != NULL) {
+ uprv_free(table->CEs);
+ }
+ table->CEs = (uint32_t *)uprv_malloc(table->position*sizeof(uint32_t));
+ if(table->CEs == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(table->offsets);
+ table->offsets = NULL;
+ return 0;
+ }
+ uprv_memset(table->CEs, '?', table->position*sizeof(uint32_t));
+
+ if(table->codePoints != NULL) {
+ uprv_free(table->codePoints);
+ }
+ table->codePoints = (UChar *)uprv_malloc(table->position*sizeof(UChar));
+ if(table->codePoints == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(table->offsets);
+ table->offsets = NULL;
+ uprv_free(table->CEs);
+ table->CEs = NULL;
+ return 0;
+ }
+ uprv_memset(table->codePoints, '?', table->position*sizeof(UChar));
+
+ /* Now stuff the things in*/
+
+ UChar *cpPointer = table->codePoints;
+ uint32_t *CEPointer = table->CEs;
+ for(i = 0; i<table->size; i++) {
+ int32_t size = table->elements[i]->position;
+ uint8_t ccMax = 0, ccMin = 255, cc = 0;
+ for(j = 1; j<size; j++) {
+ cc = u_getCombiningClass(table->elements[i]->codePoints[j]);
+ if(cc>ccMax) {
+ ccMax = cc;
+ }
+ if(cc<ccMin) {
+ ccMin = cc;
+ }
+ *(cpPointer+j) = table->elements[i]->codePoints[j];
+ }
+ *cpPointer = ((ccMin==ccMax)?1:0 << 8) | ccMax;
+
+ uprv_memcpy(CEPointer, table->elements[i]->CEs, size*sizeof(uint32_t));
+ for(j = 0; j<size; j++) {
+ if(isCntTableElement(*(CEPointer+j))) {
+ *(CEPointer+j) = constructContractCE(getCETag(*(CEPointer+j)), table->offsets[getContractOffset(*(CEPointer+j))]);
+ }
+ }
+ cpPointer += size;
+ CEPointer += size;
+ }
+
+ // TODO: this one apparently updates the contraction CEs to point to a real address (relative to the
+ // start of the flat file). However, what is done below is just wrong and it affects building of
+ // tailorings that have constructions in a bad way. At least, one should enumerate the trie. Also,
+ // keeping a list of code points that are contractions might be smart, although I'm not sure if it's
+ // feasible.
+ uint32_t CE;
+ for(i = 0; i<=0x10FFFF; i++) {
+ /*CE = ucmpe32_get(table->mapping, i);*/
+ CE = utrie_get32(table->mapping, i, NULL);
+ if(isCntTableElement(CE)) {
+ CE = constructContractCE(getCETag(CE), table->offsets[getContractOffset(CE)]);
+ /*ucmpe32_set(table->mapping, i, CE);*/
+ utrie_set32(table->mapping, i, CE);
+ }
+ }
+
+
+ return table->position;
+}
+
+static ContractionTable *uprv_cnttab_cloneContraction(ContractionTable *t, UErrorCode *status) {
+ ContractionTable *r = (ContractionTable *)uprv_malloc(sizeof(ContractionTable));
+ if(r == NULL) {
+ goto outOfMemory;
+ }
+
+ r->position = t->position;
+ r->size = t->size;
+
+ r->codePoints = (UChar *)uprv_malloc(sizeof(UChar)*t->size);
+ if(r->codePoints == NULL) {
+ goto outOfMemory;
+ }
+ r->CEs = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->size);
+ if(r->CEs == NULL) {
+ uprv_free(r->codePoints);
+ goto outOfMemory;
+ }
+ uprv_memcpy(r->codePoints, t->codePoints, sizeof(UChar)*t->size);
+ uprv_memcpy(r->CEs, t->CEs, sizeof(uint32_t)*t->size);
+
+ return r;
+
+outOfMemory:
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ if (r) uprv_free(r);
+ return NULL;
+}
+
+U_CAPI CntTable* U_EXPORT2
+uprv_cnttab_clone(CntTable *t, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+ int32_t i = 0;
+ CntTable *r = (CntTable *)uprv_malloc(sizeof(CntTable));
+ /* test for NULL */
+ if (r == NULL) {
+ goto outOfMemory;
+ }
+ r->position = t->position;
+ r->size = t->size;
+ r->capacity = t->capacity;
+
+ r->mapping = t->mapping;
+
+ r->elements = (ContractionTable **)uprv_malloc(t->capacity*sizeof(ContractionTable *));
+ /* test for NULL */
+ if (r->elements == NULL) {
+ goto outOfMemory;
+ }
+ //uprv_memcpy(r->elements, t->elements, t->capacity*sizeof(ContractionTable *));
+
+ for(i = 0; i<t->size; i++) {
+ r->elements[i] = uprv_cnttab_cloneContraction(t->elements[i], status);
+ }
+
+ if(t->CEs != NULL) {
+ r->CEs = (uint32_t *)uprv_malloc(t->position*sizeof(uint32_t));
+ /* test for NULL */
+ if (r->CEs == NULL) {
+ uprv_free(r->elements);
+ goto outOfMemory;
+ }
+ uprv_memcpy(r->CEs, t->CEs, t->position*sizeof(uint32_t));
+ } else {
+ r->CEs = NULL;
+ }
+
+ if(t->codePoints != NULL) {
+ r->codePoints = (UChar *)uprv_malloc(t->position*sizeof(UChar));
+ /* test for NULL */
+ if (r->codePoints == NULL) {
+ uprv_free(r->CEs);
+ uprv_free(r->elements);
+ goto outOfMemory;
+ }
+ uprv_memcpy(r->codePoints, t->codePoints, t->position*sizeof(UChar));
+ } else {
+ r->codePoints = NULL;
+ }
+
+ if(t->offsets != NULL) {
+ r->offsets = (int32_t *)uprv_malloc(t->size*sizeof(int32_t));
+ /* test for NULL */
+ if (r->offsets == NULL) {
+ uprv_free(r->codePoints);
+ uprv_free(r->CEs);
+ uprv_free(r->elements);
+ goto outOfMemory;
+ }
+ uprv_memcpy(r->offsets, t->offsets, t->size*sizeof(int32_t));
+ } else {
+ r->offsets = NULL;
+ }
+
+ return r;
+
+outOfMemory:
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ if (r) uprv_free(r);
+ return NULL;
+}
+
+U_CAPI void U_EXPORT2
+uprv_cnttab_close(CntTable *table) {
+ int32_t i = 0;
+ for(i = 0; i<table->size; i++) {
+ uprv_free(table->elements[i]->CEs);
+ uprv_free(table->elements[i]->codePoints);
+ uprv_free(table->elements[i]);
+ }
+ uprv_free(table->elements);
+ uprv_free(table->CEs);
+ uprv_free(table->offsets);
+ uprv_free(table->codePoints);
+ uprv_free(table);
+}
+
+/* this is for adding non contractions */
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_changeLastCE(CntTable *table, uint32_t element, uint32_t value, UErrorCode *status) {
+ element &= 0xFFFFFF;
+
+ ContractionTable *tbl = NULL;
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if((element == 0xFFFFFF) || (tbl = table->elements[element]) == NULL) {
+ return 0;
+ }
+
+ tbl->CEs[tbl->position-1] = value;
+
+ return(constructContractCE(table->currentTag, element));
+}
+
+
+/* inserts a part of contraction sequence in table. Sequences behind the offset are moved back. If element is non existent, it creates on. Returns element handle */
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_insertContraction(CntTable *table, uint32_t element, UChar codePoint, uint32_t value, UErrorCode *status) {
+
+ ContractionTable *tbl = NULL;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ element &= 0xFFFFFF;
+
+ if((element == 0xFFFFFF) || (tbl = table->elements[element]) == NULL) {
+ tbl = addATableElement(table, &element, status);
+ }
+
+ uprv_growTable(tbl, status);
+
+ uint32_t offset = 0;
+
+
+ while(tbl->codePoints[offset] < codePoint && offset<tbl->position) {
+ offset++;
+ }
+
+ uint32_t i = tbl->position;
+ for(i = tbl->position; i > offset; i--) {
+ tbl->CEs[i] = tbl->CEs[i-1];
+ tbl->codePoints[i] = tbl->codePoints[i-1];
+ }
+
+ tbl->CEs[offset] = value;
+ tbl->codePoints[offset] = codePoint;
+
+ tbl->position++;
+
+ return(constructContractCE(table->currentTag, element));
+}
+
+
+/* adds more contractions in table. If element is non existant, it creates on. Returns element handle */
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_addContraction(CntTable *table, uint32_t element, UChar codePoint, uint32_t value, UErrorCode *status) {
+
+ element &= 0xFFFFFF;
+
+ ContractionTable *tbl = NULL;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if((element == 0xFFFFFF) || (tbl = table->elements[element]) == NULL) {
+ tbl = addATableElement(table, &element, status);
+ }
+
+ uprv_growTable(tbl, status);
+
+ tbl->CEs[tbl->position] = value;
+ tbl->codePoints[tbl->position] = codePoint;
+
+ tbl->position++;
+
+ return(constructContractCE(table->currentTag, element));
+}
+
+/* sets a part of contraction sequence in table. If element is non existant, it creates on. Returns element handle */
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_setContraction(CntTable *table, uint32_t element, uint32_t offset, UChar codePoint, uint32_t value, UErrorCode *status) {
+
+ element &= 0xFFFFFF;
+ ContractionTable *tbl = NULL;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if((element == 0xFFFFFF) || (tbl = table->elements[element]) == NULL) {
+ tbl = addATableElement(table, &element, status);
+ }
+
+ if(offset >= tbl->size) {
+ *status = U_INDEX_OUTOFBOUNDS_ERROR;
+ return 0;
+ }
+ tbl->CEs[offset] = value;
+ tbl->codePoints[offset] = codePoint;
+
+ //return(offset);
+ return(constructContractCE(table->currentTag, element));
+}
+
+static ContractionTable *_cnttab_getContractionTable(CntTable *table, uint32_t element) {
+ element &= 0xFFFFFF;
+ ContractionTable *tbl = NULL;
+
+ if(element != 0xFFFFFF) {
+ tbl = table->elements[element]; /* This could also return NULL */
+ }
+ return tbl;
+}
+
+static int32_t _cnttab_findCP(ContractionTable *tbl, UChar codePoint) {
+ uint32_t position = 0;
+ if(tbl == NULL) {
+ return -1;
+ }
+
+ while(codePoint > tbl->codePoints[position]) {
+ position++;
+ if(position > tbl->position) {
+ return -1;
+ }
+ }
+ if (codePoint == tbl->codePoints[position]) {
+ return position;
+ } else {
+ return -1;
+ }
+}
+
+static uint32_t _cnttab_getCE(ContractionTable *tbl, int32_t position) {
+ if(tbl == NULL) {
+ return UCOL_NOT_FOUND;
+ }
+ if((uint32_t)position > tbl->position || position == -1) {
+ return UCOL_NOT_FOUND;
+ } else {
+ return tbl->CEs[position];
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_cnttab_findCP(CntTable *table, uint32_t element, UChar codePoint, UErrorCode *status) {
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ return _cnttab_findCP(_cnttab_getContractionTable(table, element), codePoint);
+}
+
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_getCE(CntTable *table, uint32_t element, uint32_t position, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return UCOL_NOT_FOUND;
+ }
+
+ return(_cnttab_getCE(_cnttab_getContractionTable(table, element), position));
+}
+
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_findCE(CntTable *table, uint32_t element, UChar codePoint, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return UCOL_NOT_FOUND;
+ }
+ ContractionTable *tbl = _cnttab_getContractionTable(table, element);
+ return _cnttab_getCE(tbl, _cnttab_findCP(tbl, codePoint));
+}
+
+U_CAPI UBool U_EXPORT2
+uprv_cnttab_isTailored(CntTable *table, uint32_t element, UChar *ztString, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return FALSE;
+ }
+
+ while(*(ztString)!=0) {
+ element = uprv_cnttab_findCE(table, element, *(ztString), status);
+ if(element == UCOL_NOT_FOUND) {
+ return FALSE;
+ }
+ if(!isCntTableElement(element)) {
+ return TRUE;
+ }
+ ztString++;
+ }
+ return (UBool)(uprv_cnttab_getCE(table, element, 0, status) != UCOL_NOT_FOUND);
+}
+
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_changeContraction(CntTable *table, uint32_t element, UChar codePoint, uint32_t newCE, UErrorCode *status) {
+
+ element &= 0xFFFFFF;
+ ContractionTable *tbl = NULL;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if((element == 0xFFFFFF) || (tbl = table->elements[element]) == NULL) {
+ return 0;
+ }
+
+ uint32_t position = 0;
+
+ while(codePoint > tbl->codePoints[position]) {
+ position++;
+ if(position > tbl->position) {
+ return UCOL_NOT_FOUND;
+ }
+ }
+ if (codePoint == tbl->codePoints[position]) {
+ tbl->CEs[position] = newCE;
+ return element;
+ } else {
+ return UCOL_NOT_FOUND;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_cnt.h b/Build/source/libs/icu/icu-xetex/i18n/ucol_cnt.h
new file mode 100644
index 00000000000..c16211fc4d7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_cnt.h
@@ -0,0 +1,105 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: ucol_tok.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created 02/22/2001
+* created by: Vladimir Weinstein
+*
+* This module maintains a contraction table structure in expanded form
+* and provides means to flatten this structure
+*
+*/
+
+#ifndef UCOL_CNTTABLE_H
+#define UCOL_CNTTABLE_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+/*#include "ucmpe32.h"*/
+#include "utrie.h"
+#include "uhash.h"
+#include "ucol_elm.h"
+#include "ucol_imp.h"
+
+U_CDECL_BEGIN
+
+#define UPRV_CNTTAB_NEWELEMENT 0xFFFFFF
+
+#define isCntTableElement(CE) (isSpecial((CE)) && \
+((getCETag((CE)) == CONTRACTION_TAG)||(getCETag((CE)) == SPEC_PROC_TAG)))
+
+typedef struct ContractionTable ContractionTable;
+struct ContractionTable {
+ UChar *codePoints;
+ uint32_t *CEs;
+ uint32_t position;
+ uint32_t size;
+};
+
+struct CntTable {
+ ContractionTable **elements;
+ /*CompactEIntArray *mapping;*/
+ UNewTrie *mapping;
+ UChar *codePoints;
+ uint32_t *CEs;
+ int32_t *offsets;
+ int32_t position;
+ int32_t size;
+ int32_t capacity;
+ UColCETags currentTag;
+};
+
+U_CAPI CntTable* U_EXPORT2
+/*uprv_cnttab_open(CompactEIntArray *mapping, UErrorCode *status);*/
+uprv_cnttab_open(UNewTrie *mapping, UErrorCode *status);
+U_CAPI CntTable* U_EXPORT2
+uprv_cnttab_clone(CntTable *table, UErrorCode *status);
+U_CAPI void U_EXPORT2
+uprv_cnttab_close(CntTable *table);
+
+/* construct the table for output */
+U_CAPI int32_t U_EXPORT2
+uprv_cnttab_constructTable(CntTable *table, uint32_t mainOffset, UErrorCode *status);
+/* adds more contractions in table. If element is non existant, it creates on. Returns element handle */
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_addContraction(CntTable *table, uint32_t element, UChar codePoint, uint32_t value, UErrorCode *status);
+/* sets a part of contraction sequence in table. If element is non existant, it creates on. Returns element handle */
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_setContraction(CntTable *table, uint32_t element, uint32_t offset, UChar codePoint, uint32_t value, UErrorCode *status);
+/* inserts a part of contraction sequence in table. Sequences behind the offset are moved back. If element is non existant, it creates on. Returns element handle */
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_insertContraction(CntTable *table, uint32_t element, UChar codePoint, uint32_t value, UErrorCode *status);
+/* this is for adding non contractions */
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_changeLastCE(CntTable *table, uint32_t element, uint32_t value, UErrorCode *status);
+
+U_CAPI int32_t U_EXPORT2
+uprv_cnttab_findCP(CntTable *table, uint32_t element, UChar codePoint, UErrorCode *status);
+
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_getCE(CntTable *table, uint32_t element, uint32_t position, UErrorCode *status);
+
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_changeContraction(CntTable *table, uint32_t element, UChar codePoint, uint32_t newCE, UErrorCode *status);
+
+U_CAPI uint32_t U_EXPORT2
+uprv_cnttab_findCE(CntTable *table, uint32_t element, UChar codePoint, UErrorCode *status);
+
+U_CAPI UBool U_EXPORT2
+uprv_cnttab_isTailored(CntTable *table, uint32_t element, UChar *ztString, UErrorCode *status);
+
+U_CDECL_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_elm.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucol_elm.cpp
new file mode 100644
index 00000000000..929a4db816d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_elm.cpp
@@ -0,0 +1,1985 @@
+
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: ucaelems.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created 02/22/2001
+* created by: Vladimir Weinstein
+*
+* This program reads the Franctional UCA table and generates
+* internal format for UCA table as well as inverse UCA table.
+* It then writes binary files containing the data: ucadata.dat
+* & invuca.dat
+*
+* date name comments
+* 03/02/2001 synwee added setMaxExpansion
+* 03/07/2001 synwee merged UCA's maxexpansion and tailoring's
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uchar.h"
+#include "unicode/unistr.h"
+#include "unicode/ucoleitr.h"
+#include "unicode/normlzr.h"
+#include "ucol_elm.h"
+#include "ucol_tok.h"
+#include "unormimp.h"
+#include "unicode/caniter.h"
+#include "cmemory.h"
+
+static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements *element, uint32_t existingCE, UErrorCode *status);
+
+U_CDECL_BEGIN
+static int32_t U_CALLCONV
+prefixLookupHash(const UHashTok e) {
+ UCAElements *element = (UCAElements *)e.pointer;
+ UChar buf[256];
+ UHashTok key;
+ key.pointer = buf;
+ uprv_memcpy(buf, element->cPoints, element->cSize*sizeof(UChar));
+ buf[element->cSize] = 0;
+ //key.pointer = element->cPoints;
+ //element->cPoints[element->cSize] = 0;
+ return uhash_hashUChars(key);
+}
+
+static int8_t U_CALLCONV
+prefixLookupComp(const UHashTok e1, const UHashTok e2) {
+ UCAElements *element1 = (UCAElements *)e1.pointer;
+ UCAElements *element2 = (UCAElements *)e2.pointer;
+
+ UChar buf1[256];
+ UHashTok key1;
+ key1.pointer = buf1;
+ uprv_memcpy(buf1, element1->cPoints, element1->cSize*sizeof(UChar));
+ buf1[element1->cSize] = 0;
+
+ UChar buf2[256];
+ UHashTok key2;
+ key2.pointer = buf2;
+ uprv_memcpy(buf2, element2->cPoints, element2->cSize*sizeof(UChar));
+ buf2[element2->cSize] = 0;
+
+ return uhash_compareUChars(key1, key2);
+}
+U_CDECL_END
+
+static int32_t uprv_uca_addExpansion(ExpansionTable *expansions, uint32_t value, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ if(expansions->CEs == NULL) {
+ expansions->CEs = (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE*sizeof(uint32_t));
+ /* test for NULL */
+ if (expansions->CEs == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ expansions->size = INIT_EXP_TABLE_SIZE;
+ expansions->position = 0;
+ }
+
+ if(expansions->position == expansions->size) {
+ uint32_t *newData = (uint32_t *)uprv_realloc(expansions->CEs, 2*expansions->size*sizeof(uint32_t));
+ if(newData == NULL) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "out of memory for expansions\n");
+#endif
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return -1;
+ }
+ expansions->CEs = newData;
+ expansions->size *= 2;
+ }
+
+ expansions->CEs[expansions->position] = value;
+ return(expansions->position++);
+}
+
+U_CAPI tempUCATable* U_EXPORT2
+uprv_uca_initTempTable(UCATableHeader *image, UColOptionSet *opts, const UCollator *UCA, UColCETags initTag, UColCETags supplementaryInitTag, UErrorCode *status) {
+ MaxJamoExpansionTable *maxjet;
+ MaxExpansionTable *maxet;
+ tempUCATable *t = (tempUCATable *)uprv_malloc(sizeof(tempUCATable));
+ /* test for NULL */
+ if (t == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memset(t, 0, sizeof(tempUCATable));
+
+ maxet = (MaxExpansionTable *)uprv_malloc(sizeof(MaxExpansionTable));
+ if (maxet == NULL) {
+ goto allocation_failure;
+ }
+ uprv_memset(maxet, 0, sizeof(MaxExpansionTable));
+ t->maxExpansions = maxet;
+
+ maxjet = (MaxJamoExpansionTable *)uprv_malloc(sizeof(MaxJamoExpansionTable));
+ if (maxjet == NULL) {
+ goto allocation_failure;
+ }
+ uprv_memset(maxjet, 0, sizeof(MaxJamoExpansionTable));
+ t->maxJamoExpansions = maxjet;
+
+ t->image = image;
+ t->options = opts;
+
+ t->UCA = UCA;
+ t->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable));
+ /* test for NULL */
+ if (t->expansions == NULL) {
+ goto allocation_failure;
+ }
+ uprv_memset(t->expansions, 0, sizeof(ExpansionTable));
+
+ t->mapping = utrie_open(NULL, NULL, UCOL_ELM_TRIE_CAPACITY,
+ UCOL_SPECIAL_FLAG | (initTag<<24),
+ UCOL_SPECIAL_FLAG | (supplementaryInitTag << 24),
+ TRUE); // Do your own mallocs for the structure, array and have linear Latin 1
+ if (t->mapping == NULL) {
+ goto allocation_failure;
+ }
+ t->prefixLookup = uhash_open(prefixLookupHash, prefixLookupComp, NULL, status);
+ uhash_setValueDeleter(t->prefixLookup, uhash_freeBlock);
+
+ t->contractions = uprv_cnttab_open(t->mapping, status);
+
+ /* copy UCA's maxexpansion and merge as we go along */
+ if (UCA != NULL) {
+ /* adding an extra initial value for easier manipulation */
+ maxet->size = (UCA->lastEndExpansionCE - UCA->endExpansionCE)
+ + 2;
+ maxet->position = maxet->size - 1;
+ maxet->endExpansionCE =
+ (uint32_t *)uprv_malloc(sizeof(uint32_t) * maxet->size);
+ /* test for NULL */
+ if (maxet->endExpansionCE == NULL) {
+ goto allocation_failure;
+ }
+ maxet->expansionCESize =
+ (uint8_t *)uprv_malloc(sizeof(uint8_t) * maxet->size);
+ /* test for NULL */
+ if (maxet->expansionCESize == NULL) {
+ goto allocation_failure;
+ }
+ /* initialized value */
+ *(maxet->endExpansionCE) = 0;
+ *(maxet->expansionCESize) = 0;
+ uprv_memcpy(maxet->endExpansionCE + 1, UCA->endExpansionCE,
+ sizeof(uint32_t) * (maxet->size - 1));
+ uprv_memcpy(maxet->expansionCESize + 1, UCA->expansionCESize,
+ sizeof(uint8_t) * (maxet->size - 1));
+ }
+ else {
+ maxet->size = 0;
+ }
+ maxjet->endExpansionCE = NULL;
+ maxjet->isV = NULL;
+ maxjet->size = 0;
+ maxjet->position = 0;
+ maxjet->maxLSize = 1;
+ maxjet->maxVSize = 1;
+ maxjet->maxTSize = 1;
+
+ t->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
+ /* test for NULL */
+ if (t->unsafeCP == NULL) {
+ goto allocation_failure;
+ }
+ t->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
+ /* test for NULL */
+ if (t->contrEndCP == NULL) {
+ goto allocation_failure;
+ }
+ uprv_memset(t->unsafeCP, 0, UCOL_UNSAFECP_TABLE_SIZE);
+ uprv_memset(t->contrEndCP, 0, UCOL_UNSAFECP_TABLE_SIZE);
+ t->cmLookup = NULL;
+ return t;
+
+allocation_failure:
+ uprv_uca_closeTempTable(t);
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+}
+
+U_CAPI tempUCATable* U_EXPORT2
+uprv_uca_cloneTempTable(tempUCATable *t, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ tempUCATable *r = (tempUCATable *)uprv_malloc(sizeof(tempUCATable));
+ /* test for NULL */
+ if (r == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memset(r, 0, sizeof(tempUCATable));
+
+ /* mapping */
+ if(t->mapping != NULL) {
+ /*r->mapping = ucmpe32_clone(t->mapping, status);*/
+ r->mapping = utrie_clone(NULL, t->mapping, NULL, 0);
+ }
+
+ // a hashing clone function would be very nice. We have none currently...
+ // However, we should be good, as closing should not produce any prefixed elements.
+ r->prefixLookup = NULL; // prefixes are not used in closing
+
+ /* expansions */
+ if(t->expansions != NULL) {
+ r->expansions = (ExpansionTable *)uprv_malloc(sizeof(ExpansionTable));
+ /* test for NULL */
+ if (r->expansions == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ r->expansions->position = t->expansions->position;
+ r->expansions->size = t->expansions->size;
+ if(t->expansions->CEs != NULL) {
+ r->expansions->CEs = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->expansions->size);
+ /* test for NULL */
+ if (r->expansions->CEs == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(r->expansions->CEs, t->expansions->CEs, sizeof(uint32_t)*t->expansions->position);
+ } else {
+ r->expansions->CEs = NULL;
+ }
+ }
+
+ if(t->contractions != NULL) {
+ r->contractions = uprv_cnttab_clone(t->contractions, status);
+ r->contractions->mapping = r->mapping;
+ }
+
+ if(t->maxExpansions != NULL) {
+ r->maxExpansions = (MaxExpansionTable *)uprv_malloc(sizeof(MaxExpansionTable));
+ /* test for NULL */
+ if (r->maxExpansions == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ r->maxExpansions->size = t->maxExpansions->size;
+ r->maxExpansions->position = t->maxExpansions->position;
+ if(t->maxExpansions->endExpansionCE != NULL) {
+ r->maxExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxExpansions->size);
+ uprv_memset(r->maxExpansions->endExpansionCE, 0xDB, sizeof(uint32_t)*t->maxExpansions->size);
+ /* test for NULL */
+ if (r->maxExpansions->endExpansionCE == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(r->maxExpansions->endExpansionCE, t->maxExpansions->endExpansionCE, t->maxExpansions->position*sizeof(uint32_t));
+ } else {
+ r->maxExpansions->endExpansionCE = NULL;
+ }
+ if(t->maxExpansions->expansionCESize != NULL) {
+ r->maxExpansions->expansionCESize = (uint8_t *)uprv_malloc(sizeof(uint8_t)*t->maxExpansions->size);
+ uprv_memset(r->maxExpansions->expansionCESize, 0xDB, sizeof(uint8_t)*t->maxExpansions->size);
+ /* test for NULL */
+ if (r->maxExpansions->expansionCESize == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(r->maxExpansions->expansionCESize, t->maxExpansions->expansionCESize, t->maxExpansions->position*sizeof(uint8_t));
+ } else {
+ r->maxExpansions->expansionCESize = NULL;
+ }
+ }
+
+ if(t->maxJamoExpansions != NULL) {
+ r->maxJamoExpansions = (MaxJamoExpansionTable *)uprv_malloc(sizeof(MaxJamoExpansionTable));
+ /* test for NULL */
+ if (r->maxJamoExpansions == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ r->maxJamoExpansions->size = t->maxJamoExpansions->size;
+ r->maxJamoExpansions->position = t->maxJamoExpansions->position;
+ r->maxJamoExpansions->maxLSize = t->maxJamoExpansions->maxLSize;
+ r->maxJamoExpansions->maxVSize = t->maxJamoExpansions->maxVSize;
+ r->maxJamoExpansions->maxTSize = t->maxJamoExpansions->maxTSize;
+ if(t->maxJamoExpansions->size != 0) {
+ r->maxJamoExpansions->endExpansionCE = (uint32_t *)uprv_malloc(sizeof(uint32_t)*t->maxJamoExpansions->size);
+ /* test for NULL */
+ if (r->maxJamoExpansions->endExpansionCE == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(r->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->endExpansionCE, t->maxJamoExpansions->position*sizeof(uint32_t));
+ r->maxJamoExpansions->isV = (UBool *)uprv_malloc(sizeof(UBool)*t->maxJamoExpansions->size);
+ /* test for NULL */
+ if (r->maxJamoExpansions->isV == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(r->maxJamoExpansions->isV, t->maxJamoExpansions->isV, t->maxJamoExpansions->position*sizeof(UBool));
+ } else {
+ r->maxJamoExpansions->endExpansionCE = NULL;
+ r->maxJamoExpansions->isV = NULL;
+ }
+ }
+
+ if(t->unsafeCP != NULL) {
+ r->unsafeCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
+ /* test for NULL */
+ if (r->unsafeCP == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(r->unsafeCP, t->unsafeCP, UCOL_UNSAFECP_TABLE_SIZE);
+ }
+
+ if(t->contrEndCP != NULL) {
+ r->contrEndCP = (uint8_t *)uprv_malloc(UCOL_UNSAFECP_TABLE_SIZE);
+ /* test for NULL */
+ if (r->contrEndCP == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(r->contrEndCP, t->contrEndCP, UCOL_UNSAFECP_TABLE_SIZE);
+ }
+
+ r->UCA = t->UCA;
+ r->image = t->image;
+ r->options = t->options;
+
+ return r;
+}
+
+
+U_CAPI void U_EXPORT2
+uprv_uca_closeTempTable(tempUCATable *t) {
+ if(t != NULL) {
+ if (t->expansions != NULL) {
+ uprv_free(t->expansions->CEs);
+ uprv_free(t->expansions);
+ }
+ if(t->contractions != NULL) {
+ uprv_cnttab_close(t->contractions);
+ }
+ if (t->mapping != NULL) {
+ utrie_close(t->mapping);
+ }
+
+ if(t->prefixLookup != NULL) {
+ uhash_close(t->prefixLookup);
+ }
+
+ if (t->maxExpansions != NULL) {
+ uprv_free(t->maxExpansions->endExpansionCE);
+ uprv_free(t->maxExpansions->expansionCESize);
+ uprv_free(t->maxExpansions);
+ }
+
+ if (t->maxJamoExpansions->size > 0) {
+ uprv_free(t->maxJamoExpansions->endExpansionCE);
+ uprv_free(t->maxJamoExpansions->isV);
+ }
+ uprv_free(t->maxJamoExpansions);
+
+ uprv_free(t->unsafeCP);
+ uprv_free(t->contrEndCP);
+
+ if (t->cmLookup != NULL) {
+ uprv_free(t->cmLookup->cPoints);
+ uprv_free(t->cmLookup);
+ }
+
+ uprv_free(t);
+ }
+}
+
+/**
+* Looks for the maximum length of all expansion sequences ending with the same
+* collation element. The size required for maxexpansion and maxsize is
+* returned if the arrays are too small.
+* @param endexpansion the last expansion collation element to be added
+* @param expansionsize size of the expansion
+* @param maxexpansion data structure to store the maximum expansion data.
+* @param status error status
+* @returns size of the maxexpansion and maxsize used.
+*/
+static int uprv_uca_setMaxExpansion(uint32_t endexpansion,
+ uint8_t expansionsize,
+ MaxExpansionTable *maxexpansion,
+ UErrorCode *status)
+{
+ if (maxexpansion->size == 0) {
+ /* we'll always make the first element 0, for easier manipulation */
+ maxexpansion->endExpansionCE =
+ (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(int32_t));
+ /* test for NULL */
+ if (maxexpansion->endExpansionCE == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ *(maxexpansion->endExpansionCE) = 0;
+ maxexpansion->expansionCESize =
+ (uint8_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint8_t));
+ /* test for NULL */;
+ if (maxexpansion->expansionCESize == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ *(maxexpansion->expansionCESize) = 0;
+ maxexpansion->size = INIT_EXP_TABLE_SIZE;
+ maxexpansion->position = 0;
+ }
+
+ if (maxexpansion->position + 1 == maxexpansion->size) {
+ uint32_t *neweece = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE,
+ 2 * maxexpansion->size * sizeof(uint32_t));
+ uint8_t *neweces = (uint8_t *)uprv_realloc(maxexpansion->expansionCESize,
+ 2 * maxexpansion->size * sizeof(uint8_t));
+ if (neweece == NULL || neweces == NULL) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "out of memory for maxExpansions\n");
+#endif
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return -1;
+ }
+ maxexpansion->endExpansionCE = neweece;
+ maxexpansion->expansionCESize = neweces;
+ maxexpansion->size *= 2;
+ }
+
+ uint32_t *pendexpansionce = maxexpansion->endExpansionCE;
+ uint8_t *pexpansionsize = maxexpansion->expansionCESize;
+ int pos = maxexpansion->position;
+
+ uint32_t *start = pendexpansionce;
+ uint32_t *limit = pendexpansionce + pos;
+
+ /* using binary search to determine if last expansion element is
+ already in the array */
+ uint32_t *mid;
+ int result = -1;
+ while (start < limit - 1) {
+ mid = start + ((limit - start) >> 1);
+ if (endexpansion <= *mid) {
+ limit = mid;
+ }
+ else {
+ start = mid;
+ }
+ }
+
+ if (*start == endexpansion) {
+ result = start - pendexpansionce;
+ }
+ else
+ if (*limit == endexpansion) {
+ result = limit - pendexpansionce;
+ }
+
+ if (result > -1) {
+ /* found the ce in expansion, we'll just modify the size if it is
+ smaller */
+ uint8_t *currentsize = pexpansionsize + result;
+ if (*currentsize < expansionsize) {
+ *currentsize = expansionsize;
+ }
+ }
+ else {
+ /* we'll need to squeeze the value into the array.
+ initial implementation. */
+ /* shifting the subarray down by 1 */
+ int shiftsize = (pendexpansionce + pos) - start;
+ uint32_t *shiftpos = start + 1;
+ uint8_t *sizeshiftpos = pexpansionsize + (shiftpos - pendexpansionce);
+
+ /* okay need to rearrange the array into sorted order */
+ if (shiftsize == 0 /*|| *(pendexpansionce + pos) < endexpansion*/) { /* the commented part is actually both redundant and dangerous */
+ *(pendexpansionce + pos + 1) = endexpansion;
+ *(pexpansionsize + pos + 1) = expansionsize;
+ }
+ else {
+ uprv_memmove(shiftpos + 1, shiftpos, shiftsize * sizeof(int32_t));
+ uprv_memmove(sizeshiftpos + 1, sizeshiftpos,
+ shiftsize * sizeof(uint8_t));
+ *shiftpos = endexpansion;
+ *sizeshiftpos = expansionsize;
+ }
+ maxexpansion->position ++;
+
+#ifdef UCOL_DEBUG
+ int temp;
+ UBool found = FALSE;
+ for (temp = 0; temp < maxexpansion->position; temp ++) {
+ if (pendexpansionce[temp] >= pendexpansionce[temp + 1]) {
+ fprintf(stderr, "expansions %d\n", temp);
+ }
+ if (pendexpansionce[temp] == endexpansion) {
+ found =TRUE;
+ if (pexpansionsize[temp] < expansionsize) {
+ fprintf(stderr, "expansions size %d\n", temp);
+ }
+ }
+ }
+ if (pendexpansionce[temp] == endexpansion) {
+ found =TRUE;
+ if (pexpansionsize[temp] < expansionsize) {
+ fprintf(stderr, "expansions size %d\n", temp);
+ }
+ }
+ if (!found)
+ fprintf(stderr, "expansion not found %d\n", temp);
+#endif
+ }
+
+ return maxexpansion->position;
+}
+
+/**
+* Sets the maximum length of all jamo expansion sequences ending with the same
+* collation element. The size required for maxexpansion and maxsize is
+* returned if the arrays are too small.
+* @param ch the jamo codepoint
+* @param endexpansion the last expansion collation element to be added
+* @param expansionsize size of the expansion
+* @param maxexpansion data structure to store the maximum expansion data.
+* @param status error status
+* @returns size of the maxexpansion and maxsize used.
+*/
+static int uprv_uca_setMaxJamoExpansion(UChar ch,
+ uint32_t endexpansion,
+ uint8_t expansionsize,
+ MaxJamoExpansionTable *maxexpansion,
+ UErrorCode *status)
+{
+ UBool isV = TRUE;
+ if (((uint32_t)ch - 0x1100) <= (0x1112 - 0x1100)) {
+ /* determines L for Jamo, doesn't need to store this since it is never
+ at the end of a expansion */
+ if (maxexpansion->maxLSize < expansionsize) {
+ maxexpansion->maxLSize = expansionsize;
+ }
+ return maxexpansion->position;
+ }
+
+ if (((uint32_t)ch - 0x1161) <= (0x1175 - 0x1161)) {
+ /* determines V for Jamo */
+ if (maxexpansion->maxVSize < expansionsize) {
+ maxexpansion->maxVSize = expansionsize;
+ }
+ }
+
+ if (((uint32_t)ch - 0x11A8) <= (0x11C2 - 0x11A8)) {
+ isV = FALSE;
+ /* determines T for Jamo */
+ if (maxexpansion->maxTSize < expansionsize) {
+ maxexpansion->maxTSize = expansionsize;
+ }
+ }
+
+ if (maxexpansion->size == 0) {
+ /* we'll always make the first element 0, for easier manipulation */
+ maxexpansion->endExpansionCE =
+ (uint32_t *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(uint32_t));
+ /* test for NULL */;
+ if (maxexpansion->endExpansionCE == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ *(maxexpansion->endExpansionCE) = 0;
+ maxexpansion->isV =
+ (UBool *)uprv_malloc(INIT_EXP_TABLE_SIZE * sizeof(UBool));
+ /* test for NULL */;
+ if (maxexpansion->isV == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(maxexpansion->endExpansionCE);
+ maxexpansion->endExpansionCE = NULL;
+ return 0;
+ }
+ *(maxexpansion->isV) = 0;
+ maxexpansion->size = INIT_EXP_TABLE_SIZE;
+ maxexpansion->position = 0;
+ }
+
+ if (maxexpansion->position + 1 == maxexpansion->size) {
+ maxexpansion->size *= 2;
+ maxexpansion->endExpansionCE = (uint32_t *)uprv_realloc(maxexpansion->endExpansionCE,
+ maxexpansion->size * sizeof(uint32_t));
+ if (maxexpansion->endExpansionCE == NULL) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "out of memory for maxExpansions\n");
+#endif
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ maxexpansion->isV = (UBool *)uprv_realloc(maxexpansion->isV,
+ maxexpansion->size * sizeof(UBool));
+ if (maxexpansion->isV == NULL) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "out of memory for maxExpansions\n");
+#endif
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(maxexpansion->endExpansionCE);
+ maxexpansion->endExpansionCE = NULL;
+ return 0;
+ }
+ }
+
+ uint32_t *pendexpansionce = maxexpansion->endExpansionCE;
+ int pos = maxexpansion->position;
+
+ while (pos > 0) {
+ pos --;
+ if (*(pendexpansionce + pos) == endexpansion) {
+ return maxexpansion->position;
+ }
+ }
+
+ *(pendexpansionce + maxexpansion->position) = endexpansion;
+ *(maxexpansion->isV + maxexpansion->position) = isV;
+ maxexpansion->position ++;
+
+ return maxexpansion->position;
+}
+
+
+static void ContrEndCPSet(uint8_t *table, UChar c) {
+ uint32_t hash;
+ uint8_t *htByte;
+
+ hash = c;
+ if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) {
+ hash = (hash & UCOL_UNSAFECP_TABLE_MASK) + 256;
+ }
+ htByte = &table[hash>>3];
+ *htByte |= (1 << (hash & 7));
+}
+
+
+static void unsafeCPSet(uint8_t *table, UChar c) {
+ uint32_t hash;
+ uint8_t *htByte;
+
+ hash = c;
+ if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) {
+ if (hash >= 0xd800 && hash <= 0xf8ff) {
+ /* Part of a surrogate, or in private use area. */
+ /* These don't go in the table */
+ return;
+ }
+ hash = (hash & UCOL_UNSAFECP_TABLE_MASK) + 256;
+ }
+ htByte = &table[hash>>3];
+ *htByte |= (1 << (hash & 7));
+}
+
+static void
+uprv_uca_createCMTable(tempUCATable *t, int32_t noOfCM, UErrorCode *status) {
+ t->cmLookup = (CombinClassTable *)uprv_malloc(sizeof(CombinClassTable));
+ if (t->cmLookup==NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ t->cmLookup->cPoints=(UChar *)uprv_malloc(noOfCM*sizeof(UChar));
+ if (t->cmLookup->cPoints ==NULL) {
+ uprv_free(t->cmLookup);
+ t->cmLookup = NULL;
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ t->cmLookup->size=noOfCM;
+ uprv_memset(t->cmLookup->index, 0, sizeof(t->cmLookup->index));
+
+ return;
+}
+
+static void
+uprv_uca_copyCMTable(tempUCATable *t, UChar *cm, uint16_t *index) {
+ int32_t count=0;
+
+ for (int32_t i=0; i<256; ++i) {
+ if (index[i]>0) {
+ // cPoints is ordered by combining class value.
+ uprv_memcpy(t->cmLookup->cPoints+count, cm+(i<<8), index[i]*sizeof(UChar));
+ count += index[i];
+ }
+ t->cmLookup->index[i]=count;
+ }
+ return;
+}
+
+/* 1. to the UnsafeCP hash table, add all chars with combining class != 0 */
+/* 2. build combining marks table for all chars with combining class != 0 */
+static void uprv_uca_unsafeCPAddCCNZ(tempUCATable *t, UErrorCode *status) {
+
+ UChar c;
+ uint16_t fcd; // Hi byte is lead combining class.
+ // lo byte is trailing combing class.
+ const uint16_t *fcdTrieData;
+ UBool buildCMTable = (t->cmLookup==NULL); // flag for building combining class table
+ UChar *cm=NULL;
+ uint16_t index[256];
+ int32_t count=0;
+ fcdTrieData = unorm_getFCDTrie(status);
+ if (U_FAILURE(*status)) {
+ return;
+ }
+
+ if (buildCMTable) {
+ if (cm==NULL) {
+ cm = (UChar *)uprv_malloc(sizeof(UChar)*UCOL_MAX_CM_TAB);
+ if (cm==NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ }
+ uprv_memset(index, 0, sizeof(index));
+ }
+ for (c=0; c<0xffff; c++) {
+ fcd = unorm_getFCD16(fcdTrieData, c);
+ if (fcd >= 0x100 || // if the leading combining class(c) > 0 ||
+ (UTF_IS_LEAD(c) && fcd != 0)) {// c is a leading surrogate with some FCD data
+ if (buildCMTable) {
+ uint32_t cClass = fcd & 0xff;
+ uint32_t temp=(cClass<<8)+index[cClass];
+ cm[(cClass<<8)+index[cClass]] = c; //
+ index[cClass]++;
+ count++;
+ }
+ unsafeCPSet(t->unsafeCP, c);
+ }
+ }
+
+ // copy to cm table
+ if (buildCMTable) {
+ uprv_uca_createCMTable(t, count, status);
+ if(U_FAILURE(*status)) {
+ if (cm!=NULL) {
+ uprv_free(cm);
+ }
+ return;
+ }
+ uprv_uca_copyCMTable(t, cm, index);
+ }
+
+ if(t->prefixLookup != NULL) {
+ int32_t i = -1;
+ const UHashElement *e = NULL;
+ UCAElements *element = NULL;
+ UChar NFCbuf[256];
+ uint32_t NFCbufLen = 0;
+ while((e = uhash_nextElement(t->prefixLookup, &i)) != NULL) {
+ element = (UCAElements *)e->value.pointer;
+ // codepoints here are in the NFD form. We need to add the
+ // first code point of the NFC form to unsafe, because
+ // strcoll needs to backup over them.
+ NFCbufLen = unorm_normalize(element->cPoints, element->cSize, UNORM_NFC, 0,
+ NFCbuf, 256, status);
+ unsafeCPSet(t->unsafeCP, NFCbuf[0]);
+ }
+ }
+
+ if (cm!=NULL) {
+ uprv_free(cm);
+ }
+}
+
+static uint32_t uprv_uca_addPrefix(tempUCATable *t, uint32_t CE,
+ UCAElements *element, UErrorCode *status)
+{
+ // currently the longest prefix we're supporting in Japanese is two characters
+ // long. Although this table could quite easily mimic complete contraction stuff
+ // there is no good reason to make a general solution, as it would require some
+ // error prone messing.
+ CntTable *contractions = t->contractions;
+ UChar32 cp;
+ uint32_t cpsize = 0;
+ UChar *oldCP = element->cPoints;
+ uint32_t oldCPSize = element->cSize;
+
+
+ contractions->currentTag = SPEC_PROC_TAG;
+
+ // here, we will normalize & add prefix to the table.
+ uint32_t j = 0;
+#ifdef UCOL_DEBUG
+ for(j=0; j<element->cSize; j++) {
+ fprintf(stdout, "CP: %04X ", element->cPoints[j]);
+ }
+ fprintf(stdout, "El: %08X Pref: ", CE);
+ for(j=0; j<element->prefixSize; j++) {
+ fprintf(stdout, "%04X ", element->prefix[j]);
+ }
+ fprintf(stdout, "%08X ", element->mapCE);
+#endif
+
+ for (j = 1; j<element->prefixSize; j++) { /* First add NFD prefix chars to unsafe CP hash table */
+ // Unless it is a trail surrogate, which is handled algoritmically and
+ // shouldn't take up space in the table.
+ if(!(UTF_IS_TRAIL(element->prefix[j]))) {
+ unsafeCPSet(t->unsafeCP, element->prefix[j]);
+ }
+ }
+
+ UChar tempPrefix = 0;
+
+ for(j = 0; j < /*nfcSize*/element->prefixSize/2; j++) { // prefixes are going to be looked up backwards
+ // therefore, we will promptly reverse the prefix buffer...
+ tempPrefix = *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1);
+ *(/*nfcBuffer*/element->prefix+element->prefixSize-j-1) = element->prefix[j];
+ element->prefix[j] = tempPrefix;
+ }
+
+#ifdef UCOL_DEBUG
+ fprintf(stdout, "Reversed: ");
+ for(j=0; j<element->prefixSize; j++) {
+ fprintf(stdout, "%04X ", element->prefix[j]);
+ }
+ fprintf(stdout, "%08X\n", element->mapCE);
+#endif
+
+ // the first codepoint is also unsafe, as it forms a 'contraction' with the prefix
+ if(!(UTF_IS_TRAIL(element->cPoints[0]))) {
+ unsafeCPSet(t->unsafeCP, element->cPoints[0]);
+ }
+
+ // Maybe we need this... To handle prefixes completely in the forward direction...
+ //if(element->cSize == 1) {
+ // if(!(UTF_IS_TRAIL(element->cPoints[0]))) {
+ // ContrEndCPSet(t->contrEndCP, element->cPoints[0]);
+ // }
+ //}
+
+ element->cPoints = element->prefix;
+ element->cSize = element->prefixSize;
+
+ // Add the last char of the contraction to the contraction-end hash table.
+ // unless it is a trail surrogate, which is handled algorithmically and
+ // shouldn't be in the table
+ if(!(UTF_IS_TRAIL(element->cPoints[element->cSize -1]))) {
+ ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]);
+ }
+
+ // First we need to check if contractions starts with a surrogate
+ UTF_NEXT_CHAR(element->cPoints, cpsize, element->cSize, cp);
+
+ // If there are any Jamos in the contraction, we should turn on special
+ // processing for Jamos
+ if(UCOL_ISJAMO(element->prefix[0])) {
+ t->image->jamoSpecial = TRUE;
+ }
+ /* then we need to deal with it */
+ /* we could aready have something in table - or we might not */
+
+ if(!isPrefix(CE)) {
+ /* if it wasn't contraction, we wouldn't end up here*/
+ int32_t firstContractionOffset = 0;
+ firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status);
+ uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+ uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->prefix, newCE, status);
+ uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status);
+ CE = constructContractCE(SPEC_PROC_TAG, firstContractionOffset);
+ } else { /* we are adding to existing contraction */
+ /* there were already some elements in the table, so we need to add a new contraction */
+ /* Two things can happen here: either the codepoint is already in the table, or it is not */
+ int32_t position = uprv_cnttab_findCP(contractions, CE, *element->prefix, status);
+ if(position > 0) { /* if it is we just continue down the chain */
+ uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status);
+ uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status);
+ uprv_cnttab_setContraction(contractions, CE, position, *(element->prefix), newCE, status);
+ } else { /* if it isn't, we will have to create a new sequence */
+ uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+ uprv_cnttab_insertContraction(contractions, CE, *(element->prefix), element->mapCE, status);
+ }
+ }
+
+ element->cPoints = oldCP;
+ element->cSize = oldCPSize;
+
+ return CE;
+}
+
+// Note regarding surrogate handling: We are interested only in the single
+// or leading surrogates in a contraction. If a surrogate is somewhere else
+// in the contraction, it is going to be handled as a pair of code units,
+// as it doesn't affect the performance AND handling surrogates specially
+// would complicate code way too much.
+static uint32_t uprv_uca_addContraction(tempUCATable *t, uint32_t CE,
+ UCAElements *element, UErrorCode *status)
+{
+ CntTable *contractions = t->contractions;
+ UChar32 cp;
+ uint32_t cpsize = 0;
+
+ contractions->currentTag = CONTRACTION_TAG;
+
+ // First we need to check if contractions starts with a surrogate
+ UTF_NEXT_CHAR(element->cPoints, cpsize, element->cSize, cp);
+
+ if(cpsize<element->cSize) { // This is a real contraction, if there are other characters after the first
+ uint32_t j = 0;
+ for (j=1; j<element->cSize; j++) { /* First add contraction chars to unsafe CP hash table */
+ // Unless it is a trail surrogate, which is handled algoritmically and
+ // shouldn't take up space in the table.
+ if(!(UTF_IS_TRAIL(element->cPoints[j]))) {
+ unsafeCPSet(t->unsafeCP, element->cPoints[j]);
+ }
+ }
+ // Add the last char of the contraction to the contraction-end hash table.
+ // unless it is a trail surrogate, which is handled algorithmically and
+ // shouldn't be in the table
+ if(!(UTF_IS_TRAIL(element->cPoints[element->cSize -1]))) {
+ ContrEndCPSet(t->contrEndCP, element->cPoints[element->cSize -1]);
+ }
+
+ // If there are any Jamos in the contraction, we should turn on special
+ // processing for Jamos
+ if(UCOL_ISJAMO(element->cPoints[0])) {
+ t->image->jamoSpecial = TRUE;
+ }
+ /* then we need to deal with it */
+ /* we could aready have something in table - or we might not */
+ element->cPoints+=cpsize;
+ element->cSize-=cpsize;
+ if(!isContraction(CE)) {
+ /* if it wasn't contraction, we wouldn't end up here*/
+ int32_t firstContractionOffset = 0;
+ firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, CE, status);
+ uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+ uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status);
+ uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, CE, status);
+ CE = constructContractCE(CONTRACTION_TAG, firstContractionOffset);
+ } else { /* we are adding to existing contraction */
+ /* there were already some elements in the table, so we need to add a new contraction */
+ /* Two things can happen here: either the codepoint is already in the table, or it is not */
+ int32_t position = uprv_cnttab_findCP(contractions, CE, *element->cPoints, status);
+ if(position > 0) { /* if it is we just continue down the chain */
+ uint32_t eCE = uprv_cnttab_getCE(contractions, CE, position, status);
+ uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status);
+ uprv_cnttab_setContraction(contractions, CE, position, *(element->cPoints), newCE, status);
+ } else { /* if it isn't, we will have to create a new sequence */
+ uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+ uprv_cnttab_insertContraction(contractions, CE, *(element->cPoints), newCE, status);
+ }
+ }
+ element->cPoints-=cpsize;
+ element->cSize+=cpsize;
+ /*ucmpe32_set(t->mapping, cp, CE);*/
+ utrie_set32(t->mapping, cp, CE);
+ } else if(!isContraction(CE)) { /* this is just a surrogate, and there is no contraction */
+ /*ucmpe32_set(t->mapping, cp, element->mapCE);*/
+ utrie_set32(t->mapping, cp, element->mapCE);
+ } else { /* fill out the first stage of the contraction with the surrogate CE */
+ uprv_cnttab_changeContraction(contractions, CE, 0, element->mapCE, status);
+ uprv_cnttab_changeContraction(contractions, CE, 0xFFFF, element->mapCE, status);
+ }
+ return CE;
+}
+
+
+static uint32_t uprv_uca_processContraction(CntTable *contractions, UCAElements *element, uint32_t existingCE, UErrorCode *status) {
+ int32_t firstContractionOffset = 0;
+ // uint32_t contractionElement = UCOL_NOT_FOUND;
+
+ if(U_FAILURE(*status)) {
+ return UCOL_NOT_FOUND;
+ }
+
+ /* end of recursion */
+ if(element->cSize == 1) {
+ if(isCntTableElement(existingCE) && ((UColCETags)getCETag(existingCE) == contractions->currentTag)) {
+ uprv_cnttab_changeContraction(contractions, existingCE, 0, element->mapCE, status);
+ uprv_cnttab_changeContraction(contractions, existingCE, 0xFFFF, element->mapCE, status);
+ return existingCE;
+ } else {
+ return element->mapCE; /*can't do just that. existingCe might be a contraction, meaning that we need to do another step */
+ }
+ }
+
+ /* this recursion currently feeds on the only element we have... We will have to copy it in order to accomodate */
+ /* for both backward and forward cycles */
+
+ /* we encountered either an empty space or a non-contraction element */
+ /* this means we are constructing a new contraction sequence */
+ element->cPoints++;
+ element->cSize--;
+ if(!isCntTableElement(existingCE)) {
+ /* if it wasn't contraction, we wouldn't end up here*/
+ firstContractionOffset = uprv_cnttab_addContraction(contractions, UPRV_CNTTAB_NEWELEMENT, 0, existingCE, status);
+ uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+ uprv_cnttab_addContraction(contractions, firstContractionOffset, *element->cPoints, newCE, status);
+ uprv_cnttab_addContraction(contractions, firstContractionOffset, 0xFFFF, existingCE, status);
+ existingCE = constructContractCE(contractions->currentTag, firstContractionOffset);
+ } else { /* we are adding to existing contraction */
+ /* there were already some elements in the table, so we need to add a new contraction */
+ /* Two things can happen here: either the codepoint is already in the table, or it is not */
+ int32_t position = uprv_cnttab_findCP(contractions, existingCE, *element->cPoints, status);
+ if(position > 0) { /* if it is we just continue down the chain */
+ uint32_t eCE = uprv_cnttab_getCE(contractions, existingCE, position, status);
+ uint32_t newCE = uprv_uca_processContraction(contractions, element, eCE, status);
+ uprv_cnttab_setContraction(contractions, existingCE, position, *(element->cPoints), newCE, status);
+ } else { /* if it isn't, we will have to create a new sequence */
+ uint32_t newCE = uprv_uca_processContraction(contractions, element, UCOL_NOT_FOUND, status);
+ uprv_cnttab_insertContraction(contractions, existingCE, *(element->cPoints), newCE, status);
+ }
+ }
+ element->cPoints--;
+ element->cSize++;
+ return existingCE;
+}
+
+static uint32_t uprv_uca_finalizeAddition(tempUCATable *t, UCAElements *element, UErrorCode *status) {
+ uint32_t CE = UCOL_NOT_FOUND;
+ // This should add a completely ignorable element to the
+ // unsafe table, so that backward iteration will skip
+ // over it when treating contractions.
+ uint32_t i = 0;
+ if(element->mapCE == 0) {
+ for(i = 0; i < element->cSize; i++) {
+ if(!UTF_IS_TRAIL(element->cPoints[i])) {
+ unsafeCPSet(t->unsafeCP, element->cPoints[i]);
+ }
+ }
+ }
+ if(element->cSize > 1) { /* we're adding a contraction */
+ uint32_t i = 0;
+ UChar32 cp;
+
+ UTF_NEXT_CHAR(element->cPoints, i, element->cSize, cp);
+ /*CE = ucmpe32_get(t->mapping, cp);*/
+ CE = utrie_get32(t->mapping, cp, NULL);
+
+ CE = uprv_uca_addContraction(t, CE, element, status);
+ } else { /* easy case, */
+ /*CE = ucmpe32_get(t->mapping, element->cPoints[0]);*/
+ CE = utrie_get32(t->mapping, element->cPoints[0], NULL);
+
+ if( CE != UCOL_NOT_FOUND) {
+ if(isCntTableElement(CE) /*isContraction(CE)*/) { /* adding a non contraction element (thai, expansion, single) to already existing contraction */
+ if(!isPrefix(element->mapCE)) { // we cannot reenter prefix elements - as we are going to create a dead loop
+ // Only expansions and regular CEs can go here... Contractions will never happen in this place
+ uprv_cnttab_setContraction(t->contractions, CE, 0, 0, element->mapCE, status);
+ /* This loop has to change the CE at the end of contraction REDO!*/
+ uprv_cnttab_changeLastCE(t->contractions, CE, element->mapCE, status);
+ }
+ } else {
+ /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/
+ utrie_set32(t->mapping, element->cPoints[0], element->mapCE);
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "Warning - trying to overwrite existing data %08X for cp %04X with %08X\n", CE, element->cPoints[0], element->CEs[0]);
+ //*status = U_ILLEGAL_ARGUMENT_ERROR;
+#endif
+ }
+ } else {
+ /*ucmpe32_set(t->mapping, element->cPoints[0], element->mapCE);*/
+ utrie_set32(t->mapping, element->cPoints[0], element->mapCE);
+ }
+ }
+ return CE;
+}
+
+/* This adds a read element, while testing for existence */
+U_CAPI uint32_t U_EXPORT2
+uprv_uca_addAnElement(tempUCATable *t, UCAElements *element, UErrorCode *status) {
+ U_NAMESPACE_USE
+
+ ExpansionTable *expansions = t->expansions;
+
+ uint32_t i = 1;
+ uint32_t expansion = 0;
+ uint32_t CE;
+
+ if(U_FAILURE(*status)) {
+ return 0xFFFF;
+ }
+
+ element->mapCE = 0; // clear mapCE so that we can catch expansions
+
+ if(element->noOfCEs == 1) {
+ element->mapCE = element->CEs[0];
+ } else {
+ /* ICU 2.1 long primaries */
+ /* unfortunately, it looks like we have to look for a long primary here */
+ /* since in canonical closure we are going to hit some long primaries from */
+ /* the first phase, and they will come back as continuations/expansions */
+ /* destroying the effect of the previous opitimization */
+ /* A long primary is a three byte primary with starting secondaries and tertiaries */
+ /* It can appear in long runs of only primary differences (like east Asian tailorings) */
+ /* also, it should not be an expansion, as expansions would break with this */
+ // This part came in from ucol_bld.cpp
+ //if(tok->expansion == 0
+ //&& noOfBytes[0] == 3 && noOfBytes[1] == 1 && noOfBytes[2] == 1
+ //&& CEparts[1] == (UCOL_BYTE_COMMON << 24) && CEparts[2] == (UCOL_BYTE_COMMON << 24)) {
+ /* we will construct a special CE that will go unchanged to the table */
+ if(element->noOfCEs == 2 // a two CE expansion
+ && isContinuation(element->CEs[1]) // which is a continuation
+ && (element->CEs[1] & (~(0xFF << 24 | UCOL_CONTINUATION_MARKER))) == 0 // that has only primaries in continuation,
+ && (((element->CEs[0]>>8) & 0xFF) == UCOL_BYTE_COMMON) // a common secondary
+ && ((element->CEs[0] & 0xFF) == UCOL_BYTE_COMMON) // and a common tertiary
+ ) {
+#ifdef UCOL_DEBUG
+ fprintf(stdout, "Long primary %04X\n", element->cPoints[0]);
+#endif
+ element->mapCE = UCOL_SPECIAL_FLAG | (LONG_PRIMARY_TAG<<24) // a long primary special
+ | ((element->CEs[0]>>8) & 0xFFFF00) // first and second byte of primary
+ | ((element->CEs[1]>>24) & 0xFF); // third byte of primary
+ } else {
+ expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (EXPANSION_TAG<<UCOL_TAG_SHIFT)
+ | ((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4)
+ & 0xFFFFF0);
+
+ for(i = 1; i<element->noOfCEs; i++) {
+ uprv_uca_addExpansion(expansions, element->CEs[i], status);
+ }
+ if(element->noOfCEs <= 0xF) {
+ expansion |= element->noOfCEs;
+ } else {
+ uprv_uca_addExpansion(expansions, 0, status);
+ }
+ element->mapCE = expansion;
+ uprv_uca_setMaxExpansion(element->CEs[element->noOfCEs - 1],
+ (uint8_t)element->noOfCEs,
+ t->maxExpansions,
+ status);
+ if(UCOL_ISJAMO(element->cPoints[0])) {
+ t->image->jamoSpecial = TRUE;
+ uprv_uca_setMaxJamoExpansion(element->cPoints[0],
+ element->CEs[element->noOfCEs - 1],
+ (uint8_t)element->noOfCEs,
+ t->maxJamoExpansions,
+ status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ }
+ }
+ }
+
+ // We treat digits differently - they are "uber special" and should be
+ // processed differently if numeric collation is on.
+ UChar32 uniChar = 0;
+ //printElement(element);
+ if ((element->cSize == 2) && U16_IS_LEAD(element->cPoints[0])){
+ uniChar = U16_GET_SUPPLEMENTARY(element->cPoints[0], element->cPoints[1]);
+ } else if (element->cSize == 1){
+ uniChar = element->cPoints[0];
+ }
+
+ // Here, we either have one normal CE OR mapCE is set. Therefore, we stuff only
+ // one element to the expansion buffer. When we encounter a digit and we don't
+ // do numeric collation, we will just pick the CE we have and break out of case
+ // (see ucol.cpp ucol_prv_getSpecialCE && ucol_prv_getSpecialPrevCE). If we picked
+ // a special, further processing will occur. If it's a simple CE, we'll return due
+ // to how the loop is constructed.
+ if (uniChar != 0 && u_isdigit(uniChar)){
+ expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (DIGIT_TAG<<UCOL_TAG_SHIFT) | 1); // prepare the element
+ if(element->mapCE) { // if there is an expansion, we'll pick it here
+ expansion |= ((uprv_uca_addExpansion(expansions, element->mapCE, status)+(headersize>>2))<<4);
+ } else {
+ expansion |= ((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4);
+ }
+ element->mapCE = expansion;
+
+ // Need to go back to the beginning of the digit string if in the middle!
+ if(uniChar <= 0xFFFF) { // supplementaries are always unsafe. API takes UChars
+ unsafeCPSet(t->unsafeCP, (UChar)uniChar);
+ }
+ }
+
+ // here we want to add the prefix structure.
+ // I will try to process it as a reverse contraction, if possible.
+ // prefix buffer is already reversed.
+
+ if(element->prefixSize!=0) {
+ // We keep the seen prefix starter elements in a hashtable
+ // we need it to be able to distinguish between the simple
+ // codepoints and prefix starters. Also, we need to use it
+ // for canonical closure.
+
+ UCAElements *composed = (UCAElements *)uprv_malloc(sizeof(UCAElements));
+ /* test for NULL */
+ if (composed == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ uprv_memcpy(composed, element, sizeof(UCAElements));
+ composed->cPoints = composed->uchars;
+ composed->prefix = composed->prefixChars;
+
+ composed->prefixSize = unorm_normalize(element->prefix, element->prefixSize, UNORM_NFC, 0, composed->prefix, 128, status);
+
+
+ if(t->prefixLookup != NULL) {
+ UCAElements *uCE = (UCAElements *)uhash_get(t->prefixLookup, element);
+ if(uCE != NULL) { // there is already a set of code points here
+ element->mapCE = uprv_uca_addPrefix(t, uCE->mapCE, element, status);
+ } else { // no code points, so this spot is clean
+ element->mapCE = uprv_uca_addPrefix(t, UCOL_NOT_FOUND, element, status);
+ uCE = (UCAElements *)uprv_malloc(sizeof(UCAElements));
+ /* test for NULL */
+ if (uCE == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ uprv_memcpy(uCE, element, sizeof(UCAElements));
+ uCE->cPoints = uCE->uchars;
+ uhash_put(t->prefixLookup, uCE, uCE, status);
+ }
+ if(composed->prefixSize != element->prefixSize || uprv_memcmp(composed->prefix, element->prefix, element->prefixSize)) {
+ // do it!
+ composed->mapCE = uprv_uca_addPrefix(t, element->mapCE, composed, status);
+ }
+ }
+ uprv_free(composed);
+ }
+
+ // We need to use the canonical iterator here
+ // the way we do it is to generate the canonically equivalent strings
+ // for the contraction and then add the sequences that pass FCD check
+ if(element->cSize > 1 && !(element->cSize==2 && UTF16_IS_LEAD(element->cPoints[0]) && UTF16_IS_TRAIL(element->cPoints[1]))) { // this is a contraction, we should check whether a composed form should also be included
+ UnicodeString source(element->cPoints, element->cSize);
+ CanonicalIterator it(source, *status);
+ source = it.next();
+ while(!source.isBogus()) {
+ if(Normalizer::quickCheck(source, UNORM_FCD, *status) != UNORM_NO) {
+ element->cSize = source.extract(element->cPoints, 128, *status);
+ uprv_uca_finalizeAddition(t, element, status);
+ }
+ source = it.next();
+ }
+ CE = element->mapCE;
+ } else {
+ CE = uprv_uca_finalizeAddition(t, element, status);
+ }
+
+ return CE;
+}
+
+
+/*void uprv_uca_getMaxExpansionJamo(CompactEIntArray *mapping, */
+static void uprv_uca_getMaxExpansionJamo(UNewTrie *mapping,
+ MaxExpansionTable *maxexpansion,
+ MaxJamoExpansionTable *maxjamoexpansion,
+ UBool jamospecial,
+ UErrorCode *status)
+{
+ const uint32_t VBASE = 0x1161;
+ const uint32_t TBASE = 0x11A8;
+ const uint32_t VCOUNT = 21;
+ const uint32_t TCOUNT = 28;
+
+ uint32_t v = VBASE + VCOUNT - 1;
+ uint32_t t = TBASE + TCOUNT - 1;
+ uint32_t ce;
+
+ while (v >= VBASE) {
+ /*ce = ucmpe32_get(mapping, v);*/
+ ce = utrie_get32(mapping, v, NULL);
+ if (ce < UCOL_SPECIAL_FLAG) {
+ uprv_uca_setMaxExpansion(ce, 2, maxexpansion, status);
+ }
+ v --;
+ }
+
+ while (t >= TBASE)
+ {
+ /*ce = ucmpe32_get(mapping, t);*/
+ ce = utrie_get32(mapping, t, NULL);
+ if (ce < UCOL_SPECIAL_FLAG) {
+ uprv_uca_setMaxExpansion(ce, 3, maxexpansion, status);
+ }
+ t --;
+ }
+ /* According to the docs, 99% of the time, the Jamo will not be special */
+ if (jamospecial) {
+ /* gets the max expansion in all unicode characters */
+ int count = maxjamoexpansion->position;
+ uint8_t maxTSize = (uint8_t)(maxjamoexpansion->maxLSize +
+ maxjamoexpansion->maxVSize +
+ maxjamoexpansion->maxTSize);
+ uint8_t maxVSize = (uint8_t)(maxjamoexpansion->maxLSize +
+ maxjamoexpansion->maxVSize);
+
+ while (count > 0) {
+ count --;
+ if (*(maxjamoexpansion->isV + count) == TRUE) {
+ uprv_uca_setMaxExpansion(
+ *(maxjamoexpansion->endExpansionCE + count),
+ maxVSize, maxexpansion, status);
+ }
+ else {
+ uprv_uca_setMaxExpansion(
+ *(maxjamoexpansion->endExpansionCE + count),
+ maxTSize, maxexpansion, status);
+ }
+ }
+ }
+}
+
+U_CDECL_BEGIN
+static inline uint32_t U_CALLCONV
+getFoldedValue(UNewTrie *trie, UChar32 start, int32_t offset)
+{
+ uint32_t value;
+ uint32_t tag;
+ UChar32 limit;
+ UBool inBlockZero;
+
+ limit=start+0x400;
+ while(start<limit) {
+ value=utrie_get32(trie, start, &inBlockZero);
+ tag = getCETag(value);
+ if(inBlockZero == TRUE) {
+ start+=UTRIE_DATA_BLOCK_LENGTH;
+ } else if(!(isSpecial(value) && (tag == IMPLICIT_TAG || tag == NOT_FOUND_TAG))) {
+ /* These are values that are starting in either UCA (IMPLICIT_TAG) or in the
+ * tailorings (NOT_FOUND_TAG). Presence of these tags means that there is
+ * nothing in this position and that it should be skipped.
+ */
+#ifdef UCOL_DEBUG
+ static int32_t count = 1;
+ fprintf(stdout, "%i, Folded %08X, value %08X\n", count++, start, value);
+#endif
+ return (uint32_t)(UCOL_SPECIAL_FLAG | (SURROGATE_TAG<<24) | offset);
+ } else {
+ ++start;
+ }
+ }
+ return 0;
+}
+U_CDECL_END
+
+#ifdef UCOL_DEBUG
+// This is a debug function to print the contents of a trie.
+// It is used in conjuction with the code around utrie_unserialize call
+void enumRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
+ if(start<0x10000) {
+ fprintf(stdout, "%08X, %08X, %08X\n", start, limit, value);
+ } else {
+ fprintf(stdout, "%08X=%04X %04X, %08X=%04X %04X, %08X\n", start, UTF16_LEAD(start), UTF16_TRAIL(start), limit, UTF16_LEAD(limit), UTF16_TRAIL(limit), value);
+ }
+}
+
+int32_t
+myGetFoldingOffset(uint32_t data) {
+ if(data > UCOL_NOT_FOUND && getCETag(data) == SURROGATE_TAG) {
+ return (data&0xFFFFFF);
+ } else {
+ return 0;
+ }
+}
+#endif
+
+U_CAPI UCATableHeader* U_EXPORT2
+uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status) {
+ /*CompactEIntArray *mapping = t->mapping;*/
+ UNewTrie *mapping = t->mapping;
+ ExpansionTable *expansions = t->expansions;
+ CntTable *contractions = t->contractions;
+ MaxExpansionTable *maxexpansion = t->maxExpansions;
+
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ uint32_t beforeContractions = (uint32_t)((headersize+paddedsize(expansions->position*sizeof(uint32_t)))/sizeof(UChar));
+
+ int32_t contractionsSize = 0;
+ contractionsSize = uprv_cnttab_constructTable(contractions, beforeContractions, status);
+
+ /* the following operation depends on the trie data. Therefore, we have to do it before */
+ /* the trie is compacted */
+ /* sets jamo expansions */
+ uprv_uca_getMaxExpansionJamo(mapping, maxexpansion, t->maxJamoExpansions,
+ t->image->jamoSpecial, status);
+
+ /*ucmpe32_compact(mapping);*/
+ /*UMemoryStream *ms = uprv_mstrm_openNew(8192);*/
+ /*int32_t mappingSize = ucmpe32_flattenMem(mapping, ms);*/
+ /*const uint8_t *flattened = uprv_mstrm_getBuffer(ms, &mappingSize);*/
+
+ // After setting the jamo expansions, compact the trie and get the needed size
+ int32_t mappingSize = utrie_serialize(mapping, NULL, 0, getFoldedValue /*getFoldedValue*/, FALSE, status);
+
+ uint32_t tableOffset = 0;
+ uint8_t *dataStart;
+
+ /* TODO: LATIN1 array is now in the utrie - it should be removed from the calculation */
+
+ uint32_t toAllocate =(uint32_t)(headersize+
+ paddedsize(expansions->position*sizeof(uint32_t))+
+ paddedsize(mappingSize)+
+ paddedsize(contractionsSize*(sizeof(UChar)+sizeof(uint32_t)))+
+ //paddedsize(0x100*sizeof(uint32_t)) /* Latin1 is now included in the trie */
+ /* maxexpansion array */
+ + paddedsize(maxexpansion->position * sizeof(uint32_t)) +
+ /* maxexpansion size array */
+ paddedsize(maxexpansion->position * sizeof(uint8_t)) +
+ paddedsize(UCOL_UNSAFECP_TABLE_SIZE) + /* Unsafe chars */
+ paddedsize(UCOL_UNSAFECP_TABLE_SIZE)); /* Contraction Ending chars */
+
+
+ dataStart = (uint8_t *)uprv_malloc(toAllocate);
+ /* test for NULL */
+ if (dataStart == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ UCATableHeader *myData = (UCATableHeader *)dataStart;
+ // Please, do reset all the fields!
+ uprv_memset(dataStart, 0, toAllocate);
+ // Make sure we know this is reset
+ myData->magic = UCOL_HEADER_MAGIC;
+ myData->isBigEndian = U_IS_BIG_ENDIAN;
+ myData->charSetFamily = U_CHARSET_FAMILY;
+ myData->formatVersion[0] = UCA_FORMAT_VERSION_0;
+ myData->formatVersion[1] = UCA_FORMAT_VERSION_1;
+ myData->formatVersion[2] = UCA_FORMAT_VERSION_2;
+ myData->formatVersion[3] = UCA_FORMAT_VERSION_3;
+ myData->jamoSpecial = t->image->jamoSpecial;
+
+ // Don't copy stuff from UCA header!
+ //uprv_memcpy(myData, t->image, sizeof(UCATableHeader));
+
+ myData->contractionSize = contractionsSize;
+
+ tableOffset += (uint32_t)(paddedsize(sizeof(UCATableHeader)));
+
+ myData->options = tableOffset;
+ uprv_memcpy(dataStart+tableOffset, t->options, sizeof(UColOptionSet));
+ tableOffset += (uint32_t)(paddedsize(sizeof(UColOptionSet)));
+
+ /* copy expansions */
+ /*myData->expansion = (uint32_t *)dataStart+tableOffset;*/
+ myData->expansion = tableOffset;
+ uprv_memcpy(dataStart+tableOffset, expansions->CEs, expansions->position*sizeof(uint32_t));
+ tableOffset += (uint32_t)(paddedsize(expansions->position*sizeof(uint32_t)));
+
+ /* contractions block */
+ if(contractionsSize != 0) {
+ /* copy contraction index */
+ /*myData->contractionIndex = (UChar *)(dataStart+tableOffset);*/
+ myData->contractionIndex = tableOffset;
+ uprv_memcpy(dataStart+tableOffset, contractions->codePoints, contractionsSize*sizeof(UChar));
+ tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(UChar)));
+
+ /* copy contraction collation elements */
+ /*myData->contractionCEs = (uint32_t *)(dataStart+tableOffset);*/
+ myData->contractionCEs = tableOffset;
+ uprv_memcpy(dataStart+tableOffset, contractions->CEs, contractionsSize*sizeof(uint32_t));
+ tableOffset += (uint32_t)(paddedsize(contractionsSize*sizeof(uint32_t)));
+ } else {
+ myData->contractionIndex = 0;
+ myData->contractionCEs = 0;
+ }
+
+ /* copy mapping table */
+ /*myData->mappingPosition = dataStart+tableOffset;*/
+ /*myData->mappingPosition = tableOffset;*/
+ /*uprv_memcpy(dataStart+tableOffset, flattened, mappingSize);*/
+
+ myData->mappingPosition = tableOffset;
+ utrie_serialize(mapping, dataStart+tableOffset, toAllocate-tableOffset, getFoldedValue, FALSE, status);
+#ifdef UCOL_DEBUG
+ // This is debug code to dump the contents of the trie. It needs two functions defined above
+ {
+ UTrie UCAt = { 0 };
+ uint32_t trieWord;
+ utrie_unserialize(&UCAt, dataStart+tableOffset, 9999999, status);
+ UCAt.getFoldingOffset = myGetFoldingOffset;
+ if(U_SUCCESS(*status)) {
+ utrie_enum(&UCAt, NULL, enumRange, NULL);
+ }
+ trieWord = UTRIE_GET32_FROM_LEAD(UCAt, 0xDC01)
+ }
+#endif
+ tableOffset += paddedsize(mappingSize);
+
+
+ int32_t i = 0;
+
+ /* copy max expansion table */
+ myData->endExpansionCE = tableOffset;
+ myData->endExpansionCECount = maxexpansion->position - 1;
+ /* not copying the first element which is a dummy */
+ uprv_memcpy(dataStart + tableOffset, maxexpansion->endExpansionCE + 1,
+ (maxexpansion->position - 1) * sizeof(uint32_t));
+ tableOffset += (uint32_t)(paddedsize((maxexpansion->position)* sizeof(uint32_t)));
+ myData->expansionCESize = tableOffset;
+ uprv_memcpy(dataStart + tableOffset, maxexpansion->expansionCESize + 1,
+ (maxexpansion->position - 1) * sizeof(uint8_t));
+ tableOffset += (uint32_t)(paddedsize((maxexpansion->position)* sizeof(uint8_t)));
+
+ /* Unsafe chars table. Finish it off, then copy it. */
+ uprv_uca_unsafeCPAddCCNZ(t, status);
+ if (t->UCA != 0) { /* Or in unsafebits from UCA, making a combined table. */
+ for (i=0; i<UCOL_UNSAFECP_TABLE_SIZE; i++) {
+ t->unsafeCP[i] |= t->UCA->unsafeCP[i];
+ }
+ }
+ myData->unsafeCP = tableOffset;
+ uprv_memcpy(dataStart + tableOffset, t->unsafeCP, UCOL_UNSAFECP_TABLE_SIZE);
+ tableOffset += paddedsize(UCOL_UNSAFECP_TABLE_SIZE);
+
+
+ /* Finish building Contraction Ending chars hash table and then copy it out. */
+ if (t->UCA != 0) { /* Or in unsafebits from UCA, making a combined table. */
+ for (i=0; i<UCOL_UNSAFECP_TABLE_SIZE; i++) {
+ t->contrEndCP[i] |= t->UCA->contrEndCP[i];
+ }
+ }
+ myData->contrEndCP = tableOffset;
+ uprv_memcpy(dataStart + tableOffset, t->contrEndCP, UCOL_UNSAFECP_TABLE_SIZE);
+ tableOffset += paddedsize(UCOL_UNSAFECP_TABLE_SIZE);
+
+ if(tableOffset != toAllocate) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "calculation screwup!!! Expected to write %i but wrote %i instead!!!\n", toAllocate, tableOffset);
+#endif
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ uprv_free(dataStart);
+ return 0;
+ }
+
+ myData->size = tableOffset;
+ /* This should happen upon ressurection */
+ /*const uint8_t *mapPosition = (uint8_t*)myData+myData->mappingPosition;*/
+ /*uprv_mstrm_close(ms);*/
+ return myData;
+}
+
+
+struct enumStruct {
+ tempUCATable *t;
+ UCollator *tempColl;
+ UCollationElements* colEl;
+ int32_t noOfClosures;
+ UErrorCode *status;
+};
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+_enumCategoryRangeClosureCategory(const void *context, UChar32 start, UChar32 limit, UCharCategory type) {
+
+ if (type != U_UNASSIGNED && type != U_PRIVATE_USE_CHAR) { // if the range is assigned - we might ommit more categories later
+ UErrorCode *status = ((enumStruct *)context)->status;
+ tempUCATable *t = ((enumStruct *)context)->t;
+ UCollator *tempColl = ((enumStruct *)context)->tempColl;
+ UCollationElements* colEl = ((enumStruct *)context)->colEl;
+ UCAElements el;
+ UChar decomp[256] = { 0 };
+ int32_t noOfDec = 0;
+
+ UChar32 u32 = 0;
+ UChar comp[2];
+ uint32_t len = 0;
+
+ for(u32 = start; u32 < limit; u32++) {
+ noOfDec = unorm_getDecomposition(u32, FALSE, decomp, 256);
+ //if((noOfDec = unorm_normalize(comp, len, UNORM_NFD, 0, decomp, 256, status)) > 1
+ //|| (noOfDec == 1 && *decomp != (UChar)u32))
+ if(noOfDec > 0) // if we're positive, that means there is no decomposition
+ {
+ len = 0;
+ UTF_APPEND_CHAR_UNSAFE(comp, len, u32);
+ if(ucol_strcoll(tempColl, comp, len, decomp, noOfDec) != UCOL_EQUAL) {
+#ifdef UCOL_DEBUG
+ fprintf(stderr, "Closure: %08X -> ", u32);
+ uint32_t i = 0;
+ for(i = 0; i<noOfDec; i++) {
+ fprintf(stderr, "%04X ", decomp[i]);
+ }
+ fprintf(stderr, "\n");
+#endif
+ ((enumStruct *)context)->noOfClosures++;
+ el.cPoints = decomp;
+ el.cSize = noOfDec;
+ el.noOfCEs = 0;
+ el.prefix = el.prefixChars;
+ el.prefixSize = 0;
+
+ UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, &el);
+ el.cPoints = comp;
+ el.cSize = len;
+ el.prefix = el.prefixChars;
+ el.prefixSize = 0;
+ if(prefix == NULL) {
+ el.noOfCEs = 0;
+ ucol_setText(colEl, decomp, noOfDec, status);
+ while((el.CEs[el.noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) {
+ el.noOfCEs++;
+ }
+ } else {
+ el.noOfCEs = 1;
+ el.CEs[0] = prefix->mapCE;
+ // This character uses a prefix. We have to add it
+ // to the unsafe table, as it decomposed form is already
+ // in. In Japanese, this happens for \u309e & \u30fe
+ // Since unsafeCPSet is static in ucol_elm, we are going
+ // to wrap it up in the uprv_uca_unsafeCPAddCCNZ function
+ }
+ uprv_uca_addAnElement(t, &el, status);
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+U_CDECL_END
+
+static void
+uprv_uca_setMapCE(tempUCATable *t, UCAElements *element, UErrorCode *status) {
+ uint32_t expansion = 0;
+ int32_t j;
+
+ ExpansionTable *expansions = t->expansions;
+ if(element->noOfCEs == 2 // a two CE expansion
+ && isContinuation(element->CEs[1]) // which is a continuation
+ && (element->CEs[1] & (~(0xFF << 24 | UCOL_CONTINUATION_MARKER))) == 0 // that has only primaries in continuation,
+ && (((element->CEs[0]>>8) & 0xFF) == UCOL_BYTE_COMMON) // a common secondary
+ && ((element->CEs[0] & 0xFF) == UCOL_BYTE_COMMON) // and a common tertiary
+ ) {
+ element->mapCE = UCOL_SPECIAL_FLAG | (LONG_PRIMARY_TAG<<24) // a long primary special
+ | ((element->CEs[0]>>8) & 0xFFFF00) // first and second byte of primary
+ | ((element->CEs[1]>>24) & 0xFF); // third byte of primary
+ } else {
+ expansion = (uint32_t)(UCOL_SPECIAL_FLAG | (EXPANSION_TAG<<UCOL_TAG_SHIFT)
+ | ((uprv_uca_addExpansion(expansions, element->CEs[0], status)+(headersize>>2))<<4)
+ & 0xFFFFF0);
+
+ for(j = 1; j<(int32_t)element->noOfCEs; j++) {
+ uprv_uca_addExpansion(expansions, element->CEs[j], status);
+ }
+ if(element->noOfCEs <= 0xF) {
+ expansion |= element->noOfCEs;
+ } else {
+ uprv_uca_addExpansion(expansions, 0, status);
+ }
+ element->mapCE = expansion;
+ uprv_uca_setMaxExpansion(element->CEs[element->noOfCEs - 1],
+ (uint8_t)element->noOfCEs,
+ t->maxExpansions,
+ status);
+ }
+}
+
+static void
+uprv_uca_addFCD4AccentedContractions(tempUCATable *t,
+ UCollationElements* colEl,
+ UChar *data,
+ int32_t len,
+ UCAElements *el,
+ UErrorCode *status) {
+ UChar decomp[256], comp[256];
+ int32_t decLen, compLen;
+
+ decLen = unorm_normalize(data, len, UNORM_NFD, 0, decomp, 256, status);
+ compLen = unorm_normalize(data, len, UNORM_NFC, 0, comp, 256, status);
+ decomp[decLen] = comp[compLen] = 0;
+
+ el->cPoints = decomp;
+ el->cSize = decLen;
+ el->noOfCEs = 0;
+ el->prefixSize = 0;
+ el->prefix = el->prefixChars;
+
+ UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, el);
+ el->cPoints = comp;
+ el->cSize = compLen;
+ el->prefix = el->prefixChars;
+ el->prefixSize = 0;
+ if(prefix == NULL) {
+ el->noOfCEs = 0;
+ ucol_setText(colEl, decomp, decLen, status);
+ while((el->CEs[el->noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) {
+ el->noOfCEs++;
+ }
+ uprv_uca_setMapCE(t, el, status);
+ uprv_uca_addAnElement(t, el, status);
+ }
+}
+
+static void
+uprv_uca_addMultiCMContractions(tempUCATable *t,
+ UCollationElements* colEl,
+ tempTailorContext *c,
+ UCAElements *el,
+ UErrorCode *status) {
+ CombinClassTable *cmLookup = t->cmLookup;
+ UChar newDecomp[256];
+ int32_t maxComp, newDecLen;
+ const uint16_t *fcdTrieData = unorm_getFCDTrie(status);
+ int16_t curClass = (unorm_getFCD16(fcdTrieData, c->tailoringCM) & 0xff);
+ CompData *precomp = c->precomp;
+ int32_t compLen = c->compLen;
+ UChar *comp = c->comp;
+ maxComp = c->precompLen;
+
+ for (int32_t j=0; j < maxComp; j++) {
+ int32_t count=0;
+ int32_t newClass=0;
+ do {
+ if ( count == 0 ) { // Decompose the saved precomposed char.
+ UChar temp[2];
+ temp[0]=precomp[j].cp;
+ temp[1]=0;
+ newDecLen = unorm_normalize(temp, 1, UNORM_NFD, 0,
+ newDecomp, sizeof(newDecomp)/sizeof(UChar), status);
+ newDecomp[newDecLen++] = cmLookup->cPoints[c->cmPos];
+ }
+ else { // swap 2 combining marks when they are equal.
+ uprv_memcpy(newDecomp, c->decomp, sizeof(UChar)*(c->decompLen));
+ newDecLen = c->decompLen;
+ newDecomp[newDecLen++] = precomp[j].cClass;
+ }
+ newDecomp[newDecLen] = 0;
+ compLen = unorm_normalize(newDecomp, newDecLen, UNORM_NFC, 0,
+ comp, 256, status);
+ if (compLen==1) {
+ comp[compLen++] = newDecomp[newDecLen++] = c->tailoringCM;
+ comp[compLen] = newDecomp[newDecLen] = 0;
+ el->cPoints = newDecomp;
+ el->cSize = newDecLen;
+
+ UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, el);
+ el->cPoints = c->comp;
+ el->cSize = compLen;
+ el->prefix = el->prefixChars;
+ el->prefixSize = 0;
+ if(prefix == NULL) {
+ el->noOfCEs = 0;
+ ucol_setText(colEl, newDecomp, newDecLen, status);
+ while((el->CEs[el->noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) {
+ el->noOfCEs++;
+ }
+ uprv_uca_setMapCE(t, el, status);
+ uprv_uca_finalizeAddition(t, el, status);
+
+ // Save the current precomposed char and its class to find any
+ // other combining mark combinations.
+ precomp[c->precompLen].cp=comp[0];
+ precomp[c->precompLen].cClass = curClass;
+ c->precompLen++;
+ }
+ }
+ } while (++count<2 && (precomp[j].cClass == curClass));
+ }
+
+}
+
+static void
+uprv_uca_addTailCanonicalClosures(tempUCATable *t,
+ UCollationElements* colEl,
+ UChar baseCh,
+ UChar cMark,
+ UCAElements *el,
+ UErrorCode *status) {
+ CombinClassTable *cmLookup = t->cmLookup;
+ const uint16_t *fcdTrieData = unorm_getFCDTrie(status);
+ int16_t maxIndex = (unorm_getFCD16(fcdTrieData, cMark) & 0xff );
+ UCAElements element;
+ uint16_t *index;
+ UChar decomp[256];
+ UChar comp[256];
+ CompData precomp[256]; // precomposed array
+ int32_t precompLen = 0; // count for precomp
+ int32_t i, len, decompLen, curClass, replacedPos;
+ tempTailorContext c;
+
+ if ( cmLookup == NULL ) {
+ return;
+ }
+ index = cmLookup->index;
+ int32_t cClass=(unorm_getFCD16(fcdTrieData, cMark) & 0xff);
+ maxIndex = (int32_t)index[(unorm_getFCD16(fcdTrieData, cMark) & 0xff)-1];
+ c.comp = comp;
+ c.decomp = decomp;
+ c.precomp = precomp;
+ c.tailoringCM = cMark;
+
+ if (cClass>0) {
+ maxIndex = (int32_t)index[cClass-1];
+ }
+ else {
+ maxIndex=0;
+ }
+ decomp[0]=baseCh;
+ for ( i=0; i<maxIndex ; i++ ) {
+ decomp[1] = cmLookup->cPoints[i];
+ decomp[2]=0;
+ decompLen=2;
+ len = unorm_normalize(decomp, decompLen, UNORM_NFC, 0, comp, 256, status);
+ if (len==1) {
+ // Save the current precomposed char and its class to find any
+ // other combining mark combinations.
+ precomp[precompLen].cp=comp[0];
+ curClass = precomp[precompLen].cClass =
+ index[unorm_getFCD16(fcdTrieData, decomp[1]) & 0xff];
+ precompLen++;
+ replacedPos=0;
+ for (decompLen=0; decompLen< (int32_t)el->cSize; decompLen++) {
+ decomp[decompLen] = el->cPoints[decompLen];
+ if (decomp[decompLen]==cMark) {
+ replacedPos = decompLen; // record the position for later use
+ }
+ }
+ if ( replacedPos != 0 ) {
+ decomp[replacedPos]=cmLookup->cPoints[i];
+ }
+ decomp[decompLen] = 0;
+ len = unorm_normalize(decomp, decompLen, UNORM_NFC, 0, comp, 256, status);
+ comp[len++] = decomp[decompLen++] = cMark;
+ comp[len] = decomp[decompLen] = 0;
+ element.cPoints = decomp;
+ element.cSize = decompLen;
+ element.noOfCEs = 0;
+ element.prefix = el->prefixChars;
+ element.prefixSize = 0;
+
+ UCAElements *prefix=(UCAElements *)uhash_get(t->prefixLookup, &element);
+ element.cPoints = comp;
+ element.cSize = len;
+ element.prefix = el->prefixChars;
+ element.prefixSize = 0;
+ if(prefix == NULL) {
+ element.noOfCEs = 0;
+ ucol_setText(colEl, decomp, decompLen, status);
+ while((element.CEs[element.noOfCEs] = ucol_next(colEl, status)) != (uint32_t)UCOL_NULLORDER) {
+ element.noOfCEs++;
+ }
+ uprv_uca_setMapCE(t, &element, status);
+ uprv_uca_finalizeAddition(t, &element, status);
+ }
+
+ // This is a fix for tailoring contractions with accented
+ // character at the end of contraction string.
+ if ((len>2) &&
+ (unorm_getFCD16(fcdTrieData, comp[len-2]) & 0xff00)==0) {
+ uprv_uca_addFCD4AccentedContractions(t, colEl, comp, len, &element, status);
+ }
+
+ if (precompLen >1) {
+ c.compLen = len;
+ c.decompLen = decompLen;
+ c.precompLen = precompLen;
+ c.cmPos = i;
+ uprv_uca_addMultiCMContractions(t, colEl, &c, &element, status);
+ precompLen = c.precompLen;
+ }
+ }
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+uprv_uca_canonicalClosure(tempUCATable *t,
+ UColTokenParser *src,
+ UErrorCode *status)
+{
+ enumStruct context;
+ context.noOfClosures = 0;
+ UCAElements el;
+ UColToken *tok;
+ UColToken *expt = NULL;
+ uint32_t i = 0, j = 0;
+ UChar baseChar, firstCM;
+ const uint16_t *fcdTrieData = unorm_getFCDTrie(status);
+
+ if(!U_SUCCESS(*status)) {
+ return 0;
+ }
+
+ UCollator *tempColl = NULL;
+ tempUCATable *tempTable = uprv_uca_cloneTempTable(t, status);
+
+ UCATableHeader *tempData = uprv_uca_assembleTable(tempTable, status);
+ tempColl = ucol_initCollator(tempData, 0, t->UCA, status);
+ if ( tempTable->cmLookup != NULL ) {
+ t->cmLookup = tempTable->cmLookup; // copy over to t
+ tempTable->cmLookup = NULL;
+ }
+ uprv_uca_closeTempTable(tempTable);
+
+ if(U_SUCCESS(*status)) {
+ tempColl->rb = NULL;
+ tempColl->elements = NULL;
+ tempColl->validLocale = NULL;
+ tempColl->requestedLocale = NULL;
+ tempColl->hasRealData = TRUE;
+ tempColl->freeImageOnClose = TRUE;
+ } else if(tempData != 0) {
+ uprv_free(tempData);
+ }
+
+ /* produce canonical closure */
+ UCollationElements* colEl = ucol_openElements(tempColl, NULL, 0, status);
+
+ context.t = t;
+ context.tempColl = tempColl;
+ context.colEl = colEl;
+ context.status = status;
+ u_enumCharTypes(_enumCategoryRangeClosureCategory, &context);
+
+ if ( (src==NULL) || !src->buildCCTabFlag ) {
+ ucol_closeElements(colEl);
+ ucol_close(tempColl);
+ return context.noOfClosures; // no extra contraction needed to add
+ }
+
+ for (i=0; i < src->resultLen; i++) {
+ baseChar = firstCM= (UChar)0;
+ tok = src->lh[i].first;
+ while (tok != NULL && U_SUCCESS(*status)) {
+ el.prefix = el.prefixChars;
+ el.cPoints = el.uchars;
+ if(tok->prefix != 0) {
+ el.prefixSize = tok->prefix>>24;
+ uprv_memcpy(el.prefix, src->source + (tok->prefix & 0x00FFFFFF), el.prefixSize*sizeof(UChar));
+
+ el.cSize = (tok->source >> 24)-(tok->prefix>>24);
+ uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF)+(tok->prefix>>24) + src->source, el.cSize*sizeof(UChar));
+ } else {
+ el.prefixSize = 0;
+ *el.prefix = 0;
+
+ el.cSize = (tok->source >> 24);
+ uprv_memcpy(el.uchars, (tok->source & 0x00FFFFFF) + src->source, el.cSize*sizeof(UChar));
+ }
+ if(src->UCA != NULL) {
+ for(j = 0; j<el.cSize; j++) {
+ int16_t fcd = unorm_getFCD16(fcdTrieData, el.cPoints[j]);
+ if ( (fcd & 0xff) == 0 ) {
+ baseChar = el.cPoints[j]; // last base character
+ firstCM=0; // reset combining mark value
+ }
+ else {
+ if ( (baseChar!=0) && (firstCM==0) ) {
+ firstCM = el.cPoints[j]; // first combining mark
+ }
+ }
+ }
+ }
+ if ( (baseChar!= (UChar)0) && (firstCM != (UChar)0) ) {
+ // find all the canonical rules
+ uprv_uca_addTailCanonicalClosures(t, colEl, baseChar, firstCM, &el, status);
+ }
+ tok = tok->next;
+ }
+ }
+ ucol_closeElements(colEl);
+ ucol_close(tempColl);
+
+ return context.noOfClosures;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_elm.h b/Build/source/libs/icu/icu-xetex/i18n/ucol_elm.h
new file mode 100644
index 00000000000..fbe966eaefb
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_elm.h
@@ -0,0 +1,148 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2000-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: ucol_elm.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created 02/22/2001
+* created by: Vladimir Weinstein
+*
+* This program reads the Franctional UCA table and generates
+* internal format for UCA table as well as inverse UCA table.
+* It then writes binary files containing the data: ucadata.dat
+* & invuca.dat
+*/
+#ifndef UCOL_UCAELEMS_H
+#define UCOL_UCAELEMS_H
+
+#include "unicode/utypes.h"
+#include "ucol_tok.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "ucol_cnt.h"
+#include "ucol_imp.h"
+
+#ifdef UCOL_DEBUG
+#include "cmemory.h"
+#include <stdio.h>
+#endif
+
+U_CDECL_BEGIN
+
+/* This is the maximum trie capacity for the mapping trie.
+Due to current limitations in genuca and the design of UTrie,
+this number can't be more than 256K.
+As of Unicode 5, it currently could safely go to 128K without
+a problem. Normally, less than 32K are tailored.
+*/
+#define UCOL_ELM_TRIE_CAPACITY 0x40000
+
+/* This is the maxmun capacity for temparay combining class
+ * table. The table will be compacted after scanning all the
+ * Unicode codepoints.
+*/
+#define UCOL_MAX_CM_TAB 0x10000
+
+
+typedef struct {
+ uint32_t *CEs;
+ int32_t position;
+ int32_t size;
+} ExpansionTable;
+
+typedef struct {
+ UChar prefixChars[128];
+ UChar *prefix;
+ uint32_t prefixSize;
+ UChar uchars[128];
+ UChar *cPoints;
+ uint32_t cSize; /* Number of characters in sequence - for contraction */
+ uint32_t noOfCEs; /* Number of collation elements */
+ uint32_t CEs[128]; /* These are collation elements - there could be more than one - in case of expansion */
+ uint32_t mapCE; /* This is the value element maps in original table */
+ uint32_t sizePrim[128];
+ uint32_t sizeSec[128];
+ uint32_t sizeTer[128];
+ UBool variableTop;
+ UBool caseBit;
+ UBool isThai;
+} UCAElements;
+
+typedef struct {
+ uint32_t *endExpansionCE;
+ UBool *isV;
+ int32_t position;
+ int32_t size;
+ uint8_t maxLSize;
+ uint8_t maxVSize;
+ uint8_t maxTSize;
+} MaxJamoExpansionTable;
+
+typedef struct {
+ uint32_t *endExpansionCE;
+ uint8_t *expansionCESize;
+ int32_t position;
+ int32_t size;
+} MaxExpansionTable;
+
+typedef struct {
+ uint16_t index[256]; /* index of cPoints by combining class 0-255. */
+ UChar *cPoints; /* code point array of all combining marks */
+ uint32_t size; /* total number of combining marks */
+} CombinClassTable;
+
+typedef struct {
+ /*CompactEIntArray *mapping; */
+ UNewTrie *mapping;
+ ExpansionTable *expansions;
+ struct CntTable *contractions;
+ UCATableHeader *image;
+ UColOptionSet *options;
+ MaxExpansionTable *maxExpansions;
+ MaxJamoExpansionTable *maxJamoExpansions;
+ uint8_t *unsafeCP;
+ uint8_t *contrEndCP;
+ const UCollator *UCA;
+ UHashtable *prefixLookup;
+ CombinClassTable *cmLookup; /* combining class lookup for tailoring. */
+} tempUCATable;
+
+typedef struct {
+ UChar cp;
+ uint16_t cClass; // combining class
+}CompData;
+
+typedef struct {
+ CompData *precomp;
+ int32_t precompLen;
+ UChar *decomp;
+ int32_t decompLen;
+ UChar *comp;
+ int32_t compLen;
+ uint16_t curClass;
+ uint16_t tailoringCM;
+ int32_t cmPos;
+}tempTailorContext;
+
+U_CAPI tempUCATable * U_EXPORT2 uprv_uca_initTempTable(UCATableHeader *image, UColOptionSet *opts, const UCollator *UCA, UColCETags initTag, UColCETags supplementaryInitTag, UErrorCode *status);
+U_CAPI tempUCATable * U_EXPORT2 uprv_uca_cloneTempTable(tempUCATable *t, UErrorCode *status);
+U_CAPI void U_EXPORT2 uprv_uca_closeTempTable(tempUCATable *t);
+U_CAPI uint32_t U_EXPORT2 uprv_uca_addAnElement(tempUCATable *t, UCAElements *element, UErrorCode *status);
+U_CAPI UCATableHeader * U_EXPORT2 uprv_uca_assembleTable(tempUCATable *t, UErrorCode *status);
+U_CAPI int32_t U_EXPORT2
+uprv_uca_canonicalClosure(tempUCATable *t, UColTokenParser *src, UErrorCode *status);
+#define paddedsize(something) ((something)+((((something)%4)!=0)?(4-(something)%4):0))
+#define headersize (paddedsize(sizeof(UCATableHeader))+paddedsize(sizeof(UColOptionSet)))
+
+U_CDECL_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_imp.h b/Build/source/libs/icu/icu-xetex/i18n/ucol_imp.h
new file mode 100644
index 00000000000..fcae8f02702
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_imp.h
@@ -0,0 +1,1016 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1998-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+*
+* Private implementation header for C collation
+* file name: ucol_imp.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2000dec11
+* created by: Vladimir Weinstein
+*
+* Modification history
+* Date Name Comments
+* 02/16/2001 synwee Added UCOL_GETPREVCE for the use in ucoleitr
+* 02/27/2001 synwee Added getMaxExpansion data structure in UCollator
+* 03/02/2001 synwee Added UCOL_IMPLICIT_CE
+* 03/12/2001 synwee Added pointer start to collIterate.
+*/
+
+#ifndef UCOL_IMP_H
+#define UCOL_IMP_H
+
+#include "unicode/utypes.h"
+
+#define UCA_DATA_TYPE "icu"
+#define UCA_DATA_NAME "ucadata"
+#define INVC_DATA_TYPE "icu"
+#define INVC_DATA_NAME "invuca"
+
+/**
+ * Convenience string denoting the Collation data tree
+ * @internal ICU 3.0
+ */
+#define U_ICUDATA_COLL U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "coll"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/ucol.h"
+#include "utrie.h"
+#include "uresimp.h"
+#include "unicode/udata.h"
+#include "unicode/uiter.h"
+
+/* This is the internal header file which contains important declarations for
+ * the collation framework.
+ * Ready to use collators are stored as binary images. Both UCA and tailorings
+ * share the same binary format. Individual files (currently only UCA) have a
+ * udata header in front of the image and should be opened using udata_open.
+ * Tailoring images are currently stored inside resource bundles and are intialized
+ * through ucol_open API.
+ *
+ * The following describes the formats for collation binaries
+ * (UCA & tailorings) and for the inverse UCA table.
+ * Substructures are described in the collation design document at
+ * http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm
+ *
+ * -------------------------------------------------------------
+ *
+ * Here is the format of binary collation image.
+ *
+ * Physical order of structures:
+ * - header (UCATableHeader)
+ * - options (UColOptionSet)
+ * - expansions (CE[])
+ * - contractions (UChar[contractionSize] + CE[contractionSize])
+ * - serialized UTrie with mappings of code points to CEs
+ * - max expansion tables (CE[endExpansionCECount] + uint8_t[endExpansionCECount])
+ * - two bit sets for backward processing in strcoll (identical prefixes)
+ * and for backward CE iteration (each set is uint8_t[UCOL_UNSAFECP_TABLE_SIZE])
+ * - UCA constants (UCAConstants)
+ * - UCA contractions (UChar[contractionUCACombosSize][contractionUCACombosWidth])
+ *
+ * UCATableHeader fields:
+ *
+ * int32_t size; - image size in bytes
+ *
+ * Offsets to interesting data. All offsets are in bytes.
+ * to get the address add to the header address and cast properly.
+ * Some offsets are zero if the corresponding structures are empty.
+ *
+ * Tailoring binaries that only set options and contain no mappings etc.
+ * will have all offsets 0 except for the options and expansion offsets,
+ * which give the position and length of the options array.
+ *
+ * uint32_t options; - offset to default collator options (UColOptionSet *),
+ * a set of 32-bit values. See declaration of UColOptionSet for more details
+ *
+ * uint32_t UCAConsts; - only used (!=0) in UCA image - structure which holds values for indirect positioning and implicit ranges
+ * See declaration of UCAConstants structure. This is a set of unsigned 32-bit values used to store
+ * important constant values that are defined in the UCA and used for building and runtime.
+ *
+ * uint32_t contractionUCACombos; - only used (!=0) in UCA image - list of UCA contractions. This is a zero terminated array of UChar[contractionUCACombosWidth],
+ * containing contractions from the UCA. These are needed in the build process to copy UCA contractions
+ * in case the base contraction symbol is tailored.
+ *
+ * uint32_t magic; - must contain UCOL_HEADER_MAGIC (formatVersion 2.3)
+ *
+ * uint32_t mappingPosition; - offset to UTrie (const uint8_t *mappingPosition). This is a serialized UTrie and should be treated as such.
+ * Used as a primary lookup table for collation elements.
+ *
+ * uint32_t expansion; - offset to expansion table (uint32_t *expansion). This is an array of expansion CEs. Never 0.
+ *
+ * uint32_t contractionIndex; - offset to contraction table (UChar *contractionIndex). Used to look up contraction sequences. Contents
+ * are aligned with the contents of contractionCEs table. 0 if no contractions.
+ *
+ * uint32_t contractionCEs; - offset to resulting contraction CEs (uint32_t *contractionCEs). When a contraction is resolved in the
+ * in the contractionIndex table, the resulting index is used to look up corresponding CE in this table.
+ * 0 if no contractions.
+ * uint32_t contractionSize; - size of contraction table in elements (both Index and CEs).
+ *
+ * Tables described below are used for Boyer-Moore searching algorithm - they define the size of longest expansion
+ * and last CEs in expansions.
+ * uint32_t endExpansionCE; - offset to array of last collation element in expansion (uint32_t *).
+ * Never 0.
+ * uint32_t expansionCESize; - array of maximum expansion sizes (uint8_t *)
+ * int32_t endExpansionCECount; - size of endExpansionCE. See UCOL_GETMAXEXPANSION
+ * for the usage model
+ *
+ * These two offsets point to byte tables that are used in the backup heuristics.
+ * uint32_t unsafeCP; - hash table of unsafe code points (uint8_t *). See ucol_unsafeCP function.
+ * uint32_t contrEndCP; - hash table of final code points in contractions (uint8_t *). See ucol_contractionEndCP.
+ *
+ * int32_t contractionUCACombosSize; - number of UChar[contractionUCACombosWidth] in contractionUCACombos
+ * (formatVersion 2.3)
+ * UBool jamoSpecial; - Jamo special indicator (uint8_t). If TRUE, Jamos are special, so we cannot use simple Hangul decomposition.
+ * UBool isBigEndian; - endianness of this collation binary (formatVersion 2.3)
+ * uint8_t charSetFamily; - charset family of this collation binary (formatVersion 2.3)
+ * uint8_t contractionUCACombosWidth; - number of UChars per UCA contraction in contractionUCACombos (formatVersion 2.3)
+ *
+ * Various version fields
+ * UVersionInfo version; - version 4 uint8_t
+ * UVersionInfo UCAVersion; - version 4 uint8_t
+ * UVersionInfo UCDVersion; - version 4 uint8_t
+ * UVersionInfo formatVersion; - version of the format of the collation binary
+ * same formatVersion as in ucadata.icu's UDataInfo header
+ * (formatVersion 2.3)
+ *
+ * uint8_t reserved[84]; - currently unused
+ *
+ * -------------------------------------------------------------
+ *
+ * Inverse UCA is used for constructing collators from rules. It is always an individual file
+ * and always has a UDataInfo header.
+ * here is the structure:
+ *
+ * uint32_t byteSize; - size of inverse UCA image in bytes
+ * uint32_t tableSize; - length of inverse table (number of uint32_t[3] rows)
+ * uint32_t contsSize; - size of continuation table (number of UChars in table)
+ *
+ * uint32_t table; - offset to inverse table (uint32_t *)
+ * Inverse table contains of rows of 3 uint32_t values. First two values are CE and a possible continuation
+ * the third value is either a code unit (if there is only one code unit for element) or an index to continuation
+ * (number of code units combined with an index).
+ * table. If more than one codepoint have the same CE, continuation table contains code units separated by FFFF and final
+ * code unit sequence for a CE is terminated by FFFE.
+ * uint32_t conts; - offset to continuation table (uint16_t *). Contains code units that transform to a same CE.
+ *
+ * UVersionInfo UCAVersion; - version of the UCA, read from file 4 uint8_t
+ * uint8_t padding[8]; - padding 8 uint8_t
+ * Header is followed by the table and continuation table.
+*/
+
+/* let us know whether reserved fields are reset to zero or junked */
+#define UCOL_HEADER_MAGIC 0x20030618
+
+/* UDataInfo for UCA mapping table */
+/* dataFormat="UCol" */
+#define UCA_DATA_FORMAT_0 ((uint8_t)0x55)
+#define UCA_DATA_FORMAT_1 ((uint8_t)0x43)
+#define UCA_DATA_FORMAT_2 ((uint8_t)0x6f)
+#define UCA_DATA_FORMAT_3 ((uint8_t)0x6c)
+
+#define UCA_FORMAT_VERSION_0 ((uint8_t)2)
+#define UCA_FORMAT_VERSION_1 ((uint8_t)3)
+#define UCA_FORMAT_VERSION_2 ((uint8_t)0)
+#define UCA_FORMAT_VERSION_3 ((uint8_t)0)
+
+/* UDataInfo for inverse UCA table */
+/* dataFormat="InvC" */
+#define INVUCA_DATA_FORMAT_0 ((uint8_t)0x49)
+#define INVUCA_DATA_FORMAT_1 ((uint8_t)0x6E)
+#define INVUCA_DATA_FORMAT_2 ((uint8_t)0x76)
+#define INVUCA_DATA_FORMAT_3 ((uint8_t)0x43)
+
+#define INVUCA_FORMAT_VERSION_0 ((uint8_t)2)
+#define INVUCA_FORMAT_VERSION_1 ((uint8_t)1)
+#define INVUCA_FORMAT_VERSION_2 ((uint8_t)0)
+#define INVUCA_FORMAT_VERSION_3 ((uint8_t)0)
+
+/* This is the size of the stack allocated buffer for sortkey generation and similar operations */
+/* if it is too small, heap allocation will occur.*/
+/* you can change this value if you need memory - it will affect the performance, though, since we're going to malloc */
+#define UCOL_MAX_BUFFER 128
+#define UCOL_PRIMARY_MAX_BUFFER 8*UCOL_MAX_BUFFER
+#define UCOL_SECONDARY_MAX_BUFFER UCOL_MAX_BUFFER
+#define UCOL_TERTIARY_MAX_BUFFER UCOL_MAX_BUFFER
+#define UCOL_CASE_MAX_BUFFER UCOL_MAX_BUFFER/4
+#define UCOL_QUAD_MAX_BUFFER 2*UCOL_MAX_BUFFER
+
+#define UCOL_NORMALIZATION_GROWTH 2
+#define UCOL_NORMALIZATION_MAX_BUFFER UCOL_MAX_BUFFER*UCOL_NORMALIZATION_GROWTH
+
+/* This writable buffer is used if we encounter Thai and need to reorder the string on the fly */
+/* Sometimes we already have a writable buffer (like in case of normalized strings). */
+/*
+you can change this value to any value >= 4 if you need memory -
+it will affect the performance, though, since we're going to malloc.
+Note 3 is the minimum value for Thai collation and 4 is the
+minimum number for special Jamo
+*/
+#define UCOL_WRITABLE_BUFFER_SIZE 256
+
+/* This is the size of the buffer for expansion CE's */
+/* In reality we should not have to deal with expm sequences longer then 16 */
+/* you can change this value if you need memory */
+/* WARNING THIS BUFFER DOES NOT HAVE MALLOC FALLBACK. If you make it too small, you'll get in trouble */
+/* Reasonable small value is around 10, if you don't do Arabic or other funky collations that have long expansion sequence */
+/* This is the longest expansion sequence we can handle without bombing out */
+#define UCOL_EXPAND_CE_BUFFER_SIZE 512 /* synwee :TODO revert back 64*/
+
+
+/* Unsafe UChar hash table table size. */
+/* size is 32 bytes for 1 bit for each latin 1 char + some power of two for */
+/* hashing the rest of the chars. Size in bytes */
+#define UCOL_UNSAFECP_TABLE_SIZE 1056
+ /* mask value down to "some power of two"-1 */
+ /* number of bits, not num of bytes. */
+#define UCOL_UNSAFECP_TABLE_MASK 0x1fff
+
+
+/* flags bits for collIterate.flags */
+/* */
+/* NORM - set for incremental normalize of source string */
+#define UCOL_ITER_NORM 1
+
+#define UCOL_ITER_HASLEN 2
+
+ /* UCOL_ITER_INNORMBUF - set if the "pos" is in */
+ /* the writable side buffer, handling */
+ /* incrementally normalized characters. */
+#define UCOL_ITER_INNORMBUF 4
+
+ /* UCOL_ITER_ALLOCATED - set if this iterator has */
+ /* malloced storage to expand a buffer. */
+#define UCOL_ITER_ALLOCATED 8
+ /* UCOL_HIRAGANA_Q - note if the codepoint was hiragana */
+#define UCOL_HIRAGANA_Q 16
+ /* UCOL_WAS_HIRAGANA - set to TRUE if there was a Hiragana */
+ /* otherwise set to false */
+#define UCOL_WAS_HIRAGANA 32
+ /* UCOL_USE_ITERATOR - set this if collIterate uses a */
+ /* character iterator instead of simply accessing string */
+ /* by index */
+#define UCOL_USE_ITERATOR 64
+
+#define NFC_ZERO_CC_BLOCK_LIMIT_ 0x300
+
+typedef struct collIterate {
+ UChar *string; /* Original string */
+ /* UChar *start; Pointer to the start of the source string. Either points to string
+ or to writableBuffer */
+ UChar *endp; /* string end ptr. Is undefined for null terminated strings */
+ UChar *pos; /* This is position in the string. Can be to original or writable buf */
+
+ uint32_t *toReturn; /* This is the CE from CEs buffer that should be returned */
+ uint32_t *CEpos; /* This is the position to which we have stored processed CEs */
+ UChar *writableBuffer;
+ uint32_t writableBufSize;
+ UChar *fcdPosition; /* Position in the original string to continue FCD check from. */
+ const UCollator *coll;
+ uint8_t flags;
+ uint8_t origFlags;
+ uint32_t CEs[UCOL_EXPAND_CE_BUFFER_SIZE]; /* This is where we store CEs */
+ UChar stackWritableBuffer[UCOL_WRITABLE_BUFFER_SIZE]; /* A writable buffer. */
+ UCharIterator *iterator;
+ /*int32_t iteratorIndex;*/
+} collIterate;
+
+/*
+struct used internally in getSpecial*CE.
+data similar to collIterate.
+*/
+struct collIterateState {
+ UChar *pos; /* This is position in the string. Can be to original or writable buf */
+ UChar *fcdPosition; /* Position in the original string to continue FCD check from. */
+ UChar *bufferaddress; /* address of the normalization buffer */
+ uint32_t buffersize;
+ uint8_t flags;
+ uint8_t origFlags;
+ uint32_t iteratorIndex;
+ int32_t iteratorMove;
+};
+
+U_CAPI void U_EXPORT2
+uprv_init_collIterate(const UCollator *collator, const UChar *sourceString, int32_t sourceLen, collIterate *s);
+
+
+struct UCollationElements
+{
+ /**
+ * Struct wrapper for source data
+ */
+ collIterate iteratordata_;
+ /**
+ * Indicates if this data has been reset.
+ */
+ UBool reset_;
+ /**
+ * Indicates if the data should be deleted.
+ */
+ UBool isWritable;
+};
+
+
+#define UCOL_LEVELTERMINATOR 1
+
+/* mask off anything but primary order */
+#define UCOL_PRIMARYORDERMASK 0xffff0000
+/* mask off anything but secondary order */
+#define UCOL_SECONDARYORDERMASK 0x0000ff00
+/* mask off anything but tertiary order */
+#define UCOL_TERTIARYORDERMASK 0x000000ff
+/* primary order shift */
+#define UCOL_PRIMARYORDERSHIFT 16
+/* secondary order shift */
+#define UCOL_SECONDARYORDERSHIFT 8
+
+#define UCOL_BYTE_SIZE_MASK 0xFF
+
+#define UCOL_CASE_BYTE_START 0x80
+#define UCOL_CASE_SHIFT_START 7
+
+#define UCOL_IGNORABLE 0
+
+/* get weights from a CE */
+#define UCOL_PRIMARYORDER(order) (((order) & UCOL_PRIMARYORDERMASK)>> UCOL_PRIMARYORDERSHIFT)
+#define UCOL_SECONDARYORDER(order) (((order) & UCOL_SECONDARYORDERMASK)>> UCOL_SECONDARYORDERSHIFT)
+#define UCOL_TERTIARYORDER(order) ((order) & UCOL_TERTIARYORDERMASK)
+
+/**
+ * Determine if a character is a Thai vowel (which sorts after
+ * its base consonant).
+ */
+#define UCOL_ISTHAIPREVOWEL(ch) ((((uint32_t)(ch) - 0xe40) <= (0xe44 - 0xe40)) || \
+ (((uint32_t)(ch) - 0xec0) <= (0xec4 - 0xec0)))
+
+/**
+ * Determine if a character is a Thai base consonant
+ */
+#define UCOL_ISTHAIBASECONSONANT(ch) ((uint32_t)(ch) - 0xe01) <= (0xe2e - 0xe01)
+
+#define UCOL_ISJAMO(ch) ((((uint32_t)(ch) - 0x1100) <= (0x1112 - 0x1100)) || \
+ (((uint32_t)(ch) - 0x1161) <= (0x1175 - 0x1161)) || \
+ (((uint32_t)(ch) - 0x11A8) <= (0x11C2 - 0x11A8)))
+
+
+
+#if 0
+/* initializes collIterate structure */
+/* made as macro to speed up things */
+#define init_collIterate(collator, sourceString, sourceLen, s) { \
+ (s)->start = (s)->string = (s)->pos = (UChar *)(sourceString); \
+ (s)->endp = (sourceLen) == -1 ? NULL :(UChar *)(sourceString)+(sourceLen); \
+ (s)->CEpos = (s)->toReturn = (s)->CEs; \
+ (s)->isThai = TRUE; \
+ (s)->writableBuffer = (s)->stackWritableBuffer; \
+ (s)->writableBufSize = UCOL_WRITABLE_BUFFER_SIZE; \
+ (s)->coll = (collator); \
+ (s)->fcdPosition = 0; \
+ (s)->flags = 0; \
+ if(((collator)->normalizationMode == UCOL_ON)) (s)->flags |= UCOL_ITER_NORM; \
+}
+#endif
+
+
+
+/*
+* Macro to get the maximum size of an expansion ending with the argument ce.
+* Used in the Boyer Moore algorithm.
+* Note for tailoring, the UCA maxexpansion table has been merged.
+* Hence we only have to search the tailored collator only.
+* @param coll const UCollator pointer
+* @param order last collation element of the expansion sequence
+* @param result size of the longest expansion with argument collation element
+* as the last element
+*/
+#define UCOL_GETMAXEXPANSION(coll, order, result) { \
+ const uint32_t *start; \
+ const uint32_t *limit; \
+ const uint32_t *mid; \
+ start = (coll)->endExpansionCE; \
+ limit = (coll)->lastEndExpansionCE; \
+ while (start < limit - 1) { \
+ mid = start + ((limit - start) >> 1); \
+ if ((order) <= *mid) { \
+ limit = mid; \
+ } \
+ else { \
+ start = mid; \
+ } \
+ } \
+ if (*start == order) { \
+ result = *((coll)->expansionCESize + (start - (coll)->endExpansionCE)); \
+ } \
+ else if (*limit == order) { \
+ result = *(coll->expansionCESize + (limit - coll->endExpansionCE)); \
+ } \
+ else if ((order & 0xFFFF) == 0x00C0) { \
+ result = 2; \
+ } \
+ else { \
+ result = 1; \
+ } \
+}
+
+U_CFUNC
+uint32_t ucol_prv_getSpecialCE(const UCollator *coll, UChar ch, uint32_t CE, collIterate *source, UErrorCode *status);
+
+U_CFUNC
+uint32_t ucol_prv_getSpecialPrevCE(const UCollator *coll, UChar ch, uint32_t CE,
+ collIterate *source, UErrorCode *status);
+U_CAPI uint32_t U_EXPORT2 ucol_getNextCE(const UCollator *coll, collIterate *collationSource, UErrorCode *status);
+U_CFUNC uint32_t U_EXPORT2 ucol_getPrevCE(const UCollator *coll,
+ collIterate *collationSource,
+ UErrorCode *status);
+/* function used by C++ getCollationKey to prevent restarting the calculation */
+U_CFUNC int32_t
+ucol_getSortKeyWithAllocation(const UCollator *coll,
+ const UChar *source, int32_t sourceLength,
+ uint8_t **pResult,
+ UErrorCode *pErrorCode);
+
+/* get some memory */
+void *ucol_getABuffer(const UCollator *coll, uint32_t size);
+
+/* worker function for generating sortkeys */
+U_CFUNC
+int32_t U_CALLCONV
+ucol_calcSortKey(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocatePrimary,
+ UErrorCode *status);
+
+U_CFUNC
+int32_t U_CALLCONV
+ucol_calcSortKeySimpleTertiary(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocatePrimary,
+ UErrorCode *status);
+
+U_CFUNC
+int32_t
+ucol_getSortKeySize(const UCollator *coll, collIterate *s,
+ int32_t currentSize, UColAttributeValue strength,
+ int32_t len);
+/**
+ * Makes a copy of the Collator's rule data. The format is
+ * that of .col files.
+ *
+ * @param length returns the length of the data, in bytes.
+ * @param status the error status
+ * @return memory, owned by the caller, of size 'length' bytes.
+ * @internal INTERNAL USE ONLY
+ */
+U_CAPI uint8_t* U_EXPORT2
+ucol_cloneRuleData(const UCollator *coll, int32_t *length, UErrorCode *status);
+
+/**
+ * Used to set requested and valid locales on a collator returned by the collator
+ * service.
+ */
+U_CFUNC void U_EXPORT2
+ucol_setReqValidLocales(UCollator *coll, char *requestedLocaleToAdopt, char *validLocaleToAdopt);
+
+#define UCOL_SPECIAL_FLAG 0xF0000000
+#define UCOL_TAG_SHIFT 24
+#define UCOL_TAG_MASK 0x0F000000
+#define INIT_EXP_TABLE_SIZE 1024
+#define UCOL_NOT_FOUND 0xF0000000
+#define UCOL_EXPANSION 0xF1000000
+#define UCOL_CONTRACTION 0xF2000000
+#define UCOL_THAI 0xF3000000
+#define UCOL_UNMARKED 0x03
+#define UCOL_NEW_TERTIARYORDERMASK 0x0000003f
+
+/* Bit mask for primary collation strength. */
+#define UCOL_PRIMARYMASK 0xFFFF0000
+
+/* Bit mask for secondary collation strength. */
+#define UCOL_SECONDARYMASK 0x0000FF00
+
+/* Bit mask for tertiary collation strength. */
+#define UCOL_TERTIARYMASK 0x000000FF
+
+/**
+ * Internal.
+ * This indicates the last element in a UCollationElements has been consumed.
+ * Compare with the UCOL_NULLORDER, UCOL_NULLORDER is returned if error occurs.
+ */
+#define UCOL_NO_MORE_CES 0x00010101
+#define UCOL_NO_MORE_CES_PRIMARY 0x00010000
+#define UCOL_NO_MORE_CES_SECONDARY 0x00000100
+#define UCOL_NO_MORE_CES_TERTIARY 0x00000001
+
+#define isSpecial(CE) ((((CE)&UCOL_SPECIAL_FLAG)>>28)==0xF)
+
+#define UCOL_UPPER_CASE 0x80
+#define UCOL_MIXED_CASE 0x40
+#define UCOL_LOWER_CASE 0x00
+
+#define UCOL_CONTINUATION_MARKER 0xC0
+#define UCOL_REMOVE_CONTINUATION 0xFFFFFF3F
+
+#define isContinuation(CE) (((CE) & UCOL_CONTINUATION_MARKER) == UCOL_CONTINUATION_MARKER)
+#define isFlagged(CE) (((CE) & 0x80) == 0x80)
+#define isLongPrimary(CE) (((CE) & 0xC0) == 0xC0)
+
+#define getCETag(CE) (((CE)&UCOL_TAG_MASK)>>UCOL_TAG_SHIFT)
+#define isContraction(CE) (isSpecial((CE)) && (getCETag((CE)) == CONTRACTION_TAG))
+#define isPrefix(CE) (isSpecial((CE)) && (getCETag((CE)) == SPEC_PROC_TAG))
+#define constructContractCE(tag, CE) (UCOL_SPECIAL_FLAG | ((tag)<<UCOL_TAG_SHIFT) | ((CE))&0xFFFFFF)
+#define constructSpecProcCE(CE) (UCOL_SPECIAL_FLAG | (SPEC_PROC_TAG<<UCOL_TAG_SHIFT) | ((CE))&0xFFFFFF)
+#define getContractOffset(CE) ((CE)&0xFFFFFF)
+#define getExpansionOffset(CE) (((CE)&0x00FFFFF0)>>4)
+#define getExpansionCount(CE) ((CE)&0xF)
+#define isCEIgnorable(CE) (((CE) & 0xFFFFFFBF) == 0)
+
+/* StringSearch internal use */
+#define inNormBuf(coleiter) ((coleiter)->iteratordata_.flags & UCOL_ITER_INNORMBUF)
+#define isFCDPointerNull(coleiter) ((coleiter)->iteratordata_.fcdPosition == NULL)
+#define hasExpansion(coleiter) ((coleiter)->iteratordata_.CEpos != (coleiter)->iteratordata_.CEs)
+#define getExpansionPrefix(coleiter) ((coleiter)->iteratordata_.toReturn - (coleiter)->iteratordata_.CEs)
+#define setExpansionPrefix(coleiter, offset) ((coleiter)->iteratordata_.CEs + offset)
+#define getExpansionSuffix(coleiter) ((coleiter)->iteratordata_.CEpos - (coleiter)->iteratordata_.toReturn)
+#define setExpansionSuffix(coleiter, offset) ((coleiter)->iteratordata_.toReturn = (coleiter)->iteratordata_.CEpos - leftoverces)
+
+/* This is an enum that lists magic special byte values from the fractional UCA */
+/* TODO: all the #defines that refer to special byte values from the UCA should be changed to point here */
+
+enum {
+ UCOL_BYTE_ZERO = 0x00,
+ UCOL_BYTE_LEVEL_SEPARATOR = 0x01,
+ UCOL_BYTE_SORTKEY_GLUE = 0x02,
+ UCOL_BYTE_SHIFT_PREFIX = 0x03,
+ UCOL_BYTE_UNSHIFTED_MIN = UCOL_BYTE_SHIFT_PREFIX,
+ UCOL_BYTE_FIRST_TAILORED = 0x04,
+ UCOL_BYTE_COMMON = 0x05,
+ UCOL_BYTE_FIRST_UCA = UCOL_BYTE_COMMON,
+ UCOL_CODAN_PLACEHOLDER = 0x27,
+ UCOL_BYTE_LAST_LATIN_PRIMARY = 0x4C,
+ UCOL_BYTE_FIRST_NON_LATIN_PRIMARY = 0x4D,
+ UCOL_BYTE_UNSHIFTED_MAX = 0xFF
+};
+
+#if 0
+#define UCOL_RESET_TOP_VALUE 0x9F000303
+#define UCOL_FIRST_PRIMARY_IGNORABLE 0x00008705
+#define UCOL_LAST_PRIMARY_IGNORABLE 0x0000DD05
+#define UCOL_LAST_PRIMARY_IGNORABLE_CONT 0x000051C0
+#define UCOL_FIRST_SECONDARY_IGNORABLE 0x00000000
+#define UCOL_LAST_SECONDARY_IGNORABLE 0x00000500
+#define UCOL_FIRST_TERTIARY_IGNORABLE 0x00000000
+#define UCOL_LAST_TERTIARY_IGNORABLE 0x00000000
+#define UCOL_FIRST_VARIABLE 0x05070505
+#define UCOL_LAST_VARIABLE 0x179B0505
+#define UCOL_FIRST_NON_VARIABLE 0x1A200505
+#define UCOL_LAST_NON_VARIABLE 0x7B41058F
+
+#define UCOL_NEXT_TOP_VALUE 0xE8960303
+#define UCOL_NEXT_FIRST_PRIMARY_IGNORABLE 0x00008905
+#define UCOL_NEXT_LAST_PRIMARY_IGNORABLE 0x03000303
+#define UCOL_NEXT_FIRST_SECONDARY_IGNORABLE 0x00008705
+#define UCOL_NEXT_LAST_SECONDARY_IGNORABLE 0x00000500
+#define UCOL_NEXT_FIRST_TERTIARY_IGNORABLE 0x00000000
+#define UCOL_NEXT_LAST_TERTIARY_IGNORABLE 0x00000000
+#define UCOL_NEXT_FIRST_VARIABLE 0x05090505
+#define UCOL_NEXT_LAST_VARIABLE 0x1A200505
+
+#define PRIMARY_IMPLICIT_MIN 0xE8000000
+#define PRIMARY_IMPLICIT_MAX 0xF0000000
+#endif
+
+/* These constants can be changed - sortkey size is affected by them */
+#define UCOL_PROPORTION2 0.5
+#define UCOL_PROPORTION3 0.667
+
+/* These values come from the UCA */
+#define UCOL_COMMON_BOT2 UCOL_BYTE_COMMON
+#define UCOL_COMMON_TOP2 0x86u
+#define UCOL_TOTAL2 (UCOL_COMMON_TOP2-UCOL_COMMON_BOT2-1)
+
+#define UCOL_FLAG_BIT_MASK_CASE_SW_OFF 0x80
+#define UCOL_FLAG_BIT_MASK_CASE_SW_ON 0x40
+#define UCOL_COMMON_TOP3_CASE_SW_OFF 0x85
+#define UCOL_COMMON_TOP3_CASE_SW_LOWER 0x45
+#define UCOL_COMMON_TOP3_CASE_SW_UPPER 0xC5
+
+/* These values come from the UCA */
+#define UCOL_COMMON_BOT3 0x05
+
+#define UCOL_COMMON_BOTTOM3_CASE_SW_UPPER 0x86;
+#define UCOL_COMMON_BOTTOM3_CASE_SW_LOWER UCOL_COMMON_BOT3;
+
+#define UCOL_TOP_COUNT2 (UCOL_PROPORTION2*UCOL_TOTAL2)
+#define UCOL_BOT_COUNT2 (UCOL_TOTAL2-UCOL_TOP_COUNT2)
+
+
+#define UCOL_COMMON2 UCOL_COMMON_BOT2
+#define UCOL_COMMON3_UPPERFIRST 0xC5
+#define UCOL_COMMON3_NORMAL UCOL_COMMON_BOT3
+
+#define UCOL_COMMON4 0xFF
+
+/* constants for case level/case first handling */
+/* used to instantiate UCollators fields in ucol_updateInternalState */
+#define UCOL_CASE_SWITCH 0xC0
+#define UCOL_NO_CASE_SWITCH 0x00
+
+#define UCOL_REMOVE_CASE 0x3F
+#define UCOL_KEEP_CASE 0xFF
+
+#define UCOL_CASE_BIT_MASK 0xC0
+
+#define UCOL_TERT_CASE_MASK 0xFF
+
+#define UCOL_ENDOFLATINONERANGE 0xFF
+#define UCOL_LATINONETABLELEN (UCOL_ENDOFLATINONERANGE+50)
+#define UCOL_BAIL_OUT_CE 0xFF000000
+
+
+typedef enum {
+ NOT_FOUND_TAG = 0,
+ EXPANSION_TAG = 1, /* This code point results in an expansion */
+ CONTRACTION_TAG = 2, /* Start of a contraction */
+ THAI_TAG = 3, /* Thai character - do the reordering */
+ CHARSET_TAG = 4, /* Charset processing, not yet implemented */
+ SURROGATE_TAG = 5, /* Lead surrogate that is tailored and doesn't start a contraction */
+ HANGUL_SYLLABLE_TAG = 6, /* AC00-D7AF*/
+ LEAD_SURROGATE_TAG = 7, /* D800-DBFF*/
+ TRAIL_SURROGATE_TAG = 8, /* DC00-DFFF*/
+ CJK_IMPLICIT_TAG = 9, /* 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D*/
+ IMPLICIT_TAG = 10,
+ SPEC_PROC_TAG = 11,
+ /* ICU 2.1 */
+ LONG_PRIMARY_TAG = 12, /* This is a three byte primary with starting secondaries and tertiaries */
+ /* It fits in a single 32 bit CE and is used instead of expansion to save */
+ /* space without affecting the performance (hopefully) */
+
+ DIGIT_TAG = 13, /* COllate Digits As Numbers (CODAN) implementation */
+
+ CE_TAGS_COUNT
+} UColCETags;
+
+/*
+ *****************************************************************************************
+ * set to zero
+ * NON_CHARACTER FDD0 - FDEF, FFFE, FFFF, 1FFFE, 1FFFF, 2FFFE, 2FFFF,...e.g. **FFFE, **FFFF
+ ******************************************************************************************
+ */
+
+typedef struct {
+ uint32_t variableTopValue;
+ /*UColAttributeValue*/ int32_t frenchCollation;
+ /*UColAttributeValue*/ int32_t alternateHandling; /* attribute for handling variable elements*/
+ /*UColAttributeValue*/ int32_t caseFirst; /* who goes first, lower case or uppercase */
+ /*UColAttributeValue*/ int32_t caseLevel; /* do we have an extra case level */
+ /*UColAttributeValue*/ int32_t normalizationMode; /* attribute for normalization */
+ /*UColAttributeValue*/ int32_t strength; /* attribute for strength */
+ /*UColAttributeValue*/ int32_t hiraganaQ; /* attribute for special Hiragana */
+ /*UColAttributeValue*/ int32_t numericCollation; /* attribute for numeric collation */
+ uint32_t reserved[15]; /* for future use */
+} UColOptionSet;
+
+typedef struct {
+ uint32_t UCA_FIRST_TERTIARY_IGNORABLE[2]; /*0x00000000*/
+ uint32_t UCA_LAST_TERTIARY_IGNORABLE[2]; /*0x00000000*/
+ uint32_t UCA_FIRST_PRIMARY_IGNORABLE[2]; /*0x00008705*/
+ uint32_t UCA_FIRST_SECONDARY_IGNORABLE[2]; /*0x00000000*/
+ uint32_t UCA_LAST_SECONDARY_IGNORABLE[2]; /*0x00000500*/
+ uint32_t UCA_LAST_PRIMARY_IGNORABLE[2]; /*0x0000DD05*/
+ uint32_t UCA_FIRST_VARIABLE[2]; /*0x05070505*/
+ uint32_t UCA_LAST_VARIABLE[2]; /*0x13CF0505*/
+ uint32_t UCA_FIRST_NON_VARIABLE[2]; /*0x16200505*/
+ uint32_t UCA_LAST_NON_VARIABLE[2]; /*0x767C0505*/
+ uint32_t UCA_RESET_TOP_VALUE[2]; /*0x9F000303*/
+ uint32_t UCA_FIRST_IMPLICIT[2];
+ uint32_t UCA_LAST_IMPLICIT[2];
+ uint32_t UCA_FIRST_TRAILING[2];
+ uint32_t UCA_LAST_TRAILING[2];
+
+#if 0
+ uint32_t UCA_NEXT_TOP_VALUE[2]; /*0xE8960303*/
+ uint32_t UCA_NEXT_FIRST_PRIMARY_IGNORABLE; /*0x00008905*/
+ uint32_t UCA_NEXT_LAST_PRIMARY_IGNORABLE; /*0x03000303*/
+ uint32_t UCA_NEXT_FIRST_SECONDARY_IGNORABLE; /*0x00008705*/
+ uint32_t UCA_NEXT_LAST_SECONDARY_IGNORABLE; /*0x00000500*/
+ uint32_t UCA_NEXT_FIRST_TERTIARY_IGNORABLE; /*0x00000000*/
+ uint32_t UCA_NEXT_LAST_TERTIARY_IGNORABLE; /*0x00000000*/
+ uint32_t UCA_NEXT_FIRST_VARIABLE; /*0x05090505*/
+ uint32_t UCA_NEXT_LAST_VARIABLE; /*0x16200505*/
+#endif
+
+ uint32_t UCA_PRIMARY_TOP_MIN;
+ uint32_t UCA_PRIMARY_IMPLICIT_MIN; /*0xE8000000*/
+ uint32_t UCA_PRIMARY_IMPLICIT_MAX; /*0xF0000000*/
+ uint32_t UCA_PRIMARY_TRAILING_MIN; /*0xE8000000*/
+ uint32_t UCA_PRIMARY_TRAILING_MAX; /*0xF0000000*/
+ uint32_t UCA_PRIMARY_SPECIAL_MIN; /*0xE8000000*/
+ uint32_t UCA_PRIMARY_SPECIAL_MAX; /*0xF0000000*/
+} UCAConstants;
+
+typedef struct {
+ int32_t size;
+ /* all the offsets are in bytes */
+ /* to get the address add to the header address and cast properly */
+ uint32_t options; /* these are the default options for the collator */
+ uint32_t UCAConsts; /* structure which holds values for indirect positioning and implicit ranges */
+ uint32_t contractionUCACombos; /* this one is needed only for UCA, to copy the appropriate contractions */
+ uint32_t magic; /* magic number - lets us know whether reserved data is reset or junked */
+ uint32_t mappingPosition; /* const uint8_t *mappingPosition; */
+ uint32_t expansion; /* uint32_t *expansion; */
+ uint32_t contractionIndex; /* UChar *contractionIndex; */
+ uint32_t contractionCEs; /* uint32_t *contractionCEs; */
+ uint32_t contractionSize; /* needed for various closures */
+ /*int32_t latinOneMapping;*/ /* this is now handled in the trie itself *//* fast track to latin1 chars */
+
+ uint32_t endExpansionCE; /* array of last collation element in
+ expansion */
+ uint32_t expansionCESize; /* array of maximum expansion size
+ corresponding to the expansion
+ collation elements with last element
+ in endExpansionCE*/
+ int32_t endExpansionCECount; /* size of endExpansionCE */
+ uint32_t unsafeCP; /* hash table of unsafe code points */
+ uint32_t contrEndCP; /* hash table of final code points */
+ /* in contractions. */
+
+ int32_t contractionUCACombosSize; /* number of UCA contraction items. */
+ /*Length is contractionUCACombosSize*contractionUCACombosWidth*sizeof(UChar) */
+ UBool jamoSpecial; /* is jamoSpecial */
+ UBool isBigEndian; /* is this data big endian? from the UDataInfo header*/
+ uint8_t charSetFamily; /* what is the charset family of this data from the UDataInfo header*/
+ uint8_t contractionUCACombosWidth; /* width of UCA combos field */
+ UVersionInfo version;
+ UVersionInfo UCAVersion; /* version of the UCA, read from file */
+ UVersionInfo UCDVersion; /* UCD version, obtained by u_getUnicodeVersion */
+ UVersionInfo formatVersion; /* format version from the UDataInfo header */
+ uint8_t reserved[84]; /* for future use */
+} UCATableHeader;
+
+#define U_UNKNOWN_STATE 0
+#define U_COLLATOR_STATE 0x01
+#define U_STATE_LIMIT 0x02
+
+/* This is the first structure in a state */
+/* it should be machine independent */
+typedef struct {
+ /* this structure is supposed to be readable on all the platforms.*/
+ /* first 2 fields hold the size of the structure in a platform independent way */
+ uint8_t sizeLo;
+ uint8_t sizeHi;
+ /* identifying the writing platform */
+ uint8_t isBigEndian;
+ /* see U_CHARSET_FAMILY values in utypes.h */
+ uint8_t charsetFamily;
+ /* version of ICU this state structure comes from */
+ uint8_t icuVersion[4];
+ /* What is the data following this state */
+ uint8_t type;
+ /* more stuff to come, keep it on 16 byte boundary */
+ uint8_t reserved[7];
+} UStateStruct;
+
+/* This structure follows UStatusStruct */
+/* and contains data specific for the collators */
+/* Endianess needs to be decided before accessing this structure */
+/* However, it's size IS endianess independent */
+typedef struct {
+ /* size of this structure */
+ uint8_t sizeLo;
+ uint8_t sizeHi;
+ /* This state is followed by the frozen tailoring */
+ uint8_t containsTailoring;
+ /* This state is followed by the frozen UCA */
+ uint8_t containsUCA;
+ /* Version info - the same one */
+ uint8_t versionInfo[4];
+
+ /* for charset CEs */
+ uint8_t charsetName[32];
+ /* this is the resolved locale name*/
+ uint8_t locale[32];
+
+ /* Attributes. Open ended */
+ /* all the following will be moved to uint32_t because of portability */
+ /* variable top value */
+ uint32_t variableTopValue;
+ /* attribute for handling variable elements*/
+ uint32_t /*UColAttributeValue*/ alternateHandling;
+ /* how to handle secondary weights */
+ uint32_t /*UColAttributeValue*/ frenchCollation;
+ /* who goes first, lower case or uppercase */
+ uint32_t /*UColAttributeValue*/ caseFirst;
+ /* do we have an extra case level */
+ uint32_t /*UColAttributeValue*/ caseLevel;
+ /* attribute for normalization */
+ uint32_t /*UColAttributeValue*/ normalizationMode;
+ /* attribute for strength */
+ uint32_t /*UColAttributeValue*/ strength;
+ /* to be immediately 16 byte aligned */
+ uint8_t reserved[12];
+} UColStateStruct;
+
+#define UCOL_INV_SIZEMASK 0xFFF00000
+#define UCOL_INV_OFFSETMASK 0x000FFFFF
+#define UCOL_INV_SHIFTVALUE 20
+
+U_CDECL_BEGIN
+
+typedef struct {
+ uint32_t byteSize;
+ uint32_t tableSize;
+ uint32_t contsSize;
+ uint32_t table;
+ uint32_t conts;
+ UVersionInfo UCAVersion; /* version of the UCA, read from file */
+ uint8_t padding[8];
+} InverseUCATableHeader;
+
+typedef int32_t U_CALLCONV
+SortKeyGenerator(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t **result,
+ uint32_t resultLength,
+ UBool allocatePrimary,
+ UErrorCode *status);
+
+typedef void U_CALLCONV
+ResourceCleaner(UCollator *coll);
+
+
+struct UCollator {
+ UColOptionSet *options;
+ SortKeyGenerator *sortKeyGen;
+ uint32_t *latinOneCEs;
+ char* validLocale;
+ char* requestedLocale;
+ const UChar *rules;
+ const UCollator *UCA;
+ ResourceCleaner *resCleaner;
+ UResourceBundle *rb;
+ UResourceBundle *elements;
+ const UCATableHeader *image;
+ UTrie mapping;
+ const uint32_t *latinOneMapping;
+ const uint32_t *expansion;
+ const UChar *contractionIndex;
+ const uint32_t *contractionCEs;
+ /*const uint8_t *scriptOrder;*/
+
+ const uint32_t *endExpansionCE; /* array of last ces in an expansion ce.
+ corresponds to expansionCESize */
+ const uint32_t *lastEndExpansionCE;/* pointer to the last element in endExpansionCE */
+ const uint8_t *expansionCESize; /* array of the maximum size of a
+ expansion ce with the last ce
+ corresponding to endExpansionCE,
+ terminated with a null */
+ const uint8_t *unsafeCP; /* unsafe code points hashtable */
+ const uint8_t *contrEndCP; /* Contraction ending chars hash table */
+ UChar minUnsafeCP; /* Smallest unsafe Code Point. */
+ UChar minContrEndCP; /* Smallest code point at end of a contraction */
+
+ int32_t rulesLength;
+ int32_t latinOneTableLen;
+
+ uint32_t variableTopValue;
+ UColAttributeValue frenchCollation;
+ UColAttributeValue alternateHandling; /* attribute for handling variable elements*/
+ UColAttributeValue caseFirst; /* who goes first, lower case or uppercase */
+ UColAttributeValue caseLevel; /* do we have an extra case level */
+ UColAttributeValue normalizationMode; /* attribute for normalization */
+ UColAttributeValue strength; /* attribute for strength */
+ UColAttributeValue hiraganaQ; /* attribute for Hiragana */
+ UColAttributeValue numericCollation;
+ UBool variableTopValueisDefault;
+ UBool frenchCollationisDefault;
+ UBool alternateHandlingisDefault; /* attribute for handling variable elements*/
+ UBool caseFirstisDefault; /* who goes first, lower case or uppercase */
+ UBool caseLevelisDefault; /* do we have an extra case level */
+ UBool normalizationModeisDefault; /* attribute for normalization */
+ UBool strengthisDefault; /* attribute for strength */
+ UBool hiraganaQisDefault; /* attribute for Hiragana */
+ UBool numericCollationisDefault;
+ UBool hasRealData; /* some collators have only options, like French, no rules */
+ /* to speed up things, we use the UCA image, but we don't want it */
+ /* to run around */
+
+ UBool freeOnClose;
+ UBool freeOptionsOnClose;
+ UBool freeRulesOnClose;
+ UBool freeImageOnClose;
+
+ UBool latinOneUse;
+ UBool latinOneRegenTable;
+ UBool latinOneFailed;
+
+ int32_t tertiaryAddition; /* when switching case, we need to add or subtract different values */
+ uint8_t caseSwitch;
+ uint8_t tertiaryCommon;
+ uint8_t tertiaryMask;
+ uint8_t tertiaryTop; /* Upper range when compressing */
+ uint8_t tertiaryBottom; /* Upper range when compressing */
+ uint8_t tertiaryTopCount;
+ uint8_t tertiaryBottomCount;
+
+ UVersionInfo dataVersion; /* Data info of UCA table */
+};
+
+U_CDECL_END
+
+/* various internal functions */
+
+/* do not close UCA returned by ucol_initUCA! */
+U_CFUNC
+UCollator* ucol_initUCA(UErrorCode *status);
+
+U_CFUNC
+UCollator* ucol_initCollator(const UCATableHeader *image, UCollator *fillIn, const UCollator *UCA, UErrorCode *status);
+
+U_CFUNC
+void ucol_setOptionsFromHeader(UCollator* result, UColOptionSet * opts, UErrorCode *status);
+
+U_CFUNC
+UCollator* ucol_open_internal(const char* loc, UErrorCode* status);
+
+#if 0
+U_CFUNC
+void ucol_putOptionsToHeader(UCollator* result, UColOptionSet * opts, UErrorCode *status);
+#endif
+
+U_CFUNC
+void ucol_updateInternalState(UCollator *coll, UErrorCode *status);
+
+U_CFUNC uint32_t U_EXPORT2 ucol_getFirstCE(const UCollator *coll, UChar u, UErrorCode *status);
+U_CAPI UBool U_EXPORT2 ucol_isTailored(const UCollator *coll, const UChar u, UErrorCode *status);
+
+U_CAPI const InverseUCATableHeader* U_EXPORT2 ucol_initInverseUCA(UErrorCode *status);
+
+U_CAPI void U_EXPORT2
+uprv_uca_initImplicitConstants(int32_t minPrimary, int32_t maxPrimary, UErrorCode *status);
+
+U_CAPI uint32_t U_EXPORT2
+uprv_uca_getImplicitFromRaw(UChar32 cp);
+
+/*U_CFUNC uint32_t U_EXPORT2
+uprv_uca_getImplicitPrimary(UChar32 cp);*/
+
+U_CAPI UChar32 U_EXPORT2
+uprv_uca_getRawFromImplicit(uint32_t implicit);
+
+U_CAPI UChar32 U_EXPORT2
+uprv_uca_getRawFromCodePoint(UChar32 i);
+
+U_CAPI UChar32 U_EXPORT2
+uprv_uca_getCodePointFromRaw(UChar32 i);
+
+
+
+#ifdef XP_CPLUSPLUS
+/*
+ * Test whether a character is potentially "unsafe" for use as a collation
+ * starting point. Unsafe chars are those with combining class != 0 plus
+ * those that are the 2nd thru nth character in a contraction sequence.
+ *
+ * Function is in header file because it's used in both collation and string search,
+ * and needs to be inline for performance.
+ */
+static inline UBool ucol_unsafeCP(UChar c, const UCollator *coll) {
+ int32_t hash;
+ uint8_t htbyte;
+
+ if (c < coll->minUnsafeCP) {
+ return FALSE;
+ }
+
+ hash = c;
+ if (hash >= UCOL_UNSAFECP_TABLE_SIZE*8) {
+ if(UTF_IS_LEAD(c) || UTF_IS_TRAIL(c)) {
+ /* Trail surrogate */
+ /* These are always considered unsafe. */
+ return TRUE;
+ }
+ hash = (hash & UCOL_UNSAFECP_TABLE_MASK) + 256;
+ }
+ htbyte = coll->unsafeCP[hash>>3];
+ return (((htbyte >> (hash & 7)) & 1) == 1);
+}
+#endif /* XP_CPLUSPLUS */
+
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_res.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucol_res.cpp
new file mode 100644
index 00000000000..e8cde356348
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_res.cpp
@@ -0,0 +1,737 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: ucol_res.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Description:
+* This file contains dependencies that the collation run-time doesn't normally
+* need. This mainly contains resource bundle usage and collation meta information
+*
+* Modification history
+* Date Name Comments
+* 1996-1999 various members of ICU team maintained C API for collation framework
+* 02/16/2001 synwee Added internal method getPrevSpecialCE
+* 03/01/2001 synwee Added maxexpansion functionality.
+* 03/16/2001 weiv Collation framework is rewritten in C and made UCA compliant
+* 12/08/2004 grhoten Split part of ucol.cpp into ucol_res.cpp
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+#include "unicode/uloc.h"
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/caniter.h"
+#include "unicode/ustring.h"
+
+#include "ucol_bld.h"
+#include "ucol_imp.h"
+#include "ucol_tok.h"
+#include "ucol_elm.h"
+#include "uresimp.h"
+#include "ustr_imp.h"
+#include "cstring.h"
+#include "umutex.h"
+#include "ustrenum.h"
+#include "putilimp.h"
+#include "utracimp.h"
+#include "cmemory.h"
+
+U_NAMESPACE_USE
+
+U_CDECL_BEGIN
+static void U_CALLCONV
+ucol_prv_closeResources(UCollator *coll) {
+ if(coll->rb != NULL) { /* pointing to read-only memory */
+ ures_close(coll->rb);
+ }
+ if(coll->elements != NULL) {
+ ures_close(coll->elements);
+ }
+}
+U_CDECL_END
+
+/****************************************************************************/
+/* Following are the open/close functions */
+/* */
+/****************************************************************************/
+static UCollator*
+tryOpeningFromRules(UResourceBundle *collElem, UErrorCode *status) {
+ int32_t rulesLen = 0;
+ const UChar *rules = ures_getStringByKey(collElem, "Sequence", &rulesLen, status);
+ return ucol_openRules(rules, rulesLen, UCOL_DEFAULT, UCOL_DEFAULT, NULL, status);
+
+}
+
+
+// API in ucol_imp.h
+
+U_CFUNC UCollator*
+ucol_open_internal(const char *loc,
+ UErrorCode *status)
+{
+ const UCollator* UCA = ucol_initUCA(status);
+
+ /* New version */
+ if(U_FAILURE(*status)) return 0;
+
+
+
+ UCollator *result = NULL;
+ UResourceBundle *b = ures_open(U_ICUDATA_COLL, loc, status);
+
+ /* we try to find stuff from keyword */
+ UResourceBundle *collations = ures_getByKey(b, "collations", NULL, status);
+ UResourceBundle *collElem = NULL;
+ char keyBuffer[256];
+ // if there is a keyword, we pick it up and try to get elements
+ if(!uloc_getKeywordValue(loc, "collation", keyBuffer, 256, status)) {
+ // no keyword. we try to find the default setting, which will give us the keyword value
+ UErrorCode intStatus = U_ZERO_ERROR;
+ // finding default value does not affect collation fallback status
+ UResourceBundle *defaultColl = ures_getByKeyWithFallback(collations, "default", NULL, &intStatus);
+ if(U_SUCCESS(intStatus)) {
+ int32_t defaultKeyLen = 0;
+ const UChar *defaultKey = ures_getString(defaultColl, &defaultKeyLen, &intStatus);
+ u_UCharsToChars(defaultKey, keyBuffer, defaultKeyLen);
+ keyBuffer[defaultKeyLen] = 0;
+ } else {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ return NULL;
+ }
+ ures_close(defaultColl);
+ }
+ collElem = ures_getByKeyWithFallback(collations, keyBuffer, collElem, status);
+
+ UResourceBundle *binary = NULL;
+
+ if(*status == U_MISSING_RESOURCE_ERROR) { /* We didn't find the tailoring data, we fallback to the UCA */
+ *status = U_USING_DEFAULT_WARNING;
+ result = ucol_initCollator(UCA->image, result, UCA, status);
+ // if we use UCA, real locale is root
+ result->rb = ures_open(U_ICUDATA_COLL, "", status);
+ result->elements = ures_open(U_ICUDATA_COLL, "", status);
+ if(U_FAILURE(*status)) {
+ goto clean;
+ }
+ ures_close(b);
+ result->hasRealData = FALSE;
+ } else if(U_SUCCESS(*status)) {
+ int32_t len = 0;
+ UErrorCode binaryStatus = U_ZERO_ERROR;
+
+ binary = ures_getByKey(collElem, "%%CollationBin", NULL, &binaryStatus);
+
+ if(binaryStatus == U_MISSING_RESOURCE_ERROR) { /* we didn't find the binary image, we should use the rules */
+ binary = NULL;
+ result = tryOpeningFromRules(collElem, status);
+ if(U_FAILURE(*status)) {
+ goto clean;
+ }
+ } else if(U_SUCCESS(*status)) { /* otherwise, we'll pick a collation data that exists */
+ const uint8_t *inData = ures_getBinary(binary, &len, status);
+ UCATableHeader *colData = (UCATableHeader *)inData;
+ if(uprv_memcmp(colData->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0 ||
+ uprv_memcmp(colData->UCDVersion, UCA->image->UCDVersion, sizeof(UVersionInfo)) != 0 ||
+ colData->version[0] != UCOL_BUILDER_VERSION)
+ {
+ *status = U_DIFFERENT_UCA_VERSION;
+ result = tryOpeningFromRules(collElem, status);
+ } else {
+ if(U_FAILURE(*status)){
+ goto clean;
+ }
+ if((uint32_t)len > (paddedsize(sizeof(UCATableHeader)) + paddedsize(sizeof(UColOptionSet)))) {
+ result = ucol_initCollator((const UCATableHeader *)inData, result, UCA, status);
+ if(U_FAILURE(*status)){
+ goto clean;
+ }
+ result->hasRealData = TRUE;
+ } else {
+ result = ucol_initCollator(UCA->image, result, UCA, status);
+ ucol_setOptionsFromHeader(result, (UColOptionSet *)(inData+((const UCATableHeader *)inData)->options), status);
+ if(U_FAILURE(*status)){
+ goto clean;
+ }
+ result->hasRealData = FALSE;
+ }
+ result->freeImageOnClose = FALSE;
+ }
+ }
+ result->rb = b;
+ result->elements = collElem;
+ len = 0;
+ binaryStatus = U_ZERO_ERROR;
+ result->rules = ures_getStringByKey(result->elements, "Sequence", &len, &binaryStatus);
+ result->rulesLength = len;
+ result->freeRulesOnClose = FALSE;
+ } else { /* There is another error, and we're just gonna clean up */
+ goto clean;
+ }
+
+ result->validLocale = NULL; // default is to use rb info
+
+ if(loc == NULL) {
+ loc = ures_getLocale(result->rb, status);
+ }
+ result->requestedLocale = (char *)uprv_malloc((uprv_strlen(loc)+1)*sizeof(char));
+ /* test for NULL */
+ if (result->requestedLocale == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto clean;
+ }
+ uprv_strcpy(result->requestedLocale, loc);
+
+ ures_close(binary);
+ ures_close(collations); //??? we have to decide on that. Probably affects something :)
+ result->resCleaner = ucol_prv_closeResources;
+ return result;
+
+clean:
+ ures_close(b);
+ ures_close(collElem);
+ ures_close(collations);
+ ures_close(binary);
+ return NULL;
+}
+
+U_CAPI UCollator*
+ucol_open(const char *loc,
+ UErrorCode *status)
+{
+ U_NAMESPACE_USE
+
+ UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN);
+ UTRACE_DATA1(UTRACE_INFO, "locale = \"%s\"", loc);
+ UCollator *result = NULL;
+
+ u_init(status);
+#if !UCONFIG_NO_SERVICE
+ result = Collator::createUCollator(loc, status);
+ if (result == NULL)
+#endif
+ {
+ result = ucol_open_internal(loc, status);
+ }
+ UTRACE_EXIT_PTR_STATUS(result, *status);
+ return result;
+}
+
+U_CAPI UCollator* U_EXPORT2
+ucol_openRules( const UChar *rules,
+ int32_t rulesLength,
+ UColAttributeValue normalizationMode,
+ UCollationStrength strength,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+ UColTokenParser src;
+ UColAttributeValue norm;
+ UParseError tErr;
+
+ if(status == NULL || U_FAILURE(*status)){
+ return 0;
+ }
+
+ u_init(status);
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ if(rules == NULL || rulesLength < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ if(rulesLength == -1) {
+ rulesLength = u_strlen(rules);
+ }
+
+ if(parseError == NULL){
+ parseError = &tErr;
+ }
+
+ switch(normalizationMode) {
+ case UCOL_OFF:
+ case UCOL_ON:
+ case UCOL_DEFAULT:
+ norm = normalizationMode;
+ break;
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UCollator *UCA = ucol_initUCA(status);
+
+ if(U_FAILURE(*status)){
+ return NULL;
+ }
+
+ ucol_tok_initTokenList(&src, rules, rulesLength, UCA, status);
+ ucol_tok_assembleTokenList(&src,parseError, status);
+
+ if(U_FAILURE(*status)) {
+ /* if status is U_ILLEGAL_ARGUMENT_ERROR, src->current points at the offending option */
+ /* if status is U_INVALID_FORMAT_ERROR, src->current points after the problematic part of the rules */
+ /* so something might be done here... or on lower level */
+#ifdef UCOL_DEBUG
+ if(*status == U_ILLEGAL_ARGUMENT_ERROR) {
+ fprintf(stderr, "bad option starting at offset %i\n", src.current-src.source);
+ } else {
+ fprintf(stderr, "invalid rule just before offset %i\n", src.current-src.source);
+ }
+#endif
+ ucol_tok_closeTokenList(&src);
+ return NULL;
+ }
+ UCollator *result = NULL;
+ UCATableHeader *table = NULL;
+
+ if(src.resultLen > 0 || src.removeSet != NULL) { /* we have a set of rules, let's make something of it */
+ /* also, if we wanted to remove some contractions, we should make a tailoring */
+ table = ucol_assembleTailoringTable(&src, status);
+ if(U_SUCCESS(*status)) {
+ // builder version
+ table->version[0] = UCOL_BUILDER_VERSION;
+ // no tailoring information on this level
+ table->version[1] = table->version[2] = table->version[3] = 0;
+ // set UCD version
+ u_getUnicodeVersion(table->UCDVersion);
+ // set UCA version
+ uprv_memcpy(table->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo));
+ result = ucol_initCollator(table, 0, UCA, status);
+ result->hasRealData = TRUE;
+ result->freeImageOnClose = TRUE;
+ }
+ } else { /* no rules, but no error either */
+ // must be only options
+ // We will init the collator from UCA
+ result = ucol_initCollator(UCA->image, 0, UCA, status);
+ // And set only the options
+ UColOptionSet *opts = (UColOptionSet *)uprv_malloc(sizeof(UColOptionSet));
+ /* test for NULL */
+ if (opts == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ uprv_memcpy(opts, src.opts, sizeof(UColOptionSet));
+ ucol_setOptionsFromHeader(result, opts, status);
+ result->freeOptionsOnClose = TRUE;
+ result->hasRealData = FALSE;
+ result->freeImageOnClose = FALSE;
+ }
+
+ if(U_SUCCESS(*status)) {
+ UChar *newRules;
+ result->dataVersion[0] = UCOL_BUILDER_VERSION;
+ if(rulesLength > 0) {
+ newRules = (UChar *)uprv_malloc((rulesLength+1)*U_SIZEOF_UCHAR);
+ /* test for NULL */
+ if (newRules == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto cleanup;
+ }
+ uprv_memcpy(newRules, rules, rulesLength*U_SIZEOF_UCHAR);
+ newRules[rulesLength]=0;
+ result->rules = newRules;
+ result->rulesLength = rulesLength;
+ result->freeRulesOnClose = TRUE;
+ }
+ result->rb = NULL;
+ result->elements = NULL;
+ result->validLocale = NULL;
+ result->requestedLocale = NULL;
+ ucol_setAttribute(result, UCOL_STRENGTH, strength, status);
+ ucol_setAttribute(result, UCOL_NORMALIZATION_MODE, norm, status);
+ } else {
+cleanup:
+ if(result != NULL) {
+ ucol_close(result);
+ } else {
+ if(table != NULL) {
+ uprv_free(table);
+ }
+ }
+ result = NULL;
+ }
+
+ ucol_tok_closeTokenList(&src);
+
+ return result;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_getRulesEx(const UCollator *coll, UColRuleOption delta, UChar *buffer, int32_t bufferLen) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len = 0;
+ int32_t UCAlen = 0;
+ const UChar* ucaRules = 0;
+ const UChar *rules = ucol_getRules(coll, &len);
+ if(delta == UCOL_FULL_RULES) {
+ /* take the UCA rules and append real rules at the end */
+ /* UCA rules will be probably coming from the root RB */
+ ucaRules = ures_getStringByKey(coll->rb,"UCARules",&UCAlen,&status);
+ /*
+ UResourceBundle* cresb = ures_getByKeyWithFallback(coll->rb, "collations", NULL, &status);
+ UResourceBundle* uca = ures_getByKeyWithFallback(cresb, "UCA", NULL, &status);
+ ucaRules = ures_getStringByKey(uca,"Sequence",&UCAlen,&status);
+ ures_close(uca);
+ ures_close(cresb);
+ */
+ }
+ if(U_FAILURE(status)) {
+ return 0;
+ }
+ if(buffer!=0 && bufferLen>0){
+ *buffer=0;
+ if(UCAlen > 0) {
+ u_memcpy(buffer, ucaRules, uprv_min(UCAlen, bufferLen));
+ }
+ if(len > 0 && bufferLen > UCAlen) {
+ u_memcpy(buffer+UCAlen, rules, uprv_min(len, bufferLen-UCAlen));
+ }
+ }
+ return u_terminateUChars(buffer, bufferLen, len+UCAlen, &status);
+}
+
+static const UChar _NUL = 0;
+
+U_CAPI const UChar* U_EXPORT2
+ucol_getRules( const UCollator *coll,
+ int32_t *length)
+{
+ if(coll->rules != NULL) {
+ *length = coll->rulesLength;
+ return coll->rules;
+ }
+ else {
+ *length = 0;
+ return &_NUL;
+ }
+}
+
+U_CAPI UBool U_EXPORT2
+ucol_equals(const UCollator *source, const UCollator *target) {
+ UErrorCode status = U_ZERO_ERROR;
+ // if pointers are equal, collators are equal
+ if(source == target) {
+ return TRUE;
+ }
+ int32_t i = 0, j = 0;
+ // if any of attributes are different, collators are not equal
+ for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
+ if(ucol_getAttribute(source, (UColAttribute)i, &status) != ucol_getAttribute(target, (UColAttribute)i, &status) || U_FAILURE(status)) {
+ return FALSE;
+ }
+ }
+
+ int32_t sourceRulesLen = 0, targetRulesLen = 0;
+ const UChar *sourceRules = ucol_getRules(source, &sourceRulesLen);
+ const UChar *targetRules = ucol_getRules(target, &targetRulesLen);
+
+ if(sourceRulesLen == targetRulesLen && u_strncmp(sourceRules, targetRules, sourceRulesLen) == 0) {
+ // all the attributes are equal and the rules are equal - collators are equal
+ return(TRUE);
+ }
+ // hard part, need to construct tree from rules and see if they yield the same tailoring
+ UBool result = TRUE;
+ UParseError parseError;
+ UColTokenParser sourceParser, targetParser;
+ int32_t sourceListLen = 0, targetListLen = 0;
+ ucol_tok_initTokenList(&sourceParser, sourceRules, sourceRulesLen, source->UCA, &status);
+ ucol_tok_initTokenList(&targetParser, targetRules, targetRulesLen, target->UCA, &status);
+ sourceListLen = ucol_tok_assembleTokenList(&sourceParser, &parseError, &status);
+ targetListLen = ucol_tok_assembleTokenList(&targetParser, &parseError, &status);
+
+ if(sourceListLen != targetListLen) {
+ // different number of resets
+ result = FALSE;
+ } else {
+ UColToken *sourceReset = NULL, *targetReset = NULL;
+ UChar *sourceResetString = NULL, *targetResetString = NULL;
+ int32_t sourceStringLen = 0, targetStringLen = 0;
+ for(i = 0; i < sourceListLen; i++) {
+ sourceReset = sourceParser.lh[i].reset;
+ sourceResetString = sourceParser.source+(sourceReset->source & 0xFFFFFF);
+ sourceStringLen = sourceReset->source >> 24;
+ for(j = 0; j < sourceListLen; j++) {
+ targetReset = targetParser.lh[j].reset;
+ targetResetString = targetParser.source+(targetReset->source & 0xFFFFFF);
+ targetStringLen = targetReset->source >> 24;
+ if(sourceStringLen == targetStringLen && (u_strncmp(sourceResetString, targetResetString, sourceStringLen) == 0)) {
+ sourceReset = sourceParser.lh[i].first;
+ targetReset = targetParser.lh[j].first;
+ while(sourceReset != NULL && targetReset != NULL) {
+ sourceResetString = sourceParser.source+(sourceReset->source & 0xFFFFFF);
+ sourceStringLen = sourceReset->source >> 24;
+ targetResetString = targetParser.source+(targetReset->source & 0xFFFFFF);
+ targetStringLen = targetReset->source >> 24;
+ if(sourceStringLen != targetStringLen || (u_strncmp(sourceResetString, targetResetString, sourceStringLen) != 0)) {
+ result = FALSE;
+ goto returnResult;
+ }
+ // probably also need to check the expansions
+ if(sourceReset->expansion) {
+ if(!targetReset->expansion) {
+ result = FALSE;
+ goto returnResult;
+ } else {
+ // compare expansions
+ sourceResetString = sourceParser.source+(sourceReset->expansion& 0xFFFFFF);
+ sourceStringLen = sourceReset->expansion >> 24;
+ targetResetString = targetParser.source+(targetReset->expansion & 0xFFFFFF);
+ targetStringLen = targetReset->expansion >> 24;
+ if(sourceStringLen != targetStringLen || (u_strncmp(sourceResetString, targetResetString, sourceStringLen) != 0)) {
+ result = FALSE;
+ goto returnResult;
+ }
+ }
+ } else {
+ if(targetReset->expansion) {
+ result = FALSE;
+ goto returnResult;
+ }
+ }
+ sourceReset = sourceReset->next;
+ targetReset = targetReset->next;
+ }
+ if(sourceReset != targetReset) { // at least one is not NULL
+ // there are more tailored elements in one list
+ result = FALSE;
+ goto returnResult;
+ }
+
+
+ break;
+ }
+ }
+ // couldn't find the reset anchor, so the collators are not equal
+ if(j == sourceListLen) {
+ result = FALSE;
+ goto returnResult;
+ }
+ }
+ }
+
+returnResult:
+ ucol_tok_closeTokenList(&sourceParser);
+ ucol_tok_closeTokenList(&targetParser);
+ return result;
+
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_getDisplayName( const char *objLoc,
+ const char *dispLoc,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status)
+{
+ U_NAMESPACE_USE
+
+ if(U_FAILURE(*status)) return -1;
+ UnicodeString dst;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ dst.setTo(result, 0, resultLength);
+ }
+ Collator::getDisplayName(Locale(objLoc), Locale(dispLoc), dst);
+ return dst.extract(result, resultLength, *status);
+}
+
+U_CAPI const char* U_EXPORT2
+ucol_getAvailable(int32_t index)
+{
+ int32_t count = 0;
+ const Locale *loc = Collator::getAvailableLocales(count);
+ if (loc != NULL && index < count) {
+ return loc[index].getName();
+ }
+ return NULL;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_countAvailable()
+{
+ int32_t count = 0;
+ Collator::getAvailableLocales(count);
+ return count;
+}
+
+#if !UCONFIG_NO_SERVICE
+U_CAPI UEnumeration* U_EXPORT2
+ucol_openAvailableLocales(UErrorCode *status) {
+ U_NAMESPACE_USE
+
+ // This is a wrapper over Collator::getAvailableLocales()
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ StringEnumeration *s = Collator::getAvailableLocales();
+ if (s == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ return uenum_openStringEnumeration(s, status);
+}
+#endif
+
+// Note: KEYWORDS[0] != RESOURCE_NAME - alan
+
+static const char* RESOURCE_NAME = "collations";
+
+static const char* KEYWORDS[] = { "collation" };
+
+#define KEYWORD_COUNT (sizeof(KEYWORDS)/sizeof(KEYWORDS[0]))
+
+U_CAPI UEnumeration* U_EXPORT2
+ucol_getKeywords(UErrorCode *status) {
+ UEnumeration *result = NULL;
+ if (U_SUCCESS(*status)) {
+ return uenum_openCharStringsEnumeration(KEYWORDS, KEYWORD_COUNT, status);
+ }
+ return result;
+}
+
+U_CAPI UEnumeration* U_EXPORT2
+ucol_getKeywordValues(const char *keyword, UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ // hard-coded to accept exactly one collation keyword
+ // modify if additional collation keyword is added later
+ if (keyword==NULL || uprv_strcmp(keyword, KEYWORDS[0])!=0)
+ {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ return ures_getKeywordValues(U_ICUDATA_COLL, RESOURCE_NAME, status);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_getFunctionalEquivalent(char* result, int32_t resultCapacity,
+ const char* keyword, const char* locale,
+ UBool* isAvailable, UErrorCode* status)
+{
+ // N.B.: Resource name is "collations" but keyword is "collation"
+ return ures_getFunctionalEquivalent(result, resultCapacity, U_ICUDATA_COLL,
+ "collations", keyword, locale,
+ isAvailable, TRUE, status);
+}
+
+/* returns the locale name the collation data comes from */
+U_CAPI const char * U_EXPORT2
+ucol_getLocale(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
+ return ucol_getLocaleByType(coll, type, status);
+}
+
+U_CAPI const char * U_EXPORT2
+ucol_getLocaleByType(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status) {
+ const char *result = NULL;
+ if(status == NULL || U_FAILURE(*status)) {
+ return NULL;
+ }
+ UTRACE_ENTRY(UTRACE_UCOL_GETLOCALE);
+ UTRACE_DATA1(UTRACE_INFO, "coll=%p", coll);
+
+ switch(type) {
+ case ULOC_ACTUAL_LOCALE:
+ // validLocale is set only if service registration has explicitly set the
+ // requested and valid locales. if this is the case, the actual locale
+ // is considered to be the valid locale.
+ if (coll->validLocale != NULL) {
+ result = coll->validLocale;
+ } else if(coll->elements != NULL) {
+ result = ures_getLocale(coll->elements, status);
+ }
+ break;
+ case ULOC_VALID_LOCALE:
+ if (coll->validLocale != NULL) {
+ result = coll->validLocale;
+ } else if(coll->rb != NULL) {
+ result = ures_getLocale(coll->rb, status);
+ }
+ break;
+ case ULOC_REQUESTED_LOCALE:
+ result = coll->requestedLocale;
+ break;
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ UTRACE_DATA1(UTRACE_INFO, "result = %s", result);
+ UTRACE_EXIT_STATUS(*status);
+ return result;
+}
+
+U_CFUNC void U_EXPORT2
+ucol_setReqValidLocales(UCollator *coll, char *requestedLocaleToAdopt, char *validLocaleToAdopt)
+{
+ if (coll) {
+ if (coll->validLocale) {
+ uprv_free(coll->validLocale);
+ }
+ coll->validLocale = validLocaleToAdopt;
+ if (coll->requestedLocale) { // should always have
+ uprv_free(coll->requestedLocale);
+ }
+ coll->requestedLocale = requestedLocaleToAdopt;
+ }
+}
+
+U_CAPI USet * U_EXPORT2
+ucol_getTailoredSet(const UCollator *coll, UErrorCode *status)
+{
+ U_NAMESPACE_USE
+
+ if(status == NULL || U_FAILURE(*status)) {
+ return NULL;
+ }
+ if(coll == NULL || coll->UCA == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ UParseError parseError;
+ UColTokenParser src;
+ int32_t rulesLen = 0;
+ const UChar *rules = ucol_getRules(coll, &rulesLen);
+ UBool startOfRules = TRUE;
+ // we internally use the C++ class, for the following reasons:
+ // 1. we need to utilize canonical iterator, which is a C++ only class
+ // 2. canonical iterator returns UnicodeStrings - USet cannot take them
+ // 3. USet is internally really UnicodeSet, C is just a wrapper
+ UnicodeSet *tailored = new UnicodeSet();
+ UnicodeString pattern;
+ UnicodeString empty;
+ CanonicalIterator it(empty, *status);
+
+
+ // The idea is to tokenize the rule set. For each non-reset token,
+ // we add all the canonicaly equivalent FCD sequences
+ ucol_tok_initTokenList(&src, rules, rulesLen, coll->UCA, status);
+ while (ucol_tok_parseNextToken(&src, startOfRules, &parseError, status) != NULL) {
+ startOfRules = FALSE;
+ if(src.parsedToken.strength != UCOL_TOK_RESET) {
+ const UChar *stuff = src.source+(src.parsedToken.charsOffset);
+ it.setSource(UnicodeString(stuff, src.parsedToken.charsLen), *status);
+ pattern = it.next();
+ while(!pattern.isBogus()) {
+ if(Normalizer::quickCheck(pattern, UNORM_FCD, *status) != UNORM_NO) {
+ tailored->add(pattern);
+ }
+ pattern = it.next();
+ }
+ }
+ }
+ ucol_tok_closeTokenList(&src);
+ return (USet *)tailored;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_sit.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucol_sit.cpp
new file mode 100644
index 00000000000..e496b192fe2
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_sit.cpp
@@ -0,0 +1,1184 @@
+/*
+*******************************************************************************
+* Copyright (C) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: ucol_sit.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Modification history
+* Date Name Comments
+* 03/12/2004 weiv Creation
+*/
+
+#include "unicode/ustring.h"
+
+#include "utracimp.h"
+#include "ucol_imp.h"
+#include "ucol_tok.h"
+#include "unormimp.h"
+#include "cmemory.h"
+#include "cstring.h"
+
+#if !UCONFIG_NO_COLLATION
+
+enum OptionsList {
+ UCOL_SIT_LANGUAGE = 0,
+ UCOL_SIT_SCRIPT,
+ UCOL_SIT_REGION,
+ UCOL_SIT_VARIANT,
+ UCOL_SIT_KEYWORD,
+ UCOL_SIT_RFC3166BIS,
+ UCOL_SIT_STRENGTH,
+ UCOL_SIT_CASE_LEVEL,
+ UCOL_SIT_CASE_FIRST,
+ UCOL_SIT_NUMERIC_COLLATION,
+ UCOL_SIT_ALTERNATE_HANDLING,
+ UCOL_SIT_NORMALIZATION_MODE,
+ UCOL_SIT_FRENCH_COLLATION,
+ UCOL_SIT_HIRAGANA_QUATERNARY,
+ UCOL_SIT_VARIABLE_TOP,
+ UCOL_SIT_VARIABLE_TOP_VALUE,
+ UCOL_SIT_ITEMS_COUNT
+};
+
+/* list of locales for packing of a collator to an integer.
+ * This list corresponds to ICU 3.0. If more collation bearing
+ * locales are added in the future, this won't be a simple array
+ * but a mapping allowing forward and reverse lookup would have to
+ * be established. Currently, the mapping is from locale name to
+ * index.
+ */
+static const char* const locales[] = {
+/* 00 - 09 */ "ar", "be", "bg", "ca", "cs", "da", "de", "de__PHONEBOOK", "el", "en",
+/* 10 - 19 */ "en_BE", "eo", "es", "es__TRADITIONAL", "et", "fa", "fa_AF", "fi", "fo", "fr",
+/* 20 - 29 */ "gu", "he", "hi", "hi__DIRECT", "hr", "hu", "is", "it", "ja", "kk",
+/* 30 - 39 */ "kl", "kn", "ko", "lt", "lv", "mk", "mr", "mt", "nb", "nn",
+/* 40 - 49 */ "om", "pa", "pl", "ps", "ro", "root", "ru", "sh", "sk", "sl",
+/* 50 - 59 */ "sq", "sr", "sv", "ta", "te", "th", "tr", "uk", "vi", "zh",
+/* 60 - 64 */ "zh_HK", "zh_MO", "zh_TW", "zh_TW_STROKE", "zh__PINYIN"
+};
+
+static const char* const keywords[] = {
+/* 00 */ "",
+/* 01 */ "direct",
+/* 02 */ "phonebook",
+/* 03 */ "pinyin",
+/* 04 */ "standard",
+/* 05 */ "stroke",
+/* 06 */ "traditional"
+};
+
+
+/* option starters chars. */
+static const char alternateHArg = 'A';
+static const char variableTopValArg = 'B';
+static const char caseFirstArg = 'C';
+static const char numericCollArg = 'D';
+static const char caseLevelArg = 'E';
+static const char frenchCollArg = 'F';
+static const char hiraganaQArg = 'H';
+static const char keywordArg = 'K';
+static const char languageArg = 'L';
+static const char normArg = 'N';
+static const char regionArg = 'R';
+static const char strengthArg = 'S';
+static const char variableTopArg = 'T';
+static const char variantArg = 'V';
+static const char RFC3066Arg = 'X';
+static const char scriptArg = 'Z';
+
+static const char collationKeyword[] = "@collation=";
+
+static const int32_t locElementCount = 5;
+static const int32_t locElementCapacity = 32;
+static const int32_t loc3066Capacity = 256;
+static const int32_t internalBufferSize = 512;
+
+/* structure containing specification of a collator. Initialized
+ * from a short string. Also used to construct a short string from a
+ * collator instance
+ */
+struct CollatorSpec {
+ char locElements[locElementCount][locElementCapacity];
+ char locale[loc3066Capacity];
+ UColAttributeValue options[UCOL_ATTRIBUTE_COUNT];
+ uint32_t variableTopValue;
+ UChar variableTopString[locElementCapacity];
+ int32_t variableTopStringLen;
+ UBool variableTopSet;
+ struct {
+ const char *start;
+ int32_t len;
+ } entries[UCOL_SIT_ITEMS_COUNT];
+};
+
+
+/* structure for converting between character attribute
+ * representation and real collation attribute value.
+ */
+struct AttributeConversion {
+ char letter;
+ UColAttributeValue value;
+};
+
+static const AttributeConversion conversions[12] = {
+ { '1', UCOL_PRIMARY },
+ { '2', UCOL_SECONDARY },
+ { '3', UCOL_TERTIARY },
+ { '4', UCOL_QUATERNARY },
+ { 'D', UCOL_DEFAULT },
+ { 'I', UCOL_IDENTICAL },
+ { 'L', UCOL_LOWER_FIRST },
+ { 'N', UCOL_NON_IGNORABLE },
+ { 'O', UCOL_ON },
+ { 'S', UCOL_SHIFTED },
+ { 'U', UCOL_UPPER_FIRST },
+ { 'X', UCOL_OFF }
+};
+
+
+static char
+ucol_sit_attributeValueToLetter(UColAttributeValue value, UErrorCode *status) {
+ uint32_t i = 0;
+ for(i = 0; i < sizeof(conversions)/sizeof(conversions[0]); i++) {
+ if(conversions[i].value == value) {
+ return conversions[i].letter;
+ }
+ }
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+}
+
+static UColAttributeValue
+ucol_sit_letterToAttributeValue(char letter, UErrorCode *status) {
+ uint32_t i = 0;
+ for(i = 0; i < sizeof(conversions)/sizeof(conversions[0]); i++) {
+ if(conversions[i].letter == letter) {
+ return conversions[i].value;
+ }
+ }
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return UCOL_DEFAULT;
+}
+
+/* function prototype for functions used to parse a short string */
+U_CDECL_BEGIN
+typedef const char* U_CALLCONV
+ActionFunction(CollatorSpec *spec, uint32_t value1, const char* string,
+ UErrorCode *status);
+U_CDECL_END
+
+U_CDECL_BEGIN
+static const char* U_CALLCONV
+_processLocaleElement(CollatorSpec *spec, uint32_t value, const char* string,
+ UErrorCode *status)
+{
+ int32_t len = 0;
+ do {
+ if(value == 0 || value == 4) {
+ spec->locElements[value][len++] = uprv_tolower(*string);
+ } else {
+ spec->locElements[value][len++] = *string;
+ }
+ } while(*(++string) != '_' && *string && len < locElementCapacity);
+ if(len >= locElementCapacity) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ return string;
+ }
+ // don't skip the underscore at the end
+ return string;
+}
+U_CDECL_END
+
+U_CDECL_BEGIN
+static const char* U_CALLCONV
+_processRFC3066Locale(CollatorSpec *spec, uint32_t, const char* string,
+ UErrorCode *status)
+{
+ char terminator = *string;
+ string++;
+ const char *end = uprv_strchr(string+1, terminator);
+ if(end == NULL || end - string >= loc3066Capacity) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ return string;
+ } else {
+ uprv_strncpy(spec->locale, string, end-string);
+ return end+1;
+ }
+}
+
+U_CDECL_END
+
+U_CDECL_BEGIN
+static const char* U_CALLCONV
+_processCollatorOption(CollatorSpec *spec, uint32_t option, const char* string,
+ UErrorCode *status)
+{
+ spec->options[option] = ucol_sit_letterToAttributeValue(*string, status);
+ if((*(++string) != '_' && *string) || U_FAILURE(*status)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return string;
+}
+U_CDECL_END
+
+
+static UChar
+readHexCodeUnit(const char **string, UErrorCode *status)
+{
+ UChar result = 0;
+ int32_t value = 0;
+ char c;
+ int32_t noDigits = 0;
+ while((c = **string) != 0 && noDigits < 4) {
+ if( c >= '0' && c <= '9') {
+ value = c - '0';
+ } else if ( c >= 'a' && c <= 'f') {
+ value = c - 'a' + 10;
+ } else if ( c >= 'A' && c <= 'F') {
+ value = c - 'A' + 10;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ result = (result << 4) | (UChar)value;
+ noDigits++;
+ (*string)++;
+ }
+ // if the string was terminated before we read 4 digits, set an error
+ if(noDigits < 4) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return result;
+}
+
+U_CDECL_BEGIN
+static const char* U_CALLCONV
+_processVariableTop(CollatorSpec *spec, uint32_t value1, const char* string, UErrorCode *status)
+{
+ // get four digits
+ int32_t i = 0;
+ if(!value1) {
+ while(U_SUCCESS(*status) && i < locElementCapacity && *string != 0 && *string != '_') {
+ spec->variableTopString[i++] = readHexCodeUnit(&string, status);
+ }
+ spec->variableTopStringLen = i;
+ if(i == locElementCapacity && (*string != 0 || *string != '_')) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ } else {
+ spec->variableTopValue = readHexCodeUnit(&string, status);
+ }
+ if(U_SUCCESS(*status)) {
+ spec->variableTopSet = TRUE;
+ }
+ return string;
+}
+U_CDECL_END
+
+
+/* Table for parsing short strings */
+struct ShortStringOptions {
+ char optionStart;
+ ActionFunction *action;
+ uint32_t attr;
+};
+
+static const ShortStringOptions options[UCOL_SIT_ITEMS_COUNT] =
+{
+/* 10 ALTERNATE_HANDLING */ {alternateHArg, _processCollatorOption, UCOL_ALTERNATE_HANDLING }, // alternate N, S, D
+/* 15 VARIABLE_TOP_VALUE */ {variableTopValArg, _processVariableTop, 1 },
+/* 08 CASE_FIRST */ {caseFirstArg, _processCollatorOption, UCOL_CASE_FIRST }, // case first L, U, X, D
+/* 09 NUMERIC_COLLATION */ {numericCollArg, _processCollatorOption, UCOL_NUMERIC_COLLATION }, // codan O, X, D
+/* 07 CASE_LEVEL */ {caseLevelArg, _processCollatorOption, UCOL_CASE_LEVEL }, // case level O, X, D
+/* 12 FRENCH_COLLATION */ {frenchCollArg, _processCollatorOption, UCOL_FRENCH_COLLATION }, // french O, X, D
+/* 13 HIRAGANA_QUATERNARY] */ {hiraganaQArg, _processCollatorOption, UCOL_HIRAGANA_QUATERNARY_MODE }, // hiragana O, X, D
+/* 04 KEYWORD */ {keywordArg, _processLocaleElement, 4 }, // keyword
+/* 00 LANGUAGE */ {languageArg, _processLocaleElement, 0 }, // language
+/* 11 NORMALIZATION_MODE */ {normArg, _processCollatorOption, UCOL_NORMALIZATION_MODE }, // norm O, X, D
+/* 02 REGION */ {regionArg, _processLocaleElement, 2 }, // region
+/* 06 STRENGTH */ {strengthArg, _processCollatorOption, UCOL_STRENGTH }, // strength 1, 2, 3, 4, I, D
+/* 14 VARIABLE_TOP */ {variableTopArg, _processVariableTop, 0 },
+/* 03 VARIANT */ {variantArg, _processLocaleElement, 3 }, // variant
+/* 05 RFC3066BIS */ {RFC3066Arg, _processRFC3066Locale, 0 }, // rfc3066bis locale name
+/* 01 SCRIPT */ {scriptArg, _processLocaleElement, 1 } // script
+};
+
+
+static
+const char* ucol_sit_readOption(const char *start, CollatorSpec *spec,
+ UErrorCode *status)
+{
+ int32_t i = 0;
+
+ for(i = 0; i < UCOL_SIT_ITEMS_COUNT; i++) {
+ if(*start == options[i].optionStart) {
+ spec->entries[i].start = start;
+ const char* end = options[i].action(spec, options[i].attr, start+1, status);
+ spec->entries[i].len = end - start;
+ return end;
+ }
+ }
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return start;
+}
+
+static
+void ucol_sit_initCollatorSpecs(CollatorSpec *spec)
+{
+ // reset everything
+ uprv_memset(spec, 0, sizeof(CollatorSpec));
+ // set collation options to default
+ int32_t i = 0;
+ for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
+ spec->options[i] = UCOL_DEFAULT;
+ }
+}
+
+static const char*
+ucol_sit_readSpecs(CollatorSpec *s, const char *string,
+ UParseError *parseError, UErrorCode *status)
+{
+ const char *definition = string;
+ while(U_SUCCESS(*status) && *string) {
+ string = ucol_sit_readOption(string, s, status);
+ // advance over '_'
+ while(*string && *string == '_') {
+ string++;
+ }
+ }
+ if(U_FAILURE(*status)) {
+ parseError->offset = string - definition;
+ }
+ return string;
+}
+
+static
+int32_t ucol_sit_dumpSpecs(CollatorSpec *s, char *destination, int32_t capacity, UErrorCode *status)
+{
+ int32_t i = 0, j = 0;
+ int32_t len = 0;
+ char optName;
+ if(U_SUCCESS(*status)) {
+ for(i = 0; i < UCOL_SIT_ITEMS_COUNT; i++) {
+ if(s->entries[i].start) {
+ if(len) {
+ if(len < capacity) {
+ uprv_strcat(destination, "_");
+ }
+ len++;
+ }
+ optName = *(s->entries[i].start);
+ if(optName == languageArg || optName == regionArg || optName == variantArg || optName == keywordArg) {
+ for(j = 0; j < s->entries[i].len; j++) {
+ if(len + j < capacity) {
+ destination[len+j] = uprv_toupper(*(s->entries[i].start+j));
+ }
+ }
+ len += s->entries[i].len;
+ } else {
+ len += s->entries[i].len;
+ if(len < capacity) {
+ uprv_strncat(destination,s->entries[i].start, s->entries[i].len);
+ }
+ }
+ }
+ }
+ return len;
+ } else {
+ return 0;
+ }
+}
+
+static void
+ucol_sit_calculateWholeLocale(CollatorSpec *s) {
+ // put the locale together, unless we have a done
+ // locale
+ if(s->locale[0] == 0) {
+ // first the language
+ uprv_strcat(s->locale, s->locElements[0]);
+ // then the script, if present
+ if(*(s->locElements[1])) {
+ uprv_strcat(s->locale, "_");
+ uprv_strcat(s->locale, s->locElements[1]);
+ }
+ // then the region, if present
+ if(*(s->locElements[2])) {
+ uprv_strcat(s->locale, "_");
+ uprv_strcat(s->locale, s->locElements[2]);
+ } else if(*(s->locElements[3])) { // if there is a variant, we need an underscore
+ uprv_strcat(s->locale, "_");
+ }
+ // add variant, if there
+ if(*(s->locElements[3])) {
+ uprv_strcat(s->locale, "_");
+ uprv_strcat(s->locale, s->locElements[3]);
+ }
+
+ // if there is a collation keyword, add that too
+ if(*(s->locElements[4])) {
+ uprv_strcat(s->locale, collationKeyword);
+ uprv_strcat(s->locale, s->locElements[4]);
+ }
+ }
+}
+
+
+U_CAPI void U_EXPORT2
+ucol_prepareShortStringOpen( const char *definition,
+ UBool,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return;
+
+ UParseError internalParseError;
+
+ if(!parseError) {
+ parseError = &internalParseError;
+ }
+ parseError->line = 0;
+ parseError->offset = 0;
+ parseError->preContext[0] = 0;
+ parseError->postContext[0] = 0;
+
+
+ // first we want to pick stuff out of short string.
+ // we'll end up with an UCA version, locale and a bunch of
+ // settings
+
+ // analyse the string in order to get everything we need.
+ CollatorSpec s;
+ ucol_sit_initCollatorSpecs(&s);
+ ucol_sit_readSpecs(&s, definition, parseError, status);
+ ucol_sit_calculateWholeLocale(&s);
+
+ char buffer[internalBufferSize];
+ uprv_memset(buffer, 0, internalBufferSize);
+ uloc_canonicalize(s.locale, buffer, internalBufferSize, status);
+
+ UResourceBundle *b = ures_open(U_ICUDATA_COLL, buffer, status);
+ /* we try to find stuff from keyword */
+ UResourceBundle *collations = ures_getByKey(b, "collations", NULL, status);
+ UResourceBundle *collElem = NULL;
+ char keyBuffer[256];
+ // if there is a keyword, we pick it up and try to get elements
+ if(!uloc_getKeywordValue(buffer, "collation", keyBuffer, 256, status)) {
+ // no keyword. we try to find the default setting, which will give us the keyword value
+ UResourceBundle *defaultColl = ures_getByKeyWithFallback(collations, "default", NULL, status);
+ if(U_SUCCESS(*status)) {
+ int32_t defaultKeyLen = 0;
+ const UChar *defaultKey = ures_getString(defaultColl, &defaultKeyLen, status);
+ u_UCharsToChars(defaultKey, keyBuffer, defaultKeyLen);
+ keyBuffer[defaultKeyLen] = 0;
+ } else {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ ures_close(defaultColl);
+ }
+ collElem = ures_getByKeyWithFallback(collations, keyBuffer, collElem, status);
+ ures_close(collElem);
+ ures_close(collations);
+ ures_close(b);
+}
+
+
+U_CAPI UCollator* U_EXPORT2
+ucol_openFromShortString( const char *definition,
+ UBool forceDefaults,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+ UTRACE_ENTRY_OC(UTRACE_UCOL_OPEN_FROM_SHORT_STRING);
+ UTRACE_DATA1(UTRACE_INFO, "short string = \"%s\"", definition);
+
+ if(U_FAILURE(*status)) return 0;
+
+ UParseError internalParseError;
+
+ if(!parseError) {
+ parseError = &internalParseError;
+ }
+ parseError->line = 0;
+ parseError->offset = 0;
+ parseError->preContext[0] = 0;
+ parseError->postContext[0] = 0;
+
+
+ // first we want to pick stuff out of short string.
+ // we'll end up with an UCA version, locale and a bunch of
+ // settings
+
+ // analyse the string in order to get everything we need.
+ const char *string = definition;
+ CollatorSpec s;
+ ucol_sit_initCollatorSpecs(&s);
+ string = ucol_sit_readSpecs(&s, definition, parseError, status);
+ ucol_sit_calculateWholeLocale(&s);
+
+ char buffer[internalBufferSize];
+ uprv_memset(buffer, 0, internalBufferSize);
+ uloc_canonicalize(s.locale, buffer, internalBufferSize, status);
+
+ UCollator *result = ucol_open(buffer, status);
+ int32_t i = 0;
+
+ for(i = 0; i < UCOL_ATTRIBUTE_COUNT; i++) {
+ if(s.options[i] != UCOL_DEFAULT) {
+ if(forceDefaults || ucol_getAttribute(result, (UColAttribute)i, status) != s.options[i]) {
+ ucol_setAttribute(result, (UColAttribute)i, s.options[i], status);
+ }
+
+ if(U_FAILURE(*status)) {
+ parseError->offset = string - definition;
+ ucol_close(result);
+ return NULL;
+ }
+
+ }
+ }
+ if(s.variableTopSet) {
+ if(s.variableTopString[0]) {
+ ucol_setVariableTop(result, s.variableTopString, s.variableTopStringLen, status);
+ } else { // we set by value, using 'B'
+ ucol_restoreVariableTop(result, s.variableTopValue, status);
+ }
+ }
+
+
+ if(U_FAILURE(*status)) { // here it can only be a bogus value
+ ucol_close(result);
+ result = NULL;
+ }
+
+ UTRACE_EXIT_PTR_STATUS(result, *status);
+ return result;
+}
+
+
+static void appendShortStringElement(const char *src, int32_t len, char *result, int32_t *resultSize, int32_t capacity, char arg)
+{
+ if(len) {
+ if(*resultSize) {
+ if(*resultSize < capacity) {
+ uprv_strcat(result, "_");
+ }
+ (*resultSize)++;
+ }
+ *resultSize += len + 1;
+ if(*resultSize < capacity) {
+ uprv_strncat(result, &arg, 1);
+ uprv_strncat(result, src, len);
+ }
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_getShortDefinitionString(const UCollator *coll,
+ const char *locale,
+ char *dst,
+ int32_t capacity,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return 0;
+ char buffer[internalBufferSize];
+ uprv_memset(buffer, 0, internalBufferSize*sizeof(char));
+ int32_t resultSize = 0;
+ char tempbuff[internalBufferSize];
+ char locBuff[internalBufferSize];
+ uprv_memset(buffer, 0, internalBufferSize*sizeof(char));
+ int32_t elementSize = 0;
+ UBool isAvailable = 0;
+ CollatorSpec s;
+ ucol_sit_initCollatorSpecs(&s);
+
+ if(!locale) {
+ locale = ucol_getLocale(coll, ULOC_VALID_LOCALE, status);
+ }
+ elementSize = ucol_getFunctionalEquivalent(locBuff, internalBufferSize, "collation", locale, &isAvailable, status);
+
+ if(elementSize) {
+ // we should probably canonicalize here...
+ elementSize = uloc_getLanguage(locBuff, tempbuff, internalBufferSize, status);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, capacity, languageArg);
+ elementSize = uloc_getCountry(locBuff, tempbuff, internalBufferSize, status);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, capacity, regionArg);
+ elementSize = uloc_getScript(locBuff, tempbuff, internalBufferSize, status);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, capacity, scriptArg);
+ elementSize = uloc_getVariant(locBuff, tempbuff, internalBufferSize, status);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, capacity, variantArg);
+ elementSize = uloc_getKeywordValue(locBuff, "collation", tempbuff, internalBufferSize, status);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, capacity, keywordArg);
+ }
+
+ int32_t i = 0;
+ UColAttributeValue attribute = UCOL_DEFAULT;
+ for(i = 0; i < UCOL_SIT_ITEMS_COUNT; i++) {
+ if(options[i].action == _processCollatorOption) {
+ attribute = ucol_getAttributeOrDefault(coll, (UColAttribute)options[i].attr, status);
+ if(attribute != UCOL_DEFAULT) {
+ char letter = ucol_sit_attributeValueToLetter(attribute, status);
+ appendShortStringElement(&letter, 1,
+ buffer, &resultSize, capacity, options[i].optionStart);
+ }
+ }
+ }
+ if(coll->variableTopValueisDefault == FALSE) {
+ //s.variableTopValue = ucol_getVariableTop(coll, status);
+ elementSize = T_CString_integerToString(tempbuff, coll->variableTopValue, 16);
+ appendShortStringElement(tempbuff, elementSize, buffer, &resultSize, capacity, variableTopValArg);
+ }
+
+ UParseError parseError;
+ return ucol_normalizeShortDefinitionString(buffer, dst, capacity, &parseError, status);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_normalizeShortDefinitionString(const char *definition,
+ char *destination,
+ int32_t capacity,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if(destination) {
+ uprv_memset(destination, 0, capacity*sizeof(char));
+ }
+
+ UParseError pe;
+ if(!parseError) {
+ parseError = &pe;
+ }
+
+ // validate
+ CollatorSpec s;
+ ucol_sit_initCollatorSpecs(&s);
+ ucol_sit_readSpecs(&s, definition, parseError, status);
+ return ucol_sit_dumpSpecs(&s, destination, capacity, status);
+}
+
+// structure for packing the bits of the attributes in the
+// identifier number.
+// locale is packed separately
+struct bitPacking {
+ char letter;
+ uint32_t offset;
+ uint32_t width;
+ UColAttribute attribute;
+ UColAttributeValue values[6];
+};
+
+static const bitPacking attributesToBits[UCOL_ATTRIBUTE_COUNT] = {
+ /* french */ { frenchCollArg, 29, 2, UCOL_FRENCH_COLLATION, { UCOL_DEFAULT, UCOL_OFF, UCOL_ON }},
+ /* alternate */ { alternateHArg, 27, 2, UCOL_ALTERNATE_HANDLING, { UCOL_DEFAULT, UCOL_NON_IGNORABLE, UCOL_SHIFTED }},
+ /* case first */ { caseFirstArg, 25, 2, UCOL_CASE_FIRST, { UCOL_DEFAULT, UCOL_OFF, UCOL_LOWER_FIRST, UCOL_UPPER_FIRST }},
+ /* case level */ { caseLevelArg, 23, 2, UCOL_CASE_LEVEL, { UCOL_DEFAULT, UCOL_OFF, UCOL_ON }},
+ /* normalization */ { normArg, 21, 2, UCOL_NORMALIZATION_MODE, { UCOL_DEFAULT, UCOL_OFF, UCOL_ON }},
+ /* strength */ { strengthArg, 18, 3, UCOL_STRENGTH, { UCOL_DEFAULT, UCOL_PRIMARY, UCOL_SECONDARY, UCOL_TERTIARY, UCOL_QUATERNARY, UCOL_IDENTICAL }},
+ /* hiragana */ { hiraganaQArg, 16, 2, UCOL_HIRAGANA_QUATERNARY_MODE, { UCOL_DEFAULT, UCOL_OFF, UCOL_ON }},
+ /* numeric coll */ { numericCollArg, 14, 2, UCOL_NUMERIC_COLLATION, { UCOL_DEFAULT, UCOL_OFF, UCOL_ON }}
+};
+
+static const uint32_t keywordShift = 9;
+static const uint32_t keywordWidth = 5;
+static const uint32_t localeShift = 0;
+static const uint32_t localeWidth = 7;
+
+
+static uint32_t ucol_sit_putLocaleInIdentifier(uint32_t result, const char* locale, UErrorCode* status) {
+ char buffer[internalBufferSize], keywordBuffer[internalBufferSize],
+ baseName[internalBufferSize], localeBuffer[internalBufferSize];
+ int32_t len = 0, keywordLen = 0,
+ baseNameLen = 0, localeLen = 0;
+ uint32_t i = 0;
+ UBool isAvailable = FALSE;
+ if(locale) {
+ len = uloc_canonicalize(locale, buffer, internalBufferSize, status);
+ localeLen = ucol_getFunctionalEquivalent(localeBuffer, internalBufferSize, "collation", buffer, &isAvailable, status);
+ keywordLen = uloc_getKeywordValue(buffer, "collation", keywordBuffer, internalBufferSize, status);
+ baseNameLen = uloc_getBaseName(buffer, baseName, internalBufferSize, status);
+
+ /*Binary search for the map entry for normal cases */
+
+ uint32_t low = 0;
+ uint32_t high = sizeof(locales)/sizeof(locales[0]);
+ uint32_t mid = high;
+ uint32_t oldmid = 0;
+ int32_t compVal = 0;
+
+
+ while (high > low) /*binary search*/{
+
+ mid = (high+low) >> 1; /*Finds median*/
+
+ if (mid == oldmid)
+ return UCOL_SIT_COLLATOR_NOT_ENCODABLE; // we didn't find it
+
+ compVal = uprv_strcmp(baseName, locales[mid]);
+ if (compVal < 0){
+ high = mid;
+ }
+ else if (compVal > 0){
+ low = mid;
+ }
+ else /*we found it*/{
+ break;
+ }
+ oldmid = mid;
+ }
+
+ result |= (mid & ((1 << localeWidth) - 1)) << localeShift;
+ }
+
+ if(keywordLen) {
+ for(i = 1; i < sizeof(keywords)/sizeof(keywords[0]); i++) {
+ if(uprv_strcmp(keywords[i], keywordBuffer) == 0) {
+ result |= (i & ((1 << keywordWidth) - 1)) << keywordShift;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+U_CAPI uint32_t U_EXPORT2
+ucol_collatorToIdentifier(const UCollator *coll,
+ const char *locale,
+ UErrorCode *status)
+{
+ uint32_t result = 0;
+ uint32_t i = 0, j = 0;
+ UColAttributeValue attrValue = UCOL_DEFAULT;
+
+ // if variable top is not default, we need to use strings
+ if(coll->variableTopValueisDefault != TRUE) {
+ return UCOL_SIT_COLLATOR_NOT_ENCODABLE;
+ }
+
+ if(locale == NULL) {
+ locale = ucol_getLocale(coll, ULOC_VALID_LOCALE, status);
+ }
+
+ result = ucol_sit_putLocaleInIdentifier(result, locale, status);
+
+ for(i = 0; i < sizeof(attributesToBits)/sizeof(attributesToBits[0]); i++) {
+ attrValue = ucol_getAttributeOrDefault(coll, attributesToBits[i].attribute, status);
+ j = 0;
+ while(attributesToBits[i].values[j] != attrValue) {
+ j++;
+ }
+ result |= (j & ((1 << attributesToBits[i].width) - 1)) << attributesToBits[i].offset;
+ }
+
+ return result;
+}
+
+U_CAPI UCollator* U_EXPORT2
+ucol_openFromIdentifier(uint32_t identifier,
+ UBool forceDefaults,
+ UErrorCode *status)
+{
+ uint32_t i = 0;
+ int32_t value = 0, keyword = 0;
+ char locale[internalBufferSize];
+
+ value = (identifier >> localeShift) & ((1 << localeWidth) - 1);
+ keyword = (identifier >> keywordShift) & ((1 << keywordWidth) - 1);
+
+ uprv_strcpy(locale, locales[value]);
+
+ if(keyword) {
+ uprv_strcat(locale, collationKeyword);
+ uprv_strcat(locale, keywords[keyword]);
+ }
+
+ UColAttributeValue attrValue = UCOL_DEFAULT;
+
+ UCollator *result = ucol_open(locale, status);
+
+ // variable top is not set in the identifier, so we can easily skip that on
+
+ for(i = 0; i < sizeof(attributesToBits)/sizeof(attributesToBits[0]); i++) {
+ value = (identifier >> attributesToBits[i].offset) & ((1 << attributesToBits[i].width) - 1);
+ attrValue = attributesToBits[i].values[value];
+ // the collator is all default, so we will set only the values that will differ from
+ // the default values.
+ if(attrValue != UCOL_DEFAULT) {
+ if(forceDefaults ||
+ ucol_getAttribute(result, attributesToBits[i].attribute, status) != attrValue) {
+ ucol_setAttribute(result, attributesToBits[i].attribute, attrValue, status);
+ }
+ }
+ }
+
+ return result;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_identifierToShortString(uint32_t identifier,
+ char *buffer,
+ int32_t capacity,
+ UBool forceDefaults,
+ UErrorCode *status)
+{
+ int32_t locIndex = (identifier >> localeShift) & ((1 << localeWidth) - 1);
+ int32_t keywordIndex = (identifier >> keywordShift) & ((1 << keywordWidth) - 1);
+ CollatorSpec s;
+ ucol_sit_initCollatorSpecs(&s);
+ uprv_strcpy(s.locale, locales[locIndex]);
+ if(keywordIndex) {
+ uprv_strcat(s.locale, collationKeyword);
+ uprv_strcat(s.locale, keywords[keywordIndex]);
+ }
+ UCollator *coll = ucol_openFromIdentifier(identifier, forceDefaults, status);
+ int32_t resultLen = ucol_getShortDefinitionString(coll, s.locale, buffer, capacity, status);
+ ucol_close(coll);
+ return resultLen;
+
+#if 0
+ // TODO: Crumy, crumy, crumy... Very hard to currently go algorithmically from
+ // identifier to short string. Do rethink
+ if(forceDefaults == FALSE) {
+ UCollator *coll = ucol_openFromIdentifier(identifier, FALSE, status);
+ int32_t resultLen = ucol_getShortDefinitionString(coll, s.locale, buffer, capacity, status);
+ ucol_close(coll);
+ return resultLen;
+ } else { // forceDefaults == TRUE
+ char letter;
+ UColAttributeValue value;
+ int32_t i = 0;
+ for(i = 0; i < sizeof(attributesToBits)/sizeof(attributesToBits[0]); i++) {
+ value = attributesToBits[i].values[(identifier >> attributesToBits[i].offset) & ((1 << attributesToBits[i].width) - 1)];
+ if(value != UCOL_DEFAULT) {
+ uprv_strcat(buffer, "_");
+ uprv_strncat(buffer, &attributesToBits[i].letter, 1);
+ letter = ucol_sit_attributeValueToLetter(value, status);
+ uprv_strncat(buffer, &letter, 1);
+ }
+ }
+ return ucol_sit_dumpSpecs(&s, buffer, capacity, status);
+ }
+#endif
+}
+
+U_CAPI uint32_t U_EXPORT2
+ucol_shortStringToIdentifier(const char *definition,
+ UBool forceDefaults,
+ UErrorCode *status)
+{
+ UParseError parseError;
+ CollatorSpec s;
+ uint32_t result = 0;
+ uint32_t i = 0, j = 0;
+ ucol_sit_initCollatorSpecs(&s);
+
+ ucol_sit_readSpecs(&s, definition, &parseError, status);
+ ucol_sit_calculateWholeLocale(&s);
+
+ char locBuffer[internalBufferSize];
+ UBool isAvailable = FALSE;
+ UColAttributeValue attrValue = UCOL_DEFAULT;
+
+ ucol_getFunctionalEquivalent(locBuffer, internalBufferSize, "collation", s.locale, &isAvailable, status);
+
+ if(forceDefaults == FALSE) {
+ UCollator *coll = ucol_openFromShortString(definition, FALSE, &parseError, status);
+ result = ucol_collatorToIdentifier(coll, locBuffer, status);
+ ucol_close(coll);
+ } else { // forceDefaults == TRUE
+ result = ucol_sit_putLocaleInIdentifier(result, locBuffer, status);
+
+ for(i = 0; i < sizeof(attributesToBits)/sizeof(attributesToBits[0]); i++) {
+ attrValue = s.options[i];
+ j = 0;
+ while(attributesToBits[i].values[j] != attrValue) {
+ j++;
+ }
+ result |= (j & ((1 << attributesToBits[i].width) - 1)) << attributesToBits[i].offset;
+ }
+
+ }
+ return result;
+
+}
+
+U_CAPI UColAttributeValue U_EXPORT2
+ucol_getAttributeOrDefault(const UCollator *coll, UColAttribute attr, UErrorCode *status)
+{
+ if(U_FAILURE(*status) || coll == NULL) {
+ return UCOL_DEFAULT;
+ }
+ switch(attr) {
+ case UCOL_NUMERIC_COLLATION:
+ return coll->numericCollationisDefault?UCOL_DEFAULT:coll->numericCollation;
+ case UCOL_HIRAGANA_QUATERNARY_MODE:
+ return coll->hiraganaQisDefault?UCOL_DEFAULT:coll->hiraganaQ;
+ case UCOL_FRENCH_COLLATION: /* attribute for direction of secondary weights*/
+ return coll->frenchCollationisDefault?UCOL_DEFAULT:coll->frenchCollation;
+ case UCOL_ALTERNATE_HANDLING: /* attribute for handling variable elements*/
+ return coll->alternateHandlingisDefault?UCOL_DEFAULT:coll->alternateHandling;
+ case UCOL_CASE_FIRST: /* who goes first, lower case or uppercase */
+ return coll->caseFirstisDefault?UCOL_DEFAULT:coll->caseFirst;
+ case UCOL_CASE_LEVEL: /* do we have an extra case level */
+ return coll->caseLevelisDefault?UCOL_DEFAULT:coll->caseLevel;
+ case UCOL_NORMALIZATION_MODE: /* attribute for normalization */
+ return coll->normalizationModeisDefault?UCOL_DEFAULT:coll->normalizationMode;
+ case UCOL_STRENGTH: /* attribute for strength */
+ return coll->strengthisDefault?UCOL_DEFAULT:coll->strength;
+ case UCOL_ATTRIBUTE_COUNT:
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ break;
+ }
+ return UCOL_DEFAULT;
+}
+
+
+struct contContext {
+ const UCollator *coll;
+ USet *conts;
+ USet *expansions;
+ USet *removedContractions;
+ UBool addPrefixes;
+ UErrorCode *status;
+};
+
+
+
+static void
+addSpecial(contContext *context, UChar *buffer, int32_t bufLen,
+ uint32_t CE, int32_t leftIndex, int32_t rightIndex, UErrorCode *status)
+{
+ const UCollator *coll = context->coll;
+ USet *contractions = context->conts;
+ USet *expansions = context->expansions;
+ UBool addPrefixes = context->addPrefixes;
+
+ const UChar *UCharOffset = (UChar *)coll->image+getContractOffset(CE);
+ uint32_t newCE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
+ // we might have a contraction that ends from previous level
+ if(newCE != UCOL_NOT_FOUND) {
+ if(isSpecial(CE) && getCETag(CE) == CONTRACTION_TAG && isSpecial(newCE) && getCETag(newCE) == SPEC_PROC_TAG && addPrefixes) {
+ addSpecial(context, buffer, bufLen, newCE, leftIndex, rightIndex, status);
+ }
+ if(contractions && rightIndex-leftIndex > 1) {
+ uset_addString(contractions, buffer+leftIndex, rightIndex-leftIndex);
+ if(expansions && isSpecial(CE) && getCETag(CE) == EXPANSION_TAG) {
+ uset_addString(expansions, buffer+leftIndex, rightIndex-leftIndex);
+ }
+ }
+ }
+
+ UCharOffset++;
+ // check whether we're doing contraction or prefix
+ if(getCETag(CE) == SPEC_PROC_TAG && addPrefixes) {
+ if(leftIndex == 0) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ --leftIndex;
+ while(*UCharOffset != 0xFFFF) {
+ newCE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
+ buffer[leftIndex] = *UCharOffset;
+ if(isSpecial(newCE) && (getCETag(newCE) == CONTRACTION_TAG || getCETag(newCE) == SPEC_PROC_TAG)) {
+ addSpecial(context, buffer, bufLen, newCE, leftIndex, rightIndex, status);
+ } else {
+ if(contractions) {
+ uset_addString(contractions, buffer+leftIndex, rightIndex-leftIndex);
+ }
+ if(expansions && isSpecial(newCE) && getCETag(newCE) == EXPANSION_TAG) {
+ uset_addString(expansions, buffer+leftIndex, rightIndex-leftIndex);
+ }
+ }
+ UCharOffset++;
+ }
+ } else if(getCETag(CE) == CONTRACTION_TAG) {
+ if(rightIndex == bufLen-1) {
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ return;
+ }
+ while(*UCharOffset != 0xFFFF) {
+ newCE = *(coll->contractionCEs + (UCharOffset - coll->contractionIndex));
+ buffer[rightIndex] = *UCharOffset;
+ if(isSpecial(newCE) && (getCETag(newCE) == CONTRACTION_TAG || getCETag(newCE) == SPEC_PROC_TAG)) {
+ addSpecial(context, buffer, bufLen, newCE, leftIndex, rightIndex+1, status);
+ } else {
+ if(contractions) {
+ uset_addString(contractions, buffer+leftIndex, rightIndex+1-leftIndex);
+ }
+ if(expansions && isSpecial(newCE) && getCETag(newCE) == EXPANSION_TAG) {
+ uset_addString(expansions, buffer+leftIndex, rightIndex+1-leftIndex);
+ }
+ }
+ UCharOffset++;
+ }
+ }
+
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+_processSpecials(const void *context, UChar32 start, UChar32 limit, uint32_t CE)
+{
+ UErrorCode *status = ((contContext *)context)->status;
+ USet *expansions = ((contContext *)context)->expansions;
+ USet *removed = ((contContext *)context)->removedContractions;
+ UBool addPrefixes = ((contContext *)context)->addPrefixes;
+ UChar contraction[internalBufferSize];
+ if(isSpecial(CE)) {
+ if(((getCETag(CE) == SPEC_PROC_TAG && addPrefixes) || getCETag(CE) == CONTRACTION_TAG)) {
+ while(start < limit && U_SUCCESS(*status)) {
+ // if there are suppressed contractions, we don't
+ // want to add them.
+ if(removed && uset_contains(removed, start)) {
+ start++;
+ continue;
+ }
+ // we start our contraction from middle, since we don't know if it
+ // will grow toward right or left
+ contraction[internalBufferSize/2] = (UChar)start;
+ addSpecial(((contContext *)context), contraction, internalBufferSize, CE, internalBufferSize/2, internalBufferSize/2+1, status);
+ start++;
+ }
+ } else if(expansions && getCETag(CE) == EXPANSION_TAG) {
+ while(start < limit && U_SUCCESS(*status)) {
+ uset_add(expansions, start++);
+ }
+ }
+ }
+ if(U_FAILURE(*status)) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+U_CDECL_END
+
+
+
+/**
+ * Get a set containing the contractions defined by the collator. The set includes
+ * both the UCA contractions and the contractions defined by the collator
+ * @param coll collator
+ * @param conts the set to hold the result
+ * @param status to hold the error code
+ * @return the size of the contraction set
+ *
+ * @draft ICU 3.0
+ */
+U_CAPI int32_t U_EXPORT2
+ucol_getContractions( const UCollator *coll,
+ USet *contractions,
+ UErrorCode *status)
+{
+ ucol_getContractionsAndExpansions(coll, contractions, NULL, FALSE, status);
+ return uset_getItemCount(contractions);
+}
+
+/**
+ * Get a set containing the expansions defined by the collator. The set includes
+ * both the UCA expansions and the expansions defined by the tailoring
+ * @param coll collator
+ * @param conts the set to hold the result
+ * @param addPrefixes add the prefix contextual elements to contractions
+ * @param status to hold the error code
+ *
+ * @draft ICU 3.4
+ */
+U_CAPI void U_EXPORT2
+ucol_getContractionsAndExpansions( const UCollator *coll,
+ USet *contractions,
+ USet *expansions,
+ UBool addPrefixes,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return;
+ }
+ if(coll == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ if(contractions) {
+ uset_clear(contractions);
+ }
+ if(expansions) {
+ uset_clear(expansions);
+ }
+ int32_t rulesLen = 0;
+ const UChar* rules = ucol_getRules(coll, &rulesLen);
+ UColTokenParser src;
+ ucol_tok_initTokenList(&src, rules, rulesLen, coll->UCA, status);
+
+ contContext c = { NULL, contractions, expansions, src.removeSet, addPrefixes, status };
+
+ // Add the UCA contractions
+ c.coll = coll->UCA;
+ utrie_enum(&coll->UCA->mapping, NULL, _processSpecials, &c);
+
+ // This is collator specific. Add contractions from a collator
+ c.coll = coll;
+ c.removedContractions = NULL;
+ utrie_enum(&coll->mapping, NULL, _processSpecials, &c);
+ ucol_tok_closeTokenList(&src);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_getUnsafeSet( const UCollator *coll,
+ USet *unsafe,
+ UErrorCode *status)
+{
+ UChar buffer[internalBufferSize];
+ int32_t len = 0;
+
+ uset_clear(unsafe);
+
+ // cccpattern = "[[:^tccc=0:][:^lccc=0:]]", unfortunately variant
+ static const UChar cccpattern[25] = { 0x5b, 0x5b, 0x3a, 0x5e, 0x74, 0x63, 0x63, 0x63, 0x3d, 0x30, 0x3a, 0x5d,
+ 0x5b, 0x3a, 0x5e, 0x6c, 0x63, 0x63, 0x63, 0x3d, 0x30, 0x3a, 0x5d, 0x5d, 0x00 };
+
+ // add chars that fail the fcd check
+ uset_applyPattern(unsafe, cccpattern, 24, USET_IGNORE_SPACE, status);
+
+ // add Thai/Lao prevowels
+ uset_addRange(unsafe, 0xe40, 0xe44);
+ uset_addRange(unsafe, 0xec0, 0xec4);
+ // add lead/trail surrogates
+ uset_addRange(unsafe, 0xd800, 0xdfff);
+
+ USet *contractions = uset_open(0,0);
+
+ int32_t i = 0, j = 0;
+ int32_t contsSize = ucol_getContractions(coll, contractions, status);
+ UChar32 c = 0;
+ // Contraction set consists only of strings
+ // to get unsafe code points, we need to
+ // break the strings apart and add them to the unsafe set
+ for(i = 0; i < contsSize; i++) {
+ len = uset_getItem(contractions, i, NULL, NULL, buffer, internalBufferSize, status);
+ if(len > 0) {
+ j = 0;
+ while(j < len) {
+ U16_NEXT(buffer, j, len, c);
+ if(j < len) {
+ uset_add(unsafe, c);
+ }
+ }
+ }
+ }
+
+ uset_close(contractions);
+
+ return uset_size(unsafe);
+}
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_tok.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucol_tok.cpp
new file mode 100644
index 00000000000..131c766763a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_tok.cpp
@@ -0,0 +1,1910 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: ucol_tok.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created 02/22/2001
+* created by: Vladimir Weinstein
+*
+* This module reads a tailoring rule string and produces a list of
+* tokens that will be turned into collation elements
+*
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+
+#include "ucol_tok.h"
+#include "cmemory.h"
+#include "util.h"
+
+U_CDECL_BEGIN
+static int32_t U_CALLCONV
+uhash_hashTokens(const UHashTok k)
+{
+ int32_t hash = 0;
+ //uint32_t key = (uint32_t)k.integer;
+ UColToken *key = (UColToken *)k.pointer;
+ if (key != 0) {
+ //int32_t len = (key & 0xFF000000)>>24;
+ int32_t len = (key->source & 0xFF000000)>>24;
+ int32_t inc = ((len - 32) / 32) + 1;
+
+ //const UChar *p = (key & 0x00FFFFFF) + rulesToParse;
+ const UChar *p = (key->source & 0x00FFFFFF) + key->rulesToParse;
+ const UChar *limit = p + len;
+
+ while (p<limit) {
+ hash = (hash * 37) + *p;
+ p += inc;
+ }
+ }
+ return hash;
+}
+
+static UBool U_CALLCONV
+uhash_compareTokens(const UHashTok key1, const UHashTok key2)
+{
+ //uint32_t p1 = (uint32_t) key1.integer;
+ //uint32_t p2 = (uint32_t) key2.integer;
+ UColToken *p1 = (UColToken *)key1.pointer;
+ UColToken *p2 = (UColToken *)key2.pointer;
+ const UChar *s1 = (p1->source & 0x00FFFFFF) + p1->rulesToParse;
+ const UChar *s2 = (p2->source & 0x00FFFFFF) + p2->rulesToParse;
+ uint32_t s1L = ((p1->source & 0xFF000000) >> 24);
+ uint32_t s2L = ((p2->source & 0xFF000000) >> 24);
+ const UChar *end = s1+s1L-1;
+
+ if (p1 == p2) {
+ return TRUE;
+ }
+ if (p1->source == 0 || p2->source == 0) {
+ return FALSE;
+ }
+ if(s1L != s2L) {
+ return FALSE;
+ }
+ if(p1->source == p2->source) {
+ return TRUE;
+ }
+ while((s1 < end) && *s1 == *s2) {
+ ++s1;
+ ++s2;
+ }
+ if(*s1 == *s2) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+U_CDECL_END
+
+/*static inline void U_CALLCONV
+uhash_freeBlockWrapper(void *obj) {
+ uhash_freeBlock(obj);
+}*/
+
+
+typedef struct {
+ uint32_t startCE;
+ uint32_t startContCE;
+ uint32_t limitCE;
+ uint32_t limitContCE;
+} indirectBoundaries;
+
+/* these values are used for finding CE values for indirect positioning. */
+/* Indirect positioning is a mechanism for allowing resets on symbolic */
+/* values. It only works for resets and you cannot tailor indirect names */
+/* An indirect name can define either an anchor point or a range. An */
+/* anchor point behaves in exactly the same way as a code point in reset */
+/* would, except that it cannot be tailored. A range (we currently only */
+/* know for the [top] range will explicitly set the upper bound for */
+/* generated CEs, thus allowing for better control over how many CEs can */
+/* be squeezed between in the range without performance penalty. */
+/* In that respect, we use [top] for tailoring of locales that use CJK */
+/* characters. Other indirect values are currently a pure convenience, */
+/* they can be used to assure that the CEs will be always positioned in */
+/* the same place relative to a point with known properties (e.g. first */
+/* primary ignorable). */
+static indirectBoundaries ucolIndirectBoundaries[15];
+/*
+static indirectBoundaries ucolIndirectBoundaries[11] = {
+{ UCOL_RESET_TOP_VALUE, 0,
+UCOL_NEXT_TOP_VALUE, 0 },
+{ UCOL_FIRST_PRIMARY_IGNORABLE, 0,
+0, 0 },
+{ UCOL_LAST_PRIMARY_IGNORABLE, UCOL_LAST_PRIMARY_IGNORABLE_CONT,
+0, 0 },
+{ UCOL_FIRST_SECONDARY_IGNORABLE, 0,
+0, 0 },
+{ UCOL_LAST_SECONDARY_IGNORABLE, 0,
+0, 0 },
+{ UCOL_FIRST_TERTIARY_IGNORABLE, 0,
+0, 0 },
+{ UCOL_LAST_TERTIARY_IGNORABLE, 0,
+0, 0 },
+{ UCOL_FIRST_VARIABLE, 0,
+0, 0 },
+{ UCOL_LAST_VARIABLE, 0,
+0, 0 },
+{ UCOL_FIRST_NON_VARIABLE, 0,
+0, 0 },
+{ UCOL_LAST_NON_VARIABLE, 0,
+0, 0 },
+};
+*/
+
+static void setIndirectBoundaries(uint32_t indexR, uint32_t *start, uint32_t *end) {
+
+ // Set values for the top - TODO: once we have values for all the indirects, we are going
+ // to initalize here.
+ ucolIndirectBoundaries[indexR].startCE = start[0];
+ ucolIndirectBoundaries[indexR].startContCE = start[1];
+ if(end) {
+ ucolIndirectBoundaries[indexR].limitCE = end[0];
+ ucolIndirectBoundaries[indexR].limitContCE = end[1];
+ } else {
+ ucolIndirectBoundaries[indexR].limitCE = 0;
+ ucolIndirectBoundaries[indexR].limitContCE = 0;
+ }
+}
+
+
+static inline
+void syntaxError(const UChar* rules,
+ int32_t pos,
+ int32_t rulesLen,
+ UParseError* parseError)
+{
+ parseError->offset = pos;
+ parseError->line = 0 ; /* we are not using line numbers */
+
+ // for pre-context
+ int32_t start = (pos < U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1));
+ int32_t stop = pos;
+
+ u_memcpy(parseError->preContext,rules+start,stop-start);
+ //null terminate the buffer
+ parseError->preContext[stop-start] = 0;
+
+ //for post-context
+ start = pos+1;
+ stop = ((pos+U_PARSE_CONTEXT_LEN)<= rulesLen )? (pos+(U_PARSE_CONTEXT_LEN-1)) :
+ rulesLen;
+
+ if(start < stop) {
+ u_memcpy(parseError->postContext,rules+start,stop-start);
+ //null terminate the buffer
+ parseError->postContext[stop-start]= 0;
+ } else {
+ parseError->postContext[0] = 0;
+ }
+}
+
+static
+void ucol_uprv_tok_setOptionInImage(UColOptionSet *opts, UColAttribute attrib, UColAttributeValue value) {
+ switch(attrib) {
+ case UCOL_HIRAGANA_QUATERNARY_MODE:
+ opts->hiraganaQ = value;
+ break;
+ case UCOL_FRENCH_COLLATION:
+ opts->frenchCollation = value;
+ break;
+ case UCOL_ALTERNATE_HANDLING:
+ opts->alternateHandling = value;
+ break;
+ case UCOL_CASE_FIRST:
+ opts->caseFirst = value;
+ break;
+ case UCOL_CASE_LEVEL:
+ opts->caseLevel = value;
+ break;
+ case UCOL_NORMALIZATION_MODE:
+ opts->normalizationMode = value;
+ break;
+ case UCOL_STRENGTH:
+ opts->strength = value;
+ break;
+ case UCOL_NUMERIC_COLLATION:
+ opts->numericCollation = value;
+ break;
+ case UCOL_ATTRIBUTE_COUNT:
+ default:
+ break;
+ }
+}
+
+#define UTOK_OPTION_COUNT 20
+
+static UBool didInit = FALSE;
+/* we can be strict, or we can be lenient */
+/* I'd surely be lenient with the option arguments */
+/* maybe even with options */
+U_STRING_DECL(suboption_00, "non-ignorable", 13);
+U_STRING_DECL(suboption_01, "shifted", 7);
+
+U_STRING_DECL(suboption_02, "lower", 5);
+U_STRING_DECL(suboption_03, "upper", 5);
+U_STRING_DECL(suboption_04, "off", 3);
+U_STRING_DECL(suboption_05, "on", 2);
+U_STRING_DECL(suboption_06, "1", 1);
+U_STRING_DECL(suboption_07, "2", 1);
+U_STRING_DECL(suboption_08, "3", 1);
+U_STRING_DECL(suboption_09, "4", 1);
+U_STRING_DECL(suboption_10, "I", 1);
+
+U_STRING_DECL(suboption_11, "primary", 7);
+U_STRING_DECL(suboption_12, "secondary", 9);
+U_STRING_DECL(suboption_13, "tertiary", 8);
+U_STRING_DECL(suboption_14, "variable", 8);
+U_STRING_DECL(suboption_15, "regular", 7);
+U_STRING_DECL(suboption_16, "implicit", 8);
+U_STRING_DECL(suboption_17, "trailing", 8);
+
+
+U_STRING_DECL(option_00, "undefined", 9);
+U_STRING_DECL(option_01, "rearrange", 9);
+U_STRING_DECL(option_02, "alternate", 9);
+U_STRING_DECL(option_03, "backwards", 9);
+U_STRING_DECL(option_04, "variable top", 12);
+U_STRING_DECL(option_05, "top", 3);
+U_STRING_DECL(option_06, "normalization", 13);
+U_STRING_DECL(option_07, "caseLevel", 9);
+U_STRING_DECL(option_08, "caseFirst", 9);
+U_STRING_DECL(option_09, "scriptOrder", 11);
+U_STRING_DECL(option_10, "charsetname", 11);
+U_STRING_DECL(option_11, "charset", 7);
+U_STRING_DECL(option_12, "before", 6);
+U_STRING_DECL(option_13, "hiraganaQ", 9);
+U_STRING_DECL(option_14, "strength", 8);
+U_STRING_DECL(option_15, "first", 5);
+U_STRING_DECL(option_16, "last", 4);
+U_STRING_DECL(option_17, "optimize", 8);
+U_STRING_DECL(option_18, "suppressContractions", 20);
+U_STRING_DECL(option_19, "numericOrdering", 15);
+
+
+/*
+[last variable] last variable value
+[last primary ignorable] largest CE for primary ignorable
+[last secondary ignorable] largest CE for secondary ignorable
+[last tertiary ignorable] largest CE for tertiary ignorable
+[top] guaranteed to be above all implicit CEs, for now and in the future (in 1.8)
+*/
+
+
+static const ucolTokSuboption alternateSub[2] = {
+ {suboption_00, 13, UCOL_NON_IGNORABLE},
+ {suboption_01, 7, UCOL_SHIFTED}
+};
+
+static const ucolTokSuboption caseFirstSub[3] = {
+ {suboption_02, 5, UCOL_LOWER_FIRST},
+ {suboption_03, 5, UCOL_UPPER_FIRST},
+ {suboption_04, 3, UCOL_OFF},
+};
+
+static const ucolTokSuboption onOffSub[2] = {
+ {suboption_04, 3, UCOL_OFF},
+ {suboption_05, 2, UCOL_ON}
+};
+
+static const ucolTokSuboption frenchSub[1] = {
+ {suboption_07, 1, UCOL_ON}
+};
+
+static const ucolTokSuboption beforeSub[3] = {
+ {suboption_06, 1, UCOL_PRIMARY},
+ {suboption_07, 1, UCOL_SECONDARY},
+ {suboption_08, 1, UCOL_TERTIARY}
+};
+
+static const ucolTokSuboption strengthSub[5] = {
+ {suboption_06, 1, UCOL_PRIMARY},
+ {suboption_07, 1, UCOL_SECONDARY},
+ {suboption_08, 1, UCOL_TERTIARY},
+ {suboption_09, 1, UCOL_QUATERNARY},
+ {suboption_10, 1, UCOL_IDENTICAL},
+};
+
+static const ucolTokSuboption firstLastSub[7] = {
+ {suboption_11, 7, UCOL_PRIMARY},
+ {suboption_12, 9, UCOL_PRIMARY},
+ {suboption_13, 8, UCOL_PRIMARY},
+ {suboption_14, 8, UCOL_PRIMARY},
+ {suboption_15, 7, UCOL_PRIMARY},
+ {suboption_16, 8, UCOL_PRIMARY},
+ {suboption_17, 8, UCOL_PRIMARY},
+};
+
+enum OptionNumber {
+ OPTION_ALTERNATE_HANDLING = 0,
+ OPTION_FRENCH_COLLATION,
+ OPTION_CASE_LEVEL,
+ OPTION_CASE_FIRST,
+ OPTION_NORMALIZATION_MODE,
+ OPTION_HIRAGANA_QUATERNARY,
+ OPTION_STRENGTH,
+ OPTION_NUMERIC_COLLATION,
+ OPTION_NORMAL_OPTIONS_LIMIT = OPTION_NUMERIC_COLLATION,
+ OPTION_VARIABLE_TOP,
+ OPTION_REARRANGE,
+ OPTION_BEFORE,
+ OPTION_TOP,
+ OPTION_FIRST,
+ OPTION_LAST,
+ OPTION_OPTIMIZE,
+ OPTION_SUPPRESS_CONTRACTIONS,
+ OPTION_UNDEFINED,
+ OPTION_SCRIPT_ORDER,
+ OPTION_CHARSET_NAME,
+ OPTION_CHARSET
+} ;
+
+static const ucolTokOption rulesOptions[UTOK_OPTION_COUNT] = {
+ /*00*/ {option_02, 9, alternateSub, 2, UCOL_ALTERNATE_HANDLING}, /*"alternate" */
+ /*01*/ {option_03, 9, frenchSub, 1, UCOL_FRENCH_COLLATION}, /*"backwards" */
+ /*02*/ {option_07, 9, onOffSub, 2, UCOL_CASE_LEVEL}, /*"caseLevel" */
+ /*03*/ {option_08, 9, caseFirstSub, 3, UCOL_CASE_FIRST}, /*"caseFirst" */
+ /*04*/ {option_06, 13, onOffSub, 2, UCOL_NORMALIZATION_MODE}, /*"normalization" */
+ /*05*/ {option_13, 9, onOffSub, 2, UCOL_HIRAGANA_QUATERNARY_MODE}, /*"hiraganaQ" */
+ /*06*/ {option_14, 8, strengthSub, 5, UCOL_STRENGTH}, /*"strength" */
+ /*07*/ {option_19, 15, onOffSub, 2, UCOL_NUMERIC_COLLATION}, /*"numericOrdering"*/
+ /*08*/ {option_04, 12, NULL, 0, UCOL_ATTRIBUTE_COUNT}, /*"variable top" */
+ /*09*/ {option_01, 9, NULL, 0, UCOL_ATTRIBUTE_COUNT}, /*"rearrange" */
+ /*10*/ {option_12, 6, beforeSub, 3, UCOL_ATTRIBUTE_COUNT}, /*"before" */
+ /*11*/ {option_05, 3, NULL, 0, UCOL_ATTRIBUTE_COUNT}, /*"top" */
+ /*12*/ {option_15, 5, firstLastSub, 7, UCOL_ATTRIBUTE_COUNT}, /*"first" */
+ /*13*/ {option_16, 4, firstLastSub, 7, UCOL_ATTRIBUTE_COUNT}, /*"last" */
+ /*14*/ {option_17, 8, NULL, 0, UCOL_ATTRIBUTE_COUNT}, /*"optimize" */
+ /*15*/ {option_18, 20, NULL, 0, UCOL_ATTRIBUTE_COUNT}, /*"suppressContractions" */
+ /*16*/ {option_00, 9, NULL, 0, UCOL_ATTRIBUTE_COUNT}, /*"undefined" */
+ /*17*/ {option_09, 11, NULL, 0, UCOL_ATTRIBUTE_COUNT}, /*"scriptOrder" */
+ /*18*/ {option_10, 11, NULL, 0, UCOL_ATTRIBUTE_COUNT}, /*"charsetname" */
+ /*19*/ {option_11, 7, NULL, 0, UCOL_ATTRIBUTE_COUNT} /*"charset" */
+};
+
+static
+int32_t u_strncmpNoCase(const UChar *s1,
+ const UChar *s2,
+ int32_t n)
+{
+ if(n > 0) {
+ int32_t rc;
+ for(;;) {
+ rc = (int32_t)u_tolower(*s1) - (int32_t)u_tolower(*s2);
+ if(rc != 0 || *s1 == 0 || --n == 0) {
+ return rc;
+ }
+ ++s1;
+ ++s2;
+ }
+ }
+ return 0;
+}
+
+static
+void ucol_uprv_tok_initData() {
+ if(!didInit) {
+ U_STRING_INIT(suboption_00, "non-ignorable", 13);
+ U_STRING_INIT(suboption_01, "shifted", 7);
+
+ U_STRING_INIT(suboption_02, "lower", 5);
+ U_STRING_INIT(suboption_03, "upper", 5);
+ U_STRING_INIT(suboption_04, "off", 3);
+ U_STRING_INIT(suboption_05, "on", 2);
+
+ U_STRING_INIT(suboption_06, "1", 1);
+ U_STRING_INIT(suboption_07, "2", 1);
+ U_STRING_INIT(suboption_08, "3", 1);
+ U_STRING_INIT(suboption_09, "4", 1);
+ U_STRING_INIT(suboption_10, "I", 1);
+
+ U_STRING_INIT(suboption_11, "primary", 7);
+ U_STRING_INIT(suboption_12, "secondary", 9);
+ U_STRING_INIT(suboption_13, "tertiary", 8);
+ U_STRING_INIT(suboption_14, "variable", 8);
+ U_STRING_INIT(suboption_15, "regular", 7);
+ U_STRING_INIT(suboption_16, "implicit", 8);
+ U_STRING_INIT(suboption_17, "trailing", 8);
+
+
+ U_STRING_INIT(option_00, "undefined", 9);
+ U_STRING_INIT(option_01, "rearrange", 9);
+ U_STRING_INIT(option_02, "alternate", 9);
+ U_STRING_INIT(option_03, "backwards", 9);
+ U_STRING_INIT(option_04, "variable top", 12);
+ U_STRING_INIT(option_05, "top", 3);
+ U_STRING_INIT(option_06, "normalization", 13);
+ U_STRING_INIT(option_07, "caseLevel", 9);
+ U_STRING_INIT(option_08, "caseFirst", 9);
+ U_STRING_INIT(option_09, "scriptOrder", 11);
+ U_STRING_INIT(option_10, "charsetname", 11);
+ U_STRING_INIT(option_11, "charset", 7);
+ U_STRING_INIT(option_12, "before", 6);
+ U_STRING_INIT(option_13, "hiraganaQ", 9);
+ U_STRING_INIT(option_14, "strength", 8);
+ U_STRING_INIT(option_15, "first", 5);
+ U_STRING_INIT(option_16, "last", 4);
+ U_STRING_INIT(option_17, "optimize", 8);
+ U_STRING_INIT(option_18, "suppressContractions", 20);
+ U_STRING_INIT(option_19, "numericOrdering", 15);
+ didInit = TRUE;
+ }
+}
+
+
+// This function reads basic options to set in the runtime collator
+// used by data driven tests. Should not support build time options
+U_CAPI const UChar * U_EXPORT2
+ucol_tok_getNextArgument(const UChar *start, const UChar *end,
+ UColAttribute *attrib, UColAttributeValue *value,
+ UErrorCode *status)
+{
+ uint32_t i = 0;
+ int32_t j=0;
+ UBool foundOption = FALSE;
+ const UChar *optionArg = NULL;
+
+ ucol_uprv_tok_initData();
+
+ while(start < end && u_isWhitespace(*start)) { /* eat whitespace */
+ start++;
+ }
+ if(start >= end) {
+ return NULL;
+ }
+ /* skip opening '[' */
+ if(*start == 0x005b) {
+ start++;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR; // no opening '['
+ return NULL;
+ }
+
+ while(i < UTOK_OPTION_COUNT) {
+ if(u_strncmpNoCase(start, rulesOptions[i].optionName, rulesOptions[i].optionLen) == 0) {
+ foundOption = TRUE;
+ if(end - start > rulesOptions[i].optionLen) {
+ optionArg = start+rulesOptions[i].optionLen+1; /* start of the options, skip space */
+ while(u_isWhitespace(*optionArg)) { /* eat whitespace */
+ optionArg++;
+ }
+ }
+ break;
+ }
+ i++;
+ }
+
+ if(!foundOption) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ if(optionArg) {
+ for(j = 0; j<rulesOptions[i].subSize; j++) {
+ if(u_strncmpNoCase(optionArg, rulesOptions[i].subopts[j].subName, rulesOptions[i].subopts[j].subLen) == 0) {
+ //ucol_uprv_tok_setOptionInImage(src->opts, rulesOptions[i].attr, rulesOptions[i].subopts[j].attrVal);
+ *attrib = rulesOptions[i].attr;
+ *value = rulesOptions[i].subopts[j].attrVal;
+ optionArg += rulesOptions[i].subopts[j].subLen;
+ while(u_isWhitespace(*optionArg)) { /* eat whitespace */
+ optionArg++;
+ }
+ if(*optionArg == 0x005d) {
+ optionArg++;
+ return optionArg;
+ } else {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ }
+ }
+ }
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+}
+
+static
+USet *ucol_uprv_tok_readAndSetUnicodeSet(const UChar *start, const UChar *end, UErrorCode *status) {
+ while(*start != 0x005b) { /* advance while we find the first '[' */
+ start++;
+ }
+ // now we need to get a balanced set of '[]'. The problem is that a set can have
+ // many, and *end point to the first closing '['
+ int32_t noOpenBraces = 1;
+ int32_t current = 1; // skip the opening brace
+ while(start+current < end && noOpenBraces != 0) {
+ if(start[current] == 0x005b) {
+ noOpenBraces++;
+ } else if(start[current] == 0x005D) { // closing brace
+ noOpenBraces--;
+ }
+ current++;
+ }
+
+ if(noOpenBraces != 0 || u_strchr(start+current, 0x005d /*']'*/) == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ return uset_openPattern(start, current, status);
+}
+
+static
+int32_t ucol_uprv_tok_readOption(const UChar *start, const UChar *end, const UChar **optionArg) {
+ int32_t i = 0;
+ ucol_uprv_tok_initData();
+
+ while(u_isWhitespace(*start)) { /* eat whitespace */
+ start++;
+ }
+ while(i < UTOK_OPTION_COUNT) {
+ if(u_strncmpNoCase(start, rulesOptions[i].optionName, rulesOptions[i].optionLen) == 0) {
+ if(end - start > rulesOptions[i].optionLen) {
+ *optionArg = start+rulesOptions[i].optionLen; /* start of the options*/
+ while(u_isWhitespace(**optionArg)) { /* eat whitespace */
+ (*optionArg)++;
+ }
+ }
+ break;
+ }
+ i++;
+ }
+ if(i == UTOK_OPTION_COUNT) {
+ i = -1; // didn't find an option
+ }
+ return i;
+}
+
+
+// reads and conforms to various options in rules
+// end is the position of the first closing ']'
+// However, some of the options take an UnicodeSet definition
+// which needs to duplicate the closing ']'
+// for example: '[copy [\uAC00-\uD7FF]]'
+// These options will move end to the second ']' and the
+// caller will set the current to it.
+static
+uint8_t ucol_uprv_tok_readAndSetOption(UColTokenParser *src, UErrorCode *status) {
+ const UChar* start = src->current;
+ int32_t i = 0;
+ int32_t j=0;
+ const UChar *optionArg = NULL;
+
+ uint8_t result = 0;
+
+ start++; /*skip opening '['*/
+ i = ucol_uprv_tok_readOption(start, src->end, &optionArg);
+ if(optionArg) {
+ src->current = optionArg;
+ }
+
+ if(i < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ int32_t noOpenBraces = 1;
+ switch(i) {
+ case OPTION_ALTERNATE_HANDLING:
+ case OPTION_FRENCH_COLLATION:
+ case OPTION_CASE_LEVEL:
+ case OPTION_CASE_FIRST:
+ case OPTION_NORMALIZATION_MODE:
+ case OPTION_HIRAGANA_QUATERNARY:
+ case OPTION_STRENGTH:
+ case OPTION_NUMERIC_COLLATION:
+ if(optionArg) {
+ for(j = 0; j<rulesOptions[i].subSize; j++) {
+ if(u_strncmpNoCase(optionArg, rulesOptions[i].subopts[j].subName, rulesOptions[i].subopts[j].subLen) == 0) {
+ ucol_uprv_tok_setOptionInImage(src->opts, rulesOptions[i].attr, rulesOptions[i].subopts[j].attrVal);
+ result = UCOL_TOK_SUCCESS;
+ }
+ }
+ }
+ if(result == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+ case OPTION_VARIABLE_TOP:
+ result = UCOL_TOK_SUCCESS | UCOL_TOK_VARIABLE_TOP;
+ break;
+ case OPTION_REARRANGE:
+ result = UCOL_TOK_SUCCESS;
+ break;
+ case OPTION_BEFORE:
+ if(optionArg) {
+ for(j = 0; j<rulesOptions[i].subSize; j++) {
+ if(u_strncmpNoCase(optionArg, rulesOptions[i].subopts[j].subName, rulesOptions[i].subopts[j].subLen) == 0) {
+ result = UCOL_TOK_SUCCESS | rulesOptions[i].subopts[j].attrVal + 1;
+ }
+ }
+ }
+ if(result == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+ case OPTION_TOP: /* we are going to have an array with structures of limit CEs */
+ /* index to this array will be src->parsedToken.indirectIndex*/
+ src->parsedToken.indirectIndex = 0;
+ result = UCOL_TOK_SUCCESS | UCOL_TOK_TOP;
+ break;
+ case OPTION_FIRST:
+ case OPTION_LAST: /* first, last */
+ for(j = 0; j<rulesOptions[i].subSize; j++) {
+ if(u_strncmpNoCase(optionArg, rulesOptions[i].subopts[j].subName, rulesOptions[i].subopts[j].subLen) == 0) {
+ // the calculation below assumes that OPTION_FIRST and OPTION_LAST are at i and i+1 and that the first
+ // element of indirect boundaries is reserved for top.
+ src->parsedToken.indirectIndex = (uint16_t)(i-OPTION_FIRST+1+j*2);
+ result = UCOL_TOK_SUCCESS | UCOL_TOK_TOP;;
+ }
+ }
+ if(result == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+ case OPTION_OPTIMIZE:
+ case OPTION_SUPPRESS_CONTRACTIONS: // copy and remove are handled before normalization
+ // we need to move end here
+ src->current++; // skip opening brace
+ while(src->current < src->end && noOpenBraces != 0) {
+ if(*src->current == 0x005b) {
+ noOpenBraces++;
+ } else if(*src->current == 0x005D) { // closing brace
+ noOpenBraces--;
+ }
+ src->current++;
+ }
+ result = UCOL_TOK_SUCCESS;
+ break;
+ default:
+ *status = U_UNSUPPORTED_ERROR;
+ break;
+ }
+ }
+ src->current = u_memchr(src->current, 0x005d, src->end-src->current);
+ return result;
+}
+
+
+inline void ucol_tok_addToExtraCurrent(UColTokenParser *src, const UChar *stuff, int32_t len, UErrorCode *status) {
+ if(src->extraCurrent+len >= src->extraEnd) {
+ /* reallocate */
+ UChar *newSrc = (UChar *)uprv_realloc(src->source, (src->extraEnd-src->source)*2*sizeof(UChar));
+ if(newSrc != NULL) {
+ src->current = newSrc + (src->current - src->source);
+ src->extraCurrent = newSrc + (src->extraCurrent - src->source);
+ src->end = newSrc + (src->end - src->source);
+ src->extraEnd = newSrc + (src->extraEnd-src->source)*2;
+ src->sourceCurrent = newSrc + (src->sourceCurrent-src->source);
+ src->source = newSrc;
+ } else {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
+ if(len == 1) {
+ *src->extraCurrent++ = *stuff;
+ } else {
+ uprv_memcpy(src->extraCurrent, stuff, len*sizeof(UChar));
+ src->extraCurrent += len;
+ }
+
+
+}
+
+inline UBool ucol_tok_doSetTop(UColTokenParser *src, UErrorCode *status) {
+ /*
+ top = TRUE;
+ */
+ UChar buff[5];
+ src->parsedToken.charsOffset = (uint32_t)(src->extraCurrent - src->source);
+ buff[0] = 0xFFFE;
+ buff[1] = (UChar)(ucolIndirectBoundaries[src->parsedToken.indirectIndex].startCE >> 16);
+ buff[2] = (UChar)(ucolIndirectBoundaries[src->parsedToken.indirectIndex].startCE & 0xFFFF);
+ if(ucolIndirectBoundaries[src->parsedToken.indirectIndex].startContCE == 0) {
+ src->parsedToken.charsLen = 3;
+ ucol_tok_addToExtraCurrent(src, buff, 3, status);
+ } else {
+ buff[3] = (UChar)(ucolIndirectBoundaries[src->parsedToken.indirectIndex].startContCE >> 16);
+ buff[4] = (UChar)(ucolIndirectBoundaries[src->parsedToken.indirectIndex].startContCE & 0xFFFF);
+ src->parsedToken.charsLen = 5;
+ ucol_tok_addToExtraCurrent(src, buff, 5, status);
+ }
+ return TRUE;
+}
+
+static UBool isCharNewLine(UChar c){
+ switch(c){
+ case 0x000A: /* LF */
+ case 0x000D: /* CR */
+ case 0x000C: /* FF */
+ case 0x0085: /* NEL */
+ case 0x2028: /* LS */
+ case 0x2029: /* PS */
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+U_CAPI const UChar* U_EXPORT2
+ucol_tok_parseNextToken(UColTokenParser *src,
+ UBool startOfRules,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+ /* parsing part */
+ UBool variableTop = FALSE;
+ UBool top = FALSE;
+ UBool inChars = TRUE;
+ UBool inQuote = FALSE;
+ UBool wasInQuote = FALSE;
+ uint8_t before = 0;
+ UBool isEscaped = FALSE;
+ // TODO: replace these variables with src->parsedToken counterparts
+ // no need to use them anymore since we have src->parsedToken.
+ // Ideally, token parser would be a nice class... Once, when I have
+ // more time (around 2020 probably).
+ uint32_t newExtensionLen = 0;
+ uint32_t extensionOffset = 0;
+ uint32_t newStrength = UCOL_TOK_UNSET;
+ UChar buff[10];
+
+ src->parsedToken.charsOffset = 0; src->parsedToken.charsLen = 0;
+ src->parsedToken.prefixOffset = 0; src->parsedToken.prefixLen = 0;
+ src->parsedToken.indirectIndex = 0;
+
+ while (src->current < src->end) {
+ UChar ch = *(src->current);
+
+ if (inQuote) {
+ if (ch == 0x0027/*'\''*/) {
+ inQuote = FALSE;
+ } else {
+ if ((src->parsedToken.charsLen == 0) || inChars) {
+ if(src->parsedToken.charsLen == 0) {
+ src->parsedToken.charsOffset = (uint32_t)(src->extraCurrent - src->source);
+ }
+ src->parsedToken.charsLen++;
+ } else {
+ if(newExtensionLen == 0) {
+ extensionOffset = (uint32_t)(src->extraCurrent - src->source);
+ }
+ newExtensionLen++;
+ }
+ }
+ }else if(isEscaped){
+ isEscaped =FALSE;
+ if (newStrength == UCOL_TOK_UNSET) {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ return NULL;
+ // enabling rules to start with non-tokens a < b
+ // newStrength = UCOL_TOK_RESET;
+ }
+ if(ch != 0x0000 && src->current != src->end) {
+ if (inChars) {
+ if(src->parsedToken.charsLen == 0) {
+ src->parsedToken.charsOffset = (uint32_t)(src->current - src->source);
+ }
+ src->parsedToken.charsLen++;
+ } else {
+ if(newExtensionLen == 0) {
+ extensionOffset = (uint32_t)(src->current - src->source);
+ }
+ newExtensionLen++;
+ }
+ }
+ }else {
+ if(!uprv_isRuleWhiteSpace(ch)) {
+ /* Sets the strength for this entry */
+ switch (ch) {
+ case 0x003D/*'='*/ :
+ if (newStrength != UCOL_TOK_UNSET) {
+ goto EndOfLoop;
+ }
+
+ /* if we start with strength, we'll reset to top */
+ if(startOfRules == TRUE) {
+ src->parsedToken.indirectIndex = 5;
+ top = ucol_tok_doSetTop(src, status);
+ newStrength = UCOL_TOK_RESET;
+ goto EndOfLoop;
+ }
+ newStrength = UCOL_IDENTICAL;
+ break;
+
+ case 0x002C/*','*/:
+ if (newStrength != UCOL_TOK_UNSET) {
+ goto EndOfLoop;
+ }
+
+ /* if we start with strength, we'll reset to top */
+ if(startOfRules == TRUE) {
+ src->parsedToken.indirectIndex = 5;
+ top = ucol_tok_doSetTop(src, status);
+ newStrength = UCOL_TOK_RESET;
+ goto EndOfLoop;
+ }
+ newStrength = UCOL_TERTIARY;
+ break;
+
+ case 0x003B/*';'*/:
+ if (newStrength != UCOL_TOK_UNSET) {
+ goto EndOfLoop;
+ }
+
+ /* if we start with strength, we'll reset to top */
+ if(startOfRules == TRUE) {
+ src->parsedToken.indirectIndex = 5;
+ top = ucol_tok_doSetTop(src, status);
+ newStrength = UCOL_TOK_RESET;
+ goto EndOfLoop;
+ }
+ newStrength = UCOL_SECONDARY;
+ break;
+
+ case 0x003C/*'<'*/:
+ if (newStrength != UCOL_TOK_UNSET) {
+ goto EndOfLoop;
+ }
+
+ /* if we start with strength, we'll reset to top */
+ if(startOfRules == TRUE) {
+ src->parsedToken.indirectIndex = 5;
+ top = ucol_tok_doSetTop(src, status);
+ newStrength = UCOL_TOK_RESET;
+ goto EndOfLoop;
+ }
+ /* before this, do a scan to verify whether this is */
+ /* another strength */
+ if(*(src->current+1) == 0x003C) {
+ src->current++;
+ if(*(src->current+1) == 0x003C) {
+ src->current++; /* three in a row! */
+ newStrength = UCOL_TERTIARY;
+ } else { /* two in a row */
+ newStrength = UCOL_SECONDARY;
+ }
+ } else { /* just one */
+ newStrength = UCOL_PRIMARY;
+ }
+ break;
+
+ case 0x0026/*'&'*/:
+ if (newStrength != UCOL_TOK_UNSET) {
+ /**/
+ goto EndOfLoop;
+ }
+
+ newStrength = UCOL_TOK_RESET; /* PatternEntry::RESET = 0 */
+ break;
+
+ case 0x005b/*'['*/:
+ /* options - read an option, analyze it */
+ if(u_strchr(src->current, 0x005d /*']'*/) != NULL) {
+ uint8_t result = ucol_uprv_tok_readAndSetOption(src, status);
+ if(U_SUCCESS(*status)) {
+ if(result & UCOL_TOK_TOP) {
+ if(newStrength == UCOL_TOK_RESET) {
+ top = ucol_tok_doSetTop(src, status);
+ if(before) { // This is a combination of before and indirection like '&[before 2][first regular]<b'
+ src->parsedToken.charsLen+=2;
+ buff[0] = 0x002d;
+ buff[1] = before;
+ ucol_tok_addToExtraCurrent(src, buff, 2, status);
+ }
+
+ src->current++;
+ goto EndOfLoop;
+ } else {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ }
+ } else if(result & UCOL_TOK_VARIABLE_TOP) {
+ if(newStrength != UCOL_TOK_RESET && newStrength != UCOL_TOK_UNSET) {
+ variableTop = TRUE;
+ src->parsedToken.charsOffset = (uint32_t)(src->extraCurrent - src->source);
+ src->parsedToken.charsLen = 1;
+ buff[0] = 0xFFFF;
+ ucol_tok_addToExtraCurrent(src, buff, 1, status);
+ src->current++;
+ goto EndOfLoop;
+ } else {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ }
+ } else if (result & UCOL_TOK_BEFORE){
+ if(newStrength == UCOL_TOK_RESET) {
+ before = result & UCOL_TOK_BEFORE;
+ } else {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+
+ }
+ }
+ } else {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ return NULL;
+ }
+ }
+ break;
+ case 0x0021/*! skip java thai modifier reordering*/:
+ break;
+ case 0x002F/*'/'*/:
+ wasInQuote = FALSE; /* if we were copying source characters, we want to stop now */
+ inChars = FALSE; /* we're now processing expansion */
+ break;
+ case 0x005C /* back slash for escaped chars */:
+ isEscaped = TRUE;
+ break;
+ /* found a quote, we're gonna start copying */
+ case 0x0027/*'\''*/:
+ if (newStrength == UCOL_TOK_UNSET) { /* quote is illegal until we have a strength */
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ return NULL;
+ // enabling rules to start with a non-token character a < b
+ // newStrength = UCOL_TOK_RESET;
+ }
+
+ inQuote = TRUE;
+
+ if(inChars) { /* we're doing characters */
+ if(wasInQuote == FALSE) {
+ src->parsedToken.charsOffset = (uint32_t)(src->extraCurrent - src->source);
+ }
+ if (src->parsedToken.charsLen != 0) {
+ ucol_tok_addToExtraCurrent(src, src->current - src->parsedToken.charsLen, src->parsedToken.charsLen, status);
+ }
+ src->parsedToken.charsLen++;
+ } else { /* we're doing an expansion */
+ if(wasInQuote == FALSE) {
+ extensionOffset = (uint32_t)(src->extraCurrent - src->source);
+ }
+ if (newExtensionLen != 0) {
+ ucol_tok_addToExtraCurrent(src, src->current - newExtensionLen, newExtensionLen, status);
+ }
+ newExtensionLen++;
+ }
+
+ wasInQuote = TRUE;
+
+ ch = *(++(src->current));
+ if(ch == 0x0027) { /* copy the double quote */
+ ucol_tok_addToExtraCurrent(src, &ch, 1, status);
+ inQuote = FALSE;
+ }
+ break;
+
+ /* '@' is french only if the strength is not currently set */
+ /* if it is, it's just a regular character in collation rules */
+ case 0x0040/*'@'*/:
+ if (newStrength == UCOL_TOK_UNSET) {
+ src->opts->frenchCollation = UCOL_ON;
+ break;
+ }
+
+ case 0x007C /*|*/: /* this means we have actually been reading prefix part */
+ // we want to store read characters to the prefix part and continue reading
+ // the characters (proper way would be to restart reading the chars, but in
+ // that case we would have to complicate the token hasher, which I do not
+ // intend to play with. Instead, we will do prefixes when prefixes are due
+ // (before adding the elements).
+ src->parsedToken.prefixOffset = src->parsedToken.charsOffset;
+ src->parsedToken.prefixLen = src->parsedToken.charsLen;
+
+ if(inChars) { /* we're doing characters */
+ if(wasInQuote == FALSE) {
+ src->parsedToken.charsOffset = (uint32_t)(src->extraCurrent - src->source);
+ }
+ if (src->parsedToken.charsLen != 0) {
+ ucol_tok_addToExtraCurrent(src, src->current - src->parsedToken.charsLen, src->parsedToken.charsLen, status);
+ }
+ src->parsedToken.charsLen++;
+ }
+
+ wasInQuote = TRUE;
+
+ do {
+ ch = *(++(src->current));
+ // skip whitespace between '|' and the character
+ } while (uprv_isRuleWhiteSpace(ch));
+ break;
+
+ //charsOffset = 0;
+ //newCharsLen = 0;
+ //break; // We want to store the whole prefix/character sequence. If we break
+ // the '|' is going to get lost.
+ case 0x0023 /*#*/: /* this is a comment, skip everything through the end of line */
+ do {
+ ch = *(++(src->current));
+ } while (!isCharNewLine(ch));
+
+ break;
+ default:
+ if (newStrength == UCOL_TOK_UNSET) {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ return NULL;
+ }
+
+ if (ucol_tok_isSpecialChar(ch) && (inQuote == FALSE)) {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ return NULL;
+ }
+
+ if(ch == 0x0000 && src->current+1 == src->end) {
+ break;
+ }
+
+ if (inChars) {
+ if(src->parsedToken.charsLen == 0) {
+ src->parsedToken.charsOffset = (uint32_t)(src->current - src->source);
+ }
+ src->parsedToken.charsLen++;
+ } else {
+ if(newExtensionLen == 0) {
+ extensionOffset = (uint32_t)(src->current - src->source);
+ }
+ newExtensionLen++;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if(wasInQuote) {
+ if(ch != 0x27) {
+ if(inQuote || !uprv_isRuleWhiteSpace(ch)) {
+ ucol_tok_addToExtraCurrent(src, &ch, 1, status);
+ }
+ }
+ }
+
+ src->current++;
+ }
+
+EndOfLoop:
+ wasInQuote = FALSE;
+ if (newStrength == UCOL_TOK_UNSET) {
+ return NULL;
+ }
+
+ if (src->parsedToken.charsLen == 0 && top == FALSE) {
+ syntaxError(src->source,(int32_t)(src->current-src->source),(int32_t)(src->end-src->source),parseError);
+ *status = U_INVALID_FORMAT_ERROR;
+ return NULL;
+ }
+
+ src->parsedToken.strength = newStrength;
+ src->parsedToken.extensionOffset = extensionOffset;
+ src->parsedToken.extensionLen = newExtensionLen;
+ src->parsedToken.flags = (UCOL_TOK_VARIABLE_TOP * (variableTop?1:0)) | (UCOL_TOK_TOP * (top?1:0)) | before;
+
+ return src->current;
+}
+
+/*
+Processing Description
+1 Build a ListList. Each list has a header, which contains two lists (positive
+and negative), a reset token, a baseCE, nextCE, and previousCE. The lists and
+reset may be null.
+2 As you process, you keep a LAST pointer that points to the last token you
+handled.
+*/
+
+static UColToken *ucol_tok_initAReset(UColTokenParser *src, UChar *expand, uint32_t *expandNext,
+ UParseError *parseError, UErrorCode *status)
+{
+ if(src->resultLen == src->listCapacity) {
+ // Unfortunately, this won't work, as we store addresses of lhs in token
+ src->listCapacity *= 2;
+ src->lh = (UColTokListHeader *)uprv_realloc(src->lh, src->listCapacity*sizeof(UColTokListHeader));
+ if(src->lh == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ }
+ /* do the reset thing */
+ UColToken *sourceToken = (UColToken *)uprv_malloc(sizeof(UColToken));
+ /* test for NULL */
+ if (sourceToken == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ sourceToken->rulesToParse = src->source;
+ sourceToken->source = src->parsedToken.charsLen << 24 | src->parsedToken.charsOffset;
+ sourceToken->expansion = src->parsedToken.extensionLen << 24 | src->parsedToken.extensionOffset;
+
+ sourceToken->debugSource = *(src->source + src->parsedToken.charsOffset);
+ sourceToken->debugExpansion = *(src->source + src->parsedToken.extensionOffset);
+
+ // keep the flags around so that we know about before
+ sourceToken->flags = src->parsedToken.flags;
+
+ if(src->parsedToken.prefixOffset != 0) {
+ // this is a syntax error
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,src->parsedToken.charsOffset-1,src->parsedToken.charsOffset+src->parsedToken.charsLen,parseError);
+ return 0;
+ } else {
+ sourceToken->prefix = 0;
+ }
+
+ sourceToken->polarity = UCOL_TOK_POLARITY_POSITIVE; /* TODO: this should also handle reverse */
+ sourceToken->strength = UCOL_TOK_RESET;
+ sourceToken->next = NULL;
+ sourceToken->previous = NULL;
+ sourceToken->noOfCEs = 0;
+ sourceToken->noOfExpCEs = 0;
+ sourceToken->listHeader = &src->lh[src->resultLen];
+
+ src->lh[src->resultLen].first = NULL;
+ src->lh[src->resultLen].last = NULL;
+ src->lh[src->resultLen].first = NULL;
+ src->lh[src->resultLen].last = NULL;
+
+ src->lh[src->resultLen].reset = sourceToken;
+
+ /*
+ 3 Consider each item: relation, source, and expansion: e.g. ...< x / y ...
+ First convert all expansions into normal form. Examples:
+ If "xy" doesn't occur earlier in the list or in the UCA, convert &xy * c *
+ d * ... into &x * c/y * d * ...
+ Note: reset values can never have expansions, although they can cause the
+ very next item to have one. They may be contractions, if they are found
+ earlier in the list.
+ */
+ *expandNext = 0;
+ if(expand != NULL) {
+ /* check to see if there is an expansion */
+ if(src->parsedToken.charsLen > 1) {
+ uint32_t resetCharsOffset;
+ resetCharsOffset = (uint32_t)(expand - src->source);
+ sourceToken->source = ((resetCharsOffset - src->parsedToken.charsOffset ) << 24) | src->parsedToken.charsOffset;
+ *expandNext = ((src->parsedToken.charsLen + src->parsedToken.charsOffset - resetCharsOffset)<<24) | (resetCharsOffset);
+ }
+ }
+
+ src->resultLen++;
+
+ uhash_put(src->tailored, sourceToken, sourceToken, status);
+
+ return sourceToken;
+}
+
+static
+inline UColToken *getVirginBefore(UColTokenParser *src, UColToken *sourceToken, uint8_t strength, UParseError *parseError, UErrorCode *status) {
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+ /* this is a virgin before - we need to fish the anchor from the UCA */
+ collIterate s;
+ uint32_t baseCE = UCOL_NOT_FOUND, baseContCE = UCOL_NOT_FOUND;
+ uint32_t CE, SecondCE;
+ uint32_t invPos;
+ if(sourceToken != NULL) {
+ uprv_init_collIterate(src->UCA, src->source+((sourceToken->source)&0xFFFFFF), 1, &s);
+ } else {
+ uprv_init_collIterate(src->UCA, src->source+src->parsedToken.charsOffset /**charsOffset*/, 1, &s);
+ }
+
+ baseCE = ucol_getNextCE(src->UCA, &s, status) & 0xFFFFFF3F;
+ baseContCE = ucol_getNextCE(src->UCA, &s, status);
+ if(baseContCE == UCOL_NO_MORE_CES) {
+ baseContCE = 0;
+ }
+
+
+ UCAConstants *consts = (UCAConstants *)((uint8_t *)src->UCA->image + src->UCA->image->UCAConsts);
+ uint32_t ch = 0;
+ uint32_t expandNext = 0;
+ UColToken key;
+
+ if((baseCE & 0xFF000000) >= (consts->UCA_PRIMARY_IMPLICIT_MIN<<24) && (baseCE & 0xFF000000) <= (consts->UCA_PRIMARY_IMPLICIT_MAX<<24) ) { /* implicits - */
+ uint32_t primary = baseCE & UCOL_PRIMARYMASK | (baseContCE & UCOL_PRIMARYMASK) >> 16;
+ uint32_t raw = uprv_uca_getRawFromImplicit(primary);
+ ch = uprv_uca_getCodePointFromRaw(raw-1);
+ uint32_t primaryCE = uprv_uca_getImplicitFromRaw(raw-1);
+ CE = primaryCE & UCOL_PRIMARYMASK | 0x0505;
+ SecondCE = (primaryCE << 16) & UCOL_PRIMARYMASK | UCOL_CONTINUATION_MARKER;
+
+ src->parsedToken.charsOffset = (uint32_t)(src->extraCurrent - src->source);
+ *src->extraCurrent++ = 0xFFFE;
+ *src->extraCurrent++ = (UChar)ch;
+ src->parsedToken.charsLen++;
+
+ key.source = (src->parsedToken.charsLen/**newCharsLen*/ << 24) | src->parsedToken.charsOffset/**charsOffset*/;
+ key.rulesToParse = src->source;
+
+ //sourceToken = (UColToken *)uhash_iget(src->tailored, (int32_t)key);
+ sourceToken = (UColToken *)uhash_get(src->tailored, &key);
+
+ if(sourceToken == NULL) {
+ src->lh[src->resultLen].baseCE = CE & 0xFFFFFF3F;
+ if(isContinuation(SecondCE)) {
+ src->lh[src->resultLen].baseContCE = SecondCE;
+ } else {
+ src->lh[src->resultLen].baseContCE = 0;
+ }
+ src->lh[src->resultLen].nextCE = 0;
+ src->lh[src->resultLen].nextContCE = 0;
+ src->lh[src->resultLen].previousCE = 0;
+ src->lh[src->resultLen].previousContCE = 0;
+
+ src->lh[src->resultLen].indirect = FALSE;
+
+ sourceToken = ucol_tok_initAReset(src, 0, &expandNext, parseError, status);
+ }
+
+ } else {
+ invPos = ucol_inv_getPrevCE(src, baseCE, baseContCE, &CE, &SecondCE, strength);
+
+ // we got the previous CE. Now we need to see if the difference between
+ // the two CEs is really of the requested strength.
+ // if it's a bigger difference (we asked for secondary and got primary), we
+ // need to modify the CE.
+ if(ucol_getCEStrengthDifference(baseCE, baseContCE, CE, SecondCE) < strength) {
+ // adjust the strength
+ // now we are in the situation where our baseCE should actually be modified in
+ // order to get the CE in the right position.
+ if(strength == UCOL_SECONDARY) {
+ CE = baseCE - 0x0200;
+ } else { // strength == UCOL_TERTIARY
+ CE = baseCE - 0x02;
+ }
+ if(baseContCE) {
+ if(strength == UCOL_SECONDARY) {
+ SecondCE = baseContCE - 0x0200;
+ } else { // strength == UCOL_TERTIARY
+ SecondCE = baseContCE - 0x02;
+ }
+ }
+ }
+
+#if 0
+ // the code below relies on getting a code point from the inverse table, in order to be
+ // able to merge the situations like &x < 9 &[before 1]a < d. This won't work:
+ // 1. There are many code points that have the same CE
+ // 2. The CE to codepoint table (things pointed to by CETable[3*invPos+2] are broken.
+ // Also, in case when there is no equivalent strength before an element, we have to actually
+ // construct one. For example, &[before 2]a << x won't result in x << a, because the element
+ // before a is a primary difference.
+
+ //uint32_t *CETable = (uint32_t *)((uint8_t *)src->invUCA+src->invUCA->table);
+
+
+ ch = CETable[3*invPos+2];
+
+ if((ch & UCOL_INV_SIZEMASK) != 0) {
+ uint16_t *conts = (uint16_t *)((uint8_t *)src->invUCA+src->invUCA->conts);
+ uint32_t offset = (ch & UCOL_INV_OFFSETMASK);
+ ch = conts[offset];
+ }
+
+ *src->extraCurrent++ = (UChar)ch;
+ src->parsedToken.charsOffset = (uint32_t)(src->extraCurrent - src->source - 1);
+ src->parsedToken.charsLen = 1;
+
+ // We got an UCA before. However, this might have been tailored.
+ // example:
+ // &\u30ca = \u306a
+ // &[before 3]\u306a<<<\u306a|\u309d
+
+
+ // uint32_t key = (*newCharsLen << 24) | *charsOffset;
+ key.source = (src->parsedToken.charsLen/**newCharsLen*/ << 24) | src->parsedToken.charsOffset/**charsOffset*/;
+ key.rulesToParse = src->source;
+
+ //sourceToken = (UColToken *)uhash_iget(src->tailored, (int32_t)key);
+ sourceToken = (UColToken *)uhash_get(src->tailored, &key);
+#endif
+
+ // here is how it should be. The situation such as &[before 1]a < x, should be
+ // resolved exactly as if we wrote &a > x.
+ // therefore, I don't really care if the UCA value before a has been changed.
+ // However, I do care if the strength between my element and the previous element
+ // is bigger then I wanted. So, if CE < baseCE and I wanted &[before 2], then i'll
+ // have to construct the base CE.
+
+
+
+ // if we found a tailored thing, we have to use the UCA value and construct
+ // a new reset token with constructed name
+ //if(sourceToken != NULL && sourceToken->strength != UCOL_TOK_RESET) {
+ // character to which we want to anchor is already tailored.
+ // We need to construct a new token which will be the anchor
+ // point
+ //*(src->extraCurrent-1) = 0xFFFE;
+ //*src->extraCurrent++ = (UChar)ch;
+ // grab before
+ src->parsedToken.charsOffset -= 10;
+ src->parsedToken.charsLen += 10;
+ src->lh[src->resultLen].baseCE = CE & 0xFFFFFF3F;
+ if(isContinuation(SecondCE)) {
+ src->lh[src->resultLen].baseContCE = SecondCE;
+ } else {
+ src->lh[src->resultLen].baseContCE = 0;
+ }
+ src->lh[src->resultLen].nextCE = 0;
+ src->lh[src->resultLen].nextContCE = 0;
+ src->lh[src->resultLen].previousCE = 0;
+ src->lh[src->resultLen].previousContCE = 0;
+
+ src->lh[src->resultLen].indirect = FALSE;
+
+ sourceToken = ucol_tok_initAReset(src, 0, &expandNext, parseError, status);
+ //}
+ }
+
+ return sourceToken;
+
+}
+
+uint32_t ucol_tok_assembleTokenList(UColTokenParser *src, UParseError *parseError, UErrorCode *status) {
+ UColToken *lastToken = NULL;
+ const UChar *parseEnd = NULL;
+ uint32_t expandNext = 0;
+ UBool variableTop = FALSE;
+ UBool top = FALSE;
+ uint16_t specs = 0;
+ UColTokListHeader *ListList = NULL;
+
+ src->parsedToken.strength = UCOL_TOK_UNSET;
+
+ ListList = src->lh;
+
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ while(src->current < src->end) {
+ src->parsedToken.prefixOffset = 0;
+
+ parseEnd = ucol_tok_parseNextToken(src,
+ (UBool)(lastToken == NULL),
+ parseError,
+ status);
+
+ specs = src->parsedToken.flags;
+
+
+ variableTop = ((specs & UCOL_TOK_VARIABLE_TOP) != 0);
+ top = ((specs & UCOL_TOK_TOP) != 0);
+
+ if(U_SUCCESS(*status) && parseEnd != NULL) {
+ UColToken *sourceToken = NULL;
+ //uint32_t key = 0;
+ uint32_t lastStrength = UCOL_TOK_UNSET;
+
+ if(lastToken != NULL ) {
+ lastStrength = lastToken->strength;
+ }
+
+ //key = newCharsLen << 24 | charsOffset;
+ UColToken key;
+ key.source = src->parsedToken.charsLen << 24 | src->parsedToken.charsOffset;
+ key.rulesToParse = src->source;
+
+ /* 4 Lookup each source in the CharsToToken map, and find a sourceToken */
+ sourceToken = (UColToken *)uhash_get(src->tailored, &key);
+
+ if(src->parsedToken.strength != UCOL_TOK_RESET) {
+ if(lastToken == NULL) { /* this means that rules haven't started properly */
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,0,(int32_t)(src->end-src->source),parseError);
+ return 0;
+ }
+ /* 6 Otherwise (when relation != reset) */
+ if(sourceToken == NULL) {
+ /* If sourceToken is null, create new one, */
+ sourceToken = (UColToken *)uprv_malloc(sizeof(UColToken));
+ /* test for NULL */
+ if (sourceToken == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ sourceToken->rulesToParse = src->source;
+ sourceToken->source = src->parsedToken.charsLen << 24 | src->parsedToken.charsOffset;
+
+ sourceToken->debugSource = *(src->source + src->parsedToken.charsOffset);
+
+ sourceToken->prefix = src->parsedToken.prefixLen << 24 | src->parsedToken.prefixOffset;
+ sourceToken->debugPrefix = *(src->source + src->parsedToken.prefixOffset);
+
+ sourceToken->polarity = UCOL_TOK_POLARITY_POSITIVE; /* TODO: this should also handle reverse */
+ sourceToken->next = NULL;
+ sourceToken->previous = NULL;
+ sourceToken->noOfCEs = 0;
+ sourceToken->noOfExpCEs = 0;
+ // keep the flags around so that we know about before
+ sourceToken->flags = src->parsedToken.flags;
+ uhash_put(src->tailored, sourceToken, sourceToken, status);
+ } else {
+ /* we could have fished out a reset here */
+ if(sourceToken->strength != UCOL_TOK_RESET && lastToken != sourceToken) {
+ /* otherwise remove sourceToken from where it was. */
+ if(sourceToken->next != NULL) {
+ if(sourceToken->next->strength > sourceToken->strength) {
+ sourceToken->next->strength = sourceToken->strength;
+ }
+ sourceToken->next->previous = sourceToken->previous;
+ } else {
+ sourceToken->listHeader->last = sourceToken->previous;
+ }
+
+ if(sourceToken->previous != NULL) {
+ sourceToken->previous->next = sourceToken->next;
+ } else {
+ sourceToken->listHeader->first = sourceToken->next;
+ }
+ sourceToken->next = NULL;
+ sourceToken->previous = NULL;
+ }
+ }
+
+ sourceToken->strength = src->parsedToken.strength;
+ sourceToken->listHeader = lastToken->listHeader;
+
+ /*
+ 1. Find the strongest strength in each list, and set strongestP and strongestN
+ accordingly in the headers.
+ */
+ if(lastStrength == UCOL_TOK_RESET
+ || sourceToken->listHeader->first == 0) {
+ /* If LAST is a reset
+ insert sourceToken in the list. */
+ if(sourceToken->listHeader->first == 0) {
+ sourceToken->listHeader->first = sourceToken;
+ sourceToken->listHeader->last = sourceToken;
+ } else { /* we need to find a place for us */
+ /* and we'll get in front of the same strength */
+ if(sourceToken->listHeader->first->strength <= sourceToken->strength) {
+ sourceToken->next = sourceToken->listHeader->first;
+ sourceToken->next->previous = sourceToken;
+ sourceToken->listHeader->first = sourceToken;
+ sourceToken->previous = NULL;
+ } else {
+ lastToken = sourceToken->listHeader->first;
+ while(lastToken->next != NULL && lastToken->next->strength > sourceToken->strength) {
+ lastToken = lastToken->next;
+ }
+ if(lastToken->next != NULL) {
+ lastToken->next->previous = sourceToken;
+ } else {
+ sourceToken->listHeader->last = sourceToken;
+ }
+ sourceToken->previous = lastToken;
+ sourceToken->next = lastToken->next;
+ lastToken->next = sourceToken;
+ }
+ }
+ } else {
+ /* Otherwise (when LAST is not a reset)
+ if polarity (LAST) == polarity(relation), insert sourceToken after LAST,
+ otherwise insert before.
+ when inserting after or before, search to the next position with the same
+ strength in that direction. (This is called postpone insertion). */
+ if(sourceToken != lastToken) {
+ if(lastToken->polarity == sourceToken->polarity) {
+ while(lastToken->next != NULL && lastToken->next->strength > sourceToken->strength) {
+ lastToken = lastToken->next;
+ }
+ sourceToken->previous = lastToken;
+ if(lastToken->next != NULL) {
+ lastToken->next->previous = sourceToken;
+ } else {
+ sourceToken->listHeader->last = sourceToken;
+ }
+
+ sourceToken->next = lastToken->next;
+ lastToken->next = sourceToken;
+ } else {
+ while(lastToken->previous != NULL && lastToken->previous->strength > sourceToken->strength) {
+ lastToken = lastToken->previous;
+ }
+ sourceToken->next = lastToken;
+ if(lastToken->previous != NULL) {
+ lastToken->previous->next = sourceToken;
+ } else {
+ sourceToken->listHeader->first = sourceToken;
+ }
+ sourceToken->previous = lastToken->previous;
+ lastToken->previous = sourceToken;
+ }
+ } else { /* repeated one thing twice in rules, stay with the stronger strength */
+ if(lastStrength < sourceToken->strength) {
+ sourceToken->strength = lastStrength;
+ }
+ }
+ }
+
+ /* if the token was a variable top, we're gonna put it in */
+ if(variableTop == TRUE && src->varTop == NULL) {
+ variableTop = FALSE;
+ src->varTop = sourceToken;
+ }
+
+ // Treat the expansions.
+ // There are two types of expansions: explicit (x / y) and reset based propagating expansions
+ // (&abc * d * e <=> &ab * d / c * e / c)
+ // if both of them are in effect for a token, they are combined.
+
+ sourceToken->expansion = src->parsedToken.extensionLen << 24 | src->parsedToken.extensionOffset;
+
+ if(expandNext != 0) {
+ if(sourceToken->strength == UCOL_PRIMARY) { /* primary strength kills off the implicit expansion */
+ expandNext = 0;
+ } else if(sourceToken->expansion == 0) { /* if there is no expansion, implicit is just added to the token */
+ sourceToken->expansion = expandNext;
+ } else { /* there is both explicit and implicit expansion. We need to make a combination */
+ uprv_memcpy(src->extraCurrent, src->source + (expandNext & 0xFFFFFF), (expandNext >> 24)*sizeof(UChar));
+ uprv_memcpy(src->extraCurrent+(expandNext >> 24), src->source + src->parsedToken.extensionOffset, src->parsedToken.extensionLen*sizeof(UChar));
+ sourceToken->expansion = (uint32_t)(((expandNext >> 24) + src->parsedToken.extensionLen)<<24 | (uint32_t)(src->extraCurrent - src->source));
+ src->extraCurrent += (expandNext >> 24) + src->parsedToken.extensionLen;
+ }
+ }
+
+ // This is just for debugging purposes
+ if(sourceToken->expansion != 0) {
+ sourceToken->debugExpansion = *(src->source + src->parsedToken.extensionOffset);
+ } else {
+ sourceToken->debugExpansion = 0;
+ }
+ // if the previous token was a reset before, the strength of this
+ // token must match the strength of before. Otherwise we have an
+ // undefined situation.
+ // In other words, we currently have a cludge which we use to
+ // represent &a >> x. This is written as &[before 2]a << x.
+ if((lastToken->flags & UCOL_TOK_BEFORE) != 0) {
+ uint8_t beforeStrength = (lastToken->flags & UCOL_TOK_BEFORE) - 1;
+ if(beforeStrength != sourceToken->strength) {
+ *status = U_INVALID_FORMAT_ERROR;
+ syntaxError(src->source,0,(int32_t)(src->end-src->source),parseError);
+ return 0;
+ }
+ }
+ } else {
+ if(lastToken != NULL && lastStrength == UCOL_TOK_RESET) {
+ /* if the previous token was also a reset, */
+ /*this means that we have two consecutive resets */
+ /* and we want to remove the previous one if empty*/
+ if(src->resultLen > 0 && ListList[src->resultLen-1].first == NULL) {
+ src->resultLen--;
+ }
+ }
+
+ if(sourceToken == NULL) { /* this is a reset, but it might still be somewhere in the tailoring, in shorter form */
+ uint32_t searchCharsLen = src->parsedToken.charsLen;
+ while(searchCharsLen > 1 && sourceToken == NULL) {
+ searchCharsLen--;
+ //key = searchCharsLen << 24 | charsOffset;
+ UColToken key;
+ key.source = searchCharsLen << 24 | src->parsedToken.charsOffset;
+ key.rulesToParse = src->source;
+ sourceToken = (UColToken *)uhash_get(src->tailored, &key);
+ }
+ if(sourceToken != NULL) {
+ expandNext = (src->parsedToken.charsLen - searchCharsLen) << 24 | (src->parsedToken.charsOffset + searchCharsLen);
+ }
+ }
+
+ if((specs & UCOL_TOK_BEFORE) != 0) { /* we're doing before */
+ if(top == FALSE) { /* there is no indirection */
+ uint8_t strength = (specs & UCOL_TOK_BEFORE) - 1;
+ if(sourceToken != NULL && sourceToken->strength != UCOL_TOK_RESET) {
+ /* this is a before that is already ordered in the UCA - so we need to get the previous with good strength */
+ while(sourceToken->strength > strength && sourceToken->previous != NULL) {
+ sourceToken = sourceToken->previous;
+ }
+ /* here, either we hit the strength or NULL */
+ if(sourceToken->strength == strength) {
+ if(sourceToken->previous != NULL) {
+ sourceToken = sourceToken->previous;
+ } else { /* start of list */
+ sourceToken = sourceToken->listHeader->reset;
+ }
+ } else { /* we hit NULL */
+ /* we should be doing the else part */
+ sourceToken = sourceToken->listHeader->reset;
+ sourceToken = getVirginBefore(src, sourceToken, strength, parseError, status);
+ }
+ } else {
+ sourceToken = getVirginBefore(src, sourceToken, strength, parseError, status);
+ }
+ } else { /* this is both before and indirection */
+ top = FALSE;
+ ListList[src->resultLen].previousCE = 0;
+ ListList[src->resultLen].previousContCE = 0;
+ ListList[src->resultLen].indirect = TRUE;
+ /* we need to do slightly more work. we need to get the baseCE using the */
+ /* inverse UCA & getPrevious. The next bound is not set, and will be decided */
+ /* in ucol_bld */
+ uint8_t strength = (specs & UCOL_TOK_BEFORE) - 1;
+ uint32_t baseCE = ucolIndirectBoundaries[src->parsedToken.indirectIndex].startCE;
+ uint32_t baseContCE = ucolIndirectBoundaries[src->parsedToken.indirectIndex].startContCE;//&0xFFFFFF3F;
+ uint32_t CE = UCOL_NOT_FOUND, SecondCE = UCOL_NOT_FOUND;
+
+ UCAConstants *consts = (UCAConstants *)((uint8_t *)src->UCA->image + src->UCA->image->UCAConsts);
+ if((baseCE & 0xFF000000) >= (consts->UCA_PRIMARY_IMPLICIT_MIN<<24) && (baseCE & 0xFF000000) <= (consts->UCA_PRIMARY_IMPLICIT_MAX<<24) ) { /* implicits - */
+ uint32_t primary = baseCE & UCOL_PRIMARYMASK | (baseContCE & UCOL_PRIMARYMASK) >> 16;
+ uint32_t raw = uprv_uca_getRawFromImplicit(primary);
+ uint32_t primaryCE = uprv_uca_getImplicitFromRaw(raw-1);
+ CE = primaryCE & UCOL_PRIMARYMASK | 0x0505;
+ SecondCE = (primaryCE << 16) & UCOL_PRIMARYMASK | UCOL_CONTINUATION_MARKER;
+ } else {
+ /*int32_t invPos = ucol_inv_getPrevCE(baseCE, baseContCE, &CE, &SecondCE, strength);*/
+ ucol_inv_getPrevCE(src, baseCE, baseContCE, &CE, &SecondCE, strength);
+ }
+
+ ListList[src->resultLen].baseCE = CE;
+ ListList[src->resultLen].baseContCE = SecondCE;
+ ListList[src->resultLen].nextCE = 0;
+ ListList[src->resultLen].nextContCE = 0;
+
+ sourceToken = ucol_tok_initAReset(src, 0, &expandNext, parseError, status);
+ }
+ }
+
+
+ /* 5 If the relation is a reset:
+ If sourceToken is null
+ Create new list, create new sourceToken, make the baseCE from source, put
+ the sourceToken in ListHeader of the new list */
+ if(sourceToken == NULL) {
+ /*
+ 3 Consider each item: relation, source, and expansion: e.g. ...< x / y ...
+ First convert all expansions into normal form. Examples:
+ If "xy" doesn't occur earlier in the list or in the UCA, convert &xy * c *
+ d * ... into &x * c/y * d * ...
+ Note: reset values can never have expansions, although they can cause the
+ very next item to have one. They may be contractions, if they are found
+ earlier in the list.
+ */
+ if(top == FALSE) {
+ collIterate s;
+ uint32_t CE = UCOL_NOT_FOUND, SecondCE = UCOL_NOT_FOUND;
+
+ uprv_init_collIterate(src->UCA, src->source+src->parsedToken.charsOffset, src->parsedToken.charsLen, &s);
+
+ CE = ucol_getNextCE(src->UCA, &s, status);
+ UChar *expand = s.pos;
+ SecondCE = ucol_getNextCE(src->UCA, &s, status);
+
+ ListList[src->resultLen].baseCE = CE & 0xFFFFFF3F;
+ if(isContinuation(SecondCE)) {
+ ListList[src->resultLen].baseContCE = SecondCE;
+ } else {
+ ListList[src->resultLen].baseContCE = 0;
+ }
+ ListList[src->resultLen].nextCE = 0;
+ ListList[src->resultLen].nextContCE = 0;
+ ListList[src->resultLen].previousCE = 0;
+ ListList[src->resultLen].previousContCE = 0;
+ ListList[src->resultLen].indirect = FALSE;
+ sourceToken = ucol_tok_initAReset(src, expand, &expandNext, parseError, status);
+ } else { /* top == TRUE */
+ /* just use the supplied values */
+ top = FALSE;
+ ListList[src->resultLen].previousCE = 0;
+ ListList[src->resultLen].previousContCE = 0;
+ ListList[src->resultLen].indirect = TRUE;
+ ListList[src->resultLen].baseCE = ucolIndirectBoundaries[src->parsedToken.indirectIndex].startCE;
+ ListList[src->resultLen].baseContCE = ucolIndirectBoundaries[src->parsedToken.indirectIndex].startContCE;
+ ListList[src->resultLen].nextCE = ucolIndirectBoundaries[src->parsedToken.indirectIndex].limitCE;
+ ListList[src->resultLen].nextContCE = ucolIndirectBoundaries[src->parsedToken.indirectIndex].limitContCE;
+
+ sourceToken = ucol_tok_initAReset(src, 0, &expandNext, parseError, status);
+
+ }
+ } else { /* reset to something already in rules */
+ top = FALSE;
+ }
+ }
+ /* 7 After all this, set LAST to point to sourceToken, and goto step 3. */
+ lastToken = sourceToken;
+ } else {
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ }
+ }
+
+ if(src->resultLen > 0 && ListList[src->resultLen-1].first == NULL) {
+ src->resultLen--;
+ }
+ return src->resultLen;
+}
+
+void ucol_tok_initTokenList(UColTokenParser *src, const UChar *rules, const uint32_t rulesLength, const UCollator *UCA, UErrorCode *status) {
+ U_NAMESPACE_USE
+
+ uint32_t nSize = 0;
+ uint32_t estimatedSize = (2*rulesLength+UCOL_TOK_EXTRA_RULE_SPACE_SIZE);
+ if(U_FAILURE(*status)) {
+ return;
+ }
+
+ // set everything to zero, so that we can clean up gracefully
+ uprv_memset(src, 0, sizeof(UColTokenParser));
+
+ // first we need to find options that don't like to be normalized,
+ // like copy and remove...
+ //const UChar *openBrace = rules;
+ int32_t optionNumber = -1;
+ const UChar *setStart;
+ uint32_t i = 0;
+ while(i < rulesLength) {
+ if(rules[i] == 0x005B) {
+ // while((openBrace = u_strchr(openBrace, 0x005B)) != NULL) { // find open braces
+ //optionNumber = ucol_uprv_tok_readOption(openBrace+1, rules+rulesLength, &setStart);
+ optionNumber = ucol_uprv_tok_readOption(rules+i+1, rules+rulesLength, &setStart);
+ if(optionNumber == OPTION_OPTIMIZE) { /* copy - parts of UCA to tailoring */
+ USet *newSet = ucol_uprv_tok_readAndSetUnicodeSet(setStart, rules+rulesLength, status);
+ if(U_SUCCESS(*status)) {
+ if(src->copySet == NULL) {
+ src->copySet = newSet;
+ } else {
+ uset_addAll(src->copySet, newSet);
+ uset_close(newSet);
+ }
+ } else {
+ return;
+ }
+ } else if(optionNumber == OPTION_SUPPRESS_CONTRACTIONS) {
+ USet *newSet = ucol_uprv_tok_readAndSetUnicodeSet(setStart, rules+rulesLength, status);
+ if(U_SUCCESS(*status)) {
+ if(src->removeSet == NULL) {
+ src->removeSet = newSet;
+ } else {
+ uset_addAll(src->removeSet, newSet);
+ uset_close(newSet);
+ }
+ } else {
+ return;
+ }
+ }
+ }
+ //openBrace++;
+ i++;
+ }
+
+ src->source = (UChar *)uprv_malloc(estimatedSize*sizeof(UChar));
+ /* test for NULL */
+ if (src->source == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_memset(src->source, 0, estimatedSize*sizeof(UChar));
+ nSize = unorm_normalize(rules, rulesLength, UNORM_NFD, 0, src->source, estimatedSize, status);
+ if(nSize > estimatedSize || *status == U_BUFFER_OVERFLOW_ERROR) {
+ *status = U_ZERO_ERROR;
+ src->source = (UChar *)uprv_realloc(src->source, (nSize+UCOL_TOK_EXTRA_RULE_SPACE_SIZE)*sizeof(UChar));
+ /* test for NULL */
+ if (src->source == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ nSize = unorm_normalize(rules, rulesLength, UNORM_NFD, 0, src->source, nSize+UCOL_TOK_EXTRA_RULE_SPACE_SIZE, status);
+ }
+ src->current = src->source;
+ src->end = src->source+nSize;
+ src->sourceCurrent = src->source;
+ src->extraCurrent = src->end+1; // Preserve terminating zero in the rule string so that option scanning works correctly
+ src->extraEnd = src->source+estimatedSize; //src->end+UCOL_TOK_EXTRA_RULE_SPACE_SIZE;
+ src->varTop = NULL;
+ src->UCA = UCA;
+ src->invUCA = ucol_initInverseUCA(status);
+ src->parsedToken.charsLen = 0;
+ src->parsedToken.charsOffset = 0;
+ src->parsedToken.extensionLen = 0;
+ src->parsedToken.extensionOffset = 0;
+ src->parsedToken.prefixLen = 0;
+ src->parsedToken.prefixOffset = 0;
+ src->parsedToken.flags = 0;
+ src->parsedToken.strength = UCOL_TOK_UNSET;
+ src->buildCCTabFlag = FALSE;
+
+ if(U_FAILURE(*status)) {
+ return;
+ }
+ src->tailored = uhash_open(uhash_hashTokens, uhash_compareTokens, NULL, status);
+ if(U_FAILURE(*status)) {
+ return;
+ }
+ uhash_setValueDeleter(src->tailored, uhash_freeBlock);
+
+ src->opts = (UColOptionSet *)uprv_malloc(sizeof(UColOptionSet));
+ /* test for NULL */
+ if (src->opts == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ uprv_memcpy(src->opts, UCA->options, sizeof(UColOptionSet));
+
+ // rulesToParse = src->source;
+ src->lh = 0;
+ src->listCapacity = 1024;
+ src->lh = (UColTokListHeader *)uprv_malloc(src->listCapacity*sizeof(UColTokListHeader));
+ //Test for NULL
+ if (src->lh == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_memset(src->lh, 0, src->listCapacity*sizeof(UColTokListHeader));
+ src->resultLen = 0;
+
+ UCAConstants *consts = (UCAConstants *)((uint8_t *)src->UCA->image + src->UCA->image->UCAConsts);
+
+ // UCOL_RESET_TOP_VALUE
+ setIndirectBoundaries(0, consts->UCA_LAST_NON_VARIABLE, consts->UCA_FIRST_IMPLICIT);
+ // UCOL_FIRST_PRIMARY_IGNORABLE
+ setIndirectBoundaries(1, consts->UCA_FIRST_PRIMARY_IGNORABLE, 0);
+ // UCOL_LAST_PRIMARY_IGNORABLE
+ setIndirectBoundaries(2, consts->UCA_LAST_PRIMARY_IGNORABLE, 0);
+ // UCOL_FIRST_SECONDARY_IGNORABLE
+ setIndirectBoundaries(3, consts->UCA_FIRST_SECONDARY_IGNORABLE, 0);
+ // UCOL_LAST_SECONDARY_IGNORABLE
+ setIndirectBoundaries(4, consts->UCA_LAST_SECONDARY_IGNORABLE, 0);
+ // UCOL_FIRST_TERTIARY_IGNORABLE
+ setIndirectBoundaries(5, consts->UCA_FIRST_TERTIARY_IGNORABLE, 0);
+ // UCOL_LAST_TERTIARY_IGNORABLE
+ setIndirectBoundaries(6, consts->UCA_LAST_TERTIARY_IGNORABLE, 0);
+ // UCOL_FIRST_VARIABLE
+ setIndirectBoundaries(7, consts->UCA_FIRST_VARIABLE, 0);
+ // UCOL_LAST_VARIABLE
+ setIndirectBoundaries(8, consts->UCA_LAST_VARIABLE, 0);
+ // UCOL_FIRST_NON_VARIABLE
+ setIndirectBoundaries(9, consts->UCA_FIRST_NON_VARIABLE, 0);
+ // UCOL_LAST_NON_VARIABLE
+ setIndirectBoundaries(10, consts->UCA_LAST_NON_VARIABLE, consts->UCA_FIRST_IMPLICIT);
+ // UCOL_FIRST_IMPLICIT
+ setIndirectBoundaries(11, consts->UCA_FIRST_IMPLICIT, 0);
+ // UCOL_LAST_IMPLICIT
+ setIndirectBoundaries(12, consts->UCA_LAST_IMPLICIT, consts->UCA_FIRST_TRAILING);
+ // UCOL_FIRST_TRAILING
+ setIndirectBoundaries(13, consts->UCA_FIRST_TRAILING, 0);
+ // UCOL_LAST_TRAILING
+ setIndirectBoundaries(14, consts->UCA_LAST_TRAILING, 0);
+ ucolIndirectBoundaries[14].limitCE = (consts->UCA_PRIMARY_SPECIAL_MIN<<24);
+}
+
+
+void ucol_tok_closeTokenList(UColTokenParser *src) {
+ if(src->copySet != NULL) {
+ uset_close(src->copySet);
+ }
+ if(src->removeSet != NULL) {
+ uset_close(src->removeSet);
+ }
+ if(src->tailored != NULL) {
+ uhash_close(src->tailored);
+ }
+ if(src->lh != NULL) {
+ uprv_free(src->lh);
+ }
+ if(src->source != NULL) {
+ uprv_free(src->source);
+ }
+ if(src->opts != NULL) {
+ uprv_free(src->opts);
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_tok.h b/Build/source/libs/icu/icu-xetex/i18n/ucol_tok.h
new file mode 100644
index 00000000000..fc252e94c22
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_tok.h
@@ -0,0 +1,184 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: ucol_tok.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created 02/22/2001
+* created by: Vladimir Weinstein
+*
+* This module reads a tailoring rule string and produces a list of
+* tokens that will be turned into collation elements
+*
+*/
+
+#ifndef UCOL_TOKENS_H
+#define UCOL_TOKENS_H
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "ucol_imp.h"
+#include "uhash.h"
+#include "unicode/parseerr.h"
+
+#define UCOL_TOK_UNSET 0xFFFFFFFF
+#define UCOL_TOK_RESET 0xDEADBEEF
+
+#define UCOL_TOK_POLARITY_NEGATIVE 0
+#define UCOL_TOK_POLARITY_POSITIVE 1
+
+#define UCOL_TOK_TOP 0x04
+#define UCOL_TOK_VARIABLE_TOP 0x08
+#define UCOL_TOK_BEFORE 0x03
+#define UCOL_TOK_SUCCESS 0x10
+
+/* this is space for the extra strings that need to be unquoted */
+/* during the parsing of the rules */
+#define UCOL_TOK_EXTRA_RULE_SPACE_SIZE 4096
+typedef struct UColToken UColToken;
+
+typedef struct {
+ UColToken* first;
+ UColToken* last;
+ UColToken* reset;
+ UBool indirect;
+ uint32_t baseCE;
+ uint32_t baseContCE;
+ uint32_t nextCE;
+ uint32_t nextContCE;
+ uint32_t previousCE;
+ uint32_t previousContCE;
+ int32_t pos[UCOL_STRENGTH_LIMIT];
+ uint32_t gapsLo[3*UCOL_CE_STRENGTH_LIMIT];
+ uint32_t gapsHi[3*UCOL_CE_STRENGTH_LIMIT];
+ uint32_t numStr[UCOL_CE_STRENGTH_LIMIT];
+ UColToken* fStrToken[UCOL_CE_STRENGTH_LIMIT];
+ UColToken* lStrToken[UCOL_CE_STRENGTH_LIMIT];
+} UColTokListHeader;
+
+struct UColToken {
+ UChar debugSource;
+ UChar debugExpansion;
+ UChar debugPrefix;
+ uint32_t CEs[128];
+ uint32_t noOfCEs;
+ uint32_t expCEs[128];
+ uint32_t noOfExpCEs;
+ uint32_t source;
+ uint32_t expansion;
+ uint32_t prefix;
+ uint32_t strength;
+ uint32_t toInsert;
+ uint32_t polarity; /* 1 for <, <<, <<<, , ; and -1 for >, >>, >>> */
+ UColTokListHeader *listHeader;
+ UColToken* previous;
+ UColToken* next;
+ UChar *rulesToParse;
+ uint16_t flags;
+};
+
+/*
+ * This is a token that has been parsed
+ * but not yet processed. Used to reduce
+ * the number of arguments in the parser
+ */
+typedef struct {
+ uint32_t strength;
+ uint32_t charsOffset;
+ uint32_t charsLen;
+ uint32_t extensionOffset;
+ uint32_t extensionLen;
+ uint32_t prefixOffset;
+ uint32_t prefixLen;
+ uint16_t flags;
+ uint16_t indirectIndex;
+} UColParsedToken;
+
+
+typedef struct {
+ UColParsedToken parsedToken;
+ UChar *source;
+ UChar *end;
+ const UChar *current;
+ UChar *sourceCurrent;
+ UChar *extraCurrent;
+ UChar *extraEnd;
+ const InverseUCATableHeader *invUCA;
+ const UCollator *UCA;
+ UHashtable *tailored;
+ UColOptionSet *opts;
+ uint32_t resultLen;
+ uint32_t listCapacity;
+ UColTokListHeader *lh;
+ UColToken *varTop;
+ USet *copySet;
+ USet *removeSet;
+ UBool buildCCTabFlag; /* Tailoring rule requirs building combining class table. */
+} UColTokenParser;
+
+typedef struct {
+ const UChar *subName;
+ int32_t subLen;
+ UColAttributeValue attrVal;
+} ucolTokSuboption;
+
+typedef struct {
+ const UChar *optionName;
+ int32_t optionLen;
+ const ucolTokSuboption *subopts;
+ int32_t subSize;
+ UColAttribute attr;
+} ucolTokOption;
+
+#define ucol_tok_isSpecialChar(ch) \
+ (((((ch) <= 0x002F) && ((ch) >= 0x0020)) || \
+ (((ch) <= 0x003F) && ((ch) >= 0x003A)) || \
+ (((ch) <= 0x0060) && ((ch) >= 0x005B)) || \
+ (((ch) <= 0x007E) && ((ch) >= 0x007D)) || \
+ (ch) == 0x007B))
+
+
+U_CFUNC
+uint32_t ucol_tok_assembleTokenList(UColTokenParser *src,
+ UParseError *parseError,
+ UErrorCode *status);
+
+U_CFUNC
+void ucol_tok_initTokenList(UColTokenParser *src, const UChar *rules, const uint32_t rulesLength, const UCollator *UCA, UErrorCode *status);
+
+U_CFUNC void ucol_tok_closeTokenList(UColTokenParser *src);
+
+U_CAPI const UChar* U_EXPORT2 ucol_tok_parseNextToken(UColTokenParser *src,
+ UBool startOfRules,
+ UParseError *parseError,
+ UErrorCode *status);
+
+U_CAPI const UChar * U_EXPORT2
+ucol_tok_getNextArgument(const UChar *start, const UChar *end,
+ UColAttribute *attrib, UColAttributeValue *value,
+ UErrorCode *status);
+U_CAPI int32_t U_EXPORT2 ucol_inv_getNextCE(const UColTokenParser *src,
+ uint32_t CE, uint32_t contCE,
+ uint32_t *nextCE, uint32_t *nextContCE,
+ uint32_t strength);
+U_CAPI int32_t U_EXPORT2 ucol_inv_getPrevCE(const UColTokenParser *src,
+ uint32_t CE, uint32_t contCE,
+ uint32_t *prevCE, uint32_t *prevContCE,
+ uint32_t strength);
+
+U_CAPI uint32_t U_EXPORT2 ucol_getCEStrengthDifference(uint32_t CE, uint32_t contCE,
+ uint32_t prevCE, uint32_t prevContCE);
+
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_wgt.c b/Build/source/libs/icu/icu-xetex/i18n/ucol_wgt.c
new file mode 100644
index 00000000000..f531344944c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_wgt.c
@@ -0,0 +1,564 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1999-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: ucol_wgt.c
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2001mar08
+* created by: Markus W. Scherer
+*
+* This file contains code for allocating n collation element weights
+* between two exclusive limits.
+* It is used only internally by ucol_bld.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "ucol_imp.h"
+#include "ucol_wgt.h"
+#include "cmemory.h"
+#include "uarrsort.h"
+
+#ifdef UCOL_DEBUG
+# include <stdio.h>
+#endif
+
+/* collation element weight allocation -------------------------------------- */
+
+/* helper functions for CE weights */
+
+static U_INLINE int32_t
+lengthOfWeight(uint32_t weight) {
+ if((weight&0xffffff)==0) {
+ return 1;
+ } else if((weight&0xffff)==0) {
+ return 2;
+ } else if((weight&0xff)==0) {
+ return 3;
+ } else {
+ return 4;
+ }
+}
+
+static U_INLINE uint32_t
+getWeightTrail(uint32_t weight, int32_t length) {
+ return (uint32_t)(weight>>(8*(4-length)))&0xff;
+}
+
+static U_INLINE uint32_t
+setWeightTrail(uint32_t weight, int32_t length, uint32_t trail) {
+ length=8*(4-length);
+ return (uint32_t)((weight&(0xffffff00<<length))|(trail<<length));
+}
+
+static U_INLINE uint32_t
+getWeightByte(uint32_t weight, int32_t index) {
+ return getWeightTrail(weight, index); /* same calculation */
+}
+
+static U_INLINE uint32_t
+setWeightByte(uint32_t weight, int32_t index, uint32_t byte) {
+ uint32_t mask; /* 0xffffffff except a 00 "hole" for the index-th byte */
+
+ index*=8;
+ mask=((uint32_t)0xffffffff)>>index;
+ index=32-index;
+ mask|=0xffffff00<<index;
+ return (uint32_t)((weight&mask)|(byte<<index));
+}
+
+static U_INLINE uint32_t
+truncateWeight(uint32_t weight, int32_t length) {
+ return (uint32_t)(weight&(0xffffffff<<(8*(4-length))));
+}
+
+static U_INLINE uint32_t
+incWeightTrail(uint32_t weight, int32_t length) {
+ return (uint32_t)(weight+(1UL<<(8*(4-length))));
+}
+
+static U_INLINE uint32_t
+decWeightTrail(uint32_t weight, int32_t length) {
+ return (uint32_t)(weight-(1UL<<(8*(4-length))));
+}
+
+static U_INLINE uint32_t
+incWeight(uint32_t weight, int32_t length, uint32_t maxByte) {
+ uint32_t byte;
+
+ for(;;) {
+ byte=getWeightByte(weight, length);
+ if(byte<maxByte) {
+ return setWeightByte(weight, length, byte+1);
+ } else {
+ /* roll over, set this byte to UCOL_BYTE_FIRST_TAILORED and increment the previous one */
+ weight=setWeightByte(weight, length, UCOL_BYTE_FIRST_TAILORED);
+ --length;
+ }
+ }
+}
+
+static U_INLINE int32_t
+lengthenRange(WeightRange *range, uint32_t maxByte, uint32_t countBytes) {
+ int32_t length;
+
+ length=range->length2+1;
+ range->start=setWeightTrail(range->start, length, UCOL_BYTE_FIRST_TAILORED);
+ range->end=setWeightTrail(range->end, length, maxByte);
+ range->count2*=countBytes;
+ range->length2=length;
+ return length;
+}
+
+/* for uprv_sortArray: sort ranges in weight order */
+static int32_t U_CALLCONV
+compareRanges(const void *context, const void *left, const void *right) {
+ uint32_t l, r;
+
+ l=((const WeightRange *)left)->start;
+ r=((const WeightRange *)right)->start;
+ if(l<r) {
+ return -1;
+ } else if(l>r) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * take two CE weights and calculate the
+ * possible ranges of weights between the two limits, excluding them
+ * for weights with up to 4 bytes there are up to 2*4-1=7 ranges
+ */
+static U_INLINE int32_t
+getWeightRanges(uint32_t lowerLimit, uint32_t upperLimit,
+ uint32_t maxByte, uint32_t countBytes,
+ WeightRange ranges[7]) {
+ WeightRange lower[5], middle, upper[5]; /* [0] and [1] are not used - this simplifies indexing */
+ uint32_t weight, trail;
+ int32_t length, lowerLength, upperLength, rangeCount;
+
+ /* assume that both lowerLimit & upperLimit are not 0 */
+
+ /* get the lengths of the limits */
+ lowerLength=lengthOfWeight(lowerLimit);
+ upperLength=lengthOfWeight(upperLimit);
+
+#ifdef UCOL_DEBUG
+ printf("length of lower limit 0x%08lx is %ld\n", lowerLimit, lowerLength);
+ printf("length of upper limit 0x%08lx is %ld\n", upperLimit, upperLength);
+#endif
+
+ if(lowerLimit>=upperLimit) {
+#ifdef UCOL_DEBUG
+ printf("error: no space between lower & upper limits\n");
+#endif
+ return 0;
+ }
+
+ /* check that neither is a prefix of the other */
+ if(lowerLength<upperLength) {
+ if(lowerLimit==truncateWeight(upperLimit, lowerLength)) {
+#ifdef UCOL_DEBUG
+ printf("error: lower limit 0x%08lx is a prefix of upper limit 0x%08lx\n", lowerLimit, upperLimit);
+#endif
+ return 0;
+ }
+ }
+ /* if the upper limit is a prefix of the lower limit then the earlier test lowerLimit>=upperLimit has caught it */
+
+ /* reset local variables */
+ uprv_memset(lower, 0, sizeof(lower));
+ uprv_memset(&middle, 0, sizeof(middle));
+ uprv_memset(upper, 0, sizeof(upper));
+
+ /*
+ * With the limit lengths of 1..4, there are up to 7 ranges for allocation:
+ * range minimum length
+ * lower[4] 4
+ * lower[3] 3
+ * lower[2] 2
+ * middle 1
+ * upper[2] 2
+ * upper[3] 3
+ * upper[4] 4
+ *
+ * We are now going to calculate up to 7 ranges.
+ * Some of them will typically overlap, so we will then have to merge and eliminate ranges.
+ */
+ weight=lowerLimit;
+ for(length=lowerLength; length>=2; --length) {
+ trail=getWeightTrail(weight, length);
+ if(trail<maxByte) {
+ lower[length].start=incWeightTrail(weight, length);
+ lower[length].end=setWeightTrail(weight, length, maxByte);
+ lower[length].length=length;
+ lower[length].count=maxByte-trail;
+ }
+ weight=truncateWeight(weight, length-1);
+ }
+ middle.start=incWeightTrail(weight, 1);
+
+ weight=upperLimit;
+ for(length=upperLength; length>=2; --length) {
+ trail=getWeightTrail(weight, length);
+ if(trail>UCOL_BYTE_FIRST_TAILORED) {
+ upper[length].start=setWeightTrail(weight, length, UCOL_BYTE_FIRST_TAILORED);
+ upper[length].end=decWeightTrail(weight, length);
+ upper[length].length=length;
+ upper[length].count=trail-UCOL_BYTE_FIRST_TAILORED;
+ }
+ weight=truncateWeight(weight, length-1);
+ }
+ middle.end=decWeightTrail(weight, 1);
+
+ /* set the middle range */
+ middle.length=1;
+ if(middle.end>=middle.start) {
+ middle.count=(int32_t)((middle.end-middle.start)>>24)+1;
+ } else {
+ /* eliminate overlaps */
+ uint32_t start, end;
+
+ /* remove the middle range */
+ middle.count=0;
+
+ /* reduce or remove the lower ranges that go beyond upperLimit */
+ for(length=4; length>=2; --length) {
+ if(lower[length].count>0 && upper[length].count>0) {
+ start=upper[length].start;
+ end=lower[length].end;
+
+ if(end>=start || incWeight(end, length, maxByte)==start) {
+ /* lower and upper ranges collide or are directly adjacent: merge these two and remove all shorter ranges */
+ start=lower[length].start;
+ end=lower[length].end=upper[length].end;
+ /*
+ * merging directly adjacent ranges needs to subtract the 0/1 gaps in between;
+ * it may result in a range with count>countBytes
+ */
+ lower[length].count=
+ (int32_t)(getWeightTrail(end, length)-getWeightTrail(start, length)+1+
+ countBytes*(getWeightByte(end, length-1)-getWeightByte(start, length-1)));
+ upper[length].count=0;
+ while(--length>=2) {
+ lower[length].count=upper[length].count=0;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+#ifdef UCOL_DEBUG
+ /* print ranges */
+ for(length=4; length>=2; --length) {
+ if(lower[length].count>0) {
+ printf("lower[%ld] .start=0x%08lx .end=0x%08lx .count=%ld\n", length, lower[length].start, lower[length].end, lower[length].count);
+ }
+ }
+ if(middle.count>0) {
+ printf("middle .start=0x%08lx .end=0x%08lx .count=%ld\n", middle.start, middle.end, middle.count);
+ }
+ for(length=2; length<=4; ++length) {
+ if(upper[length].count>0) {
+ printf("upper[%ld] .start=0x%08lx .end=0x%08lx .count=%ld\n", length, upper[length].start, upper[length].end, upper[length].count);
+ }
+ }
+#endif
+
+ /* copy the ranges, shortest first, into the result array */
+ rangeCount=0;
+ if(middle.count>0) {
+ uprv_memcpy(ranges, &middle, sizeof(WeightRange));
+ rangeCount=1;
+ }
+ for(length=2; length<=4; ++length) {
+ /* copy upper first so that later the middle range is more likely the first one to use */
+ if(upper[length].count>0) {
+ uprv_memcpy(ranges+rangeCount, upper+length, sizeof(WeightRange));
+ ++rangeCount;
+ }
+ if(lower[length].count>0) {
+ uprv_memcpy(ranges+rangeCount, lower+length, sizeof(WeightRange));
+ ++rangeCount;
+ }
+ }
+ return rangeCount;
+}
+
+/*
+ * call getWeightRanges and then determine heuristically
+ * which ranges to use for a given number of weights between (excluding)
+ * two limits
+ */
+U_CFUNC int32_t
+ucol_allocWeights(uint32_t lowerLimit, uint32_t upperLimit,
+ uint32_t n,
+ uint32_t maxByte,
+ WeightRange ranges[7]) {
+ /* number of usable byte values 3..maxByte */
+ uint32_t countBytes=maxByte-UCOL_BYTE_FIRST_TAILORED+1;
+
+ uint32_t lengthCounts[6]; /* [0] unused, [5] to make index checks unnecessary */
+ uint32_t maxCount;
+ int32_t i, rangeCount, minLength/*, maxLength*/;
+
+ /* countBytes to the power of index */
+ uint32_t powers[5];
+ /* gcc requires explicit initialization */
+ powers[0] = 1;
+ powers[1] = countBytes;
+ powers[2] = countBytes*countBytes;
+ powers[3] = countBytes*countBytes*countBytes;
+ powers[4] = countBytes*countBytes*countBytes*countBytes;
+
+#ifdef UCOL_DEBUG
+ puts("");
+#endif
+
+ rangeCount=getWeightRanges(lowerLimit, upperLimit, maxByte, countBytes, ranges);
+ if(rangeCount<=0) {
+#ifdef UCOL_DEBUG
+ printf("error: unable to get Weight ranges\n");
+#endif
+ return 0;
+ }
+
+ /* what is the maximum number of weights with these ranges? */
+ maxCount=0;
+ for(i=0; i<rangeCount; ++i) {
+ maxCount+=(uint32_t)ranges[i].count*powers[4-ranges[i].length];
+ }
+ if(maxCount>=n) {
+#ifdef UCOL_DEBUG
+ printf("the maximum number of %lu weights is sufficient for n=%lu\n", maxCount, n);
+#endif
+ } else {
+#ifdef UCOL_DEBUG
+ printf("error: the maximum number of %lu weights is insufficient for n=%lu\n", maxCount, n);
+#endif
+ return 0;
+ }
+
+ /* set the length2 and count2 fields */
+ for(i=0; i<rangeCount; ++i) {
+ ranges[i].length2=ranges[i].length;
+ ranges[i].count2=(uint32_t)ranges[i].count;
+ }
+
+ /* try until we find suitably large ranges */
+ for(;;) {
+ /* get the smallest number of bytes in a range */
+ minLength=ranges[0].length2;
+
+ /* sum up the number of elements that fit into ranges of each byte length */
+ uprv_memset(lengthCounts, 0, sizeof(lengthCounts));
+ for(i=0; i<rangeCount; ++i) {
+ lengthCounts[ranges[i].length2]+=ranges[i].count2;
+ }
+
+ /* now try to allocate n elements in the available short ranges */
+ if(n<=(lengthCounts[minLength]+lengthCounts[minLength+1])) {
+ /* trivial cases, use the first few ranges */
+ maxCount=0;
+ rangeCount=0;
+ do {
+ maxCount+=ranges[rangeCount].count2;
+ ++rangeCount;
+ } while(n>maxCount);
+#ifdef UCOL_DEBUG
+ printf("take first %ld ranges\n", rangeCount);
+#endif
+ break;
+ } else if(n<=ranges[0].count2*countBytes) {
+ /* easy case, just make this one range large enough by lengthening it once more, possibly split it */
+ uint32_t count1, count2, power_1, power;
+
+ /*maxLength=minLength+1;*/
+
+ /* calculate how to split the range between maxLength-1 (count1) and maxLength (count2) */
+ power_1=powers[minLength-ranges[0].length];
+ power=power_1*countBytes;
+ count2=(n+power-1)/power;
+ count1=ranges[0].count-count2;
+
+ /* split the range */
+#ifdef UCOL_DEBUG
+ printf("split the first range %ld:%ld\n", count1, count2);
+#endif
+ if(count1<1) {
+ rangeCount=1;
+
+ /* lengthen the entire range to maxLength */
+ lengthenRange(ranges, maxByte, countBytes);
+ } else {
+ /* really split the range */
+ uint32_t byte;
+
+ /* create a new range with the end and initial and current length of the old one */
+ rangeCount=2;
+ ranges[1].end=ranges[0].end;
+ ranges[1].length=ranges[0].length;
+ ranges[1].length2=minLength;
+
+ /* set the end of the first range according to count1 */
+ i=ranges[0].length;
+ byte=getWeightByte(ranges[0].start, i)+count1-1;
+
+ /*
+ * ranges[0].count and count1 may be >countBytes
+ * from merging adjacent ranges;
+ * byte>maxByte is possible
+ */
+ if(byte<=maxByte) {
+ ranges[0].end=setWeightByte(ranges[0].start, i, byte);
+ } else /* byte>maxByte */ {
+ ranges[0].end=setWeightByte(incWeight(ranges[0].start, i-1, maxByte), i, byte-countBytes);
+ }
+
+ /* set the bytes in the end weight at length+1..length2 to maxByte */
+ byte=(maxByte<<24)|(maxByte<<16)|(maxByte<<8)|maxByte; /* this used to be 0xffffffff */
+ ranges[0].end=truncateWeight(ranges[0].end, i)|
+ ((byte>>(8*i))&(byte<<(8*(4-minLength))));
+
+ /* set the start of the second range to immediately follow the end of the first one */
+ ranges[1].start=incWeight(ranges[0].end, minLength, maxByte);
+
+ /* set the count values (informational) */
+ ranges[0].count=count1;
+ ranges[1].count=count2;
+
+ ranges[0].count2=count1*power_1;
+ ranges[1].count2=count2*power_1; /* will be *countBytes when lengthened */
+
+ /* lengthen the second range to maxLength */
+ lengthenRange(ranges+1, maxByte, countBytes);
+ }
+ break;
+ }
+
+ /* no good match, lengthen all minLength ranges and iterate */
+#ifdef UCOL_DEBUG
+ printf("lengthen the short ranges from %ld bytes to %ld and iterate\n", minLength, minLength+1);
+#endif
+ for(i=0; ranges[i].length2==minLength; ++i) {
+ lengthenRange(ranges+i, maxByte, countBytes);
+ }
+ }
+
+ if(rangeCount>1) {
+ /* sort the ranges by weight values */
+ UErrorCode errorCode=U_ZERO_ERROR;
+ uprv_sortArray(ranges, rangeCount, sizeof(WeightRange), compareRanges, NULL, FALSE, &errorCode);
+ /* ignore error code: we know that the internal sort function will not fail here */
+ }
+
+#ifdef UCOL_DEBUG
+ puts("final ranges:");
+ for(i=0; i<rangeCount; ++i) {
+ printf("ranges[%ld] .start=0x%08lx .end=0x%08lx .length=%ld .length2=%ld .count=%ld .count2=%lu\n",
+ i, ranges[i].start, ranges[i].end, ranges[i].length, ranges[i].length2, ranges[i].count, ranges[i].count2);
+ }
+#endif
+
+ /* set maxByte in ranges[0] for ucol_nextWeight() */
+ ranges[0].count=maxByte;
+
+ return rangeCount;
+}
+
+/*
+ * given a set of ranges calculated by ucol_allocWeights(),
+ * iterate through the weights
+ */
+U_CFUNC uint32_t
+ucol_nextWeight(WeightRange ranges[], int32_t *pRangeCount) {
+ if(*pRangeCount<=0) {
+ return 0xffffffff;
+ } else {
+ uint32_t weight, maxByte;
+
+ /* get maxByte from the .count field */
+ maxByte=ranges[0].count;
+
+ /* get the next weight */
+ weight=ranges[0].start;
+ if(weight==ranges[0].end) {
+ /* this range is finished, remove it and move the following ones up */
+ if(--*pRangeCount>0) {
+ uprv_memmove(ranges, ranges+1, *pRangeCount*sizeof(WeightRange));
+ ranges[0].count=maxByte; /* keep maxByte in ranges[0] */
+ }
+ } else {
+ /* increment the weight for the next value */
+ ranges[0].start=incWeight(weight, ranges[0].length2, maxByte);
+ }
+
+ return weight;
+ }
+}
+
+#ifdef UCOL_DEBUG
+
+static void
+testAlloc(uint32_t lowerLimit, uint32_t upperLimit, uint32_t n, UBool enumerate) {
+ WeightRange ranges[8];
+ int32_t rangeCount;
+
+ rangeCount=ucol_allocWeights(lowerLimit, upperLimit, n, ranges);
+ if(enumerate) {
+ uint32_t weight;
+
+ while(n>0) {
+ weight=ucol_nextWeight(ranges, &rangeCount);
+ if(weight==0xffffffff) {
+ printf("error: 0xffffffff with %lu more weights to go\n", n);
+ break;
+ }
+ printf(" 0x%08lx\n", weight);
+ --n;
+ }
+ }
+}
+
+extern int
+main(int argc, const char *argv[]) {
+#if 0
+#endif
+ testAlloc(0x364214fc, 0x44b87d23, 5, FALSE);
+ testAlloc(0x36421500, 0x44b87d23, 5, FALSE);
+ testAlloc(0x36421500, 0x44b87d23, 20, FALSE);
+ testAlloc(0x36421500, 0x44b87d23, 13700, FALSE);
+ testAlloc(0x36421500, 0x38b87d23, 1, FALSE);
+ testAlloc(0x36421500, 0x38b87d23, 20, FALSE);
+ testAlloc(0x36421500, 0x38b87d23, 200, TRUE);
+ testAlloc(0x36421500, 0x38b87d23, 13700, FALSE);
+ testAlloc(0x36421500, 0x37b87d23, 13700, FALSE);
+ testAlloc(0x36ef1500, 0x37b87d23, 13700, FALSE);
+ testAlloc(0x36421500, 0x36b87d23, 13700, FALSE);
+ testAlloc(0x36b87122, 0x36b87d23, 13700, FALSE);
+ testAlloc(0x49000000, 0x4a600000, 13700, FALSE);
+ testAlloc(0x9fffffff, 0xd0000000, 13700, FALSE);
+ testAlloc(0x9fffffff, 0xd0000000, 67400, FALSE);
+ testAlloc(0x9fffffff, 0xa0030000, 67400, FALSE);
+ testAlloc(0x9fffffff, 0xa0030000, 40000, FALSE);
+ testAlloc(0xa0000000, 0xa0030000, 40000, FALSE);
+ testAlloc(0xa0031100, 0xa0030000, 40000, FALSE);
+#if 0
+#endif
+ return 0;
+}
+
+#endif
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucol_wgt.h b/Build/source/libs/icu/icu-xetex/i18n/ucol_wgt.h
new file mode 100644
index 00000000000..db6094d6d4c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucol_wgt.h
@@ -0,0 +1,72 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1999-2001, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: ucol_wgt.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2001mar08
+* created by: Markus W. Scherer
+*/
+
+#ifndef UCOL_WGT_H
+#define UCOL_WGT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "ucol_imp.h"
+
+/* definitions for CE weights */
+
+typedef struct WeightRange {
+ uint32_t start, end;
+ int32_t length, count;
+ int32_t length2;
+ uint32_t count2;
+} WeightRange;
+
+/**
+ * Determine heuristically
+ * what ranges to use for a given number of weights between (excluding)
+ * two limits.
+ *
+ * @param lowerLimit A collation element weight; the ranges will be filled to cover
+ * weights greater than this one.
+ * @param upperLimit A collation element weight; the ranges will be filled to cover
+ * weights less than this one.
+ * @param n The number of collation element weights w necessary such that
+ * lowerLimit<w<upperLimit in lexical order.
+ * @param maxByte The highest valid byte value.
+ * @param ranges An array that is filled in with one or more ranges to cover
+ * n weights between the limits.
+ * @return number of ranges, 0 if it is not possible to fit n elements between the limits
+ */
+U_CFUNC int32_t
+ucol_allocWeights(uint32_t lowerLimit, uint32_t upperLimit,
+ uint32_t n,
+ uint32_t maxByte,
+ WeightRange ranges[7]);
+
+/**
+ * Given a set of ranges calculated by ucol_allocWeights(),
+ * iterate through the weights.
+ * The ranges are modified to keep the current iteration state.
+ *
+ * @param ranges The array of ranges that ucol_allocWeights() filled in.
+ * The ranges are modified.
+ * @param pRangeCount The number of ranges. It will be decremented when necessary.
+ * @return The next weight in the ranges, or 0xffffffff if there is none left.
+ */
+U_CFUNC uint32_t
+ucol_nextWeight(WeightRange ranges[], int32_t *pRangeCount);
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucoleitr.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucoleitr.cpp
new file mode 100644
index 00000000000..d31a90f837b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucoleitr.cpp
@@ -0,0 +1,258 @@
+/*
+******************************************************************************
+* Copyright (C) 2001-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+*
+* File ucoleitr.cpp
+*
+* Modification History:
+*
+* Date Name Description
+* 02/15/2001 synwee Modified all methods to process its own function
+* instead of calling the equivalent c++ api (coleitr.h)
+******************************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/ucoleitr.h"
+#include "unicode/ustring.h"
+#include "unicode/sortkey.h"
+#include "ucol_imp.h"
+#include "cmemory.h"
+
+U_NAMESPACE_USE
+
+#define BUFFER_LENGTH 100
+
+typedef struct collIterate collIterator;
+
+/* public methods ---------------------------------------------------- */
+
+U_CAPI UCollationElements* U_EXPORT2
+ucol_openElements(const UCollator *coll,
+ const UChar *text,
+ int32_t textLength,
+ UErrorCode *status)
+{
+ UCollationElements *result;
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ result = (UCollationElements *)uprv_malloc(sizeof(UCollationElements));
+ /* test for NULL */
+ if (result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ result->reset_ = TRUE;
+ result->isWritable = FALSE;
+
+ if (text == NULL) {
+ textLength = 0;
+ }
+ uprv_init_collIterate(coll, text, textLength, &result->iteratordata_);
+
+ return result;
+}
+
+U_CAPI void U_EXPORT2
+ucol_closeElements(UCollationElements *elems)
+{
+ collIterate *ci = &elems->iteratordata_;
+ if (ci->writableBuffer != ci->stackWritableBuffer) {
+ uprv_free(ci->writableBuffer);
+ }
+ if (elems->isWritable && elems->iteratordata_.string != NULL)
+ {
+ uprv_free(elems->iteratordata_.string);
+ }
+ uprv_free(elems);
+}
+
+U_CAPI void U_EXPORT2
+ucol_reset(UCollationElements *elems)
+{
+ collIterate *ci = &(elems->iteratordata_);
+ elems->reset_ = TRUE;
+ ci->pos = ci->string;
+ if ((ci->flags & UCOL_ITER_HASLEN) == 0 || ci->endp == NULL) {
+ ci->endp = ci->string + u_strlen(ci->string);
+ }
+ ci->CEpos = ci->toReturn = ci->CEs;
+ ci->flags = UCOL_ITER_HASLEN;
+ if (ci->coll->normalizationMode == UCOL_ON) {
+ ci->flags |= UCOL_ITER_NORM;
+ }
+
+ if (ci->stackWritableBuffer != ci->writableBuffer) {
+ uprv_free(ci->writableBuffer);
+ ci->writableBuffer = ci->stackWritableBuffer;
+ ci->writableBufSize = UCOL_WRITABLE_BUFFER_SIZE;
+ }
+ ci->fcdPosition = NULL;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_next(UCollationElements *elems,
+ UErrorCode *status)
+{
+ int32_t result;
+ if (U_FAILURE(*status)) {
+ return UCOL_NULLORDER;
+ }
+
+ elems->reset_ = FALSE;
+
+ result = (int32_t)ucol_getNextCE(elems->iteratordata_.coll,
+ &elems->iteratordata_,
+ status);
+
+ if (result == UCOL_NO_MORE_CES) {
+ result = UCOL_NULLORDER;
+ }
+ return result;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_previous(UCollationElements *elems,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return UCOL_NULLORDER;
+ }
+ else
+ {
+ int32_t result;
+
+ if (elems->reset_ &&
+ (elems->iteratordata_.pos == elems->iteratordata_.string)) {
+ if (elems->iteratordata_.endp == NULL) {
+ elems->iteratordata_.endp = elems->iteratordata_.string +
+ u_strlen(elems->iteratordata_.string);
+ elems->iteratordata_.flags |= UCOL_ITER_HASLEN;
+ }
+ elems->iteratordata_.pos = elems->iteratordata_.endp;
+ elems->iteratordata_.fcdPosition = elems->iteratordata_.endp;
+ }
+
+ elems->reset_ = FALSE;
+
+ result = (int32_t)ucol_getPrevCE(elems->iteratordata_.coll,
+ &(elems->iteratordata_),
+ status);
+
+ if (result == UCOL_NO_MORE_CES) {
+ result = UCOL_NULLORDER;
+ }
+
+ return result;
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_getMaxExpansion(const UCollationElements *elems,
+ int32_t order)
+{
+ uint8_t result;
+ UCOL_GETMAXEXPANSION(elems->iteratordata_.coll, (uint32_t)order, result);
+ return result;
+}
+
+U_CAPI void U_EXPORT2
+ucol_setText( UCollationElements *elems,
+ const UChar *text,
+ int32_t textLength,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return;
+ }
+
+ if (elems->isWritable && elems->iteratordata_.string != NULL)
+ {
+ uprv_free(elems->iteratordata_.string);
+ }
+
+ if (text == NULL) {
+ textLength = 0;
+ }
+
+ elems->isWritable = FALSE;
+ uprv_init_collIterate(elems->iteratordata_.coll, text, textLength,
+ &elems->iteratordata_);
+
+ elems->reset_ = TRUE;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_getOffset(const UCollationElements *elems)
+{
+ const collIterate *ci = &(elems->iteratordata_);
+ // while processing characters in normalization buffer getOffset will
+ // return the next non-normalized character.
+ // should be inline with the old implementation since the old codes uses
+ // nextDecomp in normalizer which also decomposes the string till the
+ // first base character is found.
+ if (ci->flags & UCOL_ITER_INNORMBUF) {
+ if (ci->fcdPosition == NULL) {
+ return 0;
+ }
+ return (int32_t)(ci->fcdPosition - ci->string);
+ }
+ else {
+ return (int32_t)(ci->pos - ci->string);
+ }
+}
+
+U_CAPI void U_EXPORT2
+ucol_setOffset(UCollationElements *elems,
+ int32_t offset,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return;
+ }
+
+ // this methods will clean up any use of the writable buffer and points to
+ // the original string
+ collIterate *ci = &(elems->iteratordata_);
+ ci->pos = ci->string + offset;
+ ci->CEpos = ci->toReturn = ci->CEs;
+ if (ci->flags & UCOL_ITER_INNORMBUF) {
+ ci->flags = ci->origFlags;
+ }
+ if ((ci->flags & UCOL_ITER_HASLEN) == 0) {
+ ci->endp = ci->string + u_strlen(ci->string);
+ ci->flags |= UCOL_ITER_HASLEN;
+ }
+ ci->fcdPosition = NULL;
+ elems->reset_ = FALSE;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_primaryOrder (int32_t order)
+{
+ order &= UCOL_PRIMARYMASK;
+ return (order >> UCOL_PRIMARYORDERSHIFT);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_secondaryOrder (int32_t order)
+{
+ order &= UCOL_SECONDARYMASK;
+ return (order >> UCOL_SECONDARYORDERSHIFT);
+}
+
+U_CAPI int32_t U_EXPORT2
+ucol_tertiaryOrder (int32_t order)
+{
+ return (order & UCOL_TERTIARYMASK);
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucsdet.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucsdet.cpp
new file mode 100644
index 00000000000..d06dd336428
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucsdet.cpp
@@ -0,0 +1,180 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 2005-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+#include "unicode/ucsdet.h"
+#include "csdetect.h"
+#include "csmatch.h"
+
+#include "cmemory.h"
+
+U_NAMESPACE_USE
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
+#define DELETE_ARRAY(array) uprv_free((void *) (array))
+
+U_CDECL_BEGIN
+
+U_CAPI UCharsetDetector * U_EXPORT2
+ucsdet_open(UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ CharsetDetector* csd = new CharsetDetector(*status);
+
+ if (U_FAILURE(*status)) {
+ delete csd;
+ csd = NULL;
+ }
+
+ return (UCharsetDetector *) csd;
+}
+
+U_CAPI void U_EXPORT2
+ucsdet_close(UCharsetDetector *ucsd)
+{
+ CharsetDetector *csd = (CharsetDetector *) ucsd;
+ delete csd;
+}
+
+U_CAPI void U_EXPORT2
+ucsdet_setText(UCharsetDetector *ucsd, const char *textIn, int32_t len, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return;
+ }
+
+ ((CharsetDetector *) ucsd)->setText(textIn, len);
+}
+
+U_CAPI const char * U_EXPORT2
+ucsdet_getName(const UCharsetMatch *ucsm, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ return ((CharsetMatch *) ucsm)->getName();
+}
+
+U_CAPI int32_t U_EXPORT2
+ucsdet_getConfidence(const UCharsetMatch *ucsm, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ return ((CharsetMatch *) ucsm)->getConfidence();
+}
+
+U_CAPI const char * U_EXPORT2
+ucsdet_getLanguage(const UCharsetMatch *ucsm, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ return ((CharsetMatch *) ucsm)->getLanguage();
+}
+
+U_CAPI const UCharsetMatch * U_EXPORT2
+ucsdet_detect(UCharsetDetector *ucsd, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ return (const UCharsetMatch *) ((CharsetDetector *) ucsd)->detect(*status);
+}
+
+U_CAPI void U_EXPORT2
+ucsdet_setDeclaredEncoding(UCharsetDetector *ucsd, const char *encoding, int32_t length, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return;
+ }
+
+ ((CharsetDetector *) ucsd)->setDeclaredEncoding(encoding,length);
+}
+
+U_CAPI const UCharsetMatch**
+ucsdet_detectAll(UCharsetDetector *ucsd,
+ int32_t *maxMatchesFound, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ CharsetDetector *csd = (CharsetDetector *) ucsd;
+
+ return (const UCharsetMatch**)csd->detectAll(*maxMatchesFound,*status);
+}
+
+// U_CAPI const char * U_EXPORT2
+// ucsdet_getDetectableCharsetName(const UCharsetDetector *csd, int32_t index, UErrorCode *status)
+// {
+// if(U_FAILURE(*status)) {
+// return 0;
+// }
+// return csd->getCharsetName(index,*status);
+// }
+
+// U_CAPI int32_t U_EXPORT2
+// ucsdet_getDetectableCharsetsCount(const UCharsetDetector *csd, UErrorCode *status)
+// {
+// if(U_FAILURE(*status)) {
+// return -1;
+// }
+// return UCharsetDetector::getDetectableCount();
+// }
+
+U_CAPI UBool U_EXPORT2
+ucsdet_isInputFilterEnabled(const UCharsetDetector *ucsd)
+{
+ // todo: could use an error return...
+ if (ucsd == NULL) {
+ return FALSE;
+ }
+
+ return ((CharsetDetector *) ucsd)->getStripTagsFlag();
+}
+
+U_CAPI UBool U_EXPORT2
+ucsdet_enableInputFilter(UCharsetDetector *ucsd, UBool filter)
+{
+ // todo: could use an error return...
+ if (ucsd == NULL) {
+ return FALSE;
+ }
+
+ CharsetDetector *csd = (CharsetDetector *) ucsd;
+ UBool prev = csd->getStripTagsFlag();
+
+ csd->setStripTagsFlag(filter);
+
+ return prev;
+}
+
+U_CAPI int32_t U_EXPORT2
+ucsdet_getUChars(const UCharsetMatch *ucsm,
+ UChar *buf, int32_t cap, UErrorCode *status)
+{
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+
+ return ((CharsetMatch *) ucsm)->getUChars(buf, cap, status);
+}
+U_CDECL_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucurr.cpp b/Build/source/libs/icu/icu-xetex/i18n/ucurr.cpp
new file mode 100644
index 00000000000..d6b7f432fda
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucurr.cpp
@@ -0,0 +1,1124 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ucurr.h"
+#include "unicode/locid.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "unicode/choicfmt.h"
+#include "unicode/parsepos.h"
+#include "ustr_imp.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uassert.h"
+#include "umutex.h"
+#include "ucln_in.h"
+#include "uenumimp.h"
+#include "uresimp.h"
+
+//------------------------------------------------------------
+// Constants
+
+// Default currency meta data of last resort. We try to use the
+// defaults encoded in the meta data resource bundle. If there is a
+// configuration/build error and these are not available, we use these
+// hard-coded defaults (which should be identical).
+static const int32_t LAST_RESORT_DATA[] = { 2, 0 };
+
+// POW10[i] = 10^i, i=0..MAX_POW10
+static const int32_t POW10[] = { 1, 10, 100, 1000, 10000, 100000,
+ 1000000, 10000000, 100000000, 1000000000 };
+
+static const int32_t MAX_POW10 = (sizeof(POW10)/sizeof(POW10[0])) - 1;
+
+#define ISO_COUNTRY_CODE_LENGTH 3
+
+//------------------------------------------------------------
+// Resource tags
+//
+
+static const char CURRENCY_DATA[] = "supplementalData";
+// Tag for meta-data, in root.
+static const char CURRENCY_META[] = "CurrencyMeta";
+
+// Tag for map from countries to currencies, in root.
+static const char CURRENCY_MAP[] = "CurrencyMap";
+
+// Tag for default meta-data, in CURRENCY_META
+static const char DEFAULT_META[] = "DEFAULT";
+
+// Variant for legacy pre-euro mapping in CurrencyMap
+static const char VAR_PRE_EURO[] = "PREEURO";
+
+// Variant for legacy euro mapping in CurrencyMap
+static const char VAR_EURO[] = "EURO";
+
+// Variant delimiter
+static const char VAR_DELIM = '_';
+static const char VAR_DELIM_STR[] = "_";
+
+// Variant for legacy euro mapping in CurrencyMap
+//static const char VAR_DELIM_EURO[] = "_EURO";
+
+#define VARIANT_IS_EMPTY 0
+#define VARIANT_IS_EURO 0x1
+#define VARIANT_IS_PREEURO 0x2
+
+// Tag for localized display names (symbols) of currencies
+static const char CURRENCIES[] = "Currencies";
+
+// Marker character indicating that a display name is a ChoiceFormat
+// pattern. Strings that start with one mark are ChoiceFormat
+// patterns. Strings that start with 2 marks are static strings, and
+// the first mark is deleted.
+static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign
+
+static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0};
+
+//------------------------------------------------------------
+// Code
+
+/**
+ * Unfortunately, we have to convert the UChar* currency code to char*
+ * to use it as a resource key.
+ */
+static inline char*
+myUCharsToChars(char* resultOfLen4, const UChar* currency) {
+ u_UCharsToChars(currency, resultOfLen4, ISO_COUNTRY_CODE_LENGTH);
+ resultOfLen4[ISO_COUNTRY_CODE_LENGTH] = 0;
+ return resultOfLen4;
+}
+
+/**
+ * Internal function to look up currency data. Result is an array of
+ * two integers. The first is the fraction digits. The second is the
+ * rounding increment, or 0 if none. The rounding increment is in
+ * units of 10^(-fraction_digits).
+ */
+static const int32_t*
+_findMetaData(const UChar* currency, UErrorCode& ec) {
+
+ if (currency == 0 || *currency == 0) {
+ if (U_SUCCESS(ec)) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return LAST_RESORT_DATA;
+ }
+
+ // Get CurrencyMeta resource out of root locale file. [This may
+ // move out of the root locale file later; if it does, update this
+ // code.]
+ UResourceBundle* currencyData = ures_openDirect(NULL, CURRENCY_DATA, &ec);
+ UResourceBundle* currencyMeta = ures_getByKey(currencyData, CURRENCY_META, currencyData, &ec);
+
+ if (U_FAILURE(ec)) {
+ ures_close(currencyMeta);
+ // Config/build error; return hard-coded defaults
+ return LAST_RESORT_DATA;
+ }
+
+ // Look up our currency, or if that's not available, then DEFAULT
+ char buf[ISO_COUNTRY_CODE_LENGTH+1];
+ UErrorCode ec2 = U_ZERO_ERROR; // local error code: soft failure
+ UResourceBundle* rb = ures_getByKey(currencyMeta, myUCharsToChars(buf, currency), NULL, &ec2);
+ if (U_FAILURE(ec2)) {
+ ures_close(rb);
+ rb = ures_getByKey(currencyMeta,DEFAULT_META, NULL, &ec);
+ if (U_FAILURE(ec)) {
+ ures_close(currencyMeta);
+ ures_close(rb);
+ // Config/build error; return hard-coded defaults
+ return LAST_RESORT_DATA;
+ }
+ }
+
+ int32_t len;
+ const int32_t *data = ures_getIntVector(rb, &len, &ec);
+ if (U_FAILURE(ec) || len != 2) {
+ // Config/build error; return hard-coded defaults
+ if (U_SUCCESS(ec)) {
+ ec = U_INVALID_FORMAT_ERROR;
+ }
+ ures_close(currencyMeta);
+ ures_close(rb);
+ return LAST_RESORT_DATA;
+ }
+
+ ures_close(currencyMeta);
+ ures_close(rb);
+ return data;
+}
+
+// -------------------------------------
+
+/**
+ * @see VARIANT_IS_EURO
+ * @see VARIANT_IS_PREEURO
+ */
+static uint32_t
+idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
+{
+ uint32_t variantType = 0;
+ // !!! this is internal only, assumes buffer is not null and capacity is sufficient
+ // Extract the country name and variant name. We only
+ // recognize two variant names, EURO and PREEURO.
+ char variant[ULOC_FULLNAME_CAPACITY];
+ uloc_getCountry(locale, countryAndVariant, capacity, ec);
+ uloc_getVariant(locale, variant, sizeof(variant), ec);
+ if (variant[0] != 0) {
+ variantType = (0 == uprv_strcmp(variant, VAR_EURO))
+ | ((0 == uprv_strcmp(variant, VAR_PRE_EURO)) << 1);
+ if (variantType)
+ {
+ uprv_strcat(countryAndVariant, VAR_DELIM_STR);
+ uprv_strcat(countryAndVariant, variant);
+ }
+ }
+ return variantType;
+}
+
+// ------------------------------------------
+//
+// Registration
+//
+//-------------------------------------------
+
+// don't use ICUService since we don't need fallback
+
+#if !UCONFIG_NO_SERVICE
+U_CDECL_BEGIN
+static UBool U_CALLCONV currency_cleanup(void);
+U_CDECL_END
+struct CReg;
+
+/* Remember to call umtx_init(&gCRegLock) before using it! */
+static UMTX gCRegLock = 0;
+static CReg* gCRegHead = 0;
+
+struct CReg : public U_NAMESPACE_QUALIFIER UMemory {
+ CReg *next;
+ UChar iso[ISO_COUNTRY_CODE_LENGTH+1];
+ char id[ULOC_FULLNAME_CAPACITY];
+
+ CReg(const UChar* _iso, const char* _id)
+ : next(0)
+ {
+ int32_t len = (int32_t)uprv_strlen(_id);
+ if (len > (int32_t)(sizeof(id)-1)) {
+ len = (sizeof(id)-1);
+ }
+ uprv_strncpy(id, _id, len);
+ id[len] = 0;
+ uprv_memcpy(iso, _iso, ISO_COUNTRY_CODE_LENGTH * sizeof(const UChar));
+ iso[ISO_COUNTRY_CODE_LENGTH] = 0;
+ }
+
+ static UCurrRegistryKey reg(const UChar* _iso, const char* _id, UErrorCode* status)
+ {
+ if (status && U_SUCCESS(*status) && _iso && _id) {
+ CReg* n = new CReg(_iso, _id);
+ if (n) {
+ umtx_init(&gCRegLock);
+ umtx_lock(&gCRegLock);
+ if (!gCRegHead) {
+ /* register for the first time */
+ ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
+ }
+ n->next = gCRegHead;
+ gCRegHead = n;
+ umtx_unlock(&gCRegLock);
+ return n;
+ }
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return 0;
+ }
+
+ static UBool unreg(UCurrRegistryKey key) {
+ UBool found = FALSE;
+ umtx_init(&gCRegLock);
+ umtx_lock(&gCRegLock);
+
+ CReg** p = &gCRegHead;
+ while (*p) {
+ if (*p == key) {
+ *p = ((CReg*)key)->next;
+ delete (CReg*)key;
+ found = TRUE;
+ break;
+ }
+ p = &((*p)->next);
+ }
+
+ umtx_unlock(&gCRegLock);
+ return found;
+ }
+
+ static const UChar* get(const char* id) {
+ const UChar* result = NULL;
+ umtx_init(&gCRegLock);
+ umtx_lock(&gCRegLock);
+ CReg* p = gCRegHead;
+
+ /* register cleanup of the mutex */
+ ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
+ while (p) {
+ if (uprv_strcmp(id, p->id) == 0) {
+ result = p->iso;
+ break;
+ }
+ p = p->next;
+ }
+ umtx_unlock(&gCRegLock);
+ return result;
+ }
+
+ /* This doesn't need to be thread safe. It's for u_cleanup only. */
+ static void cleanup(void) {
+ while (gCRegHead) {
+ CReg* n = gCRegHead;
+ gCRegHead = gCRegHead->next;
+ delete n;
+ }
+ umtx_destroy(&gCRegLock);
+ }
+};
+
+/**
+ * Release all static memory held by currency.
+ */
+U_CDECL_BEGIN
+static UBool U_CALLCONV currency_cleanup(void) {
+#if !UCONFIG_NO_SERVICE
+ CReg::cleanup();
+#endif
+ return TRUE;
+}
+U_CDECL_END
+
+// -------------------------------------
+
+U_CAPI UCurrRegistryKey U_EXPORT2
+ucurr_register(const UChar* isoCode, const char* locale, UErrorCode *status)
+{
+ if (status && U_SUCCESS(*status)) {
+ char id[ULOC_FULLNAME_CAPACITY];
+ idForLocale(locale, id, sizeof(id), status);
+ return CReg::reg(isoCode, id, status);
+ }
+ return NULL;
+}
+
+// -------------------------------------
+
+U_CAPI UBool U_EXPORT2
+ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
+{
+ if (status && U_SUCCESS(*status)) {
+ return CReg::unreg(key);
+ }
+ return FALSE;
+}
+#endif /* UCONFIG_NO_SERVICE */
+
+// -------------------------------------
+
+U_CAPI int32_t U_EXPORT2
+ucurr_forLocale(const char* locale,
+ UChar* buff,
+ int32_t buffCapacity,
+ UErrorCode* ec)
+{
+ int32_t resLen = 0;
+ const UChar* s = NULL;
+ if (ec != NULL && U_SUCCESS(*ec)) {
+ if ((buff && buffCapacity) || !buffCapacity) {
+ UErrorCode localStatus = U_ZERO_ERROR;
+ char id[ULOC_FULLNAME_CAPACITY];
+ if ((resLen = uloc_getKeywordValue(locale, "currency", id, ULOC_FULLNAME_CAPACITY, &localStatus))) {
+ // there is a currency keyword. Try to see if it's valid
+ if(buffCapacity > resLen) {
+ u_charsToUChars(id, buff, resLen);
+ }
+ } else {
+ // get country or country_variant in `id'
+ uint32_t variantType = idForLocale(locale, id, sizeof(id), ec);
+
+ if (U_FAILURE(*ec)) {
+ return 0;
+ }
+
+#if !UCONFIG_NO_SERVICE
+ const UChar* result = CReg::get(id);
+ if (result) {
+ if(buffCapacity > u_strlen(result)) {
+ u_strcpy(buff, result);
+ }
+ return u_strlen(result);
+ }
+#endif
+ // Remove variants, which is only needed for registration.
+ char *idDelim = strchr(id, VAR_DELIM);
+ if (idDelim) {
+ idDelim[0] = 0;
+ }
+
+ // Look up the CurrencyMap element in the root bundle.
+ UResourceBundle *rb = ures_openDirect(NULL, CURRENCY_DATA, &localStatus);
+ UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
+ UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
+ UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
+ s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
+
+ /*
+ Get the second item when PREEURO is requested, and this is a known Euro country.
+ If the requested variant is PREEURO, and this isn't a Euro country, assume
+ that the country changed over to the Euro in the future. This is probably
+ an old version of ICU that hasn't been updated yet. The latest currency is
+ probably correct.
+ */
+ if (U_SUCCESS(localStatus)) {
+ if ((variantType & VARIANT_IS_PREEURO) && u_strcmp(s, EUR_STR) == 0) {
+ currencyReq = ures_getByIndex(countryArray, 1, currencyReq, &localStatus);
+ s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
+ }
+ else if ((variantType & VARIANT_IS_EURO)) {
+ s = EUR_STR;
+ }
+ }
+ ures_close(countryArray);
+ ures_close(currencyReq);
+
+ if ((U_FAILURE(localStatus)) && strchr(id, '_') != 0)
+ {
+ // We don't know about it. Check to see if we support the variant.
+ uloc_getParent(locale, id, sizeof(id), ec);
+ *ec = U_USING_FALLBACK_WARNING;
+ return ucurr_forLocale(id, buff, buffCapacity, ec);
+ }
+ else if (*ec == U_ZERO_ERROR || localStatus != U_ZERO_ERROR) {
+ // There is nothing to fallback to. Report the failure/warning if possible.
+ *ec = localStatus;
+ }
+ if (U_SUCCESS(*ec)) {
+ if(buffCapacity > resLen) {
+ u_strcpy(buff, s);
+ }
+ }
+ }
+ return u_terminateUChars(buff, buffCapacity, resLen, ec);
+ } else {
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ }
+ return resLen;
+}
+
+// end registration
+
+/**
+ * Modify the given locale name by removing the rightmost _-delimited
+ * element. If there is none, empty the string ("" == root).
+ * NOTE: The string "root" is not recognized; do not use it.
+ * @return TRUE if the fallback happened; FALSE if locale is already
+ * root ("").
+ */
+static UBool fallback(char *loc) {
+ if (!*loc) {
+ return FALSE;
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ uloc_getParent(loc, loc, (int32_t)uprv_strlen(loc), &status);
+ /*
+ char *i = uprv_strrchr(loc, '_');
+ if (i == NULL) {
+ i = loc;
+ }
+ *i = 0;
+ */
+ return TRUE;
+}
+
+
+U_CAPI const UChar* U_EXPORT2
+ucurr_getName(const UChar* currency,
+ const char* locale,
+ UCurrNameStyle nameStyle,
+ UBool* isChoiceFormat, // fillin
+ int32_t* len, // fillin
+ UErrorCode* ec) {
+
+ // Look up the Currencies resource for the given locale. The
+ // Currencies locale data looks like this:
+ //|en {
+ //| Currencies {
+ //| USD { "US$", "US Dollar" }
+ //| CHF { "Sw F", "Swiss Franc" }
+ //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
+ //| //...
+ //| }
+ //|}
+
+ if (U_FAILURE(*ec)) {
+ return 0;
+ }
+
+ int32_t choice = (int32_t) nameStyle;
+ if (choice < 0 || choice > 1) {
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ // In the future, resource bundles may implement multi-level
+ // fallback. That is, if a currency is not found in the en_US
+ // Currencies data, then the en Currencies data will be searched.
+ // Currently, if a Currencies datum exists in en_US and en, the
+ // en_US entry hides that in en.
+
+ // We want multi-level fallback for this resource, so we implement
+ // it manually.
+
+ // Use a separate UErrorCode here that does not propagate out of
+ // this function.
+ UErrorCode ec2 = U_ZERO_ERROR;
+
+ char loc[ULOC_FULLNAME_CAPACITY];
+ uloc_getName(locale, loc, sizeof(loc), &ec2);
+ if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ char buf[ISO_COUNTRY_CODE_LENGTH+1];
+ myUCharsToChars(buf, currency);
+
+ const UChar* s = NULL;
+ ec2 = U_ZERO_ERROR;
+ UResourceBundle* rb = ures_open(NULL, loc, &ec2);
+
+ rb = ures_getByKey(rb, CURRENCIES, rb, &ec2);
+
+ // Fetch resource with multi-level resource inheritance fallback
+ rb = ures_getByKeyWithFallback(rb, buf, rb, &ec2);
+
+ s = ures_getStringByIndex(rb, choice, len, &ec2);
+ ures_close(rb);
+
+ // If we've succeeded we're done. Otherwise, try to fallback.
+ // If that fails (because we are already at root) then exit.
+ if (U_SUCCESS(ec2)) {
+ if (ec2 == U_USING_DEFAULT_WARNING
+ || (ec2 == U_USING_FALLBACK_WARNING && *ec != U_USING_DEFAULT_WARNING)) {
+ *ec = ec2;
+ }
+ }
+
+ // Determine if this is a ChoiceFormat pattern. One leading mark
+ // indicates a ChoiceFormat. Two indicates a static string that
+ // starts with a mark. In either case, the first mark is ignored,
+ // if present. Marks in the rest of the string have no special
+ // meaning.
+ *isChoiceFormat = FALSE;
+ if (U_SUCCESS(ec2)) {
+ U_ASSERT(s != NULL);
+ int32_t i=0;
+ while (i < *len && s[i] == CHOICE_FORMAT_MARK && i < 2) {
+ ++i;
+ }
+ *isChoiceFormat = (i == 1);
+ if (i != 0) ++s; // Skip over first mark
+ return s;
+ }
+
+ // If we fail to find a match, use the ISO 4217 code
+ *len = u_strlen(currency); // Should == ISO_COUNTRY_CODE_LENGTH, but maybe not...?
+ *ec = U_USING_DEFAULT_WARNING;
+ return currency;
+}
+
+U_CAPI void
+uprv_parseCurrency(const char* locale,
+ const U_NAMESPACE_QUALIFIER UnicodeString& text,
+ U_NAMESPACE_QUALIFIER ParsePosition& pos,
+ UChar* result,
+ UErrorCode& ec)
+{
+ U_NAMESPACE_USE
+
+ // TODO: There is a slight problem with the pseudo-multi-level
+ // fallback implemented here. More-specific locales don't
+ // properly shield duplicate entries in less-specific locales.
+ // This problem will go away when real multi-level fallback is
+ // implemented. We could also fix this by recording (in a
+ // hash) which codes are used at each level of fallback, but
+ // this doesn't seem warranted.
+
+ if (U_FAILURE(ec)) {
+ return;
+ }
+
+ // Look up the Currencies resource for the given locale. The
+ // Currencies locale data looks like this:
+ //|en {
+ //| Currencies {
+ //| USD { "US$", "US Dollar" }
+ //| CHF { "Sw F", "Swiss Franc" }
+ //| INR { "=0#Rs|1#Re|1<Rs", "=0#Rupees|1#Rupee|1<Rupees" }
+ //| //...
+ //| }
+ //|}
+
+ // In the future, resource bundles may implement multi-level
+ // fallback. That is, if a currency is not found in the en_US
+ // Currencies data, then the en Currencies data will be searched.
+ // Currently, if a Currencies datum exists in en_US and en, the
+ // en_US entry hides that in en.
+
+ // We want multi-level fallback for this resource, so we implement
+ // it manually.
+
+ // Use a separate UErrorCode here that does not propagate out of
+ // this function.
+ UErrorCode ec2 = U_ZERO_ERROR;
+
+ char loc[ULOC_FULLNAME_CAPACITY];
+ uloc_getName(locale, loc, sizeof(loc), &ec2);
+ if (U_FAILURE(ec2) || ec2 == U_STRING_NOT_TERMINATED_WARNING) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ int32_t start = pos.getIndex();
+ const UChar* s = NULL;
+
+ const char* iso = NULL;
+ int32_t max = 0;
+
+ // Multi-level resource inheritance fallback loop
+ for (;;) {
+ ec2 = U_ZERO_ERROR;
+ UResourceBundle* rb = ures_open(NULL, loc, &ec2);
+ UResourceBundle* curr = ures_getByKey(rb, CURRENCIES, NULL, &ec2);
+ int32_t n = ures_getSize(curr);
+ for (int32_t i=0; i<n; ++i) {
+ UResourceBundle* names = ures_getByIndex(curr, i, NULL, &ec2);
+ int32_t len;
+ s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
+ UBool isChoice = FALSE;
+ if (len > 0 && s[0] == CHOICE_FORMAT_MARK) {
+ ++s;
+ --len;
+ if (len > 0 && s[0] != CHOICE_FORMAT_MARK) {
+ isChoice = TRUE;
+ }
+ }
+ if (isChoice) {
+ Formattable temp;
+ ChoiceFormat fmt(s, ec2);
+ fmt.parse(text, temp, pos);
+ len = pos.getIndex() - start;
+ pos.setIndex(start);
+ } else if (len > max &&
+ text.compare(pos.getIndex(), len, s) != 0) {
+ len = 0;
+ }
+ if (len > max) {
+ iso = ures_getKey(names);
+ max = len;
+ }
+ ures_close(names);
+ }
+ ures_close(curr);
+ ures_close(rb);
+
+ // Try to fallback. If that fails (because we are already at
+ // root) then exit.
+ if (!fallback(loc)) {
+ break;
+ }
+ }
+
+ if (iso != NULL) {
+ u_charsToUChars(iso, result, 4);
+ }
+
+ // If display name parse fails or if it matches fewer than 3
+ // characters, try to parse 3-letter ISO. Do this after the
+ // display name processing so 3-letter display names are
+ // preferred. Consider /[A-Z]{3}/ to be valid ISO, and parse
+ // it manually--UnicodeSet/regex are too slow and heavy.
+ if (max < 3 && (text.length() - start) >= 3) {
+ UBool valid = TRUE;
+ for (int32_t k=0; k<3; ++k) {
+ UChar ch = text.charAt(start + k); // 16-bit ok
+ if (ch < 0x41/*'A'*/ || ch > 0x5A/*'Z'*/) {
+ valid = FALSE;
+ break;
+ }
+ }
+ if (valid) {
+ text.extract(start, 3, result);
+ result[3] = 0;
+ max = 3;
+ }
+ }
+
+ pos.setIndex(start + max);
+}
+
+/**
+ * Internal method. Given a currency ISO code and a locale, return
+ * the "static" currency name. This is usually the same as the
+ * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
+ * format is applied to the number 2.0 (to yield the more common
+ * plural) to return a static name.
+ *
+ * This is used for backward compatibility with old currency logic in
+ * DecimalFormat and DecimalFormatSymbols.
+ */
+U_CAPI void
+uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
+ U_NAMESPACE_QUALIFIER UnicodeString& result, UErrorCode& ec)
+{
+ U_NAMESPACE_USE
+
+ UBool isChoiceFormat;
+ int32_t len;
+ const UChar* currname = ucurr_getName(iso, loc, UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec);
+ if (U_SUCCESS(ec)) {
+ // If this is a ChoiceFormat currency, then format an
+ // arbitrary value; pick something != 1; more common.
+ result.truncate(0);
+ if (isChoiceFormat) {
+ ChoiceFormat f(currname, ec);
+ if (U_SUCCESS(ec)) {
+ f.format(2.0, result);
+ } else {
+ result = iso;
+ }
+ } else {
+ result = currname;
+ }
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+ucurr_getDefaultFractionDigits(const UChar* currency, UErrorCode* ec) {
+ return (_findMetaData(currency, *ec))[0];
+}
+
+U_CAPI double U_EXPORT2
+ucurr_getRoundingIncrement(const UChar* currency, UErrorCode* ec) {
+ const int32_t *data = _findMetaData(currency, *ec);
+
+ // If the meta data is invalid, return 0.0.
+ if (data[0] < 0 || data[0] > MAX_POW10) {
+ if (U_SUCCESS(*ec)) {
+ *ec = U_INVALID_FORMAT_ERROR;
+ }
+ return 0.0;
+ }
+
+ // If there is no rounding, return 0.0 to indicate no rounding. A
+ // rounding value (data[1]) of 0 or 1 indicates no rounding.
+ if (data[1] < 2) {
+ return 0.0;
+ }
+
+ // Return data[1] / 10^(data[0]). The only actual rounding data,
+ // as of this writing, is CHF { 2, 5 }.
+ return double(data[1]) / POW10[data[0]];
+}
+
+U_CDECL_BEGIN
+
+typedef struct UCurrencyContext {
+ uint32_t currType; /* UCurrCurrencyType */
+ uint32_t listIdx;
+} UCurrencyContext;
+
+/*
+Please keep this list in alphabetical order.
+You can look at the CLDR supplemental data or ISO-4217 for the meaning of some
+of these items.
+ISO-4217: http://www.iso.org/iso/en/prods-services/popstds/currencycodeslist.html
+*/
+static const struct CurrencyList {
+ const char *currency;
+ uint32_t currType;
+} gCurrencyList[] = {
+ {"ADP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"AED", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"AFA", UCURR_COMMON|UCURR_DEPRECATED},
+ {"AFN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ALL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"AMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ANG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"AOA", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"AOK", UCURR_COMMON|UCURR_DEPRECATED},
+ {"AON", UCURR_COMMON|UCURR_DEPRECATED},
+ {"AOR", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ARA", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ARP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ARS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ATS", UCURR_COMMON|UCURR_DEPRECATED},
+ {"AUD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"AWG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"AZM", UCURR_COMMON|UCURR_DEPRECATED},
+ {"AZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BAD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BAM", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BDT", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BEC", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"BEF", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BEL", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"BGL", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BHD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BIF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BND", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BOB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BOP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BOV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"BRB", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BRC", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BRE", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BRL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BRN", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BRR", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BTN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BUK", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BYB", UCURR_COMMON|UCURR_DEPRECATED},
+ {"BYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"BZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"CAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"CDF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"CHE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"CHF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"CHW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"CLF", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"CLP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"CNX", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"CNY", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"COP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"COU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"CRC", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"CSD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"CSK", UCURR_COMMON|UCURR_DEPRECATED},
+ {"CUP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"CVE", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"CYP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"CZK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"DDM", UCURR_COMMON|UCURR_DEPRECATED},
+ {"DEM", UCURR_COMMON|UCURR_DEPRECATED},
+ {"DJF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"DKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"DOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"DZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ECS", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ECV", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"EEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"EGP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"EQE", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ERN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ESA", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"ESB", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"ESP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ETB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"EUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"FIM", UCURR_COMMON|UCURR_DEPRECATED},
+ {"FJD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"FKP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"FRF", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GEK", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GEL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GHC", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GHS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GIP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GNF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GNS", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GQE", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GRD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GTQ", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GWE", UCURR_COMMON|UCURR_DEPRECATED},
+ {"GWP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"GYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HNL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HRD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"HRK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HTG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"HUF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"IDR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"IEP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ILP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ILS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"INR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"IQD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"IRR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ISK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ITL", UCURR_COMMON|UCURR_DEPRECATED},
+ {"JMD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"JOD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"JPY", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"KES", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"KGS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"KHR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"KMF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"KPW", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"KRW", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"KWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"KYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"KZT", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"LAK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"LBP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"LKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"LRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"LSL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"LSM", UCURR_COMMON|UCURR_DEPRECATED},
+ {"LTL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"LTT", UCURR_COMMON|UCURR_DEPRECATED},
+ {"LUC", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"LUF", UCURR_COMMON|UCURR_DEPRECATED},
+ {"LUL", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"LVL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"LVR", UCURR_COMMON|UCURR_DEPRECATED},
+ {"LYD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MAF", UCURR_COMMON|UCURR_DEPRECATED},
+ {"MDL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MGA", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MGF", UCURR_COMMON|UCURR_DEPRECATED},
+ {"MKD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MLF", UCURR_COMMON|UCURR_DEPRECATED},
+ {"MMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MNT", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MRO", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MTL", UCURR_COMMON|UCURR_DEPRECATED},
+ {"MTP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"MUR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MVR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MWK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MXN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MXP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"MXV", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"MYR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MZE", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"MZM", UCURR_COMMON|UCURR_DEPRECATED},
+ {"MZN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"NAD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"NGN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"NIC", UCURR_COMMON|UCURR_DEPRECATED},
+ {"NIO", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"NLG", UCURR_COMMON|UCURR_DEPRECATED},
+ {"NOK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"NPR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"NZD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"OMR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"PAB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"PEI", UCURR_COMMON|UCURR_DEPRECATED},
+ {"PEN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"PES", UCURR_COMMON|UCURR_DEPRECATED},
+ {"PGK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"PHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"PKR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"PLN", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"PLZ", UCURR_COMMON|UCURR_DEPRECATED},
+ {"PTE", UCURR_COMMON|UCURR_DEPRECATED},
+ {"PYG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"QAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"RHD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ROL", UCURR_COMMON|UCURR_DEPRECATED},
+ {"RON", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"RSD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"RUB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"RUR", UCURR_COMMON|UCURR_DEPRECATED},
+ {"RWF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SBD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SCR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SDD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"SDG", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SDP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"SEK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SGD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SIT", UCURR_COMMON|UCURR_DEPRECATED},
+ {"SKK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SRG", UCURR_COMMON|UCURR_DEPRECATED},
+ {"STD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SUR", UCURR_COMMON|UCURR_DEPRECATED},
+ {"SVC", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SYP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"SZL", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"THB", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"TJR", UCURR_COMMON|UCURR_DEPRECATED},
+ {"TJS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"TMM", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"TND", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"TOP", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"TPE", UCURR_COMMON|UCURR_DEPRECATED},
+ {"TRL", UCURR_COMMON|UCURR_DEPRECATED},
+ {"TRY", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"TTD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"TWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"TZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"UAH", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"UAK", UCURR_COMMON|UCURR_DEPRECATED},
+ {"UGS", UCURR_COMMON|UCURR_DEPRECATED},
+ {"UGX", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"USD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"USN", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"USS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"UYP", UCURR_COMMON|UCURR_DEPRECATED},
+ {"UYI", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"UYU", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"VEB", UCURR_COMMON|UCURR_DEPRECATED},
+ {"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"VUV", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"WST", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"XAF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"XAG", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XAU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XBA", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XBB", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XBC", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XBD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XCD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"XDR", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XEU", UCURR_UNCOMMON|UCURR_DEPRECATED},
+ {"XFO", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XFU", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XOF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"XPD", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XPF", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"XPT", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XRE", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XTS", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"XXX", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"YDD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"YER", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"YUD", UCURR_COMMON|UCURR_DEPRECATED},
+ {"YUM", UCURR_COMMON|UCURR_DEPRECATED},
+ {"YUN", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ZAL", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
+ {"ZAR", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ZMK", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ {"ZRN", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ZRZ", UCURR_COMMON|UCURR_DEPRECATED},
+ {"ZWD", UCURR_COMMON|UCURR_NON_DEPRECATED},
+ { NULL, 0 } // Leave here to denote the end of the list.
+};
+
+#define UCURR_MATCHES_BITMASK(variable, typeToMatch) \
+ ((typeToMatch) == UCURR_ALL || ((variable) & (typeToMatch)) == (typeToMatch))
+
+static int32_t U_CALLCONV
+ucurr_countCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
+ UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
+ uint32_t currType = myContext->currType;
+ int32_t count = 0;
+
+ /* Count the number of items matching the type we are looking for. */
+ for (int32_t idx = 0; gCurrencyList[idx].currency != NULL; idx++) {
+ if (UCURR_MATCHES_BITMASK(gCurrencyList[idx].currType, currType)) {
+ count++;
+ }
+ }
+ return count;
+}
+
+static const char* U_CALLCONV
+ucurr_nextCurrencyList(UEnumeration *enumerator,
+ int32_t* resultLength,
+ UErrorCode * /*pErrorCode*/)
+{
+ UCurrencyContext *myContext = (UCurrencyContext *)(enumerator->context);
+
+ /* Find the next in the list that matches the type we are looking for. */
+ while (myContext->listIdx < (sizeof(gCurrencyList)/sizeof(gCurrencyList[0]))-1) {
+ const struct CurrencyList *currItem = &gCurrencyList[myContext->listIdx++];
+ if (UCURR_MATCHES_BITMASK(currItem->currType, myContext->currType))
+ {
+ if (resultLength) {
+ *resultLength = 3; /* Currency codes are only 3 chars long */
+ }
+ return currItem->currency;
+ }
+ }
+ /* We enumerated too far. */
+ if (resultLength) {
+ *resultLength = 0;
+ }
+ return NULL;
+}
+
+static void U_CALLCONV
+ucurr_resetCurrencyList(UEnumeration *enumerator, UErrorCode * /*pErrorCode*/) {
+ ((UCurrencyContext *)(enumerator->context))->listIdx = 0;
+}
+
+static void U_CALLCONV
+ucurr_closeCurrencyList(UEnumeration *enumerator) {
+ uprv_free(enumerator->context);
+ uprv_free(enumerator);
+}
+
+static const UEnumeration gEnumCurrencyList = {
+ NULL,
+ NULL,
+ ucurr_closeCurrencyList,
+ ucurr_countCurrencyList,
+ uenum_unextDefault,
+ ucurr_nextCurrencyList,
+ ucurr_resetCurrencyList
+};
+U_CDECL_END
+
+U_CAPI UEnumeration * U_EXPORT2
+ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode) {
+ UEnumeration *myEnum = NULL;
+ UCurrencyContext *myContext;
+
+ myEnum = (UEnumeration*)uprv_malloc(sizeof(UEnumeration));
+ if (myEnum == NULL) {
+ *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ uprv_memcpy(myEnum, &gEnumCurrencyList, sizeof(UEnumeration));
+ myContext = (UCurrencyContext*)uprv_malloc(sizeof(UCurrencyContext));
+ if (myContext == NULL) {
+ *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(myEnum);
+ return NULL;
+ }
+ myContext->currType = currType;
+ myContext->listIdx = 0;
+ myEnum->context = myContext;
+ return myEnum;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ucurrimp.h b/Build/source/libs/icu/icu-xetex/i18n/ucurrimp.h
new file mode 100644
index 00000000000..9ecad6ccee4
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ucurrimp.h
@@ -0,0 +1,57 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*/
+
+#ifndef _UCURR_IMP_H_
+#define _UCURR_IMP_H_
+
+#include "unicode/utypes.h"
+#include "unicode/unistr.h"
+#include "unicode/parsepos.h"
+
+/**
+ * Internal method. Given a currency ISO code and a locale, return
+ * the "static" currency name. This is usually the same as the
+ * UCURR_SYMBOL_NAME, but if the latter is a choice format, then the
+ * format is applied to the number 2.0 (to yield the more common
+ * plural) to return a static name.
+ *
+ * This is used for backward compatibility with old currency logic in
+ * DecimalFormat and DecimalFormatSymbols.
+ */
+U_CAPI void
+uprv_getStaticCurrencyName(const UChar* iso, const char* loc,
+ U_NAMESPACE_QUALIFIER UnicodeString& result, UErrorCode& ec);
+
+/**
+ * Attempt to parse the given string as a currency, either as a
+ * display name in the given locale, or as a 3-letter ISO 4217
+ * code. If multiple display names match, then the longest one is
+ * selected. If both a display name and a 3-letter ISO code
+ * match, then the display name is preferred, unless it's length
+ * is less than 3.
+ *
+ * @param locale the locale of the display names to match
+ * @param text the text to parse
+ * @param pos input-output position; on input, the position within
+ * text to match; must have 0 <= pos.getIndex() < text.length();
+ * on output, the position after the last matched character. If
+ * the parse fails, the position in unchanged upon output.
+ * @return the ISO 4217 code, as a string, of the best match, or
+ * null if there is no match
+ *
+ * @internal
+ */
+U_CAPI void
+uprv_parseCurrency(const char* locale,
+ const U_NAMESPACE_QUALIFIER UnicodeString& text,
+ U_NAMESPACE_QUALIFIER ParsePosition& pos,
+ UChar* result,
+ UErrorCode& ec);
+
+#endif /* #ifndef _UCURR_IMP_H_ */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/udat.cpp b/Build/source/libs/icu/icu-xetex/i18n/udat.cpp
new file mode 100644
index 00000000000..7834b4cbba8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/udat.cpp
@@ -0,0 +1,811 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/udat.h"
+
+#include "unicode/uloc.h"
+#include "unicode/datefmt.h"
+#include "unicode/timezone.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/fieldpos.h"
+#include "unicode/parsepos.h"
+#include "unicode/calendar.h"
+#include "unicode/numfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/ustring.h"
+#include "cpputils.h"
+
+U_NAMESPACE_USE
+
+U_CAPI UDateFormat* U_EXPORT2
+udat_open(UDateFormatStyle timeStyle,
+ UDateFormatStyle dateStyle,
+ const char *locale,
+ const UChar *tzID,
+ int32_t tzIDLength,
+ const UChar *pattern,
+ int32_t patternLength,
+ UErrorCode *status)
+{
+ DateFormat *fmt;
+ if(U_FAILURE(*status)) {
+ return 0;
+ }
+ if(timeStyle != UDAT_IGNORE) {
+ if(locale == 0) {
+ fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
+ (DateFormat::EStyle)timeStyle);
+ }
+ else {
+ fmt = DateFormat::createDateTimeInstance((DateFormat::EStyle)dateStyle,
+ (DateFormat::EStyle)timeStyle,
+ Locale(locale));
+ }
+ }
+ else {
+ UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
+
+ if(locale == 0) {
+ fmt = new SimpleDateFormat(pat, *status);
+ }
+ else {
+ fmt = new SimpleDateFormat(pat, Locale(locale), *status);
+ }
+ }
+
+ if(fmt == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ if(tzID != 0) {
+ TimeZone *zone = TimeZone::createTimeZone(UnicodeString((UBool)(tzIDLength == -1), tzID, tzIDLength));
+ if(zone == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ delete fmt;
+ return 0;
+ }
+ fmt->adoptTimeZone(zone);
+ }
+
+ return (UDateFormat*)fmt;
+}
+
+
+U_CAPI void U_EXPORT2
+udat_close(UDateFormat* format)
+{
+ delete (DateFormat*)format;
+}
+
+U_CAPI UDateFormat* U_EXPORT2
+udat_clone(const UDateFormat *fmt,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return 0;
+
+ Format *res = ((SimpleDateFormat*)fmt)->clone();
+
+ if(res == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ return (UDateFormat*) res;
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_format( const UDateFormat* format,
+ UDate dateToFormat,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition* position,
+ UErrorCode* status)
+{
+ if(U_FAILURE(*status)) return -1;
+
+ UnicodeString res;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res.setTo(result, 0, resultLength);
+ }
+
+ FieldPosition fp;
+
+ if(position != 0)
+ fp.setField(position->field);
+
+ ((DateFormat*)format)->format(dateToFormat, res, fp);
+
+ if(position != 0) {
+ position->beginIndex = fp.getBeginIndex();
+ position->endIndex = fp.getEndIndex();
+ }
+
+ return res.extract(result, resultLength, *status);
+}
+
+U_CAPI UDate U_EXPORT2
+udat_parse( const UDateFormat* format,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return (UDate)0;
+
+ const UnicodeString src((UBool)(textLength == -1), text, textLength);
+ ParsePosition pp;
+ int32_t stackParsePos = 0;
+ UDate res;
+
+ if(parsePos == NULL) {
+ parsePos = &stackParsePos;
+ }
+
+ pp.setIndex(*parsePos);
+
+ res = ((DateFormat*)format)->parse(src, pp);
+
+ if(pp.getErrorIndex() == -1)
+ *parsePos = pp.getIndex();
+ else {
+ *parsePos = pp.getErrorIndex();
+ *status = U_PARSE_ERROR;
+ }
+
+ return res;
+}
+
+U_CAPI void U_EXPORT2
+udat_parseCalendar(const UDateFormat* format,
+ UCalendar* calendar,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return;
+
+ const UnicodeString src((UBool)(textLength == -1), text, textLength);
+ ParsePosition pp;
+
+ if(parsePos != 0)
+ pp.setIndex(*parsePos);
+
+ ((DateFormat*)format)->parse(src, *(Calendar*)calendar, pp);
+
+ if(parsePos != 0) {
+ if(pp.getErrorIndex() == -1)
+ *parsePos = pp.getIndex();
+ else {
+ *parsePos = pp.getErrorIndex();
+ *status = U_PARSE_ERROR;
+ }
+ }
+}
+
+U_CAPI UBool U_EXPORT2
+udat_isLenient(const UDateFormat* fmt)
+{
+ return ((DateFormat*)fmt)->isLenient();
+}
+
+U_CAPI void U_EXPORT2
+udat_setLenient( UDateFormat* fmt,
+ UBool isLenient)
+{
+ ((DateFormat*)fmt)->setLenient(isLenient);
+}
+
+U_CAPI const UCalendar* U_EXPORT2
+udat_getCalendar(const UDateFormat* fmt)
+{
+ return (const UCalendar*) ((DateFormat*)fmt)->getCalendar();
+}
+
+U_CAPI void U_EXPORT2
+udat_setCalendar(UDateFormat* fmt,
+ const UCalendar* calendarToSet)
+{
+ ((DateFormat*)fmt)->setCalendar(*((Calendar*)calendarToSet));
+}
+
+U_CAPI const UNumberFormat* U_EXPORT2
+udat_getNumberFormat(const UDateFormat* fmt)
+{
+ return (const UNumberFormat*) ((DateFormat*)fmt)->getNumberFormat();
+}
+
+U_CAPI void U_EXPORT2
+udat_setNumberFormat(UDateFormat* fmt,
+ const UNumberFormat* numberFormatToSet)
+{
+ ((DateFormat*)fmt)->setNumberFormat(*((NumberFormat*)numberFormatToSet));
+}
+
+U_CAPI const char* U_EXPORT2
+udat_getAvailable(int32_t index)
+{
+ return uloc_getAvailable(index);
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_countAvailable()
+{
+ return uloc_countAvailable();
+}
+
+U_CAPI UDate U_EXPORT2
+udat_get2DigitYearStart( const UDateFormat *fmt,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return (UDate)0;
+ return ((SimpleDateFormat*)fmt)->get2DigitYearStart(*status);
+}
+
+U_CAPI void U_EXPORT2
+udat_set2DigitYearStart( UDateFormat *fmt,
+ UDate d,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return;
+ ((SimpleDateFormat*)fmt)->set2DigitYearStart(d, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_toPattern( const UDateFormat *fmt,
+ UBool localized,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return -1;
+
+ UnicodeString res;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res.setTo(result, 0, resultLength);
+ }
+
+ if(localized)
+ ((SimpleDateFormat*)fmt)->toLocalizedPattern(res, *status);
+ else
+ ((SimpleDateFormat*)fmt)->toPattern(res);
+
+ return res.extract(result, resultLength, *status);
+}
+
+// TBD: should this take an UErrorCode?
+U_CAPI void U_EXPORT2
+udat_applyPattern( UDateFormat *format,
+ UBool localized,
+ const UChar *pattern,
+ int32_t patternLength)
+{
+ const UnicodeString pat((UBool)(patternLength == -1), pattern, patternLength);
+ UErrorCode status = U_ZERO_ERROR;
+
+ if(localized)
+ ((SimpleDateFormat*)format)->applyLocalizedPattern(pat, status);
+ else
+ ((SimpleDateFormat*)format)->applyPattern(pat);
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_getSymbols(const UDateFormat *fmt,
+ UDateFormatSymbolType type,
+ int32_t index,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status)) return -1;
+
+ const DateFormatSymbols *syms =
+ ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
+ int32_t count;
+ const UnicodeString *res = NULL;
+
+ switch(type) {
+ case UDAT_ERAS:
+ res = syms->getEras(count);
+ break;
+
+ case UDAT_ERA_NAMES:
+ res = syms->getEraNames(count);
+ break;
+
+ case UDAT_MONTHS:
+ res = syms->getMonths(count);
+ break;
+
+ case UDAT_SHORT_MONTHS:
+ res = syms->getShortMonths(count);
+ break;
+
+ case UDAT_WEEKDAYS:
+ res = syms->getWeekdays(count);
+ break;
+
+ case UDAT_SHORT_WEEKDAYS:
+ res = syms->getShortWeekdays(count);
+ break;
+
+ case UDAT_AM_PMS:
+ res = syms->getAmPmStrings(count);
+ break;
+
+ case UDAT_LOCALIZED_CHARS:
+ {
+ UnicodeString res1;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res1.setTo(result, 0, resultLength);
+ }
+ syms->getLocalPatternChars(res1);
+ return res1.extract(result, resultLength, *status);
+ }
+
+ case UDAT_NARROW_MONTHS:
+ res = syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_NARROW_WEEKDAYS:
+ res = syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_STANDALONE_MONTHS:
+ res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_MONTHS:
+ res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_NARROW_MONTHS:
+ res = syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_STANDALONE_WEEKDAYS:
+ res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_WEEKDAYS:
+ res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_NARROW_WEEKDAYS:
+ res = syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_QUARTERS:
+ res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_SHORT_QUARTERS:
+ res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_QUARTERS:
+ res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_QUARTERS:
+ res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ }
+
+ if(index < count) {
+ return res[index].extract(result, resultLength, *status);
+ }
+ return 0;
+}
+
+U_CAPI int32_t U_EXPORT2
+udat_countSymbols( const UDateFormat *fmt,
+ UDateFormatSymbolType type)
+{
+ const DateFormatSymbols *syms =
+ ((SimpleDateFormat*)fmt)->getDateFormatSymbols();
+ int32_t count = 0;
+
+ switch(type) {
+ case UDAT_ERAS:
+ syms->getEras(count);
+ break;
+
+ case UDAT_MONTHS:
+ syms->getMonths(count);
+ break;
+
+ case UDAT_SHORT_MONTHS:
+ syms->getShortMonths(count);
+ break;
+
+ case UDAT_WEEKDAYS:
+ syms->getWeekdays(count);
+ break;
+
+ case UDAT_SHORT_WEEKDAYS:
+ syms->getShortWeekdays(count);
+ break;
+
+ case UDAT_AM_PMS:
+ syms->getAmPmStrings(count);
+ break;
+
+ case UDAT_LOCALIZED_CHARS:
+ count = 1;
+ break;
+
+ case UDAT_ERA_NAMES:
+ syms->getEraNames(count);
+ break;
+
+ case UDAT_NARROW_MONTHS:
+ syms->getMonths(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_NARROW_WEEKDAYS:
+ syms->getWeekdays(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_STANDALONE_MONTHS:
+ syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_MONTHS:
+ syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_NARROW_MONTHS:
+ syms->getMonths(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_STANDALONE_WEEKDAYS:
+ syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_WEEKDAYS:
+ syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_NARROW_WEEKDAYS:
+ syms->getWeekdays(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
+ break;
+
+ case UDAT_QUARTERS:
+ syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_SHORT_QUARTERS:
+ syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ case UDAT_STANDALONE_QUARTERS:
+ syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ break;
+
+ case UDAT_STANDALONE_SHORT_QUARTERS:
+ syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ break;
+
+ }
+
+ return count;
+}
+
+U_NAMESPACE_BEGIN
+
+/*
+ * This DateFormatSymbolsSingleSetter class is a friend of DateFormatSymbols
+ * solely for the purpose of avoiding to clone the array of strings
+ * just to modify one of them and then setting all of them back.
+ * For example, the old code looked like this:
+ * case UDAT_MONTHS:
+ * res = syms->getMonths(count);
+ * array = new UnicodeString[count];
+ * if(array == 0) {
+ * *status = U_MEMORY_ALLOCATION_ERROR;
+ * return;
+ * }
+ * uprv_arrayCopy(res, array, count);
+ * if(index < count)
+ * array[index] = val;
+ * syms->setMonths(array, count);
+ * break;
+ *
+ * Even worse, the old code actually cloned the entire DateFormatSymbols object,
+ * cloned one value array, changed one value, and then made the SimpleDateFormat
+ * replace its DateFormatSymbols object with the new one.
+ *
+ * markus 2002-oct-14
+ */
+class DateFormatSymbolsSingleSetter /* not : public UObject because all methods are static */ {
+public:
+ static void
+ setSymbol(UnicodeString *array, int32_t count, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ if(array!=NULL) {
+ if(index>=count) {
+ errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
+ } else if(value==NULL) {
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ array[index].setTo(value, valueLength);
+ }
+ }
+ }
+
+ static void
+ setEra(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fEras, syms->fErasCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setEraName(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fEraNames, syms->fEraNamesCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fMonths, syms->fMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setShortMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fShortMonths, syms->fShortMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setNarrowMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fNarrowMonths, syms->fNarrowMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneMonths, syms->fStandaloneMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneShortMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneShortMonths, syms->fStandaloneShortMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneNarrowMonth(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneNarrowMonths, syms->fStandaloneNarrowMonthsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fWeekdays, syms->fWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setShortWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fShortWeekdays, syms->fShortWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setNarrowWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fNarrowWeekdays, syms->fNarrowWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneWeekdays, syms->fStandaloneWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneShortWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneShortWeekdays, syms->fStandaloneShortWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneNarrowWeekday(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneNarrowWeekdays, syms->fStandaloneNarrowWeekdaysCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setQuarter(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fQuarters, syms->fQuartersCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setShortQuarter(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fShortQuarters, syms->fShortQuartersCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneQuarter(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneQuarters, syms->fStandaloneQuartersCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setStandaloneShortQuarter(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fStandaloneShortQuarters, syms->fStandaloneShortQuartersCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setAmPm(DateFormatSymbols *syms, int32_t index,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(syms->fAmPms, syms->fAmPmsCount, index, value, valueLength, errorCode);
+ }
+
+ static void
+ setLocalPatternChars(DateFormatSymbols *syms,
+ const UChar *value, int32_t valueLength, UErrorCode &errorCode)
+ {
+ setSymbol(&syms->fLocalPatternChars, 1, 0, value, valueLength, errorCode);
+ }
+};
+
+U_NAMESPACE_END
+
+U_CAPI void U_EXPORT2
+udat_setSymbols( UDateFormat *format,
+ UDateFormatSymbolType type,
+ int32_t index,
+ UChar *value,
+ int32_t valueLength,
+ UErrorCode *status)
+{
+
+ if(U_FAILURE(*status)) return;
+
+ DateFormatSymbols *syms = (DateFormatSymbols *)((SimpleDateFormat *)format)->getDateFormatSymbols();
+
+ switch(type) {
+ case UDAT_ERAS:
+ DateFormatSymbolsSingleSetter::setEra(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_ERA_NAMES:
+ DateFormatSymbolsSingleSetter::setEraName(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_MONTHS:
+ DateFormatSymbolsSingleSetter::setMonth(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_SHORT_MONTHS:
+ DateFormatSymbolsSingleSetter::setShortMonth(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_NARROW_MONTHS:
+ DateFormatSymbolsSingleSetter::setNarrowMonth(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_STANDALONE_MONTHS:
+ DateFormatSymbolsSingleSetter::setStandaloneMonth(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_STANDALONE_SHORT_MONTHS:
+ DateFormatSymbolsSingleSetter::setStandaloneShortMonth(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_STANDALONE_NARROW_MONTHS:
+ DateFormatSymbolsSingleSetter::setStandaloneNarrowMonth(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_WEEKDAYS:
+ DateFormatSymbolsSingleSetter::setWeekday(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_SHORT_WEEKDAYS:
+ DateFormatSymbolsSingleSetter::setShortWeekday(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_NARROW_WEEKDAYS:
+ DateFormatSymbolsSingleSetter::setNarrowWeekday(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_STANDALONE_WEEKDAYS:
+ DateFormatSymbolsSingleSetter::setStandaloneWeekday(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_STANDALONE_SHORT_WEEKDAYS:
+ DateFormatSymbolsSingleSetter::setStandaloneShortWeekday(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_STANDALONE_NARROW_WEEKDAYS:
+ DateFormatSymbolsSingleSetter::setStandaloneNarrowWeekday(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_QUARTERS:
+ DateFormatSymbolsSingleSetter::setQuarter(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_SHORT_QUARTERS:
+ DateFormatSymbolsSingleSetter::setShortQuarter(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_STANDALONE_QUARTERS:
+ DateFormatSymbolsSingleSetter::setStandaloneQuarter(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_STANDALONE_SHORT_QUARTERS:
+ DateFormatSymbolsSingleSetter::setStandaloneShortQuarter(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_AM_PMS:
+ DateFormatSymbolsSingleSetter::setAmPm(syms, index, value, valueLength, *status);
+ break;
+
+ case UDAT_LOCALIZED_CHARS:
+ DateFormatSymbolsSingleSetter::setLocalPatternChars(syms, value, valueLength, *status);
+ break;
+
+ default:
+ *status = U_UNSUPPORTED_ERROR;
+ break;
+
+ }
+}
+
+U_CAPI const char* U_EXPORT2
+udat_getLocaleByType(const UDateFormat *fmt,
+ ULocDataLocaleType type,
+ UErrorCode* status)
+{
+ if (fmt == NULL) {
+ if (U_SUCCESS(*status)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return NULL;
+ }
+ return ((Format*)fmt)->getLocaleID(type, *status);
+}
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/udatpg.cpp b/Build/source/libs/icu/icu-xetex/i18n/udatpg.cpp
new file mode 100644
index 00000000000..6122912b6be
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/udatpg.cpp
@@ -0,0 +1,248 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: udatpg.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2007jul30
+* created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/udatpg.h"
+#include "unicode/uenum.h"
+#include "unicode/strenum.h"
+#include "unicode/dtptngen.h"
+#include "ustrenum.h"
+
+U_NAMESPACE_USE
+
+U_DRAFT UDateTimePatternGenerator * U_EXPORT2
+udatpg_open(const char *locale, UErrorCode *pErrorCode) {
+ if(locale==NULL) {
+ return (UDateTimePatternGenerator *)DateTimePatternGenerator::createInstance(*pErrorCode);
+ } else {
+ return (UDateTimePatternGenerator *)DateTimePatternGenerator::createInstance(Locale(locale), *pErrorCode);
+ }
+}
+
+U_DRAFT UDateTimePatternGenerator * U_EXPORT2
+udatpg_openEmpty(UErrorCode *pErrorCode) {
+ return (UDateTimePatternGenerator *)DateTimePatternGenerator::createEmptyInstance(*pErrorCode);
+}
+
+U_DRAFT void U_EXPORT2
+udatpg_close(UDateTimePatternGenerator *dtpg) {
+ delete (DateTimePatternGenerator *)dtpg;
+}
+
+U_DRAFT UDateTimePatternGenerator * U_EXPORT2
+udatpg_clone(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode) {
+ if(U_FAILURE(*pErrorCode)) {
+ return NULL;
+ }
+ return (UDateTimePatternGenerator *)(((const DateTimePatternGenerator *)dtpg)->clone());
+}
+
+U_DRAFT int32_t U_EXPORT2
+udatpg_getBestPattern(UDateTimePatternGenerator *dtpg,
+ const UChar *skeleton, int32_t length,
+ UChar *bestPattern, int32_t capacity,
+ UErrorCode *pErrorCode) {
+ if(U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if(skeleton==NULL && length!=0) {
+ *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString skeletonString((UBool)(length<0), skeleton, length);
+ UnicodeString result=((DateTimePatternGenerator *)dtpg)->getBestPattern(skeletonString, *pErrorCode);
+ return result.extract(bestPattern, capacity, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+udatpg_getSkeleton(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t length,
+ UChar *skeleton, int32_t capacity,
+ UErrorCode *pErrorCode) {
+ if(U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if(pattern==NULL && length!=0) {
+ *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString patternString((UBool)(length<0), pattern, length);
+ UnicodeString result=((DateTimePatternGenerator *)dtpg)->getSkeleton(patternString, *pErrorCode);
+ return result.extract(skeleton, capacity, *pErrorCode);
+}
+
+U_DRAFT int32_t U_EXPORT2
+udatpg_getBaseSkeleton(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t length,
+ UChar *skeleton, int32_t capacity,
+ UErrorCode *pErrorCode) {
+ if(U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if(pattern==NULL && length!=0) {
+ *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString patternString((UBool)(length<0), pattern, length);
+ UnicodeString result=((DateTimePatternGenerator *)dtpg)->getBaseSkeleton(patternString, *pErrorCode);
+ return result.extract(skeleton, capacity, *pErrorCode);
+}
+
+U_DRAFT UDateTimePatternConflict U_EXPORT2
+udatpg_addPattern(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t patternLength,
+ UBool override,
+ UChar *conflictingPattern, int32_t capacity, int32_t *pLength,
+ UErrorCode *pErrorCode) {
+ if(U_FAILURE(*pErrorCode)) {
+ return UDATPG_NO_CONFLICT;
+ }
+ if(pattern==NULL && patternLength!=0) {
+ *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ return UDATPG_NO_CONFLICT;
+ }
+ UnicodeString patternString((UBool)(patternLength<0), pattern, patternLength);
+ UnicodeString conflictingPatternString;
+ UDateTimePatternConflict result=((DateTimePatternGenerator *)dtpg)->
+ addPattern(patternString, override, conflictingPatternString, *pErrorCode);
+ int32_t length=conflictingPatternString.extract(conflictingPattern, capacity, *pErrorCode);
+ if(pLength!=NULL) {
+ *pLength=length;
+ }
+ return result;
+}
+
+U_DRAFT void U_EXPORT2
+udatpg_setAppendItemFormat(UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ const UChar *value, int32_t length) {
+ UnicodeString valueString((UBool)(length<0), value, length);
+ ((DateTimePatternGenerator *)dtpg)->setAppendItemFormat(field, valueString);
+}
+
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getAppendItemFormat(const UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ int32_t *pLength) {
+ const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getAppendItemFormat(field);
+ if(pLength!=NULL) {
+ *pLength=result.length();
+ }
+ return result.getBuffer();
+}
+
+U_DRAFT void U_EXPORT2
+udatpg_setAppendItemName(UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ const UChar *value, int32_t length) {
+ UnicodeString valueString((UBool)(length<0), value, length);
+ ((DateTimePatternGenerator *)dtpg)->setAppendItemName(field, valueString);
+}
+
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getAppendItemName(const UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ int32_t *pLength) {
+ const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getAppendItemName(field);
+ if(pLength!=NULL) {
+ *pLength=result.length();
+ }
+ return result.getBuffer();
+}
+
+U_DRAFT void U_EXPORT2
+udatpg_setDateTimeFormat(const UDateTimePatternGenerator *dtpg,
+ const UChar *dtFormat, int32_t length) {
+ UnicodeString dtFormatString((UBool)(length<0), dtFormat, length);
+ ((DateTimePatternGenerator *)dtpg)->setDateTimeFormat(dtFormatString);
+}
+
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getDateTimeFormat(const UDateTimePatternGenerator *dtpg,
+ int32_t *pLength) {
+ const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getDateTimeFormat();
+ if(pLength!=NULL) {
+ *pLength=result.length();
+ }
+ return result.getBuffer();
+}
+
+U_DRAFT void U_EXPORT2
+udatpg_setDecimal(UDateTimePatternGenerator *dtpg,
+ const UChar *decimal, int32_t length) {
+ UnicodeString decimalString((UBool)(length<0), decimal, length);
+ ((DateTimePatternGenerator *)dtpg)->setDecimal(decimalString);
+}
+
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getDecimal(const UDateTimePatternGenerator *dtpg,
+ int32_t *pLength) {
+ const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getDecimal();
+ if(pLength!=NULL) {
+ *pLength=result.length();
+ }
+ return result.getBuffer();
+}
+
+U_DRAFT int32_t U_EXPORT2
+udatpg_replaceFieldTypes(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t patternLength,
+ const UChar *skeleton, int32_t skeletonLength,
+ UChar *dest, int32_t destCapacity,
+ UErrorCode *pErrorCode) {
+ if(U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ if((pattern==NULL && patternLength!=0) || (skeleton==NULL && skeletonLength!=0)) {
+ *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString patternString((UBool)(patternLength<0), pattern, patternLength);
+ UnicodeString skeletonString((UBool)(skeletonLength<0), skeleton, skeletonLength);
+ UnicodeString result=((DateTimePatternGenerator *)dtpg)->replaceFieldTypes(patternString, skeletonString, *pErrorCode);
+ return result.extract(dest, destCapacity, *pErrorCode);
+}
+
+U_DRAFT UEnumeration * U_EXPORT2
+udatpg_openSkeletons(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode) {
+ return uenum_openStringEnumeration(
+ ((DateTimePatternGenerator *)dtpg)->getSkeletons(*pErrorCode),
+ pErrorCode);
+}
+
+U_DRAFT UEnumeration * U_EXPORT2
+udatpg_openBaseSkeletons(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode) {
+ return uenum_openStringEnumeration(
+ ((DateTimePatternGenerator *)dtpg)->getBaseSkeletons(*pErrorCode),
+ pErrorCode);
+}
+
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getPatternForSkeleton(const UDateTimePatternGenerator *dtpg,
+ const UChar *skeleton, int32_t skeletonLength,
+ int32_t *pLength) {
+ UnicodeString skeletonString((UBool)(skeletonLength<0), skeleton, skeletonLength);
+ const UnicodeString &result=((const DateTimePatternGenerator *)dtpg)->getPatternForSkeleton(skeletonString);
+ if(pLength!=NULL) {
+ *pLength=result.length();
+ }
+ return result.getBuffer();
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/ulocdata.c b/Build/source/libs/icu/icu-xetex/i18n/ulocdata.c
new file mode 100644
index 00000000000..f39975ecc01
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/ulocdata.c
@@ -0,0 +1,227 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2003-2007, International Business Machines *
+* Corporation and others. All Rights Reserved. *
+* *
+******************************************************************************
+* file name: ulocdata.c
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2003Oct21
+* created by: Ram Viswanadha,John Emmons
+*/
+
+#include "cmemory.h"
+#include "unicode/ustring.h"
+#include "unicode/ulocdata.h"
+
+#define MEASUREMENT_SYSTEM "MeasurementSystem"
+#define PAPER_SIZE "PaperSize"
+
+/** A locale data object.
+ * For usage in C programs.
+ * @draft ICU 3.4
+ */
+struct ULocaleData {
+ /**
+ * Controls the "No Substitute" behavior of this locale data object
+ */
+ UBool noSubstitute;
+
+ /**
+ * Pointer to the resource bundle associated with this locale data object
+ */
+ UResourceBundle *bundle;
+};
+
+U_CAPI ULocaleData* U_EXPORT2
+ulocdata_open(const char *localeID, UErrorCode *status)
+{
+ ULocaleData *uld;
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ uld = (ULocaleData *)uprv_malloc(sizeof(ULocaleData));
+ if (uld == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return(NULL);
+ }
+
+
+ uld->noSubstitute = FALSE;
+ uld->bundle = ures_open(NULL, localeID, status);
+
+ if (U_FAILURE(*status)) {
+ uprv_free(uld);
+ return NULL;
+ }
+
+ return uld;
+}
+
+U_CAPI void U_EXPORT2
+ulocdata_close(ULocaleData *uld)
+{
+ if ( uld != NULL ) {
+ ures_close(uld->bundle);
+ uprv_free(uld);
+ }
+}
+
+U_CAPI void U_EXPORT2
+ulocdata_setNoSubstitute(ULocaleData *uld, UBool setting)
+{
+ uld->noSubstitute = setting;
+}
+
+U_CAPI UBool U_EXPORT2
+ulocdata_getNoSubstitute(ULocaleData *uld)
+{
+ return uld->noSubstitute;
+}
+
+U_CAPI USet* U_EXPORT2
+ulocdata_getExemplarSet(ULocaleData *uld, USet *fillIn,
+ uint32_t options, ULocaleDataExemplarSetType extype, UErrorCode *status){
+
+ static const char* const exemplarSetTypes[] = { "ExemplarCharacters", "AuxExemplarCharacters" };
+ const UChar *exemplarChars = NULL;
+ int32_t len = 0;
+ UErrorCode localStatus = U_ZERO_ERROR;
+
+ if (U_FAILURE(*status))
+ return NULL;
+
+ exemplarChars = ures_getStringByKey(uld->bundle, exemplarSetTypes[extype], &len, &localStatus);
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status))
+ return NULL;
+
+ if(fillIn != NULL)
+ uset_applyPattern(fillIn, exemplarChars, len,
+ USET_IGNORE_SPACE | options, status);
+ else
+ fillIn = uset_openPatternOptions(exemplarChars, len,
+ USET_IGNORE_SPACE | options, status);
+
+ return fillIn;
+
+}
+
+U_CAPI int32_t U_EXPORT2
+ulocdata_getDelimiter(ULocaleData *uld, ULocaleDataDelimiterType type,
+ UChar *result, int32_t resultLength, UErrorCode *status){
+
+ static const char* const delimiterKeys[] = {
+ "quotationStart",
+ "quotationEnd",
+ "alternateQuotationStart",
+ "alternateQuotationEnd"
+ };
+
+ UResourceBundle *delimiterBundle;
+ int32_t len = 0;
+ const UChar *delimiter = NULL;
+ UErrorCode localStatus = U_ZERO_ERROR;
+
+ if (U_FAILURE(*status))
+ return 0;
+
+ delimiterBundle = ures_getByKey(uld->bundle, "delimiters", NULL, &localStatus);
+
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status)){
+ ures_close(delimiterBundle);
+ return 0;
+ }
+
+ delimiter = ures_getStringByKey(delimiterBundle, delimiterKeys[type], &len, &localStatus);
+ ures_close(delimiterBundle);
+
+ if ( (localStatus == U_USING_DEFAULT_WARNING) && uld->noSubstitute ) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+
+ if (localStatus != U_ZERO_ERROR) {
+ *status = localStatus;
+ }
+
+ if (U_FAILURE(*status)){
+ return 0;
+ }
+
+ u_strncpy(result,delimiter,resultLength);
+ return len;
+}
+
+U_CAPI UMeasurementSystem U_EXPORT2
+ulocdata_getMeasurementSystem(const char *localeID, UErrorCode *status){
+
+ UResourceBundle* bundle=NULL;
+ UResourceBundle* measurement=NULL;
+ UMeasurementSystem system = UMS_LIMIT;
+
+ if(status == NULL || U_FAILURE(*status)){
+ return system;
+ }
+
+ bundle = ures_open(NULL, localeID, status);
+
+ measurement = ures_getByKey(bundle, MEASUREMENT_SYSTEM, NULL, status);
+
+ system = (UMeasurementSystem) ures_getInt(measurement, status);
+
+ ures_close(bundle);
+ ures_close(measurement);
+
+ return system;
+
+}
+
+U_CAPI void U_EXPORT2
+ulocdata_getPaperSize(const char* localeID, int32_t *height, int32_t *width, UErrorCode *status){
+ UResourceBundle* bundle=NULL;
+ UResourceBundle* paperSizeBundle = NULL;
+ const int32_t* paperSize=NULL;
+ int32_t len = 0;
+
+ if(status == NULL || U_FAILURE(*status)){
+ return;
+ }
+
+ bundle = ures_open(NULL, localeID, status);
+ paperSizeBundle = ures_getByKey(bundle, PAPER_SIZE, NULL, status);
+ paperSize = ures_getIntVector(paperSizeBundle, &len, status);
+
+ if(U_SUCCESS(*status)){
+ if(len < 2){
+ *status = U_INTERNAL_PROGRAM_ERROR;
+ }else{
+ *height = paperSize[0];
+ *width = paperSize[1];
+ }
+ }
+
+ ures_close(bundle);
+ ures_close(paperSizeBundle);
+
+}
diff --git a/Build/source/libs/icu/icu-xetex/i18n/umsg.cpp b/Build/source/libs/icu/icu-xetex/i18n/umsg.cpp
new file mode 100644
index 00000000000..8a58ee0442c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/umsg.cpp
@@ -0,0 +1,706 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 1999-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: umsg.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* This is a C wrapper to MessageFormat C++ API.
+*
+* Change history:
+*
+* 08/5/2001 Ram Added C wrappers for C++ API. Changed implementation of old API's
+* Removed pattern parser.
+*
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/umsg.h"
+#include "unicode/ustring.h"
+#include "unicode/fmtable.h"
+#include "unicode/msgfmt.h"
+#include "unicode/unistr.h"
+#include "cpputils.h"
+#include "uassert.h"
+#include "ustr_imp.h"
+
+U_NAMESPACE_USE
+
+U_CAPI int32_t
+u_formatMessage(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ int32_t actLen;
+ //argument checking defered to subsequent method calls
+ // start vararg processing
+ va_start(ap, status);
+
+ actLen = u_vformatMessage(locale,pattern,patternLength,result,resultLength,ap,status);
+ // end vararg processing
+ va_end(ap);
+
+ return actLen;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_vformatMessage( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ va_list ap,
+ UErrorCode *status)
+
+{
+ //argument checking defered to subsequent method calls
+ UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
+ int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
+ umsg_close(fmt);
+ return retVal;
+}
+
+U_CAPI int32_t
+u_formatMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UParseError *parseError,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ int32_t actLen;
+ //argument checking defered to subsequent method calls
+ // start vararg processing
+ va_start(ap, status);
+
+ actLen = u_vformatMessageWithError(locale,pattern,patternLength,result,resultLength,parseError,ap,status);
+
+ // end vararg processing
+ va_end(ap);
+ return actLen;
+}
+
+U_CAPI int32_t U_EXPORT2
+u_vformatMessageWithError( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UParseError *parseError,
+ va_list ap,
+ UErrorCode *status)
+
+{
+ //argument checking defered to subsequent method calls
+ UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,parseError,status);
+ int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
+ umsg_close(fmt);
+ return retVal;
+}
+
+
+// For parse, do the reverse of format:
+// 1. Call through to the C++ APIs
+// 2. Just assume the user passed in enough arguments.
+// 3. Iterate through each formattable returned, and assign to the arguments
+U_CAPI void
+u_parseMessage( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ //argument checking defered to subsequent method calls
+
+ // start vararg processing
+ va_start(ap, status);
+
+ u_vparseMessage(locale,pattern,patternLength,source,sourceLength,ap,status);
+ // end vararg processing
+ va_end(ap);
+}
+
+U_CAPI void U_EXPORT2
+u_vparseMessage(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ va_list ap,
+ UErrorCode *status)
+{
+ //argument checking defered to subsequent method calls
+ UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,NULL,status);
+ int32_t count = 0;
+ umsg_vparse(fmt,source,sourceLength,&count,ap,status);
+ umsg_close(fmt);
+}
+
+U_CAPI void
+u_parseMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ UParseError *error,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+
+ //argument checking defered to subsequent method calls
+
+ // start vararg processing
+ va_start(ap, status);
+
+ u_vparseMessageWithError(locale,pattern,patternLength,source,sourceLength,ap,error,status);
+ // end vararg processing
+ va_end(ap);
+}
+U_CAPI void U_EXPORT2
+u_vparseMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ va_list ap,
+ UParseError *error,
+ UErrorCode* status)
+{
+ //argument checking defered to subsequent method calls
+ UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,error,status);
+ int32_t count = 0;
+ umsg_vparse(fmt,source,sourceLength,&count,ap,status);
+ umsg_close(fmt);
+}
+//////////////////////////////////////////////////////////////////////////////////
+//
+// Message format C API
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+
+U_CAPI UMessageFormat* U_EXPORT2
+umsg_open( const UChar *pattern,
+ int32_t patternLength,
+ const char *locale,
+ UParseError *parseError,
+ UErrorCode *status)
+{
+ //check arguments
+ if(status==NULL || U_FAILURE(*status))
+ {
+ return 0;
+ }
+ if(pattern==NULL||patternLength<-1){
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UParseError tErr;
+
+ if(parseError==NULL)
+ {
+ parseError = &tErr;
+ }
+
+ UMessageFormat* retVal = 0;
+
+ int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
+
+ UnicodeString patString((patternLength == -1 ? TRUE:FALSE), pattern,len);
+
+ retVal = (UMessageFormat*) new MessageFormat(patString,Locale(locale),*parseError,*status);
+
+ if(retVal == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ return retVal;
+}
+
+U_CAPI void U_EXPORT2
+umsg_close(UMessageFormat* format)
+{
+ //check arguments
+ if(format==NULL){
+ return;
+ }
+ delete (MessageFormat*) format;
+}
+
+U_CAPI UMessageFormat U_EXPORT2
+umsg_clone(const UMessageFormat *fmt,
+ UErrorCode *status)
+{
+ //check arguments
+ if(status==NULL || U_FAILURE(*status)){
+ return NULL;
+ }
+ if(fmt==NULL){
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ UMessageFormat retVal = (UMessageFormat)((MessageFormat*)fmt)->clone();
+ if(retVal == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ return retVal;
+}
+
+U_CAPI void U_EXPORT2
+umsg_setLocale(UMessageFormat *fmt, const char* locale)
+{
+ //check arguments
+ if(fmt==NULL){
+ return;
+ }
+ ((MessageFormat*)fmt)->setLocale(Locale(locale));
+}
+
+U_CAPI const char* U_EXPORT2
+umsg_getLocale(const UMessageFormat *fmt)
+{
+ //check arguments
+ if(fmt==NULL){
+ return "";
+ }
+ return ((const MessageFormat*)fmt)->getLocale().getName();
+}
+
+U_CAPI void U_EXPORT2
+umsg_applyPattern(UMessageFormat *fmt,
+ const UChar* pattern,
+ int32_t patternLength,
+ UParseError* parseError,
+ UErrorCode* status)
+{
+ //check arguments
+ UParseError tErr;
+ if(status ==NULL||U_FAILURE(*status)){
+ return ;
+ }
+ if(fmt==NULL||pattern==NULL||patternLength<-1){
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return ;
+ }
+
+ if(parseError==NULL){
+ parseError = &tErr;
+ }
+ if(patternLength<-1){
+ patternLength=u_strlen(pattern);
+ }
+
+ ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);
+}
+
+U_CAPI int32_t U_EXPORT2
+umsg_toPattern(const UMessageFormat *fmt,
+ UChar* result,
+ int32_t resultLength,
+ UErrorCode* status)
+{
+ //check arguments
+ if(status ==NULL||U_FAILURE(*status)){
+ return -1;
+ }
+ if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)){
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+
+ UnicodeString res;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res.setTo(result, 0, resultLength);
+ }
+ ((const MessageFormat*)fmt)->toPattern(res);
+ return res.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t
+umsg_format( const UMessageFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ int32_t actLen;
+ //argument checking defered to last method call umsg_vformat which
+ //saves time when arguments are valid and we dont care when arguments are not
+ //since we return an error anyway
+
+
+ // start vararg processing
+ va_start(ap, status);
+
+ actLen = umsg_vformat(fmt,result,resultLength,ap,status);
+
+ // end vararg processing
+ va_end(ap);
+
+ return actLen;
+}
+
+U_NAMESPACE_BEGIN
+/**
+ * This class isolates our access to private internal methods of
+ * MessageFormat. It is never instantiated; it exists only for C++
+ * access management.
+ */
+class MessageFormatAdapter {
+public:
+ static const Formattable::Type* getArgTypeList(const MessageFormat& m,
+ int32_t& count);
+};
+const Formattable::Type*
+MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
+ int32_t& count) {
+ return m.getArgTypeList(count);
+}
+U_NAMESPACE_END
+
+U_CAPI int32_t U_EXPORT2
+umsg_vformat( const UMessageFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ va_list ap,
+ UErrorCode *status)
+{
+ //check arguments
+ if(status==0 || U_FAILURE(*status))
+ {
+ return -1;
+ }
+ if(fmt==NULL||resultLength<0 || (resultLength>0 && result==0)) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ int32_t count =0;
+ const Formattable::Type* argTypes =
+ MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, count);
+ // Allocate at least one element. Allocating an array of length
+ // zero causes problems on some platforms (e.g. Win32).
+ Formattable* args = new Formattable[count ? count : 1];
+
+ // iterate through the vararg list, and get the arguments out
+ for(int32_t i = 0; i < count; ++i) {
+
+ UChar *stringVal;
+ double tDouble=0;
+ int32_t tInt =0;
+ int64_t tInt64 = 0;
+ UDate tempDate = 0;
+ switch(argTypes[i]) {
+ case Formattable::kDate:
+ tempDate = va_arg(ap, UDate);
+ args[i].setDate(tempDate);
+ break;
+
+ case Formattable::kDouble:
+ tDouble =va_arg(ap, double);
+ args[i].setDouble(tDouble);
+ break;
+
+ case Formattable::kLong:
+ tInt = va_arg(ap, int32_t);
+ args[i].setLong(tInt);
+ break;
+
+ case Formattable::kInt64:
+ tInt64 = va_arg(ap, int64_t);
+ args[i].setInt64(tInt64);
+ break;
+
+ case Formattable::kString:
+ // For some reason, a temporary is needed
+ stringVal = va_arg(ap, UChar*);
+ if(stringVal){
+ args[i].setString(stringVal);
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kArray:
+ // throw away this argument
+ // this is highly platform-dependent, and probably won't work
+ // so, if you try to skip arguments in the list (and not use them)
+ // you'll probably crash
+ va_arg(ap, int);
+ break;
+
+ case Formattable::kObject:
+ // This will never happen because MessageFormat doesn't
+ // support kObject. When MessageFormat is changed to
+ // understand MeasureFormats, modify this code to do the
+ // right thing. [alan]
+ U_ASSERT(FALSE);
+ break;
+ }
+ }
+ UnicodeString resultStr;
+ FieldPosition fieldPosition(0);
+
+ /* format the message */
+ ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
+
+ delete[] args;
+
+ if(U_FAILURE(*status)){
+ return -1;
+ }
+
+ return resultStr.extract(result, resultLength, *status);
+}
+
+U_CAPI void
+umsg_parse( const UMessageFormat *fmt,
+ const UChar *source,
+ int32_t sourceLength,
+ int32_t *count,
+ UErrorCode *status,
+ ...)
+{
+ va_list ap;
+ //argument checking defered to last method call umsg_vparse which
+ //saves time when arguments are valid and we dont care when arguments are not
+ //since we return an error anyway
+
+ // start vararg processing
+ va_start(ap, status);
+
+ umsg_vparse(fmt,source,sourceLength,count,ap,status);
+
+ // end vararg processing
+ va_end(ap);
+}
+
+U_CAPI void U_EXPORT2
+umsg_vparse(const UMessageFormat *fmt,
+ const UChar *source,
+ int32_t sourceLength,
+ int32_t *count,
+ va_list ap,
+ UErrorCode *status)
+{
+ //check arguments
+ if(status==NULL||U_FAILURE(*status))
+ {
+ return;
+ }
+ if(fmt==NULL||source==NULL || sourceLength<-1 || count==NULL){
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if(sourceLength==-1){
+ sourceLength=u_strlen(source);
+ }
+
+ UnicodeString srcString(source,sourceLength);
+ Formattable *args = ((const MessageFormat*)fmt)->parse(source,*count,*status);
+ UDate *aDate;
+ double *aDouble;
+ UChar *aString;
+ int32_t* aInt;
+ int64_t* aInt64;
+ UnicodeString temp;
+ int len =0;
+ // assign formattables to varargs
+ for(int32_t i = 0; i < *count; i++) {
+ switch(args[i].getType()) {
+
+ case Formattable::kDate:
+ aDate = va_arg(ap, UDate*);
+ if(aDate){
+ *aDate = args[i].getDate();
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kDouble:
+ aDouble = va_arg(ap, double*);
+ if(aDouble){
+ *aDouble = args[i].getDouble();
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kLong:
+ aInt = va_arg(ap, int32_t*);
+ if(aInt){
+ *aInt = (int32_t) args[i].getLong();
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kInt64:
+ aInt64 = va_arg(ap, int64_t*);
+ if(aInt64){
+ *aInt64 = args[i].getInt64();
+ }else{
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kString:
+ aString = va_arg(ap, UChar*);
+ if(aString){
+ args[i].getString(temp);
+ len = temp.length();
+ temp.extract(0,len,aString);
+ aString[len]=0;
+ }else{
+ *status= U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ break;
+
+ case Formattable::kObject:
+ // This will never happen because MessageFormat doesn't
+ // support kObject. When MessageFormat is changed to
+ // understand MeasureFormats, modify this code to do the
+ // right thing. [alan]
+ U_ASSERT(FALSE);
+ break;
+
+ // better not happen!
+ case Formattable::kArray:
+ U_ASSERT(FALSE);
+ break;
+ }
+ }
+
+ // clean up
+ delete [] args;
+}
+
+#define SINGLE_QUOTE ((UChar)0x0027)
+#define CURLY_BRACE_LEFT ((UChar)0x007B)
+#define CURLY_BRACE_RIGHT ((UChar)0x007D)
+
+#define STATE_INITIAL 0
+#define STATE_SINGLE_QUOTE 1
+#define STATE_IN_QUOTE 2
+#define STATE_MSG_ELEMENT 3
+
+#define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
+
+int32_t umsg_autoQuoteApostrophe(const UChar* pattern,
+ int32_t patternLength,
+ UChar* dest,
+ int32_t destCapacity,
+ UErrorCode* ec)
+{
+ int32_t state = STATE_INITIAL;
+ int32_t braceCount = 0;
+ int32_t len = 0;
+
+ if (ec == NULL || U_FAILURE(*ec)) {
+ return -1;
+ }
+
+ if (pattern == NULL || patternLength < -1 || (dest == NULL && destCapacity > 0)) {
+ *ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ if (patternLength == -1) {
+ patternLength = u_strlen(pattern);
+ }
+
+ for (int i = 0; i < patternLength; ++i) {
+ UChar c = pattern[i];
+ switch (state) {
+ case STATE_INITIAL:
+ switch (c) {
+ case SINGLE_QUOTE:
+ state = STATE_SINGLE_QUOTE;
+ break;
+ case CURLY_BRACE_LEFT:
+ state = STATE_MSG_ELEMENT;
+ ++braceCount;
+ break;
+ }
+ break;
+
+ case STATE_SINGLE_QUOTE:
+ switch (c) {
+ case SINGLE_QUOTE:
+ state = STATE_INITIAL;
+ break;
+ case CURLY_BRACE_LEFT:
+ case CURLY_BRACE_RIGHT:
+ state = STATE_IN_QUOTE;
+ break;
+ default:
+ MAppend(SINGLE_QUOTE);
+ state = STATE_INITIAL;
+ break;
+ }
+ break;
+
+ case STATE_IN_QUOTE:
+ switch (c) {
+ case SINGLE_QUOTE:
+ state = STATE_INITIAL;
+ break;
+ }
+ break;
+
+ case STATE_MSG_ELEMENT:
+ switch (c) {
+ case CURLY_BRACE_LEFT:
+ ++braceCount;
+ break;
+ case CURLY_BRACE_RIGHT:
+ if (--braceCount == 0) {
+ state = STATE_INITIAL;
+ }
+ break;
+ }
+ break;
+
+ default: // Never happens.
+ break;
+ }
+
+ MAppend(c);
+ }
+
+ // End of scan
+ if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
+ MAppend(SINGLE_QUOTE);
+ }
+
+ return u_terminateUChars(dest, destCapacity, len, ec);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/umsg_imp.h b/Build/source/libs/icu/icu-xetex/i18n/umsg_imp.h
new file mode 100644
index 00000000000..78bbf966bce
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/umsg_imp.h
@@ -0,0 +1,45 @@
+/*
+**********************************************************************
+* Copyright (C) 2001, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* file name: umsg_imp.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2001jun22
+* created by: George Rhoten
+*/
+
+#ifndef UMISC_H
+#define UMISC_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+/* global variables used by the C and C++ message formatting API. */
+
+extern const UChar *g_umsgTypeList[];
+extern const UChar *g_umsgModifierList[];
+extern const UChar *g_umsgDateModifierList[];
+extern const int32_t g_umsgListLength;
+
+extern const UChar g_umsg_number[];
+extern const UChar g_umsg_date[];
+extern const UChar g_umsg_time[];
+extern const UChar g_umsg_choice[];
+
+extern const UChar g_umsg_currency[];
+extern const UChar g_umsg_percent[];
+extern const UChar g_umsg_integer[];
+
+extern const UChar g_umsg_short[];
+extern const UChar g_umsg_medium[];
+extern const UChar g_umsg_long[];
+extern const UChar g_umsg_full[];
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unesctrn.cpp b/Build/source/libs/icu/icu-xetex/i18n/unesctrn.cpp
new file mode 100644
index 00000000000..45ced8b1e9b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unesctrn.cpp
@@ -0,0 +1,287 @@
+/*
+ **********************************************************************
+ * Copyright (c) 2001-2004, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 11/19/2001 aliu Creation.
+ **********************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uchar.h"
+#include "unesctrn.h"
+#include "util.h"
+
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Special character marking the end of the spec[] array.
+ */
+static const UChar END = 0xFFFF;
+
+// Unicode: "U+10FFFF" hex, min=4, max=6
+static const UChar SPEC_Unicode[] = {
+ 2, 0, 16, 4, 6, 85/*U*/, 43/*+*/,
+ END
+};
+
+// Java: "\\uFFFF" hex, min=4, max=4
+static const UChar SPEC_Java[] = {
+ 2, 0, 16, 4, 4, 92/*\*/, 117/*u*/,
+ END
+};
+
+// C: "\\uFFFF" hex, min=4, max=4; \\U0010FFFF hex, min=8, max=8
+static const UChar SPEC_C[] = {
+ 2, 0, 16, 4, 4, 92/*\*/, 117/*u*/,
+ 2, 0, 16, 8, 8, 92/*\*/, 85/*U*/,
+ END
+};
+
+// XML: "&#x10FFFF;" hex, min=1, max=6
+static const UChar SPEC_XML[] = {
+ 3, 1, 16, 1, 6, 38/*&*/, 35/*#*/, 120/*x*/, 59/*;*/,
+ END
+};
+
+// XML10: "&#1114111;" dec, min=1, max=7 (not really "Hex-Any")
+static const UChar SPEC_XML10[] = {
+ 2, 1, 10, 1, 7, 38/*&*/, 35/*#*/, 59/*;*/,
+ END
+};
+
+// Perl: "\\x{263A}" hex, min=1, max=6
+static const UChar SPEC_Perl[] = {
+ 3, 1, 16, 1, 6, 92/*\*/, 120/*x*/, 123/*{*/, 125/*}*/,
+ END
+};
+
+// All: Java, C, Perl, XML, XML10, Unicode
+static const UChar SPEC_Any[] = {
+ 2, 0, 16, 4, 6, 85/*U*/, 43/*+*/, // Unicode
+ 2, 0, 16, 4, 4, 92/*\*/, 117/*u*/, // Java
+ 2, 0, 16, 8, 8, 92/*\*/, 85/*U*/, // C (surrogates)
+ 3, 1, 16, 1, 6, 38/*&*/, 35/*#*/, 120/*x*/, 59/*;*/, // XML
+ 2, 1, 10, 1, 7, 38/*&*/, 35/*#*/, 59/*;*/, // XML10
+ 3, 1, 16, 1, 6, 92/*\*/, 120/*x*/, 123/*{*/, 125/*}*/, // Perl
+ END
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnescapeTransliterator)
+
+static UChar* copySpec(const UChar* spec) {
+ int32_t len = 0;
+ while (spec[len] != END) {
+ ++len;
+ }
+ ++len;
+ UChar *result = (UChar *)uprv_malloc(len*sizeof(UChar));
+ uprv_memcpy(result, spec, len*sizeof(result[0]));
+ return result;
+}
+
+/**
+ * Factory methods. Ignore the context.
+ */
+static Transliterator* _createUnicode(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ return new UnescapeTransliterator(ID, SPEC_Unicode);
+}
+static Transliterator* _createJava(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ return new UnescapeTransliterator(ID, SPEC_Java);
+}
+static Transliterator* _createC(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ return new UnescapeTransliterator(ID, SPEC_C);
+}
+static Transliterator* _createXML(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ return new UnescapeTransliterator(ID, SPEC_XML);
+}
+static Transliterator* _createXML10(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ return new UnescapeTransliterator(ID, SPEC_XML10);
+}
+static Transliterator* _createPerl(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ return new UnescapeTransliterator(ID, SPEC_Perl);
+}
+static Transliterator* _createAny(const UnicodeString& ID, Transliterator::Token /*context*/) {
+ return new UnescapeTransliterator(ID, SPEC_Any);
+}
+
+/**
+ * Registers standard variants with the system. Called by
+ * Transliterator during initialization.
+ */
+void UnescapeTransliterator::registerIDs() {
+ Token t = integerToken(0);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Hex-Any/Unicode"), _createUnicode, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Hex-Any/Java"), _createJava, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Hex-Any/C"), _createC, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Hex-Any/XML"), _createXML, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Hex-Any/XML10"), _createXML10, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Hex-Any/Perl"), _createPerl, t);
+
+ Transliterator::_registerFactory(UNICODE_STRING_SIMPLE("Hex-Any"), _createAny, t);
+}
+
+/**
+ * Constructor. Takes the encoded spec array.
+ */
+UnescapeTransliterator::UnescapeTransliterator(const UnicodeString& newID,
+ const UChar *newSpec) :
+ Transliterator(newID, NULL)
+{
+ this->spec = copySpec(newSpec);
+}
+
+/**
+ * Copy constructor.
+ */
+UnescapeTransliterator::UnescapeTransliterator(const UnescapeTransliterator& o) :
+ Transliterator(o) {
+ this->spec = copySpec(o.spec);
+}
+
+UnescapeTransliterator::~UnescapeTransliterator() {
+ uprv_free(spec);
+}
+
+/**
+ * Transliterator API.
+ */
+Transliterator* UnescapeTransliterator::clone() const {
+ return new UnescapeTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ */
+void UnescapeTransliterator::handleTransliterate(Replaceable& text, UTransPosition& pos,
+ UBool isIncremental) const {
+ int32_t start = pos.start;
+ int32_t limit = pos.limit;
+ int32_t i, j, ipat;
+
+ while (start < limit) {
+ // Loop over the forms in spec[]. Exit this loop when we
+ // match one of the specs. Exit the outer loop if a
+ // partial match is detected and isIncremental is true.
+ for (j=0, ipat=0; spec[ipat] != END; ++j) {
+
+ // Read the header
+ int32_t prefixLen = spec[ipat++];
+ int32_t suffixLen = spec[ipat++];
+ int8_t radix = (int8_t) spec[ipat++];
+ int32_t minDigits = spec[ipat++];
+ int32_t maxDigits = spec[ipat++];
+
+ // s is a copy of start that is advanced over the
+ // characters as we parse them.
+ int32_t s = start;
+ UBool match = TRUE;
+
+ for (i=0; i<prefixLen; ++i) {
+ if (s >= limit) {
+ if (i > 0) {
+ // We've already matched a character. This is
+ // a partial match, so we return if in
+ // incremental mode. In non-incremental mode,
+ // go to the next spec.
+ if (isIncremental) {
+ goto exit;
+ }
+ match = FALSE;
+ break;
+ }
+ }
+ UChar c = text.charAt(s++);
+ if (c != spec[ipat + i]) {
+ match = FALSE;
+ break;
+ }
+ }
+
+ if (match) {
+ UChar32 u = 0;
+ int32_t digitCount = 0;
+ for (;;) {
+ if (s >= limit) {
+ // Check for partial match in incremental mode.
+ if (s > start && isIncremental) {
+ goto exit;
+ }
+ break;
+ }
+ UChar32 ch = text.char32At(s);
+ int32_t digit = u_digit(ch, radix);
+ if (digit < 0) {
+ break;
+ }
+ s += UTF_CHAR_LENGTH(ch);
+ u = (u * radix) + digit;
+ if (++digitCount == maxDigits) {
+ break;
+ }
+ }
+
+ match = (digitCount >= minDigits);
+
+ if (match) {
+ for (i=0; i<suffixLen; ++i) {
+ if (s >= limit) {
+ // Check for partial match in incremental mode.
+ if (s > start && isIncremental) {
+ goto exit;
+ }
+ match = FALSE;
+ break;
+ }
+ UChar c = text.charAt(s++);
+ if (c != spec[ipat + prefixLen + i]) {
+ match = FALSE;
+ break;
+ }
+ }
+
+ if (match) {
+ // At this point, we have a match
+ UnicodeString str(u);
+ text.handleReplaceBetween(start, s, str);
+ limit -= s - start - str.length();
+ // The following break statement leaves the
+ // loop that is traversing the forms in
+ // spec[]. We then parse the next input
+ // character.
+ break;
+ }
+ }
+ }
+
+ ipat += prefixLen + suffixLen;
+ }
+
+ if (start < limit) {
+ start += UTF_CHAR_LENGTH(text.char32At(start));
+ }
+ }
+
+ exit:
+ pos.contextLimit += limit - pos.limit;
+ pos.limit = limit;
+ pos.start = start;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unesctrn.h b/Build/source/libs/icu/icu-xetex/i18n/unesctrn.h
new file mode 100644
index 00000000000..bfde6fc134f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unesctrn.h
@@ -0,0 +1,110 @@
+/*
+ **********************************************************************
+ * Copyright (c) 2001-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * Date Name Description
+ * 11/20/2001 aliu Creation.
+ **********************************************************************
+ */
+#ifndef UNESCTRN_H
+#define UNESCTRN_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that converts Unicode escape forms to the
+ * characters they represent. Escape forms have a prefix, a suffix, a
+ * radix, and minimum and maximum digit counts.
+ *
+ * <p>This class is package private. It registers several standard
+ * variants with the system which are then accessed via their IDs.
+ *
+ * @author Alan Liu
+ */
+class UnescapeTransliterator : public Transliterator {
+
+ private:
+
+ /**
+ * The encoded pattern specification. The pattern consists of
+ * zero or more forms. Each form consists of a prefix, suffix,
+ * radix, minimum digit count, and maximum digit count. These
+ * values are stored as a five character header. That is, their
+ * numeric values are cast to 16-bit characters and stored in the
+ * string. Following these five characters, the prefix
+ * characters, then suffix characters are stored. Each form thus
+ * takes n+5 characters, where n is the total length of the prefix
+ * and suffix. The end is marked by a header of length one
+ * consisting of the character END.
+ */
+ UChar* spec; // owned; may not be NULL
+
+ public:
+
+ /**
+ * Registers standard variants with the system. Called by
+ * Transliterator during initialization.
+ */
+ static void registerIDs();
+
+ /**
+ * Constructor. Takes the encoded spec array (does not adopt it).
+ * @param ID the string identifier for this transliterator
+ * @param spec the encoded spec array
+ */
+ UnescapeTransliterator(const UnicodeString& ID,
+ const UChar *spec);
+
+ /**
+ * Copy constructor.
+ */
+ UnescapeTransliterator(const UnescapeTransliterator&);
+
+ /**
+ * Destructor.
+ */
+ virtual ~UnescapeTransliterator();
+
+ /**
+ * Transliterator API.
+ */
+ virtual Transliterator* clone() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+ protected:
+
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param offset the start and limit of the text, the position
+ * of the cursor, and the start and limit of transliteration.
+ * @param incremental if true, assume more text may be coming after
+ * pos.contextLimit. Otherwise, assume the text is complete.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& offset,
+ UBool isIncremental) const;
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/uni2name.cpp b/Build/source/libs/icu/icu-xetex/i18n/uni2name.cpp
new file mode 100644
index 00000000000..5eba79daceb
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/uni2name.cpp
@@ -0,0 +1,120 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 06/06/01 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/unifilt.h"
+#include "unicode/uchar.h"
+#include "uni2name.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "uprops.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeNameTransliterator)
+
+static const UChar OPEN_DELIM[] = {92,78,123,0}; // "\N{"
+static const UChar CLOSE_DELIM = 125; // "}"
+#define OPEN_DELIM_LEN 3
+
+/**
+ * Constructs a transliterator.
+ */
+UnicodeNameTransliterator::UnicodeNameTransliterator(UnicodeFilter* adoptedFilter) :
+ Transliterator(UNICODE_STRING("Any-Name", 8), adoptedFilter) {
+}
+
+/**
+ * Destructor.
+ */
+UnicodeNameTransliterator::~UnicodeNameTransliterator() {}
+
+/**
+ * Copy constructor.
+ */
+UnicodeNameTransliterator::UnicodeNameTransliterator(const UnicodeNameTransliterator& o) :
+ Transliterator(o) {}
+
+/**
+ * Assignment operator.
+ */
+/*UnicodeNameTransliterator& UnicodeNameTransliterator::operator=(
+ const UnicodeNameTransliterator& o) {
+ Transliterator::operator=(o);
+ return *this;
+}*/
+
+/**
+ * Transliterator API.
+ */
+Transliterator* UnicodeNameTransliterator::clone(void) const {
+ return new UnicodeNameTransliterator(*this);
+}
+
+/**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * Ignore isIncremental since we don't need the context, and
+ * we work on codepoints.
+ */
+void UnicodeNameTransliterator::handleTransliterate(Replaceable& text, UTransPosition& offsets,
+ UBool /*isIncremental*/) const {
+ // The failure mode, here and below, is to behave like Any-Null,
+ // if either there is no name data (max len == 0) or there is no
+ // memory (malloc() => NULL).
+
+ int32_t maxLen = uprv_getMaxCharNameLength();
+ if (maxLen == 0) {
+ offsets.start = offsets.limit;
+ return;
+ }
+
+ // Accomodate the longest possible name plus padding
+ char* buf = (char*) uprv_malloc(maxLen);
+ if (buf == NULL) {
+ offsets.start = offsets.limit;
+ return;
+ }
+
+ int32_t cursor = offsets.start;
+ int32_t limit = offsets.limit;
+
+ UnicodeString str(FALSE, OPEN_DELIM, OPEN_DELIM_LEN);
+ UErrorCode status;
+ int32_t len;
+
+ while (cursor < limit) {
+ UChar32 c = text.char32At(cursor);
+ int32_t clen = UTF_CHAR_LENGTH(c);
+ status = U_ZERO_ERROR;
+ if ((len = u_charName(c, U_EXTENDED_CHAR_NAME, buf, maxLen, &status)) >0 && !U_FAILURE(status)) {
+ str.truncate(OPEN_DELIM_LEN);
+ str.append(UnicodeString(buf, len, US_INV)).append(CLOSE_DELIM);
+ text.handleReplaceBetween(cursor, cursor+clen, str);
+ len += OPEN_DELIM_LEN + 1; // adjust for delimiters
+ cursor += len; // advance cursor and adjust for new text
+ limit += len-clen; // change in length
+ } else {
+ cursor += clen;
+ }
+ }
+
+ offsets.contextLimit += limit - offsets.limit;
+ offsets.limit = limit;
+ offsets.start = cursor;
+
+ uprv_free(buf);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/uni2name.h b/Build/source/libs/icu/icu-xetex/i18n/uni2name.h
new file mode 100644
index 00000000000..aede864564a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/uni2name.h
@@ -0,0 +1,87 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 06/06/01 aliu Creation.
+**********************************************************************
+*/
+#ifndef UNI2NAME_H
+#define UNI2NAME_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A transliterator that performs character to name mapping.
+ * It generates the Perl syntax \N{name}.
+ * @author Alan Liu
+ */
+class UnicodeNameTransliterator : public Transliterator {
+
+ public:
+
+ /**
+ * Constructs a transliterator.
+ * @param adoptedFilter the filter to be adopted.
+ */
+ UnicodeNameTransliterator(UnicodeFilter* adoptedFilter = 0);
+
+ /**
+ * Destructor.
+ */
+ virtual ~UnicodeNameTransliterator();
+
+ /**
+ * Copy constructor.
+ */
+ UnicodeNameTransliterator(const UnicodeNameTransliterator&);
+
+ /**
+ * Transliterator API.
+ */
+ virtual Transliterator* clone(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
+
+ protected:
+
+ /**
+ * Implements {@link Transliterator#handleTransliterate}.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param offset the start and limit of the text, the position
+ * of the cursor, and the start and limit of transliteration.
+ * @param incremental if true, assume more text may be coming after
+ * pos.contextLimit. Otherwise, assume the text is complete.
+ */
+ virtual void handleTransliterate(Replaceable& text, UTransPosition& offset,
+ UBool isIncremental) const;
+
+private:
+ /**
+ * Assignment operator.
+ */
+ UnicodeNameTransliterator& operator=(const UnicodeNameTransliterator&);
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/basictz.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/basictz.h
new file mode 100644
index 00000000000..a49effd5b0b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/basictz.h
@@ -0,0 +1,210 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef BASICTZ_H
+#define BASICTZ_H
+
+/**
+ * \file
+ * \brief C++ API: ICU TimeZone base class
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/timezone.h"
+#include "unicode/tzrule.h"
+#include "unicode/tztrans.h"
+
+U_NAMESPACE_BEGIN
+
+// forward declarations
+class UVector;
+
+/**
+ * <code>BasicTimeZone</code> is an abstract class extending <code>TimeZone</code>.
+ * This class provides some additional methods to access time zone transitions and rules.
+ * All ICU <code>TimeZone</code> concrete subclasses extend this class.
+ * @draft ICU 3.8
+ */
+class U_I18N_API BasicTimeZone: public TimeZone {
+public:
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~BasicTimeZone();
+
+ /**
+ * Gets the first time zone transition after the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the first transition after the base time.
+ * @return TRUE if the transition is found.
+ * @draft ICU 3.8
+ */
+ virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ = 0;
+
+ /**
+ * Gets the most recent time zone transition before the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the most recent transition before the base time.
+ * @return TRUE if the transition is found.
+ * @draft ICU 3.8
+ */
+ virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ = 0;
+
+ /**
+ * Checks if the time zone has equivalent transitions in the time range.
+ * This method returns true when all of transition times, from/to standard
+ * offsets and DST savings used by this time zone match the other in the
+ * time range.
+ * @param tz The <code>BasicTimeZone</code> object to be compared with.
+ * @param start The start time of the evaluated time range (inclusive)
+ * @param end The end time of the evaluated time range (inclusive)
+ * @param ignoreDstAmount
+ * When true, any transitions with only daylight saving amount
+ * changes will be ignored, except either of them is zero.
+ * For example, a transition from rawoffset 3:00/dstsavings 1:00
+ * to rawoffset 2:00/dstsavings 2:00 is excluded from the comparison,
+ * but a transtion from rawoffset 2:00/dstsavings 1:00 to
+ * rawoffset 3:00/dstsavings 0:00 is included.
+ * @param ec Output param to filled in with a success or an error.
+ * @return true if the other time zone has the equivalent transitions in the
+ * time range.
+ * @draft ICU 3.8
+ */
+ virtual UBool hasEquivalentTransitions(/*const*/ BasicTimeZone& tz, UDate start, UDate end,
+ UBool ignoreDstAmount, UErrorCode& ec) /*const*/;
+
+ /**
+ * Returns the number of <code>TimeZoneRule</code>s which represents time transitions,
+ * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except
+ * <code>InitialTimeZoneRule</code>. The return value range is 0 or any positive value.
+ * @param status Receives error status code.
+ * @return The number of <code>TimeZoneRule</code>s representing time transitions.
+ * @draft ICU 3.8
+ */
+ virtual int32_t countTransitionRules(UErrorCode& status) /*const*/ = 0;
+
+ /**
+ * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code>
+ * which represent time transitions for this time zone. On successful return,
+ * the argument initial points to non-NULL <code>InitialTimeZoneRule</code> and
+ * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code>
+ * instances up to the size specified by trscount. The results are referencing the
+ * rule instance held by this time zone instance. Therefore, after this time zone
+ * is destructed, they are no longer available.
+ * @param initial Receives the initial timezone rule
+ * @param trsrules Receives the timezone transition rules
+ * @param trscount On input, specify the size of the array 'transitions' receiving
+ * the timezone transition rules. On output, actual number of
+ * rules filled in the array will be set.
+ * @param status Receives error status code.
+ * @draft ICU 3.8
+ */
+ virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/ = 0;
+
+ /**
+ * Gets the set of time zone rules valid at the specified time. Some known external time zone
+ * implementations are not capable to handle historic time zone rule changes. Also some
+ * implementations can only handle certain type of rule definitions.
+ * If this time zone does not use any daylight saving time within about 1 year from the specified
+ * time, only the <code>InitialTimeZone</code> is returned. Otherwise, the rule for standard
+ * time and daylight saving time transitions are returned in addition to the
+ * <code>InitialTimeZoneRule</code>. The standard and daylight saving time transition rules are
+ * represented by <code>AnnualTimeZoneRule</code> with <code>DateTimeRule::DOW</code> for its date
+ * rule and <code>DateTimeRule::WALL_TIME</code> for its time rule. Because daylight saving time
+ * rule is changing time to time in many time zones and also mapping a transition time rule to
+ * different type is lossy transformation, the set of rules returned by this method may be valid
+ * for short period of time.
+ * The time zone rule objects returned by this method is owned by the caller, so the caller is
+ * responsible for deleting them after use.
+ * @param date The date used for extracting time zone rules.
+ * @param initial Receives the <code>InitialTimeZone</code>, always not NULL.
+ * @param std Receives the <code>AnnualTimeZoneRule</code> for standard time transitions.
+ * When this time time zone does not observe daylight saving times around the
+ * specified date, NULL is set.
+ * @param dst Receives the <code>AnnualTimeZoneRule</code> for daylight saving time
+ * transitions. When this time zone does not observer daylight saving times
+ * around the specified date, NULL is set.
+ * @param status Receives error status code.
+ * @draft ICU 3.8
+ */
+ virtual void getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
+ AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) /*const*/;
+
+
+ /**
+ * The time type option bit flags used by getOffsetFromLocal
+ * @internal
+ */
+ enum {
+ kStandard = 0x01,
+ kDaylight = 0x03,
+ kFormer = 0x04,
+ kLatter = 0x0C
+ };
+
+ /**
+ * Get time zone offsets from local wall time.
+ * @internal
+ */
+ virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/;
+
+protected:
+
+ /**
+ * The time type option bit masks used by getOffsetFromLocal
+ * @internal
+ */
+ enum {
+ kStdDstMask = kDaylight,
+ kFormerLatterMask = kLatter
+ };
+
+ /**
+ * Default constructor.
+ * @draft ICU 3.8
+ */
+ BasicTimeZone();
+
+ /**
+ * Construct a timezone with a given ID.
+ * @param id a system time zone ID
+ * @draft ICU 3.8
+ */
+ BasicTimeZone(const UnicodeString &id);
+
+ /**
+ * Copy constructor.
+ * @param source the object to be copied.
+ * @draft ICU 3.8
+ */
+ BasicTimeZone(const BasicTimeZone& source);
+
+ /**
+ * Gets the set of TimeZoneRule instances applicable to the specified time and after.
+ * @param start The start date used for extracting time zone rules
+ * @param initial Receives the InitialTimeZone, always not NULL
+ * @param transitionRules Receives the transition rules, could be NULL
+ * @param status Receives error status code
+ */
+ void getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial, UVector*& transitionRules,
+ UErrorCode& status) /*const*/;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // BASICTZ_H
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/calendar.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/calendar.h
new file mode 100644
index 00000000000..d048a8b8a8a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/calendar.h
@@ -0,0 +1,2161 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File CALENDAR.H
+*
+* Modification History:
+*
+* Date Name Description
+* 04/22/97 aliu Expanded and corrected comments and other header
+* contents.
+* 05/01/97 aliu Made equals(), before(), after() arguments const.
+* 05/20/97 aliu Replaced fAreFieldsSet with fAreFieldsInSync and
+* fAreAllFieldsSet.
+* 07/27/98 stephen Sync up with JDK 1.2
+* 11/15/99 weiv added YEAR_WOY and DOW_LOCAL
+* to EDateFields
+* 8/19/2002 srl Removed Javaisms
+* 11/07/2003 srl Update, clean up documentation.
+********************************************************************************
+*/
+
+#ifndef CALENDAR_H
+#define CALENDAR_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Calendar object
+ */
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "unicode/locid.h"
+#include "unicode/timezone.h"
+#include "unicode/ucal.h"
+#include "unicode/umisc.h"
+
+U_NAMESPACE_BEGIN
+
+class ICUServiceFactory;
+
+/**
+ * @internal
+ */
+typedef int32_t UFieldResolutionTable[12][8];
+
+/**
+ * <code>Calendar</code> is an abstract base class for converting between
+ * a <code>UDate</code> object and a set of integer fields such as
+ * <code>YEAR</code>, <code>MONTH</code>, <code>DAY</code>, <code>HOUR</code>,
+ * and so on. (A <code>UDate</code> object represents a specific instant in
+ * time with millisecond precision. See UDate
+ * for information about the <code>UDate</code> class.)
+ *
+ * <p>
+ * Subclasses of <code>Calendar</code> interpret a <code>UDate</code>
+ * according to the rules of a specific calendar system.
+ * The most commonly used subclass of <code>Calendar</code> is
+ * <code>GregorianCalendar</code>. Other subclasses could represent
+ * the various types of lunar calendars in use in many parts of the world.
+ *
+ * <p>
+ * <b>NOTE</b>: (ICU 2.6) The subclass interface should be considered unstable
+ * - it WILL change.
+ *
+ * <p>
+ * Like other locale-sensitive classes, <code>Calendar</code> provides a
+ * static method, <code>createInstance</code>, for getting a generally useful
+ * object of this type. <code>Calendar</code>'s <code>createInstance</code> method
+ * returns the appropriate <code>Calendar</code> subclass whose
+ * time fields have been initialized with the current date and time:
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * Calendar *rightNow = Calendar::createInstance(errCode);
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * <p>
+ * A <code>Calendar</code> object can produce all the time field values
+ * needed to implement the date-time formatting for a particular language
+ * and calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
+ *
+ * <p>
+ * When computing a <code>UDate</code> from time fields, two special circumstances
+ * may arise: there may be insufficient information to compute the
+ * <code>UDate</code> (such as only year and month but no day in the month),
+ * or there may be inconsistent information (such as "Tuesday, July 15, 1996"
+ * -- July 15, 1996 is actually a Monday).
+ *
+ * <p>
+ * <strong>Insufficient information.</strong> The calendar will use default
+ * information to specify the missing fields. This may vary by calendar; for
+ * the Gregorian calendar, the default for a field is the same as that of the
+ * start of the epoch: i.e., YEAR = 1970, MONTH = JANUARY, DATE = 1, etc.
+ *
+ * <p>
+ * <strong>Inconsistent information.</strong> If fields conflict, the calendar
+ * will give preference to fields set more recently. For example, when
+ * determining the day, the calendar will look for one of the following
+ * combinations of fields. The most recent combination, as determined by the
+ * most recently set single field, will be used.
+ *
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * MONTH + DAY_OF_MONTH
+ * MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+ * MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+ * DAY_OF_YEAR
+ * DAY_OF_WEEK + WEEK_OF_YEAR
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * For the time of day:
+ *
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * HOUR_OF_DAY
+ * AM_PM + HOUR
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * <p>
+ * <strong>Note:</strong> for some non-Gregorian calendars, different
+ * fields may be necessary for complete disambiguation. For example, a full
+ * specification of the historial Arabic astronomical calendar requires year,
+ * month, day-of-month <em>and</em> day-of-week in some cases.
+ *
+ * <p>
+ * <strong>Note:</strong> There are certain possible ambiguities in
+ * interpretation of certain singular times, which are resolved in the
+ * following ways:
+ * <ol>
+ * <li> 24:00:00 "belongs" to the following day. That is,
+ * 23:59 on Dec 31, 1969 &lt; 24:00 on Jan 1, 1970 &lt; 24:01:00 on Jan 1, 1970
+ *
+ * <li> Although historically not precise, midnight also belongs to "am",
+ * and noon belongs to "pm", so on the same day,
+ * 12:00 am (midnight) &lt; 12:01 am, and 12:00 pm (noon) &lt; 12:01 pm
+ * </ol>
+ *
+ * <p>
+ * The date or time format strings are not part of the definition of a
+ * calendar, as those must be modifiable or overridable by the user at
+ * runtime. Use {@link DateFormat}
+ * to format dates.
+ *
+ * <p>
+ * <code>Calendar</code> provides an API for field "rolling", where fields
+ * can be incremented or decremented, but wrap around. For example, rolling the
+ * month up in the date <code>December 12, <b>1996</b></code> results in
+ * <code>January 12, <b>1996</b></code>.
+ *
+ * <p>
+ * <code>Calendar</code> also provides a date arithmetic function for
+ * adding the specified (signed) amount of time to a particular time field.
+ * For example, subtracting 5 days from the date <code>September 12, 1996</code>
+ * results in <code>September 7, 1996</code>.
+ *
+ * @stable ICU 2.0
+ */
+class U_I18N_API Calendar : public UObject {
+public:
+
+ /**
+ * Field IDs for date and time. Used to specify date/time fields. ERA is calendar
+ * specific. Example ranges given are for illustration only; see specific Calendar
+ * subclasses for actual ranges.
+ * @deprecated ICU 2.6. Use C enum UCalendarDateFields defined in ucal.h
+ */
+ enum EDateFields {
+#ifndef U_HIDE_DEPRECATED_API
+ ERA, // Example: 0..1
+ YEAR, // Example: 1..big number
+ MONTH, // Example: 0..11
+ WEEK_OF_YEAR, // Example: 1..53
+ WEEK_OF_MONTH, // Example: 1..4
+ DATE, // Example: 1..31
+ DAY_OF_YEAR, // Example: 1..365
+ DAY_OF_WEEK, // Example: 1..7
+ DAY_OF_WEEK_IN_MONTH, // Example: 1..4, may be specified as -1
+ AM_PM, // Example: 0..1
+ HOUR, // Example: 0..11
+ HOUR_OF_DAY, // Example: 0..23
+ MINUTE, // Example: 0..59
+ SECOND, // Example: 0..59
+ MILLISECOND, // Example: 0..999
+ ZONE_OFFSET, // Example: -12*U_MILLIS_PER_HOUR..12*U_MILLIS_PER_HOUR
+ DST_OFFSET, // Example: 0 or U_MILLIS_PER_HOUR
+ YEAR_WOY, // 'Y' Example: 1..big number - Year of Week of Year
+ DOW_LOCAL, // 'e' Example: 1..7 - Day of Week / Localized
+
+ FIELD_COUNT = UCAL_FIELD_COUNT // See ucal.h for other fields.
+#endif /* U_HIDE_DEPRECATED_API */
+ };
+
+ /**
+ * Useful constant for days of week. Note: Calendar day-of-week is 1-based. Clients
+ * who create locale resources for the field of first-day-of-week should be aware of
+ * this. For instance, in US locale, first-day-of-week is set to 1, i.e., SUNDAY.
+ * @deprecated ICU 2.6. Use C enum UCalendarDaysOfWeek defined in ucal.h
+ */
+ enum EDaysOfWeek {
+#ifndef U_HIDE_DEPRECATED_API
+ SUNDAY = 1,
+ MONDAY,
+ TUESDAY,
+ WEDNESDAY,
+ THURSDAY,
+ FRIDAY,
+ SATURDAY
+#endif /* U_HIDE_DEPRECATED_API */
+ };
+
+ /**
+ * Useful constants for month. Note: Calendar month is 0-based.
+ * @deprecated ICU 2.6. Use C enum UCalendarMonths defined in ucal.h
+ */
+ enum EMonths {
+#ifndef U_HIDE_DEPRECATED_API
+ JANUARY,
+ FEBRUARY,
+ MARCH,
+ APRIL,
+ MAY,
+ JUNE,
+ JULY,
+ AUGUST,
+ SEPTEMBER,
+ OCTOBER,
+ NOVEMBER,
+ DECEMBER,
+ UNDECIMBER
+#endif /* U_HIDE_DEPRECATED_API */
+ };
+
+ /**
+ * Useful constants for hour in 12-hour clock. Used in GregorianCalendar.
+ * @deprecated ICU 2.6. Use C enum UCalendarAMPMs defined in ucal.h
+ */
+ enum EAmpm {
+#ifndef U_HIDE_DEPRECATED_API
+ AM,
+ PM
+#endif /* U_HIDE_DEPRECATED_API */
+ };
+
+ /**
+ * destructor
+ * @stable ICU 2.0
+ */
+ virtual ~Calendar();
+
+ /**
+ * Create and return a polymorphic copy of this calendar.
+ *
+ * @return a polymorphic copy of this calendar.
+ * @stable ICU 2.0
+ */
+ virtual Calendar* clone(void) const = 0;
+
+ /**
+ * Creates a Calendar using the default timezone and locale. Clients are responsible
+ * for deleting the object returned.
+ *
+ * @param success Indicates the success/failure of Calendar creation. Filled in
+ * with U_ZERO_ERROR if created successfully, set to a failure result
+ * otherwise. U_MISSING_RESOURCE_ERROR will be returned if the resource data
+ * requests a calendar type which has not been installed.
+ * @return A Calendar if created successfully. NULL otherwise.
+ * @stable ICU 2.0
+ */
+ static Calendar* U_EXPORT2 createInstance(UErrorCode& success);
+
+ /**
+ * Creates a Calendar using the given timezone and the default locale.
+ * The Calendar takes ownership of zoneToAdopt; the
+ * client must not delete it.
+ *
+ * @param zoneToAdopt The given timezone to be adopted.
+ * @param success Indicates the success/failure of Calendar creation. Filled in
+ * with U_ZERO_ERROR if created successfully, set to a failure result
+ * otherwise.
+ * @return A Calendar if created successfully. NULL otherwise.
+ * @stable ICU 2.0
+ */
+ static Calendar* U_EXPORT2 createInstance(TimeZone* zoneToAdopt, UErrorCode& success);
+
+ /**
+ * Creates a Calendar using the given timezone and the default locale. The TimeZone
+ * is _not_ adopted; the client is still responsible for deleting it.
+ *
+ * @param zone The timezone.
+ * @param success Indicates the success/failure of Calendar creation. Filled in
+ * with U_ZERO_ERROR if created successfully, set to a failure result
+ * otherwise.
+ * @return A Calendar if created successfully. NULL otherwise.
+ * @stable ICU 2.0
+ */
+ static Calendar* U_EXPORT2 createInstance(const TimeZone& zone, UErrorCode& success);
+
+ /**
+ * Creates a Calendar using the default timezone and the given locale.
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the success/failure of Calendar creation. Filled in
+ * with U_ZERO_ERROR if created successfully, set to a failure result
+ * otherwise.
+ * @return A Calendar if created successfully. NULL otherwise.
+ * @stable ICU 2.0
+ */
+ static Calendar* U_EXPORT2 createInstance(const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Creates a Calendar using the given timezone and given locale.
+ * The Calendar takes ownership of zoneToAdopt; the
+ * client must not delete it.
+ *
+ * @param zoneToAdopt The given timezone to be adopted.
+ * @param aLocale The given locale.
+ * @param success Indicates the success/failure of Calendar creation. Filled in
+ * with U_ZERO_ERROR if created successfully, set to a failure result
+ * otherwise.
+ * @return A Calendar if created successfully. NULL otherwise.
+ * @stable ICU 2.0
+ */
+ static Calendar* U_EXPORT2 createInstance(TimeZone* zoneToAdopt, const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Gets a Calendar using the given timezone and given locale. The TimeZone
+ * is _not_ adopted; the client is still responsible for deleting it.
+ *
+ * @param zoneToAdopt The given timezone to be adopted.
+ * @param aLocale The given locale.
+ * @param success Indicates the success/failure of Calendar creation. Filled in
+ * with U_ZERO_ERROR if created successfully, set to a failure result
+ * otherwise.
+ * @return A Calendar if created successfully. NULL otherwise.
+ * @stable ICU 2.0
+ */
+ static Calendar* U_EXPORT2 createInstance(const TimeZone& zoneToAdopt, const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Returns a list of the locales for which Calendars are installed.
+ *
+ * @param count Number of locales returned.
+ * @return An array of Locale objects representing the set of locales for which
+ * Calendars are installed. The system retains ownership of this list;
+ * the caller must NOT delete it. Does not include user-registered Calendars.
+ * @stable ICU 2.0
+ */
+ static const Locale* U_EXPORT2 getAvailableLocales(int32_t& count);
+
+ /**
+ * Returns the current UTC (GMT) time measured in milliseconds since 0:00:00 on 1/1/70
+ * (derived from the system time).
+ *
+ * @return The current UTC time in milliseconds.
+ * @stable ICU 2.0
+ */
+ static UDate U_EXPORT2 getNow(void);
+
+ /**
+ * Gets this Calendar's time as milliseconds. May involve recalculation of time due
+ * to previous calls to set time field values. The time specified is non-local UTC
+ * (GMT) time. Although this method is const, this object may actually be changed
+ * (semantically const).
+ *
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @return The current time in UTC (GMT) time, or zero if the operation
+ * failed.
+ * @stable ICU 2.0
+ */
+ inline UDate getTime(UErrorCode& status) const { return getTimeInMillis(status); }
+
+ /**
+ * Sets this Calendar's current time with the given UDate. The time specified should
+ * be in non-local UTC (GMT) time.
+ *
+ * @param date The given UDate in UTC (GMT) time.
+ * @param status Output param set to success/failure code on exit. If any value
+ * set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @stable ICU 2.0
+ */
+ inline void setTime(UDate date, UErrorCode& status) { setTimeInMillis(date, status); }
+
+ /**
+ * Compares the equality of two Calendar objects. Objects of different subclasses
+ * are considered unequal. This comparison is very exacting; two Calendar objects
+ * must be in exactly the same state to be considered equal. To compare based on the
+ * represented time, use equals() instead.
+ *
+ * @param that The Calendar object to be compared with.
+ * @return True if the given Calendar is the same as this Calendar; false
+ * otherwise.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Calendar& that) const;
+
+ /**
+ * Compares the inequality of two Calendar objects.
+ *
+ * @param that The Calendar object to be compared with.
+ * @return True if the given Calendar is not the same as this Calendar; false
+ * otherwise.
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const Calendar& that) const {return !operator==(that);}
+
+ /**
+ * Returns TRUE if the given Calendar object is equivalent to this
+ * one. An equivalent Calendar will behave exactly as this one
+ * does, but it may be set to a different time. By contrast, for
+ * the operator==() method to return TRUE, the other Calendar must
+ * be set to the same time.
+ *
+ * @param other the Calendar to be compared with this Calendar
+ * @stable ICU 2.4
+ */
+ virtual UBool isEquivalentTo(const Calendar& other) const;
+
+ /**
+ * Compares the Calendar time, whereas Calendar::operator== compares the equality of
+ * Calendar objects.
+ *
+ * @param when The Calendar to be compared with this Calendar. Although this is a
+ * const parameter, the object may be modified physically
+ * (semantically const).
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @return True if the current time of this Calendar is equal to the time of
+ * Calendar when; false otherwise.
+ * @stable ICU 2.0
+ */
+ UBool equals(const Calendar& when, UErrorCode& status) const;
+
+ /**
+ * Returns true if this Calendar's current time is before "when"'s current time.
+ *
+ * @param when The Calendar to be compared with this Calendar. Although this is a
+ * const parameter, the object may be modified physically
+ * (semantically const).
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @return True if the current time of this Calendar is before the time of
+ * Calendar when; false otherwise.
+ * @stable ICU 2.0
+ */
+ UBool before(const Calendar& when, UErrorCode& status) const;
+
+ /**
+ * Returns true if this Calendar's current time is after "when"'s current time.
+ *
+ * @param when The Calendar to be compared with this Calendar. Although this is a
+ * const parameter, the object may be modified physically
+ * (semantically const).
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @return True if the current time of this Calendar is after the time of
+ * Calendar when; false otherwise.
+ * @stable ICU 2.0
+ */
+ UBool after(const Calendar& when, UErrorCode& status) const;
+
+ /**
+ * UDate Arithmetic function. Adds the specified (signed) amount of time to the given
+ * time field, based on the calendar's rules. For example, to subtract 5 days from
+ * the current time of the calendar, call add(Calendar::DATE, -5). When adding on
+ * the month or Calendar::MONTH field, other fields like date might conflict and
+ * need to be changed. For instance, adding 1 month on the date 01/31/96 will result
+ * in 02/29/96.
+ *
+ * @param field Specifies which date field to modify.
+ * @param amount The amount of time to be added to the field, in the natural unit
+ * for that field (e.g., days for the day fields, hours for the hour
+ * field.)
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @deprecated ICU 2.6. use add(UCalendarDateFields field, int32_t amount, UErrorCode& status) instead.
+ */
+ virtual void add(EDateFields field, int32_t amount, UErrorCode& status);
+
+ /**
+ * UDate Arithmetic function. Adds the specified (signed) amount of time to the given
+ * time field, based on the calendar's rules. For example, to subtract 5 days from
+ * the current time of the calendar, call add(Calendar::DATE, -5). When adding on
+ * the month or Calendar::MONTH field, other fields like date might conflict and
+ * need to be changed. For instance, adding 1 month on the date 01/31/96 will result
+ * in 02/29/96.
+ *
+ * @param field Specifies which date field to modify.
+ * @param amount The amount of time to be added to the field, in the natural unit
+ * for that field (e.g., days for the day fields, hours for the hour
+ * field.)
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @stable ICU 2.6.
+ */
+ virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode& status);
+
+ /**
+ * Time Field Rolling function. Rolls (up/down) a single unit of time on the given
+ * time field. For example, to roll the current date up by one day, call
+ * roll(Calendar::DATE, true). When rolling on the year or Calendar::YEAR field, it
+ * will roll the year value in the range between getMinimum(Calendar::YEAR) and the
+ * value returned by getMaximum(Calendar::YEAR). When rolling on the month or
+ * Calendar::MONTH field, other fields like date might conflict and, need to be
+ * changed. For instance, rolling the month up on the date 01/31/96 will result in
+ * 02/29/96. Rolling up always means rolling forward in time; e.g., rolling the year
+ * up on "100 BC" will result in "99 BC", for Gregorian calendar. When rolling on the
+ * hour-in-day or Calendar::HOUR_OF_DAY field, it will roll the hour value in the range
+ * between 0 and 23, which is zero-based.
+ * <P>
+ * NOTE: Do not use this method -- use roll(EDateFields, int, UErrorCode&) instead.
+ *
+ * @param field The time field.
+ * @param up Indicates if the value of the specified time field is to be rolled
+ * up or rolled down. Use true if rolling up, false otherwise.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @deprecated ICU 2.6. Use roll(UCalendarDateFields field, UBool up, UErrorCode& status) instead.
+ */
+ inline void roll(EDateFields field, UBool up, UErrorCode& status);
+
+ /**
+ * Time Field Rolling function. Rolls (up/down) a single unit of time on the given
+ * time field. For example, to roll the current date up by one day, call
+ * roll(Calendar::DATE, true). When rolling on the year or Calendar::YEAR field, it
+ * will roll the year value in the range between getMinimum(Calendar::YEAR) and the
+ * value returned by getMaximum(Calendar::YEAR). When rolling on the month or
+ * Calendar::MONTH field, other fields like date might conflict and, need to be
+ * changed. For instance, rolling the month up on the date 01/31/96 will result in
+ * 02/29/96. Rolling up always means rolling forward in time; e.g., rolling the year
+ * up on "100 BC" will result in "99 BC", for Gregorian calendar. When rolling on the
+ * hour-in-day or Calendar::HOUR_OF_DAY field, it will roll the hour value in the range
+ * between 0 and 23, which is zero-based.
+ * <P>
+ * NOTE: Do not use this method -- use roll(UCalendarDateFields, int, UErrorCode&) instead.
+ *
+ * @param field The time field.
+ * @param up Indicates if the value of the specified time field is to be rolled
+ * up or rolled down. Use true if rolling up, false otherwise.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @stable ICU 2.6.
+ */
+ inline void roll(UCalendarDateFields field, UBool up, UErrorCode& status);
+
+ /**
+ * Time Field Rolling function. Rolls by the given amount on the given
+ * time field. For example, to roll the current date up by one day, call
+ * roll(Calendar::DATE, +1, status). When rolling on the month or
+ * Calendar::MONTH field, other fields like date might conflict and, need to be
+ * changed. For instance, rolling the month up on the date 01/31/96 will result in
+ * 02/29/96. Rolling by a positive value always means rolling forward in time;
+ * e.g., rolling the year by +1 on "100 BC" will result in "99 BC", for Gregorian
+ * calendar. When rolling on the hour-in-day or Calendar::HOUR_OF_DAY field, it will
+ * roll the hour value in the range between 0 and 23, which is zero-based.
+ * <P>
+ * The only difference between roll() and add() is that roll() does not change
+ * the value of more significant fields when it reaches the minimum or maximum
+ * of its range, whereas add() does.
+ *
+ * @param field The time field.
+ * @param amount Indicates amount to roll.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ * @deprecated ICU 2.6. Use roll(UCalendarDateFields field, int32_t amount, UErrorCode& status) instead.
+ */
+ virtual void roll(EDateFields field, int32_t amount, UErrorCode& status);
+
+ /**
+ * Time Field Rolling function. Rolls by the given amount on the given
+ * time field. For example, to roll the current date up by one day, call
+ * roll(Calendar::DATE, +1, status). When rolling on the month or
+ * Calendar::MONTH field, other fields like date might conflict and, need to be
+ * changed. For instance, rolling the month up on the date 01/31/96 will result in
+ * 02/29/96. Rolling by a positive value always means rolling forward in time;
+ * e.g., rolling the year by +1 on "100 BC" will result in "99 BC", for Gregorian
+ * calendar. When rolling on the hour-in-day or Calendar::HOUR_OF_DAY field, it will
+ * roll the hour value in the range between 0 and 23, which is zero-based.
+ * <P>
+ * The only difference between roll() and add() is that roll() does not change
+ * the value of more significant fields when it reaches the minimum or maximum
+ * of its range, whereas add() does.
+ *
+ * @param field The time field.
+ * @param amount Indicates amount to roll.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ * @stable ICU 2.6.
+ */
+ virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode& status);
+
+ /**
+ * Return the difference between the given time and the time this
+ * calendar object is set to. If this calendar is set
+ * <em>before</em> the given time, the returned value will be
+ * positive. If this calendar is set <em>after</em> the given
+ * time, the returned value will be negative. The
+ * <code>field</code> parameter specifies the units of the return
+ * value. For example, if <code>fieldDifference(when,
+ * Calendar::MONTH)</code> returns 3, then this calendar is set to
+ * 3 months before <code>when</code>, and possibly some addition
+ * time less than one month.
+ *
+ * <p>As a side effect of this call, this calendar is advanced
+ * toward <code>when</code> by the given amount. That is, calling
+ * this method has the side effect of calling <code>add(field,
+ * n)</code>, where <code>n</code> is the return value.
+ *
+ * <p>Usage: To use this method, call it first with the largest
+ * field of interest, then with progressively smaller fields. For
+ * example:
+ *
+ * <pre>
+ * int y = cal->fieldDifference(when, Calendar::YEAR, err);
+ * int m = cal->fieldDifference(when, Calendar::MONTH, err);
+ * int d = cal->fieldDifference(when, Calendar::DATE, err);</pre>
+ *
+ * computes the difference between <code>cal</code> and
+ * <code>when</code> in years, months, and days.
+ *
+ * <p>Note: <code>fieldDifference()</code> is
+ * <em>asymmetrical</em>. That is, in the following code:
+ *
+ * <pre>
+ * cal->setTime(date1, err);
+ * int m1 = cal->fieldDifference(date2, Calendar::MONTH, err);
+ * int d1 = cal->fieldDifference(date2, Calendar::DATE, err);
+ * cal->setTime(date2, err);
+ * int m2 = cal->fieldDifference(date1, Calendar::MONTH, err);
+ * int d2 = cal->fieldDifference(date1, Calendar::DATE, err);</pre>
+ *
+ * one might expect that <code>m1 == -m2 && d1 == -d2</code>.
+ * However, this is not generally the case, because of
+ * irregularities in the underlying calendar system (e.g., the
+ * Gregorian calendar has a varying number of days per month).
+ *
+ * @param when the date to compare this calendar's time to
+ * @param field the field in which to compute the result
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ * @return the difference, either positive or negative, between
+ * this calendar's time and <code>when</code>, in terms of
+ * <code>field</code>.
+ * @deprecated ICU 2.6. Use fieldDifference(UDate when, UCalendarDateFields field, UErrorCode& status).
+ */
+ virtual int32_t fieldDifference(UDate when, EDateFields field, UErrorCode& status);
+
+ /**
+ * Return the difference between the given time and the time this
+ * calendar object is set to. If this calendar is set
+ * <em>before</em> the given time, the returned value will be
+ * positive. If this calendar is set <em>after</em> the given
+ * time, the returned value will be negative. The
+ * <code>field</code> parameter specifies the units of the return
+ * value. For example, if <code>fieldDifference(when,
+ * Calendar::MONTH)</code> returns 3, then this calendar is set to
+ * 3 months before <code>when</code>, and possibly some addition
+ * time less than one month.
+ *
+ * <p>As a side effect of this call, this calendar is advanced
+ * toward <code>when</code> by the given amount. That is, calling
+ * this method has the side effect of calling <code>add(field,
+ * n)</code>, where <code>n</code> is the return value.
+ *
+ * <p>Usage: To use this method, call it first with the largest
+ * field of interest, then with progressively smaller fields. For
+ * example:
+ *
+ * <pre>
+ * int y = cal->fieldDifference(when, Calendar::YEAR, err);
+ * int m = cal->fieldDifference(when, Calendar::MONTH, err);
+ * int d = cal->fieldDifference(when, Calendar::DATE, err);</pre>
+ *
+ * computes the difference between <code>cal</code> and
+ * <code>when</code> in years, months, and days.
+ *
+ * <p>Note: <code>fieldDifference()</code> is
+ * <em>asymmetrical</em>. That is, in the following code:
+ *
+ * <pre>
+ * cal->setTime(date1, err);
+ * int m1 = cal->fieldDifference(date2, Calendar::MONTH, err);
+ * int d1 = cal->fieldDifference(date2, Calendar::DATE, err);
+ * cal->setTime(date2, err);
+ * int m2 = cal->fieldDifference(date1, Calendar::MONTH, err);
+ * int d2 = cal->fieldDifference(date1, Calendar::DATE, err);</pre>
+ *
+ * one might expect that <code>m1 == -m2 && d1 == -d2</code>.
+ * However, this is not generally the case, because of
+ * irregularities in the underlying calendar system (e.g., the
+ * Gregorian calendar has a varying number of days per month).
+ *
+ * @param when the date to compare this calendar's time to
+ * @param field the field in which to compute the result
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ * @return the difference, either positive or negative, between
+ * this calendar's time and <code>when</code>, in terms of
+ * <code>field</code>.
+ * @stable ICU 2.6.
+ */
+ virtual int32_t fieldDifference(UDate when, UCalendarDateFields field, UErrorCode& status);
+
+ /**
+ * Sets the calendar's time zone to be the one passed in. The Calendar takes ownership
+ * of the TimeZone; the caller is no longer responsible for deleting it. If the
+ * given time zone is NULL, this function has no effect.
+ *
+ * @param value The given time zone.
+ * @stable ICU 2.0
+ */
+ void adoptTimeZone(TimeZone* value);
+
+ /**
+ * Sets the calendar's time zone to be the same as the one passed in. The TimeZone
+ * passed in is _not_ adopted; the client is still responsible for deleting it.
+ *
+ * @param zone The given time zone.
+ * @stable ICU 2.0
+ */
+ void setTimeZone(const TimeZone& zone);
+
+ /**
+ * Returns a reference to the time zone owned by this calendar. The returned reference
+ * is only valid until clients make another call to adoptTimeZone or setTimeZone,
+ * or this Calendar is destroyed.
+ *
+ * @return The time zone object associated with this calendar.
+ * @stable ICU 2.0
+ */
+ const TimeZone& getTimeZone(void) const;
+
+ /**
+ * Returns the time zone owned by this calendar. The caller owns the returned object
+ * and must delete it when done. After this call, the new time zone associated
+ * with this Calendar is the default TimeZone as returned by TimeZone::createDefault().
+ *
+ * @return The time zone object which was associated with this calendar.
+ * @stable ICU 2.0
+ */
+ TimeZone* orphanTimeZone(void);
+
+ /**
+ * Queries if the current date for this Calendar is in Daylight Savings Time.
+ *
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return True if the current date for this Calendar is in Daylight Savings Time,
+ * false, otherwise.
+ * @stable ICU 2.0
+ */
+ virtual UBool inDaylightTime(UErrorCode& status) const = 0;
+
+ /**
+ * Specifies whether or not date/time interpretation is to be lenient. With lenient
+ * interpretation, a date such as "February 942, 1996" will be treated as being
+ * equivalent to the 941st day after February 1, 1996. With strict interpretation,
+ * such dates will cause an error when computing time from the time field values
+ * representing the dates.
+ *
+ * @param lenient True specifies date/time interpretation to be lenient.
+ *
+ * @see DateFormat#setLenient
+ * @stable ICU 2.0
+ */
+ void setLenient(UBool lenient);
+
+ /**
+ * Tells whether date/time interpretation is to be lenient.
+ *
+ * @return True tells that date/time interpretation is to be lenient.
+ * @stable ICU 2.0
+ */
+ UBool isLenient(void) const;
+
+ /**
+ * Sets what the first day of the week is; e.g., Sunday in US, Monday in France.
+ *
+ * @param value The given first day of the week.
+ * @deprecated ICU 2.6. Use setFirstDayOfWeek(UCalendarDaysOfWeek value) instead.
+ */
+ void setFirstDayOfWeek(EDaysOfWeek value);
+
+ /**
+ * Sets what the first day of the week is; e.g., Sunday in US, Monday in France.
+ *
+ * @param value The given first day of the week.
+ * @stable ICU 2.6.
+ */
+ void setFirstDayOfWeek(UCalendarDaysOfWeek value);
+
+ /**
+ * Gets what the first day of the week is; e.g., Sunday in US, Monday in France.
+ *
+ * @return The first day of the week.
+ * @deprecated ICU 2.6 use the overload with error code
+ */
+ EDaysOfWeek getFirstDayOfWeek(void) const;
+
+ /**
+ * Gets what the first day of the week is; e.g., Sunday in US, Monday in France.
+ *
+ * @param status error code
+ * @return The first day of the week.
+ * @stable ICU 2.6
+ */
+ UCalendarDaysOfWeek getFirstDayOfWeek(UErrorCode &status) const;
+
+ /**
+ * Sets what the minimal days required in the first week of the year are; For
+ * example, if the first week is defined as one that contains the first day of the
+ * first month of a year, call the method with value 1. If it must be a full week,
+ * use value 7.
+ *
+ * @param value The given minimal days required in the first week of the year.
+ * @stable ICU 2.0
+ */
+ void setMinimalDaysInFirstWeek(uint8_t value);
+
+ /**
+ * Gets what the minimal days required in the first week of the year are; e.g., if
+ * the first week is defined as one that contains the first day of the first month
+ * of a year, getMinimalDaysInFirstWeek returns 1. If the minimal days required must
+ * be a full week, getMinimalDaysInFirstWeek returns 7.
+ *
+ * @return The minimal days required in the first week of the year.
+ * @stable ICU 2.0
+ */
+ uint8_t getMinimalDaysInFirstWeek(void) const;
+
+ /**
+ * Gets the minimum value for the given time field. e.g., for Gregorian
+ * DAY_OF_MONTH, 1.
+ *
+ * @param field The given time field.
+ * @return The minimum value for the given time field.
+ * @deprecated ICU 2.6. Use getMinimum(UCalendarDateFields field) instead.
+ */
+ virtual int32_t getMinimum(EDateFields field) const;
+
+ /**
+ * Gets the minimum value for the given time field. e.g., for Gregorian
+ * DAY_OF_MONTH, 1.
+ *
+ * @param field The given time field.
+ * @return The minimum value for the given time field.
+ * @stable ICU 2.6.
+ */
+ virtual int32_t getMinimum(UCalendarDateFields field) const;
+
+ /**
+ * Gets the maximum value for the given time field. e.g. for Gregorian DAY_OF_MONTH,
+ * 31.
+ *
+ * @param field The given time field.
+ * @return The maximum value for the given time field.
+ * @deprecated ICU 2.6. Use getMaximum(UCalendarDateFields field) instead.
+ */
+ virtual int32_t getMaximum(EDateFields field) const;
+
+ /**
+ * Gets the maximum value for the given time field. e.g. for Gregorian DAY_OF_MONTH,
+ * 31.
+ *
+ * @param field The given time field.
+ * @return The maximum value for the given time field.
+ * @stable ICU 2.6.
+ */
+ virtual int32_t getMaximum(UCalendarDateFields field) const;
+
+ /**
+ * Gets the highest minimum value for the given field if varies. Otherwise same as
+ * getMinimum(). For Gregorian, no difference.
+ *
+ * @param field The given time field.
+ * @return The highest minimum value for the given time field.
+ * @deprecated ICU 2.6. Use getGreatestMinimum(UCalendarDateFields field) instead.
+ */
+ virtual int32_t getGreatestMinimum(EDateFields field) const;
+
+ /**
+ * Gets the highest minimum value for the given field if varies. Otherwise same as
+ * getMinimum(). For Gregorian, no difference.
+ *
+ * @param field The given time field.
+ * @return The highest minimum value for the given time field.
+ * @stable ICU 2.6.
+ */
+ virtual int32_t getGreatestMinimum(UCalendarDateFields field) const;
+
+ /**
+ * Gets the lowest maximum value for the given field if varies. Otherwise same as
+ * getMaximum(). e.g., for Gregorian DAY_OF_MONTH, 28.
+ *
+ * @param field The given time field.
+ * @return The lowest maximum value for the given time field.
+ * @deprecated ICU 2.6. Use getLeastMaximum(UCalendarDateFields field) instead.
+ */
+ virtual int32_t getLeastMaximum(EDateFields field) const;
+
+ /**
+ * Gets the lowest maximum value for the given field if varies. Otherwise same as
+ * getMaximum(). e.g., for Gregorian DAY_OF_MONTH, 28.
+ *
+ * @param field The given time field.
+ * @return The lowest maximum value for the given time field.
+ * @stable ICU 2.6.
+ */
+ virtual int32_t getLeastMaximum(UCalendarDateFields field) const;
+
+ /**
+ * Return the minimum value that this field could have, given the current date.
+ * For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
+ *
+ * The version of this function on Calendar uses an iterative algorithm to determine the
+ * actual minimum value for the field. There is almost always a more efficient way to
+ * accomplish this (in most cases, you can simply return getMinimum()). GregorianCalendar
+ * overrides this function with a more efficient implementation.
+ *
+ * @param field the field to determine the minimum of
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return the minimum of the given field for the current date of this Calendar
+ * @deprecated ICU 2.6. Use getActualMinimum(UCalendarDateFields field, UErrorCode& status) instead.
+ */
+ int32_t getActualMinimum(EDateFields field, UErrorCode& status) const;
+
+ /**
+ * Return the minimum value that this field could have, given the current date.
+ * For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
+ *
+ * The version of this function on Calendar uses an iterative algorithm to determine the
+ * actual minimum value for the field. There is almost always a more efficient way to
+ * accomplish this (in most cases, you can simply return getMinimum()). GregorianCalendar
+ * overrides this function with a more efficient implementation.
+ *
+ * @param field the field to determine the minimum of
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return the minimum of the given field for the current date of this Calendar
+ * @stable ICU 2.6.
+ */
+ int32_t getActualMinimum(UCalendarDateFields field, UErrorCode& status) const;
+
+ /**
+ * Return the maximum value that this field could have, given the current date.
+ * For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field, the actual
+ * maximum would be 28; for "Feb 3, 1996" it s 29. Similarly for a Hebrew calendar,
+ * for some years the actual maximum for MONTH is 12, and for others 13.
+ *
+ * The version of this function on Calendar uses an iterative algorithm to determine the
+ * actual maximum value for the field. There is almost always a more efficient way to
+ * accomplish this (in most cases, you can simply return getMaximum()). GregorianCalendar
+ * overrides this function with a more efficient implementation.
+ *
+ * @param field the field to determine the maximum of
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return the maximum of the given field for the current date of this Calendar
+ * @deprecated ICU 2.6. Use getActualMaximum(UCalendarDateFields field, UErrorCode& status) instead.
+ */
+ int32_t getActualMaximum(EDateFields field, UErrorCode& status) const;
+
+ /**
+ * Return the maximum value that this field could have, given the current date.
+ * For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field, the actual
+ * maximum would be 28; for "Feb 3, 1996" it s 29. Similarly for a Hebrew calendar,
+ * for some years the actual maximum for MONTH is 12, and for others 13.
+ *
+ * The version of this function on Calendar uses an iterative algorithm to determine the
+ * actual maximum value for the field. There is almost always a more efficient way to
+ * accomplish this (in most cases, you can simply return getMaximum()). GregorianCalendar
+ * overrides this function with a more efficient implementation.
+ *
+ * @param field the field to determine the maximum of
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return the maximum of the given field for the current date of this Calendar
+ * @stable ICU 2.6.
+ */
+ int32_t getActualMaximum(UCalendarDateFields field, UErrorCode& status) const;
+
+ /**
+ * Gets the value for a given time field. Recalculate the current time field values
+ * if the time value has been changed by a call to setTime(). Return zero for unset
+ * fields if any fields have been explicitly set by a call to set(). To force a
+ * recomputation of all fields regardless of the previous state, call complete().
+ * This method is semantically const, but may alter the object in memory.
+ *
+ * @param field The given time field.
+ * @param status Fill-in parameter which receives the status of the operation.
+ * @return The value for the given time field, or zero if the field is unset,
+ * and set() has been called for any other field.
+ * @deprecated ICU 2.6. Use get(UCalendarDateFields field, UErrorCode& status) instead.
+ */
+ int32_t get(EDateFields field, UErrorCode& status) const;
+
+ /**
+ * Gets the value for a given time field. Recalculate the current time field values
+ * if the time value has been changed by a call to setTime(). Return zero for unset
+ * fields if any fields have been explicitly set by a call to set(). To force a
+ * recomputation of all fields regardless of the previous state, call complete().
+ * This method is semantically const, but may alter the object in memory.
+ *
+ * @param field The given time field.
+ * @param status Fill-in parameter which receives the status of the operation.
+ * @return The value for the given time field, or zero if the field is unset,
+ * and set() has been called for any other field.
+ * @stable ICU 2.6.
+ */
+ int32_t get(UCalendarDateFields field, UErrorCode& status) const;
+
+ /**
+ * Determines if the given time field has a value set. This can affect in the
+ * resolving of time in Calendar. Unset fields have a value of zero, by definition.
+ *
+ * @param field The given time field.
+ * @return True if the given time field has a value set; false otherwise.
+ * @deprecated ICU 2.6. Use isSet(UCalendarDateFields field) instead.
+ */
+ UBool isSet(EDateFields field) const;
+
+ /**
+ * Determines if the given time field has a value set. This can affect in the
+ * resolving of time in Calendar. Unset fields have a value of zero, by definition.
+ *
+ * @param field The given time field.
+ * @return True if the given time field has a value set; false otherwise.
+ * @stable ICU 2.6.
+ */
+ UBool isSet(UCalendarDateFields field) const;
+
+ /**
+ * Sets the given time field with the given value.
+ *
+ * @param field The given time field.
+ * @param value The value to be set for the given time field.
+ * @deprecated ICU 2.6. Use set(UCalendarDateFields field, int32_t value) instead.
+ */
+ void set(EDateFields field, int32_t value);
+
+ /**
+ * Sets the given time field with the given value.
+ *
+ * @param field The given time field.
+ * @param value The value to be set for the given time field.
+ * @stable ICU 2.6.
+ */
+ void set(UCalendarDateFields field, int32_t value);
+
+ /**
+ * Sets the values for the fields YEAR, MONTH, and DATE. Other field values are
+ * retained; call clear() first if this is not desired.
+ *
+ * @param year The value used to set the YEAR time field.
+ * @param month The value used to set the MONTH time field. Month value is 0-based.
+ * e.g., 0 for January.
+ * @param date The value used to set the DATE time field.
+ * @stable ICU 2.0
+ */
+ void set(int32_t year, int32_t month, int32_t date);
+
+ /**
+ * Sets the values for the fields YEAR, MONTH, DATE, HOUR_OF_DAY, and MINUTE. Other
+ * field values are retained; call clear() first if this is not desired.
+ *
+ * @param year The value used to set the YEAR time field.
+ * @param month The value used to set the MONTH time field. Month value is
+ * 0-based. E.g., 0 for January.
+ * @param date The value used to set the DATE time field.
+ * @param hour The value used to set the HOUR_OF_DAY time field.
+ * @param minute The value used to set the MINUTE time field.
+ * @stable ICU 2.0
+ */
+ void set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute);
+
+ /**
+ * Sets the values for the fields YEAR, MONTH, DATE, HOUR_OF_DAY, MINUTE, and SECOND.
+ * Other field values are retained; call clear() first if this is not desired.
+ *
+ * @param year The value used to set the YEAR time field.
+ * @param month The value used to set the MONTH time field. Month value is
+ * 0-based. E.g., 0 for January.
+ * @param date The value used to set the DATE time field.
+ * @param hour The value used to set the HOUR_OF_DAY time field.
+ * @param minute The value used to set the MINUTE time field.
+ * @param second The value used to set the SECOND time field.
+ * @stable ICU 2.0
+ */
+ void set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute, int32_t second);
+
+ /**
+ * Clears the values of all the time fields, making them both unset and assigning
+ * them a value of zero. The field values will be determined during the next
+ * resolving of time into time fields.
+ * @stable ICU 2.0
+ */
+ void clear(void);
+
+ /**
+ * Clears the value in the given time field, both making it unset and assigning it a
+ * value of zero. This field value will be determined during the next resolving of
+ * time into time fields.
+ *
+ * @param field The time field to be cleared.
+ * @deprecated ICU 2.6. Use clear(UCalendarDateFields field) instead.
+ */
+ void clear(EDateFields field);
+
+ /**
+ * Clears the value in the given time field, both making it unset and assigning it a
+ * value of zero. This field value will be determined during the next resolving of
+ * time into time fields.
+ *
+ * @param field The time field to be cleared.
+ * @stable ICU 2.6.
+ */
+ void clear(UCalendarDateFields field);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual method. This method is to
+ * implement a simple version of RTTI, since not all C++ compilers support genuine
+ * RTTI. Polymorphic operator==() and clone() methods call this method.
+ * <P>
+ * Concrete subclasses of Calendar must implement getDynamicClassID() and also a
+ * static method and data member:
+ *
+ * static UClassID getStaticClassID() { return (UClassID)&amp;fgClassID; }
+ * static char fgClassID;
+ *
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const = 0;
+
+ /**
+ * Returns the resource key string used for this calendar type.
+ * For example, prepending "Eras_" to this string could return "Eras_japanese"
+ * or "Eras_gregorian".
+ *
+ * @returns static string, for example, "gregorian" or "japanese"
+ * @internal
+ */
+ virtual const char * getType() const = 0;
+
+protected:
+
+ /**
+ * Constructs a Calendar with the default time zone as returned by
+ * TimeZone::createInstance(), and the default locale.
+ *
+ * @param success Indicates the status of Calendar object construction. Returns
+ * U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ Calendar(UErrorCode& success);
+
+ /**
+ * Copy constructor
+ *
+ * @param source Calendar object to be copied from
+ * @stable ICU 2.0
+ */
+ Calendar(const Calendar& source);
+
+ /**
+ * Default assignment operator
+ *
+ * @param right Calendar object to be copied
+ * @stable ICU 2.0
+ */
+ Calendar& operator=(const Calendar& right);
+
+ /**
+ * Constructs a Calendar with the given time zone and locale. Clients are no longer
+ * responsible for deleting the given time zone object after it's adopted.
+ *
+ * @param zone The given time zone.
+ * @param aLocale The given locale.
+ * @param success Indicates the status of Calendar object construction. Returns
+ * U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ Calendar(TimeZone* zone, const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Constructs a Calendar with the given time zone and locale.
+ *
+ * @param zone The given time zone.
+ * @param aLocale The given locale.
+ * @param success Indicates the status of Calendar object construction. Returns
+ * U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ Calendar(const TimeZone& zone, const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Converts Calendar's time field values to GMT as milliseconds.
+ *
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @stable ICU 2.0
+ */
+ virtual void computeTime(UErrorCode& status);
+
+ /**
+ * Converts GMT as milliseconds to time field values. This allows you to sync up the
+ * time field values with a new time that is set for the calendar. This method
+ * does NOT recompute the time first; to recompute the time, then the fields, use
+ * the method complete().
+ *
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @stable ICU 2.0
+ */
+ virtual void computeFields(UErrorCode& status);
+
+ /**
+ * Gets this Calendar's current time as a long.
+ *
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @return the current time as UTC milliseconds from the epoch.
+ * @stable ICU 2.0
+ */
+ double getTimeInMillis(UErrorCode& status) const;
+
+ /**
+ * Sets this Calendar's current time from the given long value.
+ * @param millis the new time in UTC milliseconds from the epoch.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @stable ICU 2.0
+ */
+ void setTimeInMillis( double millis, UErrorCode& status );
+
+ /**
+ * Recomputes the current time from currently set fields, and then fills in any
+ * unset fields in the time field list.
+ *
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ * @stable ICU 2.0
+ */
+ void complete(UErrorCode& status);
+
+ /**
+ * Gets the value for a given time field. Subclasses can use this function to get
+ * field values without forcing recomputation of time.
+ *
+ * @param field The given time field.
+ * @return The value for the given time field.
+ * @deprecated ICU 2.6. Use internalGet(UCalendarDateFields field) instead.
+ */
+ inline int32_t internalGet(EDateFields field) const {return fFields[field];}
+
+ /**
+ * Gets the value for a given time field. Subclasses can use this function to get
+ * field values without forcing recomputation of time. If the field's stamp is UNSET,
+ * the defaultValue is used.
+ *
+ * @param field The given time field.
+ * @param defaultValue a default value used if the field is unset.
+ * @return The value for the given time field.
+ * @internal
+ */
+ inline int32_t internalGet(UCalendarDateFields field, int32_t defaultValue) const {return fStamp[field]>kUnset ? fFields[field] : defaultValue;}
+
+ /**
+ * Gets the value for a given time field. Subclasses can use this function to get
+ * field values without forcing recomputation of time.
+ *
+ * @param field The given time field.
+ * @return The value for the given time field.
+ * @internal
+ */
+ inline int32_t internalGet(UCalendarDateFields field) const {return fFields[field];}
+
+ /**
+ * Sets the value for a given time field. This is a fast internal method for
+ * subclasses. It does not affect the areFieldsInSync, isTimeSet, or areAllFieldsSet
+ * flags.
+ *
+ * @param field The given time field.
+ * @param value The value for the given time field.
+ * @deprecated ICU 2.6. Use internalSet(UCalendarDateFields field, int32_t value) instead.
+ */
+ void internalSet(EDateFields field, int32_t value);
+
+ /**
+ * Sets the value for a given time field. This is a fast internal method for
+ * subclasses. It does not affect the areFieldsInSync, isTimeSet, or areAllFieldsSet
+ * flags.
+ *
+ * @param field The given time field.
+ * @param value The value for the given time field.
+ * @stable ICU 2.6.
+ */
+ inline void internalSet(UCalendarDateFields field, int32_t value);
+
+ /**
+ * Prepare this calendar for computing the actual minimum or maximum.
+ * This method modifies this calendar's fields; it is called on a
+ * temporary calendar.
+ * @internal
+ */
+ virtual void prepareGetActual(UCalendarDateFields field, UBool isMinimum, UErrorCode &status);
+
+ /**
+ * Limit enums. Not in sync with UCalendarLimitType (refers to internal fields).
+ * @internal
+ */
+ enum ELimitType {
+ UCAL_LIMIT_MINIMUM = 0,
+ UCAL_LIMIT_GREATEST_MINIMUM,
+ UCAL_LIMIT_LEAST_MAXIMUM,
+ UCAL_LIMIT_MAXIMUM,
+ UCAL_LIMIT_COUNT
+ };
+
+ /**
+ * Subclass API for defining limits of different types.
+ * Subclasses must implement this method to return limits for the
+ * following fields:
+ *
+ * <pre>UCAL_ERA
+ * UCAL_YEAR
+ * UCAL_MONTH
+ * UCAL_WEEK_OF_YEAR
+ * UCAL_WEEK_OF_MONTH
+ * UCAL_DATE (DAY_OF_MONTH on Java)
+ * UCAL_DAY_OF_YEAR
+ * UCAL_DAY_OF_WEEK_IN_MONTH
+ * UCAL_YEAR_WOY
+ * UCAL_EXTENDED_YEAR</pre>
+ *
+ * @param field one of the above field numbers
+ * @param limitType one of <code>MINIMUM</code>, <code>GREATEST_MINIMUM</code>,
+ * <code>LEAST_MAXIMUM</code>, or <code>MAXIMUM</code>
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const = 0;
+
+ /**
+ * Return a limit for a field.
+ * @param field the field, from <code>0..UCAL_MAX_FIELD</code>
+ * @param limitType the type specifier for the limit
+ * @see #ELimitType
+ * @internal
+ */
+ virtual int32_t getLimit(UCalendarDateFields field, ELimitType limitType) const;
+
+
+ /**
+ * Return the Julian day number of day before the first day of the
+ * given month in the given extended year. Subclasses should override
+ * this method to implement their calendar system.
+ * @param eyear the extended year
+ * @param month the zero-based month, or 0 if useMonth is false
+ * @param useMonth if false, compute the day before the first day of
+ * the given year, otherwise, compute the day before the first day of
+ * the given month
+ * @return the Julian day number of the day before the first
+ * day of the given month and year
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month,
+ UBool useMonth) const = 0;
+
+ /**
+ * Return the number of days in the given month of the given extended
+ * year of this calendar system. Subclasses should override this
+ * method if they can provide a more correct or more efficient
+ * implementation than the default implementation in Calendar.
+ * @internal
+ */
+ virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const ;
+
+ /**
+ * Return the number of days in the given extended year of this
+ * calendar system. Subclasses should override this method if they can
+ * provide a more correct or more efficient implementation than the
+ * default implementation in Calendar.
+ * @stable ICU 2.0
+ */
+ virtual int32_t handleGetYearLength(int32_t eyear) const;
+
+
+ /**
+ * Return the extended year defined by the current fields. This will
+ * use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
+ * as UCAL_ERA) specific to the calendar system, depending on which set of
+ * fields is newer.
+ * @return the extended year
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear() = 0;
+
+ /**
+ * Subclasses may override this. This method calls
+ * handleGetMonthLength() to obtain the calendar-specific month
+ * length.
+ * @param bestField which field to use to calculate the date
+ * @return julian day specified by calendar fields.
+ * @internal
+ */
+ virtual int32_t handleComputeJulianDay(UCalendarDateFields bestField);
+
+ /**
+ * Subclasses must override this to convert from week fields
+ * (YEAR_WOY and WEEK_OF_YEAR) to an extended year in the case
+ * where YEAR, EXTENDED_YEAR are not set.
+ * The Calendar implementation assumes yearWoy is in extended gregorian form
+ * @internal
+ * @return the extended year, UCAL_EXTENDED_YEAR
+ */
+ virtual int32_t handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy);
+
+ /**
+ * Compute the Julian day from fields. Will determine whether to use
+ * the JULIAN_DAY field directly, or other fields.
+ * @return the julian day
+ * @internal
+ */
+ int32_t computeJulianDay();
+
+ /**
+ * Compute the milliseconds in the day from the fields. This is a
+ * value from 0 to 23:59:59.999 inclusive, unless fields are out of
+ * range, in which case it can be an arbitrary value. This value
+ * reflects local zone wall time.
+ * @internal
+ */
+ int32_t computeMillisInDay();
+
+ /**
+ * This method can assume EXTENDED_YEAR has been set.
+ * @param millis milliseconds of the date fields
+ * @param millisInDay milliseconds of the time fields; may be out
+ * or range.
+ * @param ec Output param set to failure code on function return
+ * when this function fails.
+ * @internal
+ */
+ int32_t computeZoneOffset(double millis, int32_t millisInDay, UErrorCode &ec);
+
+
+ /**
+ * Determine the best stamp in a range.
+ * @param start first enum to look at
+ * @param end last enum to look at
+ * @param bestSoFar stamp prior to function call
+ * @return the stamp value of the best stamp
+ * @internal
+ */
+ int32_t newestStamp(UCalendarDateFields start, UCalendarDateFields end, int32_t bestSoFar) const;
+
+ /**
+ * Values for field resolution tables
+ * @see #resolveFields
+ * @internal
+ */
+ enum {
+ /** Marker for end of resolve set (row or group). */
+ kResolveSTOP = -1,
+ /** Value to be bitwised "ORed" against resolve table field values for remapping. Example: (UCAL_DATE | kResolveRemap) in 1st column will cause 'UCAL_DATE' to be returned, but will not examine the value of UCAL_DATE. */
+ kResolveRemap = 32
+ };
+
+ /**
+ * Precedence table for Dates
+ * @see #resolveFields
+ * @internal
+ */
+ static const UFieldResolutionTable kDatePrecedence[];
+
+ /**
+ * Precedence table for Year
+ * @see #resolveFields
+ * @internal
+ */
+ static const UFieldResolutionTable kYearPrecedence[];
+
+ /**
+ * Precedence table for Day of Week
+ * @see #resolveFields
+ * @internal
+ */
+ static const UFieldResolutionTable kDOWPrecedence[];
+
+ /**
+ * Given a precedence table, return the newest field combination in
+ * the table, or UCAL_FIELD_COUNT if none is found.
+ *
+ * <p>The precedence table is a 3-dimensional array of integers. It
+ * may be thought of as an array of groups. Each group is an array of
+ * lines. Each line is an array of field numbers. Within a line, if
+ * all fields are set, then the time stamp of the line is taken to be
+ * the stamp of the most recently set field. If any field of a line is
+ * unset, then the line fails to match. Within a group, the line with
+ * the newest time stamp is selected. The first field of the line is
+ * returned to indicate which line matched.
+ *
+ * <p>In some cases, it may be desirable to map a line to field that
+ * whose stamp is NOT examined. For example, if the best field is
+ * DAY_OF_WEEK then the DAY_OF_WEEK_IN_MONTH algorithm may be used. In
+ * order to do this, insert the value <code>kResolveRemap | F</code> at
+ * the start of the line, where <code>F</code> is the desired return
+ * field value. This field will NOT be examined; it only determines
+ * the return value if the other fields in the line are the newest.
+ *
+ * <p>If all lines of a group contain at least one unset field, then no
+ * line will match, and the group as a whole will fail to match. In
+ * that case, the next group will be processed. If all groups fail to
+ * match, then UCAL_FIELD_COUNT is returned.
+ * @internal
+ */
+ UCalendarDateFields resolveFields(const UFieldResolutionTable *precedenceTable);
+
+
+ /**
+ * @internal
+ */
+ virtual const UFieldResolutionTable* getFieldResolutionTable() const;
+
+ /**
+ * Return the field that is newer, either defaultField, or
+ * alternateField. If neither is newer or neither is set, return defaultField.
+ * @internal
+ */
+ UCalendarDateFields newerField(UCalendarDateFields defaultField, UCalendarDateFields alternateField) const;
+
+
+private:
+ /**
+ * Helper function for calculating limits by trial and error
+ * @param field The field being investigated
+ * @param startValue starting (least max) value of field
+ * @param endValue ending (greatest max) value of field
+ * @param status return type
+ * @internal
+ */
+ int32_t getActualHelper(UCalendarDateFields field, int32_t startValue, int32_t endValue, UErrorCode &status) const;
+
+
+protected:
+ /**
+ * The flag which indicates if the current time is set in the calendar.
+ * @stable ICU 2.0
+ */
+ UBool fIsTimeSet;
+
+ /**
+ * True if the fields are in sync with the currently set time of this Calendar.
+ * If false, then the next attempt to get the value of a field will
+ * force a recomputation of all fields from the current value of the time
+ * field.
+ * <P>
+ * This should really be named areFieldsInSync, but the old name is retained
+ * for backward compatibility.
+ * @stable ICU 2.0
+ */
+ UBool fAreFieldsSet;
+
+ /**
+ * True if all of the fields have been set. This is initially false, and set to
+ * true by computeFields().
+ * @stable ICU 2.0
+ */
+ UBool fAreAllFieldsSet;
+
+ /**
+ * True if all fields have been virtually set, but have not yet been
+ * computed. This occurs only in setTimeInMillis(). A calendar set
+ * to this state will compute all fields from the time if it becomes
+ * necessary, but otherwise will delay such computation.
+ * @stable ICU 3.0
+ */
+ UBool fAreFieldsVirtuallySet;
+
+ /**
+ * Get the current time without recomputing.
+ *
+ * @return the current time without recomputing.
+ * @stable ICU 2.0
+ */
+ UDate internalGetTime(void) const { return fTime; }
+
+ /**
+ * Set the current time without affecting flags or fields.
+ *
+ * @param time The time to be set
+ * @return the current time without recomputing.
+ * @stable ICU 2.0
+ */
+ void internalSetTime(UDate time) { fTime = time; }
+
+ /**
+ * The time fields containing values into which the millis is computed.
+ * @stable ICU 2.0
+ */
+ int32_t fFields[UCAL_FIELD_COUNT];
+
+ /**
+ * The flags which tell if a specified time field for the calendar is set.
+ * @deprecated ICU 2.8 use (fStamp[n]!=kUnset)
+ */
+ UBool fIsSet[UCAL_FIELD_COUNT];
+
+ /** Special values of stamp[]
+ * @stable ICU 2.0
+ */
+ enum {
+ kUnset = 0,
+ kInternallySet,
+ kMinimumUserStamp
+ };
+
+ /**
+ * Pseudo-time-stamps which specify when each field was set. There
+ * are two special values, UNSET and INTERNALLY_SET. Values from
+ * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
+ * @stable ICU 2.0
+ */
+ int32_t fStamp[UCAL_FIELD_COUNT];
+
+ /**
+ * Subclasses may override this method to compute several fields
+ * specific to each calendar system. These are:
+ *
+ * <ul><li>ERA
+ * <li>YEAR
+ * <li>MONTH
+ * <li>DAY_OF_MONTH
+ * <li>DAY_OF_YEAR
+ * <li>EXTENDED_YEAR</ul>
+ *
+ * Subclasses can refer to the DAY_OF_WEEK and DOW_LOCAL fields, which
+ * will be set when this method is called. Subclasses can also call
+ * the getGregorianXxx() methods to obtain Gregorian calendar
+ * equivalents for the given Julian day.
+ *
+ * <p>In addition, subclasses should compute any subclass-specific
+ * fields, that is, fields from BASE_FIELD_COUNT to
+ * getFieldCount() - 1.
+ *
+ * <p>The default implementation in <code>Calendar</code> implements
+ * a pure proleptic Gregorian calendar.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
+
+ /**
+ * Return the extended year on the Gregorian calendar as computed by
+ * <code>computeGregorianFields()</code>.
+ * @internal
+ */
+ int32_t getGregorianYear() const {
+ return fGregorianYear;
+ }
+
+ /**
+ * Return the month (0-based) on the Gregorian calendar as computed by
+ * <code>computeGregorianFields()</code>.
+ * @internal
+ */
+ int32_t getGregorianMonth() const {
+ return fGregorianMonth;
+ }
+
+ /**
+ * Return the day of year (1-based) on the Gregorian calendar as
+ * computed by <code>computeGregorianFields()</code>.
+ * @internal
+ */
+ int32_t getGregorianDayOfYear() const {
+ return fGregorianDayOfYear;
+ }
+
+ /**
+ * Return the day of month (1-based) on the Gregorian calendar as
+ * computed by <code>computeGregorianFields()</code>.
+ * @internal
+ */
+ int32_t getGregorianDayOfMonth() const {
+ return fGregorianDayOfMonth;
+ }
+
+ /**
+ * Called by computeJulianDay. Returns the default month (0-based) for the year,
+ * taking year and era into account. Defaults to 0 for Gregorian, which doesn't care.
+ * @internal
+ * @internal
+ */
+ virtual int32_t getDefaultMonthInYear() ;
+
+
+ /**
+ * Called by computeJulianDay. Returns the default day (1-based) for the month,
+ * taking currently-set year and era into account. Defaults to 1 for Gregorian.
+ * @internal
+ */
+ virtual int32_t getDefaultDayInMonth(int32_t /*month*/);
+
+ //-------------------------------------------------------------------------
+ // Protected utility methods for use by subclasses. These are very handy
+ // for implementing add, roll, and computeFields.
+ //-------------------------------------------------------------------------
+
+ /**
+ * Adjust the specified field so that it is within
+ * the allowable range for the date to which this calendar is set.
+ * For example, in a Gregorian calendar pinning the {@link #UCalendarDateFields DAY_OF_MONTH}
+ * field for a calendar set to April 31 would cause it to be set
+ * to April 30.
+ * <p>
+ * <b>Subclassing:</b>
+ * <br>
+ * This utility method is intended for use by subclasses that need to implement
+ * their own overrides of {@link #roll roll} and {@link #add add}.
+ * <p>
+ * <b>Note:</b>
+ * <code>pinField</code> is implemented in terms of
+ * {@link #getActualMinimum getActualMinimum}
+ * and {@link #getActualMaximum getActualMaximum}. If either of those methods uses
+ * a slow, iterative algorithm for a particular field, it would be
+ * unwise to attempt to call <code>pinField</code> for that field. If you
+ * really do need to do so, you should override this method to do
+ * something more efficient for that field.
+ * <p>
+ * @param field The calendar field whose value should be pinned.
+ * @param status Output param set to failure code on function return
+ * when this function fails.
+ *
+ * @see #getActualMinimum
+ * @see #getActualMaximum
+ * @stable ICU 2.0
+ */
+ virtual void pinField(UCalendarDateFields field, UErrorCode& status);
+
+ /**
+ * Return the week number of a day, within a period. This may be the week number in
+ * a year or the week number in a month. Usually this will be a value >= 1, but if
+ * some initial days of the period are excluded from week 1, because
+ * {@link #getMinimalDaysInFirstWeek getMinimalDaysInFirstWeek} is > 1, then
+ * the week number will be zero for those
+ * initial days. This method requires the day number and day of week for some
+ * known date in the period in order to determine the day of week
+ * on the desired day.
+ * <p>
+ * <b>Subclassing:</b>
+ * <br>
+ * This method is intended for use by subclasses in implementing their
+ * {@link #computeTime computeTime} and/or {@link #computeFields computeFields} methods.
+ * It is often useful in {@link #getActualMinimum getActualMinimum} and
+ * {@link #getActualMaximum getActualMaximum} as well.
+ * <p>
+ * This variant is handy for computing the week number of some other
+ * day of a period (often the first or last day of the period) when its day
+ * of the week is not known but the day number and day of week for some other
+ * day in the period (e.g. the current date) <em>is</em> known.
+ * <p>
+ * @param desiredDay The {@link #UCalendarDateFields DAY_OF_YEAR} or
+ * {@link #UCalendarDateFields DAY_OF_MONTH} whose week number is desired.
+ * Should be 1 for the first day of the period.
+ *
+ * @param dayOfPeriod The {@link #UCalendarDateFields DAY_OF_YEAR}
+ * or {@link #UCalendarDateFields DAY_OF_MONTH} for a day in the period whose
+ * {@link #UCalendarDateFields DAY_OF_WEEK} is specified by the
+ * <code>knownDayOfWeek</code> parameter.
+ * Should be 1 for first day of period.
+ *
+ * @param dayOfWeek The {@link #UCalendarDateFields DAY_OF_WEEK} for the day
+ * corresponding to the <code>knownDayOfPeriod</code> parameter.
+ * 1-based with 1=Sunday.
+ *
+ * @return The week number (one-based), or zero if the day falls before
+ * the first week because
+ * {@link #getMinimalDaysInFirstWeek getMinimalDaysInFirstWeek}
+ * is more than one.
+ *
+ * @stable ICU 2.8
+ */
+ int32_t weekNumber(int32_t desiredDay, int32_t dayOfPeriod, int32_t dayOfWeek);
+
+
+ /**
+ * Return the week number of a day, within a period. This may be the week number in
+ * a year, or the week number in a month. Usually this will be a value >= 1, but if
+ * some initial days of the period are excluded from week 1, because
+ * {@link #getMinimalDaysInFirstWeek getMinimalDaysInFirstWeek} is > 1,
+ * then the week number will be zero for those
+ * initial days. This method requires the day of week for the given date in order to
+ * determine the result.
+ * <p>
+ * <b>Subclassing:</b>
+ * <br>
+ * This method is intended for use by subclasses in implementing their
+ * {@link #computeTime computeTime} and/or {@link #computeFields computeFields} methods.
+ * It is often useful in {@link #getActualMinimum getActualMinimum} and
+ * {@link #getActualMaximum getActualMaximum} as well.
+ * <p>
+ * @param dayOfPeriod The {@link #UCalendarDateFields DAY_OF_YEAR} or
+ * {@link #UCalendarDateFields DAY_OF_MONTH} whose week number is desired.
+ * Should be 1 for the first day of the period.
+ *
+ * @param dayOfWeek The {@link #UCalendarDateFields DAY_OF_WEEK} for the day
+ * corresponding to the <code>dayOfPeriod</code> parameter.
+ * 1-based with 1=Sunday.
+ *
+ * @return The week number (one-based), or zero if the day falls before
+ * the first week because
+ * {@link #getMinimalDaysInFirstWeek getMinimalDaysInFirstWeek}
+ * is more than one.
+ * @internal
+ */
+ inline int32_t weekNumber(int32_t dayOfPeriod, int32_t dayOfWeek);
+
+ /**
+ * returns the local DOW, valid range 0..6
+ * @internal
+ */
+ int32_t getLocalDOW();
+
+private:
+
+ /**
+ * The next available value for fStamp[]
+ */
+ int32_t fNextStamp;// = MINIMUM_USER_STAMP;
+
+ /**
+ * The current time set for the calendar.
+ */
+ UDate fTime;
+
+ /**
+ * @see #setLenient
+ */
+ UBool fLenient;
+
+ /**
+ * Time zone affects the time calculation done by Calendar. Calendar subclasses use
+ * the time zone data to produce the local time.
+ */
+ TimeZone* fZone;
+
+ /**
+ * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent. They are
+ * used to figure out the week count for a specific date for a given locale. These
+ * must be set when a Calendar is constructed. For example, in US locale,
+ * firstDayOfWeek is SUNDAY; minimalDaysInFirstWeek is 1. They are used to figure
+ * out the week count for a specific date for a given locale. These must be set when
+ * a Calendar is constructed.
+ */
+ UCalendarDaysOfWeek fFirstDayOfWeek;
+ uint8_t fMinimalDaysInFirstWeek;
+
+ /**
+ * Sets firstDayOfWeek and minimalDaysInFirstWeek. Called at Calendar construction
+ * time.
+ *
+ * @param desiredLocale The given locale.
+ * @param type The calendar type identifier, e.g: gregorian, buddhist, etc.
+ * @param success Indicates the status of setting the week count data from
+ * the resource for the given locale. Returns U_ZERO_ERROR if
+ * constructed successfully.
+ */
+ void setWeekCountData(const Locale& desiredLocale, const char *type, UErrorCode& success);
+
+ /**
+ * Recompute the time and update the status fields isTimeSet
+ * and areFieldsSet. Callers should check isTimeSet and only
+ * call this method if isTimeSet is false.
+ *
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid or restricted by
+ * leniency, this will be set to an error status.
+ */
+ void updateTime(UErrorCode& status);
+
+ /**
+ * The Gregorian year, as computed by computeGregorianFields() and
+ * returned by getGregorianYear().
+ * @see #computeGregorianFields
+ */
+ int32_t fGregorianYear;
+
+ /**
+ * The Gregorian month, as computed by computeGregorianFields() and
+ * returned by getGregorianMonth().
+ * @see #computeGregorianFields
+ */
+ int32_t fGregorianMonth;
+
+ /**
+ * The Gregorian day of the year, as computed by
+ * computeGregorianFields() and returned by getGregorianDayOfYear().
+ * @see #computeGregorianFields
+ */
+ int32_t fGregorianDayOfYear;
+
+ /**
+ * The Gregorian day of the month, as computed by
+ * computeGregorianFields() and returned by getGregorianDayOfMonth().
+ * @see #computeGregorianFields
+ */
+ int32_t fGregorianDayOfMonth;
+
+ /* calculations */
+
+ /**
+ * Compute the Gregorian calendar year, month, and day of month from
+ * the given Julian day. These values are not stored in fields, but in
+ * member variables gregorianXxx. Also compute the DAY_OF_WEEK and
+ * DOW_LOCAL fields.
+ */
+ void computeGregorianAndDOWFields(int32_t julianDay, UErrorCode &ec);
+
+ /**
+ * Compute the Gregorian calendar year, month, and day of month from the
+ * Julian day. These values are not stored in fields, but in member
+ * variables gregorianXxx. They are used for time zone computations and by
+ * subclasses that are Gregorian derivatives. Subclasses may call this
+ * method to perform a Gregorian calendar millis->fields computation.
+ * To perform a Gregorian calendar fields->millis computation, call
+ * computeGregorianMonthStart().
+ * @see #computeGregorianMonthStart
+ */
+ void computeGregorianFields(int32_t julianDay, UErrorCode &ec);
+
+ /**
+ * Compute the fields WEEK_OF_YEAR, YEAR_WOY, WEEK_OF_MONTH,
+ * DAY_OF_WEEK_IN_MONTH, and DOW_LOCAL from EXTENDED_YEAR, YEAR,
+ * DAY_OF_WEEK, and DAY_OF_YEAR. The latter fields are computed by the
+ * subclass based on the calendar system.
+ *
+ * <p>The YEAR_WOY field is computed simplistically. It is equal to YEAR
+ * most of the time, but at the year boundary it may be adjusted to YEAR-1
+ * or YEAR+1 to reflect the overlap of a week into an adjacent year. In
+ * this case, a simple increment or decrement is performed on YEAR, even
+ * though this may yield an invalid YEAR value. For instance, if the YEAR
+ * is part of a calendar system with an N-year cycle field CYCLE, then
+ * incrementing the YEAR may involve incrementing CYCLE and setting YEAR
+ * back to 0 or 1. This is not handled by this code, and in fact cannot be
+ * simply handled without having subclasses define an entire parallel set of
+ * fields for fields larger than or equal to a year. This additional
+ * complexity is not warranted, since the intention of the YEAR_WOY field is
+ * to support ISO 8601 notation, so it will typically be used with a
+ * proleptic Gregorian calendar, which has no field larger than a year.
+ */
+ void computeWeekFields(UErrorCode &ec);
+
+
+ /**
+ * Ensure that each field is within its valid range by calling {@link
+ * #validateField(int, int&)} on each field that has been set. This method
+ * should only be called if this calendar is not lenient.
+ * @see #isLenient
+ * @see #validateField(int, int&)
+ * @internal
+ */
+ void validateFields(UErrorCode &status);
+
+ /**
+ * Validate a single field of this calendar. Subclasses should
+ * override this method to validate any calendar-specific fields.
+ * Generic fields can be handled by
+ * <code>Calendar.validateField()</code>.
+ * @see #validateField(int, int, int, int&)
+ * @internal
+ */
+ virtual void validateField(UCalendarDateFields field, UErrorCode &status);
+
+ /**
+ * Validate a single field of this calendar given its minimum and
+ * maximum allowed value. If the field is out of range,
+ * <code>U_ILLEGAL_ARGUMENT_ERROR</code> will be set. Subclasses may
+ * use this method in their implementation of {@link
+ * #validateField(int, int&)}.
+ * @internal
+ */
+ void validateField(UCalendarDateFields field, int32_t min, int32_t max, UErrorCode& status);
+
+ protected:
+ /**
+ * Convert a quasi Julian date to the day of the week. The Julian date used here is
+ * not a true Julian date, since it is measured from midnight, not noon. Return
+ * value is one-based.
+ *
+ * @param julian The given Julian date number.
+ * @return Day number from 1..7 (SUN..SAT).
+ * @internal
+ */
+ static uint8_t julianDayToDayOfWeek(double julian);
+
+ private:
+ char validLocale[ULOC_FULLNAME_CAPACITY];
+ char actualLocale[ULOC_FULLNAME_CAPACITY];
+
+ public:
+#if !UCONFIG_NO_SERVICE
+ /**
+ * INTERNAL FOR 2.6 -- Registration.
+ */
+
+ /**
+ * Return a StringEnumeration over the locales available at the time of the call,
+ * including registered locales.
+ * @return a StringEnumeration over the locales available at the time of the call
+ * @internal
+ */
+ static StringEnumeration* getAvailableLocales(void);
+
+ /**
+ * Register a new Calendar factory. The factory will be adopted.
+ * INTERNAL in 2.6
+ * @param toAdopt the factory instance to be adopted
+ * @param status the in/out status code, no special meanings are assigned
+ * @return a registry key that can be used to unregister this factory
+ * @internal
+ */
+ static URegistryKey registerFactory(ICUServiceFactory* toAdopt, UErrorCode& status);
+
+ /**
+ * Unregister a previously-registered CalendarFactory using the key returned from the
+ * register call. Key becomes invalid after a successful call and should not be used again.
+ * The CalendarFactory corresponding to the key will be deleted.
+ * INTERNAL in 2.6
+ * @param key the registry key returned by a previous call to registerFactory
+ * @param status the in/out status code, no special meanings are assigned
+ * @return TRUE if the factory for the key was successfully unregistered
+ * @internal
+ */
+ static UBool unregister(URegistryKey key, UErrorCode& status);
+
+ /**
+ * Multiple Calendar Implementation
+ * @internal
+ */
+ friend class CalendarFactory;
+
+ /**
+ * Multiple Calendar Implementation
+ * @internal
+ */
+ friend class CalendarService;
+
+ /**
+ * Multiple Calendar Implementation
+ * @internal
+ */
+ friend class DefaultCalendarFactory;
+#endif /* !UCONFIG_NO_SERVICE */
+
+ /**
+ * @internal
+ * @return TRUE if this calendar has a default century (i.e. 03 -> 2003)
+ */
+ virtual UBool haveDefaultCentury() const = 0;
+
+ /**
+ * @internal
+ * @return the start of the default century, as a UDate
+ */
+ virtual UDate defaultCenturyStart() const = 0;
+ /**
+ * @internal
+ * @return the beginning year of the default century, as a year
+ */
+ virtual int32_t defaultCenturyStartYear() const = 0;
+
+ /** Get the locale for this calendar object. You can choose between valid and actual locale.
+ * @param type type of the locale we're looking for (valid or actual)
+ * @param status error code for the operation
+ * @return the locale
+ * @stable ICU 2.8
+ */
+ Locale getLocale(ULocDataLocaleType type, UErrorCode &status) const;
+
+ /** Get the locale for this calendar object. You can choose between valid and actual locale.
+ * @param type type of the locale we're looking for (valid or actual)
+ * @param status error code for the operation
+ * @return the locale
+ * @internal
+ */
+ const char* getLocaleID(ULocDataLocaleType type, UErrorCode &status) const;
+
+};
+
+// -------------------------------------
+
+inline Calendar*
+Calendar::createInstance(TimeZone* zone, UErrorCode& errorCode)
+{
+ // since the Locale isn't specified, use the default locale
+ return createInstance(zone, Locale::getDefault(), errorCode);
+}
+
+// -------------------------------------
+
+inline void
+Calendar::roll(UCalendarDateFields field, UBool up, UErrorCode& status)
+{
+ roll(field, (int32_t)(up ? +1 : -1), status);
+}
+
+inline void
+Calendar::roll(EDateFields field, UBool up, UErrorCode& status)
+{
+ roll((UCalendarDateFields) field, up, status);
+}
+
+
+// -------------------------------------
+
+/**
+ * Fast method for subclasses. The caller must maintain fUserSetDSTOffset and
+ * fUserSetZoneOffset, as well as the isSet[] array.
+ */
+
+inline void
+Calendar::internalSet(UCalendarDateFields field, int32_t value)
+{
+ fFields[field] = value;
+ fStamp[field] = kInternallySet;
+ fIsSet[field] = TRUE; // Remove later
+}
+
+inline int32_t Calendar::weekNumber(int32_t dayOfPeriod, int32_t dayOfWeek)
+{
+ return weekNumber(dayOfPeriod, dayOfPeriod, dayOfWeek);
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _CALENDAR
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/choicfmt.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/choicfmt.h
new file mode 100644
index 00000000000..409966a4c8f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/choicfmt.h
@@ -0,0 +1,780 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File CHOICFMT.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/20/97 helena Finished first cut of implementation and got rid
+* of nextDouble/previousDouble and replaced with
+* boolean array.
+* 4/10/97 aliu Clean up. Modified to work on AIX.
+* 8/6/97 nos Removed overloaded constructor, member var 'buffer'.
+* 07/22/98 stephen Removed operator!= (implemented in Format)
+********************************************************************************
+*/
+
+#ifndef CHOICFMT_H
+#define CHOICFMT_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Choice Format.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/numfmt.h"
+#include "unicode/fieldpos.h"
+#include "unicode/format.h"
+
+U_NAMESPACE_BEGIN
+
+class MessageFormat;
+
+/**
+ * ChoiceFormat converts between ranges of numeric values
+ * and string names for those ranges. A <code>ChoiceFormat</code> splits
+ * the real number line <code>-Inf</code> to <code>+Inf</code> into two
+ * or more contiguous ranges. Each range is mapped to a
+ * string. <code>ChoiceFormat</code> is generally used in a
+ * <code>MessageFormat</code> for displaying grammatically correct
+ * plurals such as &quot;There are 2 files.&quot;</p>
+ *
+ * <p>There are two methods of defining a <code>ChoiceFormat</code>; both
+ * are equivalent. The first is by using a string pattern. This is the
+ * preferred method in most cases. The second method is through direct
+ * specification of the arrays that make up the
+ * <code>ChoiceFormat</code>.</p>
+ *
+ * <p><strong>Patterns</strong></p>
+ *
+ * <p>In most cases, the preferred way to define a
+ * <code>ChoiceFormat</code> is with a pattern. Here is an example of a
+ * <code>ChoiceFormat</code> pattern:</p>
+ *
+ * \htmlonly<pre> 0&#x2264;are no files|1&#x2264;is one file|1&lt;are many files</pre>\endhtmlonly
+ *
+ * <p>or equivalently,</p>
+ *
+ * \htmlonly<pre> 0#are no files|1#is one file|1&lt;are many files</pre>\endhtmlonly
+ *
+ * <p>The pattern consists of a number or <em>range specifiers</em>
+ * separated by vertical bars '|' (U+007C). There is no
+ * vertical bar after the last range. Each range specifier is of the
+ * form:</p>
+ *
+ * \htmlonly<blockquote><em>Number Separator String</em></blockquote>\endhtmlonly
+ *
+ * <p><em>Number</em> is a floating point number that can be parsed by a
+ * default <code>NumberFormat</code> for the US locale. It gives the
+ * lower limit of this range. The lower limit is either inclusive or
+ * exclusive, depending on the <em>separator</em>. The upper limit is
+ * given by the lower limit of the next range. The Unicode infinity
+ * sign \htmlonly&#x221E \endhtmlonly (U+221E) is recognized for positive infinity. It may be preceded by
+ * '-' (U+002D) to indicate negative infinity.</p>
+ *
+ * <p><em>String</em> is the format string for this range, with special
+ * characters enclosed in single quotes (<code>'The #
+ * sign'</code>). Single quotes themselves are indicated by two single
+ * quotes in a row (<code>'o''clock'</code>).</p>
+ *
+ * <p><em>Separator</em> is one of the following single characters:
+ *
+ * <ul>
+ * <li>\htmlonly'&#x2264;' \endhtmlonly (U+2264) or '#' (U+0023)
+ * indicates that the lower limit given by <em>Number</em> is
+ * inclusive. (The two characters are equivalent to ChoiceFormat.)
+ * This means that the limit value <em>Number</em> belongs to this
+ * range. Another way of saying this is that the corresponding
+ * closure is <code>FALSE</code>.</li>
+ *
+ * <li>'<' (U+003C) indicates that the lower limit given by
+ * <em>Number</em> is exclusive. This means that the value
+ * <em>Number</em> belongs to the prior range.</li> Another way of
+ * saying this is that the corresponding closure is
+ * <code>TRUE</code>.
+ * </ul>
+ *
+ * <p>See below for more information about closures.</p>
+ *
+ * <p><strong>Arrays</strong></p>
+ *
+ * <p>A <code>ChoiceFormat</code> defining <code>n</code> intervals
+ * (<code>n</code> &gt;= 2) is specified by three arrays of
+ * <code>n</code> items:
+ *
+ * <ul>
+ * <li><code>double limits[]</code> gives the start of each
+ * interval. This must be a non-decreasing list of values, none of
+ * which may be <code>NaN</code>.</li>
+ * <li><code>UBool closures[]</code> determines whether each limit
+ * value is contained in the interval below it or in the interval
+ * above it. If <code>closures[i]</code> is <code>FALSE</code>, then
+ * <code>limits[i]</code> is a member of interval
+ * <code>i</code>. Otherwise it is a member of interval
+ * <code>i+1</code>. If no closures array is specified, this is
+ * equivalent to having all closures be <code>FALSE</code>. Closures
+ * allow one to specify half-open, open, or closed intervals.</li>
+ * <li><code>UnicodeString formats[]</code> gives the string label
+ * associated with each interval.</li>
+ * </ul>
+ *
+ * <p><strong>Formatting and Parsing</strong></p>
+ *
+ * <p>During formatting, a number is converted to a
+ * string. <code>ChoiceFormat</code> accomplishes this by mapping the
+ * number to an interval using the following rule. Given a number
+ * <code>X</code> and and index value <code>j</code> in the range
+ * <code>0..n-1</code>, where <code>n</code> is the number of ranges:</p>
+ *
+ * \htmlonly<blockquote>\endhtmlonly<code>X</code> matches <code>j</code> if and only if
+ * <code>limit[j] &lt;= X &lt; limit[j+1]</code>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * <p>(This assumes that all closures are <code>FALSE</code>. If some
+ * closures are <code>TRUE</code> then the relations must be changed to
+ * <code>&lt;=</code> or <code>&lt;</code> as appropriate.) If there is
+ * no match, then either the first or last index is used, depending on
+ * whether the number is too low or too high. Once a number is mapped to
+ * an interval <code>j</code>, the string <code>formats[j]</code> is
+ * output.</p>
+ *
+ * <p>During parsing, a string is converted to a
+ * number. <code>ChoiceFormat</code> finds the element
+ * <code>formats[j]</code> equal to the string, and returns
+ * <code>limits[j]</code> as the parsed value.</p>
+ *
+ * <p><strong>Notes</strong></p>
+ *
+ * <p>The first limit value does not define a range boundary. For
+ * example, in the pattern \htmlonly&quot;<code>1.0#a|2.0#b</code>&quot;\endhtmlonly, the
+ * intervals are [-Inf, 2.0) and [2.0, +Inf]. It appears that the first
+ * interval should be [1.0, 2.0). However, since all values that are too
+ * small are mapped to range zero, the first interval is effectively
+ * [-Inf, 2.0). However, the first limit value <em>is</em> used during
+ * formatting. In this example, <code>parse(&quot;a&quot;)</code> returns
+ * 1.0.</p>
+ *
+ * <p>There are no gaps between intervals and the entire number line is
+ * covered. A <code>ChoiceFormat</code> maps <em>all</em> possible
+ * double values to a finite set of intervals.</p>
+ *
+ * <p>The non-number <code>NaN</code> is mapped to interval zero during
+ * formatting.</p>
+ *
+ * <p><strong>Examples</strong></p>
+ *
+ * <p>Here is an example of two arrays that map the number
+ * <code>1..7</code> to the English day of the week abbreviations
+ * <code>Sun..Sat</code>. No closures array is given; this is the same as
+ * specifying all closures to be <code>FALSE</code>.</p>
+ *
+ * <pre> {1,2,3,4,5,6,7},
+ * {&quot;Sun&quot;,&quot;Mon&quot;,&quot;Tue&quot;,&quot;Wed&quot;,&quot;Thur&quot;,&quot;Fri&quot;,&quot;Sat&quot;}</pre>
+ *
+ * <p>Here is an example that maps the ranges [-Inf, 1), [1, 1], and (1,
+ * +Inf] to three strings. That is, the number line is split into three
+ * ranges: x &lt; 1.0, x = 1.0, and x &gt; 1.0.</p>
+ *
+ * <pre> {0, 1, 1},
+ * {FALSE, FALSE, TRUE},
+ * {&quot;no files&quot;, &quot;one file&quot;, &quot;many files&quot;}</pre>
+ *
+ * <p>Here is a simple example that shows formatting and parsing: </p>
+ *
+ * \code
+ * #include <unicode/choicfmt.h>
+ * #include <unicode/unistr.h>
+ * #include <iostream.h>
+ *
+ * int main(int argc, char *argv[]) {
+ * double limits[] = {1,2,3,4,5,6,7};
+ * UnicodeString monthNames[] = {
+ * "Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
+ * ChoiceFormat fmt(limits, monthNames, 7);
+ * UnicodeString str;
+ * char buf[256];
+ * for (double x = 1.0; x <= 8.0; x += 1.0) {
+ * fmt.format(x, str);
+ * str.extract(0, str.length(), buf, 256, "");
+ * str.truncate(0);
+ * cout << x << " -> "
+ * << buf << endl;
+ * }
+ * cout << endl;
+ * return 0;
+ * }
+ * \endcode
+ *
+ * <p>Here is a more complex example using a <code>ChoiceFormat</code>
+ * constructed from a pattern together with a
+ * <code>MessageFormat</code>.</p>
+ *
+ * \code
+ * #include <unicode/choicfmt.h>
+ * #include <unicode/msgfmt.h>
+ * #include <unicode/unistr.h>
+ * #include <iostream.h>
+ *
+ * int main(int argc, char *argv[]) {
+ * UErrorCode status = U_ZERO_ERROR;
+ * double filelimits[] = {0,1,2};
+ * UnicodeString filepart[] =
+ * {"are no files","is one file","are {0} files"};
+ * ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3 );
+ * Format* testFormats[] =
+ * {fileform, NULL, NumberFormat::createInstance(status)};
+ * MessageFormat pattform("There {0} on {1}", status );
+ * pattform.adoptFormats(testFormats, 3);
+ * Formattable testArgs[] = {0L, "Disk A"};
+ * FieldPosition fp(0);
+ * UnicodeString str;
+ * char buf[256];
+ * for (int32_t i = 0; i < 4; ++i) {
+ * Formattable fInt(i);
+ * testArgs[0] = fInt;
+ * pattform.format(testArgs, 2, str, fp, status );
+ * str.extract(0, str.length(), buf, "");
+ * str.truncate(0);
+ * cout << "Output for i=" << i << " : " << buf << endl;
+ * }
+ * cout << endl;
+ * return 0;
+ * }
+ * \endcode
+ *
+ * <p><em>User subclasses are not supported.</em> While clients may write
+ * subclasses, such code will not necessarily work and will not be
+ * guaranteed to work stably from release to release.
+ */
+class U_I18N_API ChoiceFormat: public NumberFormat {
+public:
+ /**
+ * Construct a new ChoiceFormat with the limits and the corresponding formats
+ * based on the pattern.
+ *
+ * @param pattern Pattern used to construct object.
+ * @param status Output param to receive success code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ ChoiceFormat(const UnicodeString& pattern,
+ UErrorCode& status);
+
+
+ /**
+ * Construct a new ChoiceFormat with the given limits and formats. Copy
+ * the limits and formats instead of adopting them.
+ *
+ * @param limits Array of limit values.
+ * @param formats Array of formats.
+ * @param count Size of 'limits' and 'formats' arrays.
+ * @stable ICU 2.0
+ */
+
+ ChoiceFormat(const double* limits,
+ const UnicodeString* formats,
+ int32_t count );
+
+ /**
+ * Construct a new ChoiceFormat with the given limits and formats.
+ * Copy the limits and formats (instead of adopting them). By
+ * default, each limit in the array specifies the inclusive lower
+ * bound of its range, and the exclusive upper bound of the previous
+ * range. However, if the isLimitOpen element corresponding to a
+ * limit is TRUE, then the limit is the exclusive lower bound of its
+ * range, and the inclusive upper bound of the previous range.
+ * @param limits Array of limit values
+ * @param closures Array of booleans specifying whether each
+ * element of 'limits' is open or closed. If FALSE, then the
+ * corresponding limit is a member of the range above it. If TRUE,
+ * then the limit belongs to the range below it.
+ * @param formats Array of formats
+ * @param count Size of 'limits', 'closures', and 'formats' arrays
+ * @stable ICU 2.4
+ */
+ ChoiceFormat(const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t count);
+
+ /**
+ * Copy constructor.
+ *
+ * @param that ChoiceFormat object to be copied from
+ * @stable ICU 2.0
+ */
+ ChoiceFormat(const ChoiceFormat& that);
+
+ /**
+ * Assignment operator.
+ *
+ * @param that ChoiceFormat object to be copied
+ * @stable ICU 2.0
+ */
+ const ChoiceFormat& operator=(const ChoiceFormat& that);
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~ChoiceFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the
+ * result and should delete it when done.
+ *
+ * @return a copy of this object
+ * @stable ICU 2.0
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Return true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ *
+ * @param other ChoiceFormat object to be compared
+ * @return true if other is the same as this.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Sets the pattern.
+ * @param pattern The pattern to be applied.
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Sets the pattern.
+ * @param pattern The pattern to be applied.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Gets the pattern.
+ *
+ * @param pattern Output param which will recieve the pattern
+ * Previous contents are deleted.
+ * @return A reference to 'pattern'
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toPattern(UnicodeString &pattern) const;
+
+#ifdef U_USE_CHOICE_FORMAT_DEPRECATES
+ /**
+ * Set the choices to be used in formatting. The arrays are adopted and
+ * should not be deleted by the caller.
+ *
+ * @param limitsToAdopt Contains the top value that you want
+ * parsed with that format,and should be in
+ * ascending sorted order. When formatting X,
+ * the choice will be the i, where limit[i]
+ * &lt;= X &lt; limit[i+1].
+ * @param formatsToAdopt The format strings you want to use for each limit.
+ * @param count The size of the above arrays.
+ * @obsolete ICU 2.6. Use setChoices instead since this API will be removed in that release.
+ */
+ virtual void adoptChoices(double* limitsToAdopt,
+ UnicodeString* formatsToAdopt,
+ int32_t count );
+
+ /**
+ * Set the choices to be used in formatting. The arrays are adopted
+ * and should not be deleted by the caller. See class description
+ * for documenatation of the limits, closures, and formats arrays.
+ * @param limitsToAdopt Array of limits to adopt
+ * @param closuresToAdopt Array of limit booleans to adopt
+ * @param formatsToAdopt Array of format string to adopt
+ * @param count The size of the above arrays
+ * @obsolete ICU 2.6. Use setChoices instead since this API will be removed in that release.
+ */
+ virtual void adoptChoices(double* limitsToAdopt,
+ UBool* closuresToAdopt,
+ UnicodeString* formatsToAdopt,
+ int32_t count);
+#endif
+
+ /**
+ * Set the choices to be used in formatting.
+ *
+ * @param limitsToCopy Contains the top value that you want
+ * parsed with that format,and should be in
+ * ascending sorted order. When formatting X,
+ * the choice will be the i, where limit[i]
+ * &lt;= X &lt; limit[i+1].
+ * @param formatsToCopy The format strings you want to use for each limit.
+ * @param count The size of the above arrays.
+ * @stable ICU 2.0
+ */
+ virtual void setChoices(const double* limitsToCopy,
+ const UnicodeString* formatsToCopy,
+ int32_t count );
+
+ /**
+ * Set the choices to be used in formatting. See class description
+ * for documenatation of the limits, closures, and formats arrays.
+ * @param limits Array of limits
+ * @param closures Array of limit booleans
+ * @param formats Array of format string
+ * @param count The size of the above arrays
+ * @stable ICU 2.4
+ */
+ virtual void setChoices(const double* limits,
+ const UBool* closures,
+ const UnicodeString* formats,
+ int32_t count);
+
+ /**
+ * Get the limits passed in the constructor.
+ *
+ * @param count The size of the limits arrays
+ * @return the limits.
+ * @stable ICU 2.0
+ */
+ virtual const double* getLimits(int32_t& count) const;
+
+ /**
+ * Get the limit booleans passed in the constructor. The caller
+ * must not delete the result.
+ *
+ * @param count The size of the arrays
+ * @return the closures
+ * @stable ICU 2.4
+ */
+ virtual const UBool* getClosures(int32_t& count) const;
+
+ /**
+ * Get the formats passed in the constructor.
+ *
+ * @param count The size of the arrays
+ * @return the formats.
+ * @stable ICU 2.0
+ */
+ virtual const UnicodeString* getFormats(int32_t& count) const;
+
+ /**
+ * Format a double or long number using this object's choices.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+ /**
+ * Format a int_32t number using this object's choices.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format an int64_t number using this object's choices.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.8
+ */
+ virtual UnicodeString& format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format an array of objects using this object's choices.
+ *
+ * @param objs The array of objects to be formatted.
+ * @param cnt The size of objs.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param success Output param set to success/failure code on
+ * exit.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable* objs,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& success) const;
+ /**
+ * Format an object using this object's choices.
+ *
+ *
+ * @param obj The object to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param set to success/failure code on
+ * exit.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ *
+ * @param obj The object to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Output param set to success/failure code on
+ * exit.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * Format a double number. These methods call the NumberFormat
+ * pure virtual format() methods with the default FieldPosition.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format( double number,
+ UnicodeString& appendTo) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * Format a long number. These methods call the NumberFormat
+ * pure virtual format() methods with the default FieldPosition.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format( int32_t number,
+ UnicodeString& appendTo) const;
+
+ /**
+ * Return a long if possible (e.g. within range LONG_MAX,
+ * LONG_MAX], and with no decimals), otherwise a double. If
+ * IntegerOnly is set, will stop at a decimal point (or equivalent;
+ * e.g. for rational numbers "1 2/3", will stop after the 1).
+ * <P>
+ * If no object can be parsed, parsePosition is unchanged, and NULL is
+ * returned.
+ *
+ * @param text The text to be parsed.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param parsePosition The position to start parsing at on input.
+ * On output, moved to after the last successfully
+ * parse character. On parse failure, does not change.
+ * @see NumberFormat::isParseIntegerOnly
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& parsePosition) const;
+
+ /**
+ * Return a long if possible (e.g. within range LONG_MAX,
+ * LONG_MAX], and with no decimals), otherwise a double. If
+ * IntegerOnly is set, will stop at a decimal point (or equivalent;
+ * e.g. for rational numbers "1 2/3", will stop after the 1).
+ * <P>
+ * If no object can be parsed, parsePosition is unchanged, and NULL is
+ * returned.
+ *
+ * @param text The text to be parsed.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param status Output param with the formatted string.
+ * @see NumberFormat::isParseIntegerOnly
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const;
+
+
+public:
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override.
+ * This method is to implement a simple version of RTTI, since not all
+ * C++ compilers support genuine RTTI. Polymorphic operator==() and
+ * clone() methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for
+ * comparing to a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . Derived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+private:
+ // static cache management (thread-safe)
+ // static NumberFormat* getNumberFormat(UErrorCode &status); // call this function to 'check out' a numberformat from the cache.
+ // static void releaseNumberFormat(NumberFormat *adopt); // call this function to 'return' the number format to the cache.
+
+ /**
+ * Converts a string to a double value using a default NumberFormat object
+ * which is static (shared by all ChoiceFormat instances).
+ * @param string the string to be converted with.
+ * @return the converted double number.
+ */
+ static double stod(const UnicodeString& string);
+
+ /**
+ * Converts a double value to a string using a default NumberFormat object
+ * which is static (shared by all ChoiceFormat instances).
+ * @param value the double number to be converted with.
+ * @param string the result string.
+ * @return the converted string.
+ */
+ static UnicodeString& dtos(double value, UnicodeString& string);
+
+ ChoiceFormat(); // default constructor not implemented
+
+ /**
+ * Construct a new ChoiceFormat with the limits and the corresponding formats
+ * based on the pattern.
+ *
+ * @param newPattern Pattern used to construct object.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered.
+ * @param status Output param to receive success code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ ChoiceFormat(const UnicodeString& newPattern,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ friend class MessageFormat;
+ /**
+ * Each ChoiceFormat divides the range -Inf..+Inf into fCount
+ * intervals. The intervals are:
+ *
+ * 0: fChoiceLimits[0]..fChoiceLimits[1]
+ * 1: fChoiceLimits[1]..fChoiceLimits[2]
+ * ...
+ * fCount-2: fChoiceLimits[fCount-2]..fChoiceLimits[fCount-1]
+ * fCount-1: fChoiceLimits[fCount-1]..+Inf
+ *
+ * Interval 0 is special; during formatting (mapping numbers to
+ * strings), it also contains all numbers less than
+ * fChoiceLimits[0], as well as NaN values.
+ *
+ * Interval i maps to and from string fChoiceFormats[i]. When
+ * parsing (mapping strings to numbers), then intervals map to
+ * their lower limit, that is, interval i maps to fChoiceLimit[i].
+ *
+ * The intervals may be closed, half open, or open. This affects
+ * formatting but does not affect parsing. Interval i is affected
+ * by fClosures[i] and fClosures[i+1]. If fClosures[i]
+ * is FALSE, then the value fChoiceLimits[i] is in interval i.
+ * That is, intervals i and i are:
+ *
+ * i-1: ... x < fChoiceLimits[i]
+ * i: fChoiceLimits[i] <= x ...
+ *
+ * If fClosures[i] is TRUE, then the value fChoiceLimits[i] is
+ * in interval i-1. That is, intervals i-1 and i are:
+ *
+ * i-1: ... x <= fChoiceLimits[i]
+ * i: fChoiceLimits[i] < x ...
+ *
+ * Because of the nature of interval 0, fClosures[0] has no
+ * effect.
+
+ */
+ double* fChoiceLimits;
+ UBool* fClosures;
+ UnicodeString* fChoiceFormats;
+ int32_t fCount;
+};
+
+inline UnicodeString&
+ChoiceFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ // Don't use Format:: - use immediate base class only,
+ // in case immediate base modifies behavior later.
+ return NumberFormat::format(obj, appendTo, status);
+}
+
+inline UnicodeString&
+ChoiceFormat::format(double number,
+ UnicodeString& appendTo) const {
+ return NumberFormat::format(number, appendTo);
+}
+
+inline UnicodeString&
+ChoiceFormat::format(int32_t number,
+ UnicodeString& appendTo) const {
+ return NumberFormat::format(number, appendTo);
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _CHOICFMT
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/coleitr.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/coleitr.h
new file mode 100644
index 00000000000..51b5d2887d9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/coleitr.h
@@ -0,0 +1,399 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 1997-2005, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ******************************************************************************
+ */
+
+/**
+* File coleitr.h
+*
+*
+*
+* Created by: Helena Shih
+*
+* Modification History:
+*
+* Date Name Description
+*
+* 8/18/97 helena Added internal API documentation.
+* 08/03/98 erm Synched with 1.2 version CollationElementIterator.java
+* 12/10/99 aliu Ported Thai collation support from Java.
+* 01/25/01 swquek Modified into a C++ wrapper calling C APIs (ucoliter.h)
+* 02/19/01 swquek Removed CollationElementsIterator() since it is
+* private constructor and no calls are made to it
+*/
+
+#ifndef COLEITR_H
+#define COLEITR_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Collation Element Iterator.
+ */
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uobject.h"
+#include "unicode/tblcoll.h"
+#include "unicode/ucoleitr.h"
+
+/**
+ * The UCollationElements struct.
+ * For usage in C programs.
+ * @stable ICU 2.0
+ */
+typedef struct UCollationElements UCollationElements;
+
+U_NAMESPACE_BEGIN
+
+/**
+* The CollationElementIterator class is used as an iterator to walk through
+* each character of an international string. Use the iterator to return the
+* ordering priority of the positioned character. The ordering priority of a
+* character, which we refer to as a key, defines how a character is collated in
+* the given collation object.
+* For example, consider the following in Spanish:
+* <pre>
+* "ca" -> the first key is key('c') and second key is key('a').
+* "cha" -> the first key is key('ch') and second key is key('a').</pre>
+* And in German,
+* <pre> \htmlonly "&#x00E6;b"-> the first key is key('a'), the second key is key('e'), and
+* the third key is key('b'). \endhtmlonly </pre>
+* The key of a character, is an integer composed of primary order(short),
+* secondary order(char), and tertiary order(char). Java strictly defines the
+* size and signedness of its primitive data types. Therefore, the static
+* functions primaryOrder(), secondaryOrder(), and tertiaryOrder() return
+* int32_t to ensure the correctness of the key value.
+* <p>Example of the iterator usage: (without error checking)
+* <pre>
+* \code
+* void CollationElementIterator_Example()
+* {
+* UnicodeString str = "This is a test";
+* UErrorCode success = U_ZERO_ERROR;
+* RuleBasedCollator* rbc =
+* (RuleBasedCollator*) RuleBasedCollator::createInstance(success);
+* CollationElementIterator* c =
+* rbc->createCollationElementIterator( str );
+* int32_t order = c->next(success);
+* c->reset();
+* order = c->previous(success);
+* delete c;
+* delete rbc;
+* }
+* \endcode
+* </pre>
+* <p>
+* CollationElementIterator::next returns the collation order of the next
+* character based on the comparison level of the collator.
+* CollationElementIterator::previous returns the collation order of the
+* previous character based on the comparison level of the collator.
+* The Collation Element Iterator moves only in one direction between calls to
+* CollationElementIterator::reset. That is, CollationElementIterator::next()
+* and CollationElementIterator::previous can not be inter-used. Whenever
+* CollationElementIterator::previous is to be called after
+* CollationElementIterator::next() or vice versa,
+* CollationElementIterator::reset has to be called first to reset the status,
+* shifting pointers to either the end or the start of the string. Hence at the
+* next call of CollationElementIterator::previous or
+* CollationElementIterator::next(), the first or last collation order will be
+* returned.
+* If a change of direction is done without a CollationElementIterator::reset(),
+* the result is undefined.
+* The result of a forward iterate (CollationElementIterator::next) and
+* reversed result of the backward iterate (CollationElementIterator::previous)
+* on the same string are equivalent, if collation orders with the value
+* UCOL_IGNORABLE are ignored.
+* Character based on the comparison level of the collator. A collation order
+* consists of primary order, secondary order and tertiary order. The data
+* type of the collation order is <strong>t_int32</strong>.
+*
+* Note, CollationElementIterator should not be subclassed.
+* @see Collator
+* @see RuleBasedCollator
+* @version 1.8 Jan 16 2001
+*/
+class U_I18N_API CollationElementIterator : public UObject {
+public:
+
+ // CollationElementIterator public data member ------------------------------
+
+ enum {
+ /**
+ * NULLORDER indicates that an error has occured while processing
+ * @stable ICU 2.0
+ */
+ NULLORDER = (int32_t)0xffffffff
+ };
+
+ // CollationElementIterator public constructor/destructor -------------------
+
+ /**
+ * Copy constructor.
+ *
+ * @param other the object to be copied from
+ * @stable ICU 2.0
+ */
+ CollationElementIterator(const CollationElementIterator& other);
+
+ /**
+ * Destructor
+ * @stable ICU 2.0
+ */
+ virtual ~CollationElementIterator();
+
+ // CollationElementIterator public methods ----------------------------------
+
+ /**
+ * Returns true if "other" is the same as "this"
+ *
+ * @param other the object to be compared
+ * @return true if "other" is the same as "this"
+ * @stable ICU 2.0
+ */
+ UBool operator==(const CollationElementIterator& other) const;
+
+ /**
+ * Returns true if "other" is not the same as "this".
+ *
+ * @param other the object to be compared
+ * @return true if "other" is not the same as "this"
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const CollationElementIterator& other) const;
+
+ /**
+ * Resets the cursor to the beginning of the string.
+ * @stable ICU 2.0
+ */
+ void reset(void);
+
+ /**
+ * Gets the ordering priority of the next character in the string.
+ * @param status the error code status.
+ * @return the next character's ordering. otherwise returns NULLORDER if an
+ * error has occured or if the end of string has been reached
+ * @stable ICU 2.0
+ */
+ int32_t next(UErrorCode& status);
+
+ /**
+ * Get the ordering priority of the previous collation element in the string.
+ * @param status the error code status.
+ * @return the previous element's ordering. otherwise returns NULLORDER if an
+ * error has occured or if the start of string has been reached
+ * @stable ICU 2.0
+ */
+ int32_t previous(UErrorCode& status);
+
+ /**
+ * Gets the primary order of a collation order.
+ * @param order the collation order
+ * @return the primary order of a collation order.
+ * @stable ICU 2.0
+ */
+ static inline int32_t primaryOrder(int32_t order);
+
+ /**
+ * Gets the secondary order of a collation order.
+ * @param order the collation order
+ * @return the secondary order of a collation order.
+ * @stable ICU 2.0
+ */
+ static inline int32_t secondaryOrder(int32_t order);
+
+ /**
+ * Gets the tertiary order of a collation order.
+ * @param order the collation order
+ * @return the tertiary order of a collation order.
+ * @stable ICU 2.0
+ */
+ static inline int32_t tertiaryOrder(int32_t order);
+
+ /**
+ * Return the maximum length of any expansion sequences that end with the
+ * specified comparison order.
+ * @param order a collation order returned by previous or next.
+ * @return maximum size of the expansion sequences ending with the collation
+ * element or 1 if collation element does not occur at the end of any
+ * expansion sequence
+ * @stable ICU 2.0
+ */
+ int32_t getMaxExpansion(int32_t order) const;
+
+ /**
+ * Gets the comparison order in the desired strength. Ignore the other
+ * differences.
+ * @param order The order value
+ * @stable ICU 2.0
+ */
+ int32_t strengthOrder(int32_t order) const;
+
+ /**
+ * Sets the source string.
+ * @param str the source string.
+ * @param status the error code status.
+ * @stable ICU 2.0
+ */
+ void setText(const UnicodeString& str, UErrorCode& status);
+
+ /**
+ * Sets the source string.
+ * @param str the source character iterator.
+ * @param status the error code status.
+ * @stable ICU 2.0
+ */
+ void setText(CharacterIterator& str, UErrorCode& status);
+
+ /**
+ * Checks if a comparison order is ignorable.
+ * @param order the collation order.
+ * @return TRUE if a character is ignorable, FALSE otherwise.
+ * @stable ICU 2.0
+ */
+ static inline UBool isIgnorable(int32_t order);
+
+ /**
+ * Gets the offset of the currently processed character in the source string.
+ * @return the offset of the character.
+ * @stable ICU 2.0
+ */
+ int32_t getOffset(void) const;
+
+ /**
+ * Sets the offset of the currently processed character in the source string.
+ * @param newOffset the new offset.
+ * @param status the error code status.
+ * @return the offset of the character.
+ * @stable ICU 2.0
+ */
+ void setOffset(int32_t newOffset, UErrorCode& status);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+protected:
+
+ // CollationElementIterator protected constructors --------------------------
+ /**
+ * @stable ICU 2.0
+ */
+ friend class RuleBasedCollator;
+
+ /**
+ * CollationElementIterator constructor. This takes the source string and the
+ * collation object. The cursor will walk thru the source string based on the
+ * predefined collation rules. If the source string is empty, NULLORDER will
+ * be returned on the calls to next().
+ * @param sourceText the source string.
+ * @param order the collation object.
+ * @param status the error code status.
+ * @stable ICU 2.0
+ */
+ CollationElementIterator(const UnicodeString& sourceText,
+ const RuleBasedCollator* order, UErrorCode& status);
+
+ /**
+ * CollationElementIterator constructor. This takes the source string and the
+ * collation object. The cursor will walk thru the source string based on the
+ * predefined collation rules. If the source string is empty, NULLORDER will
+ * be returned on the calls to next().
+ * @param sourceText the source string.
+ * @param order the collation object.
+ * @param status the error code status.
+ * @stable ICU 2.0
+ */
+ CollationElementIterator(const CharacterIterator& sourceText,
+ const RuleBasedCollator* order, UErrorCode& status);
+
+ // CollationElementIterator protected methods -------------------------------
+
+ /**
+ * Assignment operator
+ *
+ * @param other the object to be copied
+ * @stable ICU 2.0
+ */
+ const CollationElementIterator&
+ operator=(const CollationElementIterator& other);
+
+private:
+ CollationElementIterator(); // default constructor not implemented
+
+ // CollationElementIterator private data members ----------------------------
+
+ /**
+ * Data wrapper for collation elements
+ */
+ UCollationElements *m_data_;
+
+ /**
+ * Indicates if m_data_ belongs to this object.
+ */
+ UBool isDataOwned_;
+
+};
+
+// CollationElementIterator inline method defination --------------------------
+
+/**
+* Get the primary order of a collation order.
+* @param order the collation order
+* @return the primary order of a collation order.
+*/
+inline int32_t CollationElementIterator::primaryOrder(int32_t order)
+{
+ order &= RuleBasedCollator::PRIMARYORDERMASK;
+ return (order >> RuleBasedCollator::PRIMARYORDERSHIFT);
+}
+
+/**
+* Get the secondary order of a collation order.
+* @param order the collation order
+* @return the secondary order of a collation order.
+*/
+inline int32_t CollationElementIterator::secondaryOrder(int32_t order)
+{
+ order = order & RuleBasedCollator::SECONDARYORDERMASK;
+ return (order >> RuleBasedCollator::SECONDARYORDERSHIFT);
+}
+
+/**
+* Get the tertiary order of a collation order.
+* @param order the collation order
+* @return the tertiary order of a collation order.
+*/
+inline int32_t CollationElementIterator::tertiaryOrder(int32_t order)
+{
+ return (order &= RuleBasedCollator::TERTIARYORDERMASK);
+}
+
+inline int32_t CollationElementIterator::getMaxExpansion(int32_t order) const
+{
+ return ucol_getMaxExpansion(m_data_, (uint32_t)order);
+}
+
+inline UBool CollationElementIterator::isIgnorable(int32_t order)
+{
+ return (primaryOrder(order) == RuleBasedCollator::PRIMIGNORABLE);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/coll.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/coll.h
new file mode 100644
index 00000000000..c3ebca16f23
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/coll.h
@@ -0,0 +1,1035 @@
+/*
+******************************************************************************
+* Copyright (C) 1996-2007, International Business Machines *
+* Corporation and others. All Rights Reserved. *
+******************************************************************************
+*/
+
+/**
+* File coll.h
+*
+* Created by: Helena Shih
+*
+* Modification History:
+*
+* Date Name Description
+* 02/5/97 aliu Modified createDefault to load collation data from
+* binary files when possible. Added related methods
+* createCollationFromFile, chopLocale, createPathName.
+* 02/11/97 aliu Added members addToCache, findInCache, and fgCache.
+* 02/12/97 aliu Modified to create objects from RuleBasedCollator cache.
+* Moved cache out of Collation class.
+* 02/13/97 aliu Moved several methods out of this class and into
+* RuleBasedCollator, with modifications. Modified
+* createDefault() to call new RuleBasedCollator(Locale&)
+* constructor. General clean up and documentation.
+* 02/20/97 helena Added clone, operator==, operator!=, operator=, copy
+* constructor and getDynamicClassID.
+* 03/25/97 helena Updated with platform independent data types.
+* 05/06/97 helena Added memory allocation error detection.
+* 06/20/97 helena Java class name change.
+* 09/03/97 helena Added createCollationKeyValues().
+* 02/10/98 damiba Added compare() with length as parameter.
+* 04/23/99 stephen Removed EDecompositionMode, merged with
+* Normalizer::EMode.
+* 11/02/99 helena Collator performance enhancements. Eliminates the
+* UnicodeString construction and special case for NO_OP.
+* 11/23/99 srl More performance enhancements. Inlining of
+* critical accessors.
+* 05/15/00 helena Added version information API.
+* 01/29/01 synwee Modified into a C++ wrapper which calls C apis
+* (ucoll.h).
+*/
+
+#ifndef COLL_H
+#define COLL_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Collation Service.
+ */
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uobject.h"
+#include "unicode/ucol.h"
+#include "unicode/normlzr.h"
+#include "unicode/locid.h"
+#include "unicode/uniset.h"
+#include "unicode/umisc.h"
+
+U_NAMESPACE_BEGIN
+
+class StringEnumeration;
+
+#if !UCONFIG_NO_SERVICE
+/**
+ * @stable ICU 2.6
+ */
+class CollatorFactory;
+#endif
+
+/**
+* @stable ICU 2.0
+*/
+class CollationKey;
+
+/**
+* The <code>Collator</code> class performs locale-sensitive string
+* comparison.<br>
+* You use this class to build searching and sorting routines for natural
+* language text.<br>
+* <em>Important: </em>The ICU collation service has been reimplemented
+* in order to achieve better performance and UCA compliance.
+* For details, see the
+* <a href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm">
+* collation design document</a>.
+* <p>
+* <code>Collator</code> is an abstract base class. Subclasses implement
+* specific collation strategies. One subclass,
+* <code>RuleBasedCollator</code>, is currently provided and is applicable
+* to a wide set of languages. Other subclasses may be created to handle more
+* specialized needs.
+* <p>
+* Like other locale-sensitive classes, you can use the static factory method,
+* <code>createInstance</code>, to obtain the appropriate
+* <code>Collator</code> object for a given locale. You will only need to
+* look at the subclasses of <code>Collator</code> if you need to
+* understand the details of a particular collation strategy or if you need to
+* modify that strategy.
+* <p>
+* The following example shows how to compare two strings using the
+* <code>Collator</code> for the default locale.
+* \htmlonly<blockquote>\endhtmlonly
+* <pre>
+* \code
+* // Compare two strings in the default locale
+* UErrorCode success = U_ZERO_ERROR;
+* Collator* myCollator = Collator::createInstance(success);
+* if (myCollator->compare("abc", "ABC") < 0)
+* cout << "abc is less than ABC" << endl;
+* else
+* cout << "abc is greater than or equal to ABC" << endl;
+* \endcode
+* </pre>
+* \htmlonly</blockquote>\endhtmlonly
+* <p>
+* You can set a <code>Collator</code>'s <em>strength</em> property to
+* determine the level of difference considered significant in comparisons.
+* Five strengths are provided: <code>PRIMARY</code>, <code>SECONDARY</code>,
+* <code>TERTIARY</code>, <code>QUATERNARY</code> and <code>IDENTICAL</code>.
+* The exact assignment of strengths to language features is locale dependant.
+* For example, in Czech, "e" and "f" are considered primary differences,
+* while "e" and "\u00EA" are secondary differences, "e" and "E" are tertiary
+* differences and "e" and "e" are identical. The following shows how both case
+* and accents could be ignored for US English.
+* \htmlonly<blockquote>\endhtmlonly
+* <pre>
+* \code
+* //Get the Collator for US English and set its strength to PRIMARY
+* UErrorCode success = U_ZERO_ERROR;
+* Collator* usCollator = Collator::createInstance(Locale::US, success);
+* usCollator->setStrength(Collator::PRIMARY);
+* if (usCollator->compare("abc", "ABC") == 0)
+* cout << "'abc' and 'ABC' strings are equivalent with strength PRIMARY" << endl;
+* \endcode
+* </pre>
+* \htmlonly</blockquote>\endhtmlonly
+* <p>
+* For comparing strings exactly once, the <code>compare</code> method
+* provides the best performance. When sorting a list of strings however, it
+* is generally necessary to compare each string multiple times. In this case,
+* sort keys provide better performance. The <code>getSortKey</code> methods
+* convert a string to a series of bytes that can be compared bitwise against
+* other sort keys using <code>strcmp()</code>. Sort keys are written as
+* zero-terminated byte strings. They consist of several substrings, one for
+* each collation strength level, that are delimited by 0x01 bytes.
+* If the string code points are appended for UCOL_IDENTICAL, then they are
+* processed for correct code point order comparison and may contain 0x01
+* bytes but not zero bytes.
+* </p>
+* <p>
+* An older set of APIs returns a <code>CollationKey</code> object that wraps
+* the sort key bytes instead of returning the bytes themselves.
+* Its use is deprecated, but it is still available for compatibility with
+* Java.
+* </p>
+* <p>
+* <strong>Note:</strong> <code>Collator</code>s with different Locale,
+* and CollationStrength settings will return different sort
+* orders for the same set of strings. Locales have specific collation rules,
+* and the way in which secondary and tertiary differences are taken into
+* account, for example, will result in a different sorting order for same
+* strings.
+* </p>
+* @see RuleBasedCollator
+* @see CollationKey
+* @see CollationElementIterator
+* @see Locale
+* @see Normalizer
+* @version 2.0 11/15/01
+*/
+
+class U_I18N_API Collator : public UObject {
+public:
+
+ // Collator public enums -----------------------------------------------
+
+ /**
+ * Base letter represents a primary difference. Set comparison level to
+ * PRIMARY to ignore secondary and tertiary differences.<br>
+ * Use this to set the strength of a Collator object.<br>
+ * Example of primary difference, "abc" &lt; "abd"
+ *
+ * Diacritical differences on the same base letter represent a secondary
+ * difference. Set comparison level to SECONDARY to ignore tertiary
+ * differences. Use this to set the strength of a Collator object.<br>
+ * Example of secondary difference, "&auml;" >> "a".
+ *
+ * Uppercase and lowercase versions of the same character represents a
+ * tertiary difference. Set comparison level to TERTIARY to include all
+ * comparison differences. Use this to set the strength of a Collator
+ * object.<br>
+ * Example of tertiary difference, "abc" &lt;&lt;&lt; "ABC".
+ *
+ * Two characters are considered "identical" when they have the same unicode
+ * spellings.<br>
+ * For example, "&auml;" == "&auml;".
+ *
+ * UCollationStrength is also used to determine the strength of sort keys
+ * generated from Collator objects.
+ * @stable ICU 2.0
+ */
+ enum ECollationStrength
+ {
+ PRIMARY = 0,
+ SECONDARY = 1,
+ TERTIARY = 2,
+ QUATERNARY = 3,
+ IDENTICAL = 15
+ };
+
+ /**
+ * LESS is returned if source string is compared to be less than target
+ * string in the compare() method.
+ * EQUAL is returned if source string is compared to be equal to target
+ * string in the compare() method.
+ * GREATER is returned if source string is compared to be greater than
+ * target string in the compare() method.
+ * @see Collator#compare
+ * @deprecated ICU 2.6. Use C enum UCollationResult defined in ucol.h
+ */
+ enum EComparisonResult
+ {
+ LESS = -1,
+ EQUAL = 0,
+ GREATER = 1
+ };
+
+ // Collator public destructor -----------------------------------------
+
+ /**
+ * Destructor
+ * @stable ICU 2.0
+ */
+ virtual ~Collator();
+
+ // Collator public methods --------------------------------------------
+
+ /**
+ * Returns true if "other" is the same as "this"
+ * @param other Collator object to be compared
+ * @return true if other is the same as this.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Collator& other) const;
+
+ /**
+ * Returns true if "other" is not the same as "this".
+ * @param other Collator object to be compared
+ * @return true if other is not the same as this.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator!=(const Collator& other) const;
+
+ /**
+ * Makes a shallow copy of the current object.
+ * @return a copy of this object
+ * @stable ICU 2.0
+ */
+ virtual Collator* clone(void) const = 0;
+
+ /**
+ * Creates the Collator object for the current default locale.
+ * The default locale is determined by Locale::getDefault.
+ * The UErrorCode& err parameter is used to return status information to the user.
+ * To check whether the construction succeeded or not, you should check the
+ * value of U_SUCCESS(err). If you wish more detailed information, you can
+ * check for informational error results which still indicate success.
+ * U_USING_FALLBACK_ERROR indicates that a fall back locale was used. For
+ * example, 'de_CH' was requested, but nothing was found there, so 'de' was
+ * used. U_USING_DEFAULT_ERROR indicates that the default locale data was
+ * used; neither the requested locale nor any of its fall back locales
+ * could be found.
+ * The caller owns the returned object and is responsible for deleting it.
+ *
+ * @param err the error code status.
+ * @return the collation object of the default locale.(for example, en_US)
+ * @see Locale#getDefault
+ * @stable ICU 2.0
+ */
+ static Collator* U_EXPORT2 createInstance(UErrorCode& err);
+
+ /**
+ * Gets the table-based collation object for the desired locale. The
+ * resource of the desired locale will be loaded by ResourceLoader.
+ * Locale::ENGLISH is the base collation table and all other languages are
+ * built on top of it with additional language-specific modifications.
+ * The UErrorCode& err parameter is used to return status information to the user.
+ * To check whether the construction succeeded or not, you should check
+ * the value of U_SUCCESS(err). If you wish more detailed information, you
+ * can check for informational error results which still indicate success.
+ * U_USING_FALLBACK_ERROR indicates that a fall back locale was used. For
+ * example, 'de_CH' was requested, but nothing was found there, so 'de' was
+ * used. U_USING_DEFAULT_ERROR indicates that the default locale data was
+ * used; neither the requested locale nor any of its fall back locales
+ * could be found.
+ * The caller owns the returned object and is responsible for deleting it.
+ * @param loc The locale ID for which to open a collator.
+ * @param err the error code status.
+ * @return the created table-based collation object based on the desired
+ * locale.
+ * @see Locale
+ * @see ResourceLoader
+ * @stable ICU 2.2
+ */
+ static Collator* U_EXPORT2 createInstance(const Locale& loc, UErrorCode& err);
+
+#ifdef U_USE_COLLATION_OBSOLETE_2_6
+ /**
+ * Create a Collator with a specific version.
+ * This is the same as createInstance(loc, err) except that getVersion() of
+ * the returned object is guaranteed to be the same as the version
+ * parameter.
+ * This is designed to be used to open the same collator for a given
+ * locale even when ICU is updated.
+ * The same locale and version guarantees the same sort keys and
+ * comparison results.
+ * <p>
+ * Note: this API will be removed in a future release. Use
+ * <tt>createInstance(const Locale&, UErrorCode&) instead.</tt></p>
+ *
+ * @param loc The locale ID for which to open a collator.
+ * @param version The requested collator version.
+ * @param err A reference to a UErrorCode,
+ * must not indicate a failure before calling this function.
+ * @return A pointer to a Collator, or 0 if an error occurred
+ * or a collator with the requested version is not available.
+ *
+ * @see getVersion
+ * @obsolete ICU 2.6
+ */
+ static Collator *createInstance(const Locale &loc, UVersionInfo version, UErrorCode &err);
+#endif
+
+ /**
+ * The comparison function compares the character data stored in two
+ * different strings. Returns information about whether a string is less
+ * than, greater than or equal to another string.
+ * @param source the source string to be compared with.
+ * @param target the string that is to be compared with the source string.
+ * @return Returns a byte value. GREATER if source is greater
+ * than target; EQUAL if source is equal to target; LESS if source is less
+ * than target
+ * @deprecated ICU 2.6 use the overload with UErrorCode &
+ */
+ virtual EComparisonResult compare(const UnicodeString& source,
+ const UnicodeString& target) const;
+
+ /**
+ * The comparison function compares the character data stored in two
+ * different strings. Returns information about whether a string is less
+ * than, greater than or equal to another string.
+ * @param source the source string to be compared with.
+ * @param target the string that is to be compared with the source string.
+ * @param status possible error code
+ * @return Returns an enum value. UCOL_GREATER if source is greater
+ * than target; UCOL_EQUAL if source is equal to target; UCOL_LESS if source is less
+ * than target
+ * @stable ICU 2.6
+ */
+ virtual UCollationResult compare(const UnicodeString& source,
+ const UnicodeString& target,
+ UErrorCode &status) const = 0;
+
+ /**
+ * Does the same thing as compare but limits the comparison to a specified
+ * length
+ * @param source the source string to be compared with.
+ * @param target the string that is to be compared with the source string.
+ * @param length the length the comparison is limited to
+ * @return Returns a byte value. GREATER if source (up to the specified
+ * length) is greater than target; EQUAL if source (up to specified
+ * length) is equal to target; LESS if source (up to the specified
+ * length) is less than target.
+ * @deprecated ICU 2.6 use the overload with UErrorCode &
+ */
+ virtual EComparisonResult compare(const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length) const;
+
+ /**
+ * Does the same thing as compare but limits the comparison to a specified
+ * length
+ * @param source the source string to be compared with.
+ * @param target the string that is to be compared with the source string.
+ * @param length the length the comparison is limited to
+ * @param status possible error code
+ * @return Returns an enum value. UCOL_GREATER if source (up to the specified
+ * length) is greater than target; UCOL_EQUAL if source (up to specified
+ * length) is equal to target; UCOL_LESS if source (up to the specified
+ * length) is less than target.
+ * @stable ICU 2.6
+ */
+ virtual UCollationResult compare(const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length,
+ UErrorCode &status) const = 0;
+
+ /**
+ * The comparison function compares the character data stored in two
+ * different string arrays. Returns information about whether a string array
+ * is less than, greater than or equal to another string array.
+ * @param source the source string array to be compared with.
+ * @param sourceLength the length of the source string array. If this value
+ * is equal to -1, the string array is null-terminated.
+ * @param target the string that is to be compared with the source string.
+ * @param targetLength the length of the target string array. If this value
+ * is equal to -1, the string array is null-terminated.
+ * @return Returns a byte value. GREATER if source is greater than target;
+ * EQUAL if source is equal to target; LESS if source is less than
+ * target
+ * @deprecated ICU 2.6 use the overload with UErrorCode &
+ */
+ virtual EComparisonResult compare(const UChar* source, int32_t sourceLength,
+ const UChar* target, int32_t targetLength)
+ const;
+
+ /**
+ * The comparison function compares the character data stored in two
+ * different string arrays. Returns information about whether a string array
+ * is less than, greater than or equal to another string array.
+ * @param source the source string array to be compared with.
+ * @param sourceLength the length of the source string array. If this value
+ * is equal to -1, the string array is null-terminated.
+ * @param target the string that is to be compared with the source string.
+ * @param targetLength the length of the target string array. If this value
+ * is equal to -1, the string array is null-terminated.
+ * @param status possible error code
+ * @return Returns an enum value. UCOL_GREATER if source is greater
+ * than target; UCOL_EQUAL if source is equal to target; UCOL_LESS if source is less
+ * than target
+ * @stable ICU 2.6
+ */
+ virtual UCollationResult compare(const UChar* source, int32_t sourceLength,
+ const UChar* target, int32_t targetLength,
+ UErrorCode &status) const = 0;
+
+ /**
+ * Transforms the string into a series of characters that can be compared
+ * with CollationKey::compareTo. It is not possible to restore the original
+ * string from the chars in the sort key. The generated sort key handles
+ * only a limited number of ignorable characters.
+ * <p>Use CollationKey::equals or CollationKey::compare to compare the
+ * generated sort keys.
+ * If the source string is null, a null collation key will be returned.
+ * @param source the source string to be transformed into a sort key.
+ * @param key the collation key to be filled in
+ * @param status the error code status.
+ * @return the collation key of the string based on the collation rules.
+ * @see CollationKey#compare
+ * @deprecated ICU 2.8 Use getSortKey(...) instead
+ */
+ virtual CollationKey& getCollationKey(const UnicodeString& source,
+ CollationKey& key,
+ UErrorCode& status) const = 0;
+
+ /**
+ * Transforms the string into a series of characters that can be compared
+ * with CollationKey::compareTo. It is not possible to restore the original
+ * string from the chars in the sort key. The generated sort key handles
+ * only a limited number of ignorable characters.
+ * <p>Use CollationKey::equals or CollationKey::compare to compare the
+ * generated sort keys.
+ * <p>If the source string is null, a null collation key will be returned.
+ * @param source the source string to be transformed into a sort key.
+ * @param sourceLength length of the collation key
+ * @param key the collation key to be filled in
+ * @param status the error code status.
+ * @return the collation key of the string based on the collation rules.
+ * @see CollationKey#compare
+ * @deprecated ICU 2.8 Use getSortKey(...) instead
+ */
+ virtual CollationKey& getCollationKey(const UChar*source,
+ int32_t sourceLength,
+ CollationKey& key,
+ UErrorCode& status) const = 0;
+ /**
+ * Generates the hash code for the collation object
+ * @stable ICU 2.0
+ */
+ virtual int32_t hashCode(void) const = 0;
+
+ /**
+ * Gets the locale of the Collator
+ *
+ * @param type can be either requested, valid or actual locale. For more
+ * information see the definition of ULocDataLocaleType in
+ * uloc.h
+ * @param status the error code status.
+ * @return locale where the collation data lives. If the collator
+ * was instantiated from rules, locale is empty.
+ * @deprecated ICU 2.8 This API is under consideration for revision
+ * in ICU 3.0.
+ */
+ virtual const Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const = 0;
+
+ /**
+ * Convenience method for comparing two strings based on the collation rules.
+ * @param source the source string to be compared with.
+ * @param target the target string to be compared with.
+ * @return true if the first string is greater than the second one,
+ * according to the collation rules. false, otherwise.
+ * @see Collator#compare
+ * @stable ICU 2.0
+ */
+ UBool greater(const UnicodeString& source, const UnicodeString& target)
+ const;
+
+ /**
+ * Convenience method for comparing two strings based on the collation rules.
+ * @param source the source string to be compared with.
+ * @param target the target string to be compared with.
+ * @return true if the first string is greater than or equal to the second
+ * one, according to the collation rules. false, otherwise.
+ * @see Collator#compare
+ * @stable ICU 2.0
+ */
+ UBool greaterOrEqual(const UnicodeString& source,
+ const UnicodeString& target) const;
+
+ /**
+ * Convenience method for comparing two strings based on the collation rules.
+ * @param source the source string to be compared with.
+ * @param target the target string to be compared with.
+ * @return true if the strings are equal according to the collation rules.
+ * false, otherwise.
+ * @see Collator#compare
+ * @stable ICU 2.0
+ */
+ UBool equals(const UnicodeString& source, const UnicodeString& target) const;
+
+ /**
+ * Determines the minimum strength that will be use in comparison or
+ * transformation.
+ * <p>E.g. with strength == SECONDARY, the tertiary difference is ignored
+ * <p>E.g. with strength == PRIMARY, the secondary and tertiary difference
+ * are ignored.
+ * @return the current comparison level.
+ * @see Collator#setStrength
+ * @deprecated ICU 2.6 Use getAttribute(UCOL_STRENGTH...) instead
+ */
+ virtual ECollationStrength getStrength(void) const = 0;
+
+ /**
+ * Sets the minimum strength to be used in comparison or transformation.
+ * <p>Example of use:
+ * <pre>
+ * \code
+ * UErrorCode status = U_ZERO_ERROR;
+ * Collator*myCollation = Collator::createInstance(Locale::US, status);
+ * if (U_FAILURE(status)) return;
+ * myCollation->setStrength(Collator::PRIMARY);
+ * // result will be "abc" == "ABC"
+ * // tertiary differences will be ignored
+ * Collator::ComparisonResult result = myCollation->compare("abc", "ABC");
+ * \endcode
+ * </pre>
+ * @see Collator#getStrength
+ * @param newStrength the new comparison level.
+ * @deprecated ICU 2.6 Use setAttribute(UCOL_STRENGTH...) instead
+ */
+ virtual void setStrength(ECollationStrength newStrength) = 0;
+
+ /**
+ * Get name of the object for the desired Locale, in the desired langauge
+ * @param objectLocale must be from getAvailableLocales
+ * @param displayLocale specifies the desired locale for output
+ * @param name the fill-in parameter of the return value
+ * @return display-able name of the object for the object locale in the
+ * desired language
+ * @stable ICU 2.0
+ */
+ static UnicodeString& U_EXPORT2 getDisplayName(const Locale& objectLocale,
+ const Locale& displayLocale,
+ UnicodeString& name);
+
+ /**
+ * Get name of the object for the desired Locale, in the langauge of the
+ * default locale.
+ * @param objectLocale must be from getAvailableLocales
+ * @param name the fill-in parameter of the return value
+ * @return name of the object for the desired locale in the default language
+ * @stable ICU 2.0
+ */
+ static UnicodeString& U_EXPORT2 getDisplayName(const Locale& objectLocale,
+ UnicodeString& name);
+
+ /**
+ * Get the set of Locales for which Collations are installed.
+ *
+ * <p>Note this does not include locales supported by registered collators.
+ * If collators might have been registered, use the overload of getAvailableLocales
+ * that returns a StringEnumeration.</p>
+ *
+ * @param count the output parameter of number of elements in the locale list
+ * @return the list of available locales for which collations are installed
+ * @stable ICU 2.0
+ */
+ static const Locale* U_EXPORT2 getAvailableLocales(int32_t& count);
+
+ /**
+ * Return a StringEnumeration over the locales available at the time of the call,
+ * including registered locales. If a severe error occurs (such as out of memory
+ * condition) this will return null. If there is no locale data, an empty enumeration
+ * will be returned.
+ * @return a StringEnumeration over the locales available at the time of the call
+ * @stable ICU 2.6
+ */
+ static StringEnumeration* U_EXPORT2 getAvailableLocales(void);
+
+ /**
+ * Create a string enumerator of all possible keywords that are relevant to
+ * collation. At this point, the only recognized keyword for this
+ * service is "collation".
+ * @param status input-output error code
+ * @return a string enumeration over locale strings. The caller is
+ * responsible for closing the result.
+ * @stable ICU 3.0
+ */
+ static StringEnumeration* U_EXPORT2 getKeywords(UErrorCode& status);
+
+ /**
+ * Given a keyword, create a string enumeration of all values
+ * for that keyword that are currently in use.
+ * @param keyword a particular keyword as enumerated by
+ * ucol_getKeywords. If any other keyword is passed in, status is set
+ * to U_ILLEGAL_ARGUMENT_ERROR.
+ * @param status input-output error code
+ * @return a string enumeration over collation keyword values, or NULL
+ * upon error. The caller is responsible for deleting the result.
+ * @stable ICU 3.0
+ */
+ static StringEnumeration* U_EXPORT2 getKeywordValues(const char *keyword, UErrorCode& status);
+
+ /**
+ * Return the functionally equivalent locale for the given
+ * requested locale, with respect to given keyword, for the
+ * collation service. If two locales return the same result, then
+ * collators instantiated for these locales will behave
+ * equivalently. The converse is not always true; two collators
+ * may in fact be equivalent, but return different results, due to
+ * internal details. The return result has no other meaning than
+ * that stated above, and implies nothing as to the relationship
+ * between the two locales. This is intended for use by
+ * applications who wish to cache collators, or otherwise reuse
+ * collators when possible. The functional equivalent may change
+ * over time. For more information, please see the <a
+ * href="http://icu-project.org/userguide/locale.html#services">
+ * Locales and Services</a> section of the ICU User Guide.
+ * @param keyword a particular keyword as enumerated by
+ * ucol_getKeywords.
+ * @param locale the requested locale
+ * @param isAvailable reference to a fillin parameter that
+ * indicates whether the requested locale was 'available' to the
+ * collation service. A locale is defined as 'available' if it
+ * physically exists within the collation locale data.
+ * @param status reference to input-output error code
+ * @return the functionally equivalent collation locale, or the root
+ * locale upon error.
+ * @stable ICU 3.0
+ */
+ static Locale U_EXPORT2 getFunctionalEquivalent(const char* keyword, const Locale& locale,
+ UBool& isAvailable, UErrorCode& status);
+
+#if !UCONFIG_NO_SERVICE
+ /**
+ * Register a new Collator. The collator will be adopted.
+ * @param toAdopt the Collator instance to be adopted
+ * @param locale the locale with which the collator will be associated
+ * @param status the in/out status code, no special meanings are assigned
+ * @return a registry key that can be used to unregister this collator
+ * @stable ICU 2.6
+ */
+ static URegistryKey U_EXPORT2 registerInstance(Collator* toAdopt, const Locale& locale, UErrorCode& status);
+
+ /**
+ * Register a new CollatorFactory. The factory will be adopted.
+ * @param toAdopt the CollatorFactory instance to be adopted
+ * @param status the in/out status code, no special meanings are assigned
+ * @return a registry key that can be used to unregister this collator
+ * @stable ICU 2.6
+ */
+ static URegistryKey U_EXPORT2 registerFactory(CollatorFactory* toAdopt, UErrorCode& status);
+
+ /**
+ * Unregister a previously-registered Collator or CollatorFactory
+ * using the key returned from the register call. Key becomes
+ * invalid after a successful call and should not be used again.
+ * The object corresponding to the key will be deleted.
+ * @param key the registry key returned by a previous call to registerInstance
+ * @param status the in/out status code, no special meanings are assigned
+ * @return TRUE if the collator for the key was successfully unregistered
+ * @stable ICU 2.6
+ */
+ static UBool U_EXPORT2 unregister(URegistryKey key, UErrorCode& status);
+#endif /* UCONFIG_NO_SERVICE */
+
+ /**
+ * Gets the version information for a Collator.
+ * @param info the version # information, the result will be filled in
+ * @stable ICU 2.0
+ */
+ virtual void getVersion(UVersionInfo info) const = 0;
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual method.
+ * This method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ * @return The class ID for this object. All objects of a given class have
+ * the same class ID. Objects of other classes have different class
+ * IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const = 0;
+
+ /**
+ * Universal attribute setter
+ * @param attr attribute type
+ * @param value attribute value
+ * @param status to indicate whether the operation went on smoothly or
+ * there were errors
+ * @stable ICU 2.2
+ */
+ virtual void setAttribute(UColAttribute attr, UColAttributeValue value,
+ UErrorCode &status) = 0;
+
+ /**
+ * Universal attribute getter
+ * @param attr attribute type
+ * @param status to indicate whether the operation went on smoothly or
+ * there were errors
+ * @return attribute value
+ * @stable ICU 2.2
+ */
+ virtual UColAttributeValue getAttribute(UColAttribute attr,
+ UErrorCode &status) = 0;
+
+ /**
+ * Sets the variable top to a collation element value of a string supplied.
+ * @param varTop one or more (if contraction) UChars to which the variable top should be set
+ * @param len length of variable top string. If -1 it is considered to be zero terminated.
+ * @param status error code. If error code is set, the return value is undefined. Errors set by this function are: <br>
+ * U_CE_NOT_FOUND_ERROR if more than one character was passed and there is no such a contraction<br>
+ * U_PRIMARY_TOO_LONG_ERROR if the primary for the variable top has more than two bytes
+ * @return a 32 bit value containing the value of the variable top in upper 16 bits. Lower 16 bits are undefined
+ * @stable ICU 2.0
+ */
+ virtual uint32_t setVariableTop(const UChar *varTop, int32_t len, UErrorCode &status) = 0;
+
+ /**
+ * Sets the variable top to a collation element value of a string supplied.
+ * @param varTop an UnicodeString size 1 or more (if contraction) of UChars to which the variable top should be set
+ * @param status error code. If error code is set, the return value is undefined. Errors set by this function are: <br>
+ * U_CE_NOT_FOUND_ERROR if more than one character was passed and there is no such a contraction<br>
+ * U_PRIMARY_TOO_LONG_ERROR if the primary for the variable top has more than two bytes
+ * @return a 32 bit value containing the value of the variable top in upper 16 bits. Lower 16 bits are undefined
+ * @stable ICU 2.0
+ */
+ virtual uint32_t setVariableTop(const UnicodeString varTop, UErrorCode &status) = 0;
+
+ /**
+ * Sets the variable top to a collation element value supplied. Variable top is set to the upper 16 bits.
+ * Lower 16 bits are ignored.
+ * @param varTop CE value, as returned by setVariableTop or ucol)getVariableTop
+ * @param status error code (not changed by function)
+ * @stable ICU 2.0
+ */
+ virtual void setVariableTop(const uint32_t varTop, UErrorCode &status) = 0;
+
+ /**
+ * Gets the variable top value of a Collator.
+ * Lower 16 bits are undefined and should be ignored.
+ * @param status error code (not changed by function). If error code is set, the return value is undefined.
+ * @stable ICU 2.0
+ */
+ virtual uint32_t getVariableTop(UErrorCode &status) const = 0;
+
+ /**
+ * Get an UnicodeSet that contains all the characters and sequences
+ * tailored in this collator.
+ * @param status error code of the operation
+ * @return a pointer to a UnicodeSet object containing all the
+ * code points and sequences that may sort differently than
+ * in the UCA. The object must be disposed of by using delete
+ * @stable ICU 2.4
+ */
+ virtual UnicodeSet *getTailoredSet(UErrorCode &status) const;
+
+
+ /**
+ * Thread safe cloning operation
+ * @return pointer to the new clone, user should remove it.
+ * @stable ICU 2.2
+ */
+ virtual Collator* safeClone(void) = 0;
+
+ /**
+ * Get the sort key as an array of bytes from an UnicodeString.
+ * Sort key byte arrays are zero-terminated and can be compared using
+ * strcmp().
+ * @param source string to be processed.
+ * @param result buffer to store result in. If NULL, number of bytes needed
+ * will be returned.
+ * @param resultLength length of the result buffer. If if not enough the
+ * buffer will be filled to capacity.
+ * @return Number of bytes needed for storing the sort key
+ * @stable ICU 2.2
+ */
+ virtual int32_t getSortKey(const UnicodeString& source,
+ uint8_t* result,
+ int32_t resultLength) const = 0;
+
+ /**
+ * Get the sort key as an array of bytes from an UChar buffer.
+ * Sort key byte arrays are zero-terminated and can be compared using
+ * strcmp().
+ * @param source string to be processed.
+ * @param sourceLength length of string to be processed.
+ * If -1, the string is 0 terminated and length will be decided by the
+ * function.
+ * @param result buffer to store result in. If NULL, number of bytes needed
+ * will be returned.
+ * @param resultLength length of the result buffer. If if not enough the
+ * buffer will be filled to capacity.
+ * @return Number of bytes needed for storing the sort key
+ * @stable ICU 2.2
+ */
+ virtual int32_t getSortKey(const UChar*source, int32_t sourceLength,
+ uint8_t*result, int32_t resultLength) const = 0;
+
+ /**
+ * Produce a bound for a given sortkey and a number of levels.
+ * Return value is always the number of bytes needed, regardless of
+ * whether the result buffer was big enough or even valid.<br>
+ * Resulting bounds can be used to produce a range of strings that are
+ * between upper and lower bounds. For example, if bounds are produced
+ * for a sortkey of string "smith", strings between upper and lower
+ * bounds with one level would include "Smith", "SMITH", "sMiTh".<br>
+ * There are two upper bounds that can be produced. If UCOL_BOUND_UPPER
+ * is produced, strings matched would be as above. However, if bound
+ * produced using UCOL_BOUND_UPPER_LONG is used, the above example will
+ * also match "Smithsonian" and similar.<br>
+ * For more on usage, see example in cintltst/capitst.c in procedure
+ * TestBounds.
+ * Sort keys may be compared using <TT>strcmp</TT>.
+ * @param source The source sortkey.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * (If an unmodified sortkey is passed, it is always null
+ * terminated).
+ * @param boundType Type of bound required. It can be UCOL_BOUND_LOWER, which
+ * produces a lower inclusive bound, UCOL_BOUND_UPPER, that
+ * produces upper bound that matches strings of the same length
+ * or UCOL_BOUND_UPPER_LONG that matches strings that have the
+ * same starting substring as the source string.
+ * @param noOfLevels Number of levels required in the resulting bound (for most
+ * uses, the recommended value is 1). See users guide for
+ * explanation on number of levels a sortkey can have.
+ * @param result A pointer to a buffer to receive the resulting sortkey.
+ * @param resultLength The maximum size of result.
+ * @param status Used for returning error code if something went wrong. If the
+ * number of levels requested is higher than the number of levels
+ * in the source key, a warning (U_SORT_KEY_TOO_SHORT_WARNING) is
+ * issued.
+ * @return The size needed to fully store the bound.
+ * @see ucol_keyHashCode
+ * @stable ICU 2.1
+ */
+ static int32_t U_EXPORT2 getBound(const uint8_t *source,
+ int32_t sourceLength,
+ UColBoundMode boundType,
+ uint32_t noOfLevels,
+ uint8_t *result,
+ int32_t resultLength,
+ UErrorCode &status);
+
+
+protected:
+
+ // Collator protected constructors -------------------------------------
+
+ /**
+ * Default constructor.
+ * Constructor is different from the old default Collator constructor.
+ * The task for determing the default collation strength and normalization
+ * mode is left to the child class.
+ * @stable ICU 2.0
+ */
+ Collator();
+
+ /**
+ * Constructor.
+ * Empty constructor, does not handle the arguments.
+ * This constructor is done for backward compatibility with 1.7 and 1.8.
+ * The task for handling the argument collation strength and normalization
+ * mode is left to the child class.
+ * @param collationStrength collation strength
+ * @param decompositionMode
+ * @deprecated ICU 2.4. Subclasses should use the default constructor
+ * instead and handle the strength and normalization mode themselves.
+ */
+ Collator(UCollationStrength collationStrength,
+ UNormalizationMode decompositionMode);
+
+ /**
+ * Copy constructor.
+ * @param other Collator object to be copied from
+ * @stable ICU 2.0
+ */
+ Collator(const Collator& other);
+
+ // Collator protected methods -----------------------------------------
+
+
+ /**
+ * Used internally by registraton to define the requested and valid locales.
+ * @param requestedLocale the requsted locale
+ * @param validLocale the valid locale
+ * @internal
+ */
+ virtual void setLocales(const Locale& requestedLocale, const Locale& validLocale);
+
+public:
+#if !UCONFIG_NO_SERVICE
+ /**
+ * used only by ucol_open, not for public use
+ * @internal
+ */
+ static UCollator* createUCollator(const char* loc, UErrorCode* status);
+#endif
+private:
+ /**
+ * Assignment operator. Private for now.
+ * @internal
+ */
+ Collator& operator=(const Collator& other);
+
+ friend class CFactory;
+ friend class SimpleCFactory;
+ friend class ICUCollatorFactory;
+ friend class ICUCollatorService;
+ static Collator* makeInstance(const Locale& desiredLocale,
+ UErrorCode& status);
+
+ // Collator private data members ---------------------------------------
+
+ /*
+ synwee : removed as attributes to be handled by child class
+ UCollationStrength strength;
+ Normalizer::EMode decmp;
+ */
+ /* This is useless information */
+/* static const UVersionInfo fVersion;*/
+};
+
+#if !UCONFIG_NO_SERVICE
+/**
+ * A factory, used with registerFactory, the creates multiple collators and provides
+ * display names for them. A factory supports some number of locales-- these are the
+ * locales for which it can create collators. The factory can be visible, in which
+ * case the supported locales will be enumerated by getAvailableLocales, or invisible,
+ * in which they are not. Invisible locales are still supported, they are just not
+ * listed by getAvailableLocales.
+ * <p>
+ * If standard locale display names are sufficient, Collator instances can
+ * be registered using registerInstance instead.</p>
+ * <p>
+ * Note: if the collators are to be used from C APIs, they must be instances
+ * of RuleBasedCollator.</p>
+ *
+ * @stable ICU 2.6
+ */
+class U_I18N_API CollatorFactory : public UObject {
+public:
+
+ /**
+ * Destructor
+ * @stable ICU 3.0
+ */
+ virtual ~CollatorFactory();
+
+ /**
+ * Return true if this factory is visible. Default is true.
+ * If not visible, the locales supported by this factory will not
+ * be listed by getAvailableLocales.
+ * @return true if the factory is visible.
+ * @stable ICU 2.6
+ */
+ virtual UBool visible(void) const;
+
+ /**
+ * Return a collator for the provided locale. If the locale
+ * is not supported, return NULL.
+ * @param loc the locale identifying the collator to be created.
+ * @return a new collator if the locale is supported, otherwise NULL.
+ * @stable ICU 2.6
+ */
+ virtual Collator* createCollator(const Locale& loc) = 0;
+
+ /**
+ * Return the name of the collator for the objectLocale, localized for the displayLocale.
+ * If objectLocale is not supported, or the factory is not visible, set the result string
+ * to bogus.
+ * @param objectLocale the locale identifying the collator
+ * @param displayLocale the locale for which the display name of the collator should be localized
+ * @param result an output parameter for the display name, set to bogus if not supported.
+ * @return the display name
+ * @stable ICU 2.6
+ */
+ virtual UnicodeString& getDisplayName(const Locale& objectLocale,
+ const Locale& displayLocale,
+ UnicodeString& result);
+
+ /**
+ * Return an array of all the locale names directly supported by this factory.
+ * The number of names is returned in count. This array is owned by the factory.
+ * Its contents must never change.
+ * @param count output parameter for the number of locales supported by the factory
+ * @param status the in/out error code
+ * @return a pointer to an array of count UnicodeStrings.
+ * @stable ICU 2.6
+ */
+ virtual const UnicodeString * getSupportedIDs(int32_t &count, UErrorCode& status) = 0;
+};
+#endif /* UCONFIG_NO_SERVICE */
+
+// Collator inline methods -----------------------------------------------
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/curramt.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/curramt.h
new file mode 100644
index 00000000000..c33e6f1f833
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/curramt.h
@@ -0,0 +1,130 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 26, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#ifndef __CURRENCYAMOUNT_H__
+#define __CURRENCYAMOUNT_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/measure.h"
+#include "unicode/currunit.h"
+
+/**
+ * \file
+ * \brief C++ API: Currency Amount Object.
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ *
+ * A currency together with a numeric amount, such as 200 USD.
+ *
+ * @author Alan Liu
+ * @stable ICU 3.0
+ */
+class U_I18N_API CurrencyAmount: public Measure {
+ public:
+ /**
+ * Construct an object with the given numeric amount and the given
+ * ISO currency code.
+ * @param amount a numeric object; amount.isNumeric() must be TRUE
+ * @param isoCode the 3-letter ISO 4217 currency code; must not be
+ * NULL and must have length 3
+ * @param ec input-output error code. If the amount or the isoCode
+ * is invalid, then this will be set to a failing value.
+ * @stable ICU 3.0
+ */
+ CurrencyAmount(const Formattable& amount, const UChar* isoCode,
+ UErrorCode &ec);
+
+ /**
+ * Construct an object with the given numeric amount and the given
+ * ISO currency code.
+ * @param amount the amount of the given currency
+ * @param isoCode the 3-letter ISO 4217 currency code; must not be
+ * NULL and must have length 3
+ * @param ec input-output error code. If the isoCode is invalid,
+ * then this will be set to a failing value.
+ * @stable ICU 3.0
+ */
+ CurrencyAmount(double amount, const UChar* isoCode,
+ UErrorCode &ec);
+
+ /**
+ * Copy constructor
+ * @stable ICU 3.0
+ */
+ CurrencyAmount(const CurrencyAmount& other);
+
+ /**
+ * Assignment operator
+ * @stable ICU 3.0
+ */
+ CurrencyAmount& operator=(const CurrencyAmount& other);
+
+ /**
+ * Return a polymorphic clone of this object. The result will
+ * have the same class as returned by getDynamicClassID().
+ * @stable ICU 3.0
+ */
+ virtual UObject* clone() const;
+
+ /**
+ * Destructor
+ * @stable ICU 3.0
+ */
+ virtual ~CurrencyAmount();
+
+ /**
+ * Returns a unique class ID for this object POLYMORPHICALLY.
+ * This method implements a simple form of RTTI used by ICU.
+ * @return The class ID for this object. All objects of a given
+ * class have the same class ID. Objects of other classes have
+ * different class IDs.
+ * @stable ICU 3.0
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * Returns the class ID for this class. This is used to compare to
+ * the return value of getDynamicClassID().
+ * @return The class ID for all objects of this class.
+ * @stable ICU 3.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * Return the currency unit object of this object.
+ * @stable ICU 3.0
+ */
+ inline const CurrencyUnit& getCurrency() const;
+
+ /**
+ * Return the ISO currency code of this object.
+ * @stable ICU 3.0
+ */
+ inline const UChar* getISOCurrency() const;
+};
+
+inline const CurrencyUnit& CurrencyAmount::getCurrency() const {
+ return (const CurrencyUnit&) getUnit();
+}
+
+inline const UChar* CurrencyAmount::getISOCurrency() const {
+ return getCurrency().getISOCurrency();
+}
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
+#endif // __CURRENCYAMOUNT_H__
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/currunit.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/currunit.h
new file mode 100644
index 00000000000..ecd94110292
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/currunit.h
@@ -0,0 +1,117 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 26, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#ifndef __CURRENCYUNIT_H__
+#define __CURRENCYUNIT_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/measunit.h"
+
+/**
+ * \file
+ * \brief C++ API: Currency Unit Information.
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A unit of currency, such as USD (U.S. dollars) or JPY (Japanese
+ * yen). This class is a thin wrapper over a UChar string that
+ * subclasses MeasureUnit, for use with Measure and MeasureFormat.
+ *
+ * @author Alan Liu
+ * @stable ICU 3.0
+ */
+class U_I18N_API CurrencyUnit: public MeasureUnit {
+ public:
+ /**
+ * Construct an object with the given ISO currency code.
+ * @param isoCode the 3-letter ISO 4217 currency code; must not be
+ * NULL and must have length 3
+ * @param ec input-output error code. If the isoCode is invalid,
+ * then this will be set to a failing value.
+ * @stable ICU 3.0
+ */
+ CurrencyUnit(const UChar* isoCode, UErrorCode &ec);
+
+ /**
+ * Copy constructor
+ * @stable ICU 3.0
+ */
+ CurrencyUnit(const CurrencyUnit& other);
+
+ /**
+ * Assignment operator
+ * @stable ICU 3.0
+ */
+ CurrencyUnit& operator=(const CurrencyUnit& other);
+
+ /**
+ * Return a polymorphic clone of this object. The result will
+ * have the same class as returned by getDynamicClassID().
+ * @stable ICU 3.0
+ */
+ virtual UObject* clone() const;
+
+ /**
+ * Destructor
+ * @stable ICU 3.0
+ */
+ virtual ~CurrencyUnit();
+
+ /**
+ * Equality operator. Return true if this object is equal
+ * to the given object.
+ * @stable ICU 3.0
+ */
+ UBool operator==(const UObject& other) const;
+
+ /**
+ * Returns a unique class ID for this object POLYMORPHICALLY.
+ * This method implements a simple form of RTTI used by ICU.
+ * @return The class ID for this object. All objects of a given
+ * class have the same class ID. Objects of other classes have
+ * different class IDs.
+ * @stable ICU 3.0
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * Returns the class ID for this class. This is used to compare to
+ * the return value of getDynamicClassID().
+ * @return The class ID for all objects of this class.
+ * @stable ICU 3.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * Return the ISO currency code of this object.
+ * @stable ICU 3.0
+ */
+ inline const UChar* getISOCurrency() const;
+
+ private:
+ /**
+ * The ISO 4217 code of this object.
+ */
+ UChar isoCode[4];
+};
+
+inline const UChar* CurrencyUnit::getISOCurrency() const {
+ return isoCode;
+}
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
+#endif // __CURRENCYUNIT_H__
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/datefmt.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/datefmt.h
new file mode 100644
index 00000000000..0022a99791b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/datefmt.h
@@ -0,0 +1,672 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 1997-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************************
+ *
+ * File DATEFMT.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 02/19/97 aliu Converted from java.
+ * 04/01/97 aliu Added support for centuries.
+ * 07/23/98 stephen JDK 1.2 sync
+ * 11/15/99 weiv Added support for week of year/day of week formatting
+ ********************************************************************************
+ */
+
+#ifndef DATEFMT_H
+#define DATEFMT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/udat.h"
+#include "unicode/calendar.h"
+#include "unicode/numfmt.h"
+#include "unicode/format.h"
+#include "unicode/locid.h"
+
+/**
+ * \file
+ * \brief C++ API: Abstract class for converting dates.
+ */
+
+U_NAMESPACE_BEGIN
+
+class TimeZone;
+
+/**
+ * DateFormat is an abstract class for a family of classes that convert dates and
+ * times from their internal representations to textual form and back again in a
+ * language-independent manner. Converting from the internal representation (milliseconds
+ * since midnight, January 1, 1970) to text is known as "formatting," and converting
+ * from text to millis is known as "parsing." We currently define only one concrete
+ * subclass of DateFormat: SimpleDateFormat, which can handle pretty much all normal
+ * date formatting and parsing actions.
+ * <P>
+ * DateFormat helps you to format and parse dates for any locale. Your code can
+ * be completely independent of the locale conventions for months, days of the
+ * week, or even the calendar format: lunar vs. solar.
+ * <P>
+ * To format a date for the current Locale, use one of the static factory
+ * methods:
+ * <pre>
+ * \code
+ * DateFormat* dfmt = DateFormat::createDateInstance();
+ * UDate myDate = Calendar::getNow();
+ * UnicodeString myString;
+ * myString = dfmt->format( myDate, myString );
+ * \endcode
+ * </pre>
+ * If you are formatting multiple numbers, it is more efficient to get the
+ * format and use it multiple times so that the system doesn't have to fetch the
+ * information about the local language and country conventions multiple times.
+ * <pre>
+ * \code
+ * DateFormat* df = DateFormat::createDateInstance();
+ * UnicodeString myString;
+ * UDate myDateArr[] = { 0.0, 100000000.0, 2000000000.0 }; // test values
+ * for (int32_t i = 0; i < 3; ++i) {
+ * myString.remove();
+ * cout << df->format( myDateArr[i], myString ) << endl;
+ * }
+ * \endcode
+ * </pre>
+ * To get specific fields of a date, you can use UFieldPosition to
+ * get specific fields.
+ * <pre>
+ * \code
+ * DateFormat* dfmt = DateFormat::createDateInstance();
+ * FieldPosition pos(DateFormat::YEAR_FIELD);
+ * UnicodeString myString;
+ * myString = dfmt->format( myDate, myString );
+ * cout << myString << endl;
+ * cout << pos.getBeginIndex() << "," << pos. getEndIndex() << endl;
+ * \endcode
+ * </pre>
+ * To format a date for a different Locale, specify it in the call to
+ * createDateInstance().
+ * <pre>
+ * \code
+ * DateFormat* df =
+ * DateFormat::createDateInstance( DateFormat::SHORT, Locale::getFrance());
+ * \endcode
+ * </pre>
+ * You can use a DateFormat to parse also.
+ * <pre>
+ * \code
+ * UErrorCode status = U_ZERO_ERROR;
+ * UDate myDate = df->parse(myString, status);
+ * \endcode
+ * </pre>
+ * Use createDateInstance() to produce the normal date format for that country.
+ * There are other static factory methods available. Use createTimeInstance()
+ * to produce the normal time format for that country. Use createDateTimeInstance()
+ * to produce a DateFormat that formats both date and time. You can pass in
+ * different options to these factory methods to control the length of the
+ * result; from SHORT to MEDIUM to LONG to FULL. The exact result depends on the
+ * locale, but generally:
+ * <ul type=round>
+ * <li> SHORT is completely numeric, such as 12/13/52 or 3:30pm
+ * <li> MEDIUM is longer, such as Jan 12, 1952
+ * <li> LONG is longer, such as January 12, 1952 or 3:30:32pm
+ * <li> FULL is pretty completely specified, such as
+ * Tuesday, April 12, 1952 AD or 3:30:42pm PST.
+ * </ul>
+ * You can also set the time zone on the format if you wish. If you want even
+ * more control over the format or parsing, (or want to give your users more
+ * control), you can try casting the DateFormat you get from the factory methods
+ * to a SimpleDateFormat. This will work for the majority of countries; just
+ * remember to chck getDynamicClassID() before carrying out the cast.
+ * <P>
+ * You can also use forms of the parse and format methods with ParsePosition and
+ * FieldPosition to allow you to
+ * <ul type=round>
+ * <li> Progressively parse through pieces of a string.
+ * <li> Align any particular field, or find out where it is for selection
+ * on the screen.
+ * </ul>
+ *
+ * <p><em>User subclasses are not supported.</em> While clients may write
+ * subclasses, such code will not necessarily work and will not be
+ * guaranteed to work stably from release to release.
+ */
+class U_I18N_API DateFormat : public Format {
+public:
+
+ /**
+ * Constants for various style patterns. These reflect the order of items in
+ * the DateTimePatterns resource. There are 4 time patterns, 4 date patterns,
+ * and then the date-time pattern. Each block of 4 values in the resource occurs
+ * in the order full, long, medium, short.
+ * @stable ICU 2.4
+ */
+ enum EStyle
+ {
+ kNone = -1,
+
+ kFull = 0,
+ kLong = 1,
+ kMedium = 2,
+ kShort = 3,
+
+ kDateOffset = kShort + 1,
+ // kFull + kDateOffset = 4
+ // kLong + kDateOffset = 5
+ // kMedium + kDateOffset = 6
+ // kShort + kDateOffset = 7
+
+ kDateTime = 8,
+
+
+ // relative dates
+ kRelative = (1 << 7),
+
+ kFullRelative = (kFull | kRelative),
+
+ kLongRelative = kLong | kRelative,
+
+ kMediumRelative = kMedium | kRelative,
+
+ kShortRelative = kShort | kRelative,
+
+
+ kDefault = kMedium,
+
+
+
+ /**
+ * These constants are provided for backwards compatibility only.
+ * Please use the C++ style constants defined above.
+ */
+ FULL = kFull,
+ LONG = kLong,
+ MEDIUM = kMedium,
+ SHORT = kShort,
+ DEFAULT = kDefault,
+ DATE_OFFSET = kDateOffset,
+ NONE = kNone,
+ DATE_TIME = kDateTime
+ };
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~DateFormat();
+
+ /**
+ * Equality operator. Returns true if the two formats have the same behavior.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Format&) const;
+
+ /**
+ * Format an object to produce a string. This method handles Formattable
+ * objects with a UDate type. If a the Formattable object type is not a Date,
+ * then it returns a failing UErrorCode.
+ *
+ * @param obj The object to format. Must be a Date.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Formats a date into a date/time string. This is an abstract method which
+ * concrete subclasses must implement.
+ * <P>
+ * On input, the FieldPosition parameter may have its "field" member filled with
+ * an enum value specifying a field. On output, the FieldPosition will be filled
+ * in with the text offsets for that field.
+ * <P> For example, given a time text
+ * "1996.07.10 AD at 15:08:56 PDT", if the given fieldPosition.field is
+ * UDAT_YEAR_FIELD, the offsets fieldPosition.beginIndex and
+ * statfieldPositionus.getEndIndex will be set to 0 and 4, respectively.
+ * <P> Notice
+ * that if the same time field appears more than once in a pattern, the status will
+ * be set for the first occurence of that time field. For instance,
+ * formatting a UDate to the time string "1 PM PDT (Pacific Daylight Time)"
+ * using the pattern "h a z (zzzz)" and the alignment field
+ * DateFormat::TIMEZONE_FIELD, the offsets fieldPosition.beginIndex and
+ * fieldPosition.getEndIndex will be set to 5 and 8, respectively, for the first
+ * occurence of the timezone pattern character 'z'.
+ *
+ * @param cal Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param fieldPosition On input: an alignment field, if desired (see examples above)
+ * On output: the offsets of the alignment field (see examples above)
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.1
+ */
+ virtual UnicodeString& format( Calendar& cal,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition) const = 0;
+
+ /**
+ * Formats a UDate into a date/time string.
+ * <P>
+ * On input, the FieldPosition parameter may have its "field" member filled with
+ * an enum value specifying a field. On output, the FieldPosition will be filled
+ * in with the text offsets for that field.
+ * <P> For example, given a time text
+ * "1996.07.10 AD at 15:08:56 PDT", if the given fieldPosition.field is
+ * UDAT_YEAR_FIELD, the offsets fieldPosition.beginIndex and
+ * statfieldPositionus.getEndIndex will be set to 0 and 4, respectively.
+ * <P> Notice
+ * that if the same time field appears more than once in a pattern, the status will
+ * be set for the first occurence of that time field. For instance,
+ * formatting a UDate to the time string "1 PM PDT (Pacific Daylight Time)"
+ * using the pattern "h a z (zzzz)" and the alignment field
+ * DateFormat::TIMEZONE_FIELD, the offsets fieldPosition.beginIndex and
+ * fieldPosition.getEndIndex will be set to 5 and 8, respectively, for the first
+ * occurence of the timezone pattern character 'z'.
+ *
+ * @param date UDate to be formatted into a date/time string.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param fieldPosition On input: an alignment field, if desired (see examples above)
+ * On output: the offsets of the alignment field (see examples above)
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format( UDate date,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition) const;
+
+ /**
+ * Formats a UDate into a date/time string. If there is a problem, you won't
+ * know, using this method. Use the overloaded format() method which takes a
+ * FieldPosition& to detect formatting problems.
+ *
+ * @param date The UDate value to be formatted into a string.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(UDate date, UnicodeString& appendTo) const;
+
+ /**
+ * Redeclared Format method.
+ *
+ * @param obj The object to be formatted into a string.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const;
+
+ /**
+ * Parse a date/time string.
+ *
+ * @param text The string to be parsed into a UDate value.
+ * @param status Output param to be set to success/failure code. If
+ * 'text' cannot be parsed, it will be set to a failure
+ * code.
+ * @result The parsed UDate value, if successful.
+ * @stable ICU 2.0
+ */
+ virtual UDate parse( const UnicodeString& text,
+ UErrorCode& status) const;
+
+ /**
+ * Parse a date/time string beginning at the given parse position. For
+ * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
+ * that is equivalent to Date(837039928046).
+ * <P>
+ * By default, parsing is lenient: If the input is not in the form used by
+ * this object's format method but can still be parsed as a date, then the
+ * parse succeeds. Clients may insist on strict adherence to the format by
+ * calling setLenient(false).
+ *
+ * @see DateFormat::setLenient(boolean)
+ *
+ * @param text The date/time string to be parsed
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @param pos On input, the position at which to start parsing; on
+ * output, the position at which parsing terminated, or the
+ * start position if the parse failed.
+ * @return A valid UDate if the input could be parsed.
+ * @stable ICU 2.1
+ */
+ virtual void parse( const UnicodeString& text,
+ Calendar& cal,
+ ParsePosition& pos) const = 0;
+
+ /**
+ * Parse a date/time string beginning at the given parse position. For
+ * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
+ * that is equivalent to Date(837039928046).
+ * <P>
+ * By default, parsing is lenient: If the input is not in the form used by
+ * this object's format method but can still be parsed as a date, then the
+ * parse succeeds. Clients may insist on strict adherence to the format by
+ * calling setLenient(false).
+ *
+ * @see DateFormat::setLenient(boolean)
+ *
+ * @param text The date/time string to be parsed
+ * @param pos On input, the position at which to start parsing; on
+ * output, the position at which parsing terminated, or the
+ * start position if the parse failed.
+ * @return A valid UDate if the input could be parsed.
+ * @stable ICU 2.0
+ */
+ UDate parse( const UnicodeString& text,
+ ParsePosition& pos) const;
+
+ /**
+ * Parse a string to produce an object. This methods handles parsing of
+ * date/time strings into Formattable objects with UDate types.
+ * <P>
+ * Before calling, set parse_pos.index to the offset you want to start
+ * parsing at in the source. After calling, parse_pos.index is the end of
+ * the text you parsed. If error occurs, index is unchanged.
+ * <P>
+ * When parsing, leading whitespace is discarded (with a successful parse),
+ * while trailing whitespace is left as is.
+ * <P>
+ * See Format::parseObject() for more.
+ *
+ * @param source The string to be parsed into an object.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param parse_pos The position to start parsing at. Upon return
+ * this param is set to the position after the
+ * last character successfully parsed. If the
+ * source is not parsed successfully, this param
+ * will remain unchanged.
+ * @return A newly created Formattable* object, or NULL
+ * on failure. The caller owns this and should
+ * delete it when done.
+ * @stable ICU 2.0
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& parse_pos) const;
+
+ /**
+ * Create a default date/time formatter that uses the SHORT style for both
+ * the date and the time.
+ *
+ * @return A date/time formatter which the caller owns.
+ * @stable ICU 2.0
+ */
+ static DateFormat* U_EXPORT2 createInstance(void);
+
+ /**
+ * Creates a time formatter with the given formatting style for the given
+ * locale.
+ *
+ * @param style The given formatting style. For example,
+ * SHORT for "h:mm a" in the US locale.
+ * @param aLocale The given locale.
+ * @return A time formatter which the caller owns.
+ * @stable ICU 2.0
+ */
+ static DateFormat* U_EXPORT2 createTimeInstance(EStyle style = kDefault,
+ const Locale& aLocale = Locale::getDefault());
+
+ /**
+ * Creates a date formatter with the given formatting style for the given
+ * const locale.
+ *
+ * @param style The given formatting style. For example,
+ * SHORT for "M/d/yy" in the US locale.
+ * @param aLocale The given locale.
+ * @return A date formatter which the caller owns.
+ * @stable ICU 2.0
+ */
+ static DateFormat* U_EXPORT2 createDateInstance(EStyle style = kDefault,
+ const Locale& aLocale = Locale::getDefault());
+
+ /**
+ * Creates a date/time formatter with the given formatting styles for the
+ * given locale.
+ *
+ * @param dateStyle The given formatting style for the date portion of the result.
+ * For example, SHORT for "M/d/yy" in the US locale.
+ * @param timeStyle The given formatting style for the time portion of the result.
+ * For example, SHORT for "h:mm a" in the US locale.
+ * @param aLocale The given locale.
+ * @return A date/time formatter which the caller owns.
+ * @stable ICU 2.0
+ */
+ static DateFormat* U_EXPORT2 createDateTimeInstance(EStyle dateStyle = kDefault,
+ EStyle timeStyle = kDefault,
+ const Locale& aLocale = Locale::getDefault());
+
+ /**
+ * Gets the set of locales for which DateFormats are installed.
+ * @param count Filled in with the number of locales in the list that is returned.
+ * @return the set of locales for which DateFormats are installed. The caller
+ * does NOT own this list and must not delete it.
+ * @stable ICU 2.0
+ */
+ static const Locale* U_EXPORT2 getAvailableLocales(int32_t& count);
+
+ /**
+ * Returns true if the formatter is set for lenient parsing.
+ * @stable ICU 2.0
+ */
+ virtual UBool isLenient(void) const;
+
+ /**
+ * Specify whether or not date/time parsing is to be lenient. With lenient
+ * parsing, the parser may use heuristics to interpret inputs that do not
+ * precisely match this object's format. With strict parsing, inputs must
+ * match this object's format.
+ *
+ * @param lenient True specifies date/time interpretation to be lenient.
+ * @see Calendar::setLenient
+ * @stable ICU 2.0
+ */
+ virtual void setLenient(UBool lenient);
+
+ /**
+ * Gets the calendar associated with this date/time formatter.
+ * @return the calendar associated with this date/time formatter.
+ * @stable ICU 2.0
+ */
+ virtual const Calendar* getCalendar(void) const;
+
+ /**
+ * Set the calendar to be used by this date format. Initially, the default
+ * calendar for the specified or default locale is used. The caller should
+ * not delete the Calendar object after it is adopted by this call.
+ * Adopting a new calendar will change to the default symbols.
+ *
+ * @param calendarToAdopt Calendar object to be adopted.
+ * @stable ICU 2.0
+ */
+ virtual void adoptCalendar(Calendar* calendarToAdopt);
+
+ /**
+ * Set the calendar to be used by this date format. Initially, the default
+ * calendar for the specified or default locale is used.
+ *
+ * @param newCalendar Calendar object to be set.
+ * @stable ICU 2.0
+ */
+ virtual void setCalendar(const Calendar& newCalendar);
+
+
+ /**
+ * Gets the number formatter which this date/time formatter uses to format
+ * and parse the numeric portions of the pattern.
+ * @return the number formatter which this date/time formatter uses.
+ * @stable ICU 2.0
+ */
+ virtual const NumberFormat* getNumberFormat(void) const;
+
+ /**
+ * Allows you to set the number formatter. The caller should
+ * not delete the NumberFormat object after it is adopted by this call.
+ * @param formatToAdopt NumberFormat object to be adopted.
+ * @stable ICU 2.0
+ */
+ virtual void adoptNumberFormat(NumberFormat* formatToAdopt);
+
+ /**
+ * Allows you to set the number formatter.
+ * @param newNumberFormat NumberFormat object to be set.
+ * @stable ICU 2.0
+ */
+ virtual void setNumberFormat(const NumberFormat& newNumberFormat);
+
+ /**
+ * Returns a reference to the TimeZone used by this DateFormat's calendar.
+ * @return the time zone associated with the calendar of DateFormat.
+ * @stable ICU 2.0
+ */
+ virtual const TimeZone& getTimeZone(void) const;
+
+ /**
+ * Sets the time zone for the calendar of this DateFormat object. The caller
+ * no longer owns the TimeZone object and should not delete it after this call.
+ * @param zoneToAdopt the TimeZone to be adopted.
+ * @stable ICU 2.0
+ */
+ virtual void adoptTimeZone(TimeZone* zoneToAdopt);
+
+ /**
+ * Sets the time zone for the calendar of this DateFormat object.
+ * @param zone the new time zone.
+ * @stable ICU 2.0
+ */
+ virtual void setTimeZone(const TimeZone& zone);
+
+protected:
+ /**
+ * Default constructor. Creates a DateFormat with no Calendar or NumberFormat
+ * associated with it. This constructor depends on the subclasses to fill in
+ * the calendar and numberFormat fields.
+ * @stable ICU 2.0
+ */
+ DateFormat();
+
+ /**
+ * Copy constructor.
+ * @stable ICU 2.0
+ */
+ DateFormat(const DateFormat&);
+
+ /**
+ * Default assignment operator.
+ * @stable ICU 2.0
+ */
+ DateFormat& operator=(const DateFormat&);
+
+ /**
+ * The calendar that DateFormat uses to produce the time field values needed
+ * to implement date/time formatting. Subclasses should generally initialize
+ * this to the default calendar for the locale associated with this DateFormat.
+ * @stable ICU 2.4
+ */
+ Calendar* fCalendar;
+
+ /**
+ * The number formatter that DateFormat uses to format numbers in dates and
+ * times. Subclasses should generally initialize this to the default number
+ * format for the locale associated with this DateFormat.
+ * @stable ICU 2.4
+ */
+ NumberFormat* fNumberFormat;
+
+private:
+ /**
+ * Gets the date/time formatter with the given formatting styles for the
+ * given locale.
+ * @param dateStyle the given date formatting style.
+ * @param timeStyle the given time formatting style.
+ * @param inLocale the given locale.
+ * @return a date/time formatter, or 0 on failure.
+ */
+ static DateFormat* U_EXPORT2 create(EStyle timeStyle, EStyle dateStyle, const Locale&);
+
+public:
+ /**
+ * Field selector for FieldPosition for DateFormat fields.
+ * @obsolete ICU 3.4 use UDateFormatField instead, since this API will be
+ * removed in that release
+ */
+ enum EField
+ {
+ // Obsolete; use UDateFormatField instead
+ kEraField = UDAT_ERA_FIELD,
+ kYearField = UDAT_YEAR_FIELD,
+ kMonthField = UDAT_MONTH_FIELD,
+ kDateField = UDAT_DATE_FIELD,
+ kHourOfDay1Field = UDAT_HOUR_OF_DAY1_FIELD,
+ kHourOfDay0Field = UDAT_HOUR_OF_DAY0_FIELD,
+ kMinuteField = UDAT_MINUTE_FIELD,
+ kSecondField = UDAT_SECOND_FIELD,
+ kMillisecondField = UDAT_FRACTIONAL_SECOND_FIELD,
+ kDayOfWeekField = UDAT_DAY_OF_WEEK_FIELD,
+ kDayOfYearField = UDAT_DAY_OF_YEAR_FIELD,
+ kDayOfWeekInMonthField = UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
+ kWeekOfYearField = UDAT_WEEK_OF_YEAR_FIELD,
+ kWeekOfMonthField = UDAT_WEEK_OF_MONTH_FIELD,
+ kAmPmField = UDAT_AM_PM_FIELD,
+ kHour1Field = UDAT_HOUR1_FIELD,
+ kHour0Field = UDAT_HOUR0_FIELD,
+ kTimezoneField = UDAT_TIMEZONE_FIELD,
+ kYearWOYField = UDAT_YEAR_WOY_FIELD,
+ kDOWLocalField = UDAT_DOW_LOCAL_FIELD,
+ kExtendedYearField = UDAT_EXTENDED_YEAR_FIELD,
+ kJulianDayField = UDAT_JULIAN_DAY_FIELD,
+ kMillisecondsInDayField = UDAT_MILLISECONDS_IN_DAY_FIELD,
+
+ // Obsolete; use UDateFormatField instead
+ ERA_FIELD = UDAT_ERA_FIELD,
+ YEAR_FIELD = UDAT_YEAR_FIELD,
+ MONTH_FIELD = UDAT_MONTH_FIELD,
+ DATE_FIELD = UDAT_DATE_FIELD,
+ HOUR_OF_DAY1_FIELD = UDAT_HOUR_OF_DAY1_FIELD,
+ HOUR_OF_DAY0_FIELD = UDAT_HOUR_OF_DAY0_FIELD,
+ MINUTE_FIELD = UDAT_MINUTE_FIELD,
+ SECOND_FIELD = UDAT_SECOND_FIELD,
+ MILLISECOND_FIELD = UDAT_FRACTIONAL_SECOND_FIELD,
+ DAY_OF_WEEK_FIELD = UDAT_DAY_OF_WEEK_FIELD,
+ DAY_OF_YEAR_FIELD = UDAT_DAY_OF_YEAR_FIELD,
+ DAY_OF_WEEK_IN_MONTH_FIELD = UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
+ WEEK_OF_YEAR_FIELD = UDAT_WEEK_OF_YEAR_FIELD,
+ WEEK_OF_MONTH_FIELD = UDAT_WEEK_OF_MONTH_FIELD,
+ AM_PM_FIELD = UDAT_AM_PM_FIELD,
+ HOUR1_FIELD = UDAT_HOUR1_FIELD,
+ HOUR0_FIELD = UDAT_HOUR0_FIELD,
+ TIMEZONE_FIELD = UDAT_TIMEZONE_FIELD
+ };
+};
+
+inline UnicodeString&
+DateFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ return Format::format(obj, appendTo, status);
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DATEFMT
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/dcfmtsym.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/dcfmtsym.h
new file mode 100644
index 00000000000..bc5547d4cdd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/dcfmtsym.h
@@ -0,0 +1,370 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File DCFMTSYM.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/18/97 clhuang Updated per C++ implementation.
+* 03/27/97 helena Updated to pass the simple test after code review.
+* 08/26/97 aliu Added currency/intl currency symbol support.
+* 07/22/98 stephen Changed to match C++ style
+* currencySymbol -> fCurrencySymbol
+* Constants changed from CAPS to kCaps
+* 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
+* 09/22/00 grhoten Marked deprecation tags with a pointer to replacement
+* functions.
+********************************************************************************
+*/
+
+#ifndef DCFMTSYM_H
+#define DCFMTSYM_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "unicode/locid.h"
+
+/**
+ * \file
+ * \brief C++ API: Symbols for formatting numbers.
+ */
+
+
+U_NAMESPACE_BEGIN
+
+/**
+ * This class represents the set of symbols needed by DecimalFormat
+ * to format numbers. DecimalFormat creates for itself an instance of
+ * DecimalFormatSymbols from its locale data. If you need to change any
+ * of these symbols, you can get the DecimalFormatSymbols object from
+ * your DecimalFormat and modify it.
+ * <P>
+ * Here are the special characters used in the parts of the
+ * subpattern, with notes on their usage.
+ * <pre>
+ * \code
+ * Symbol Meaning
+ * 0 a digit
+ * # a digit, zero shows as absent
+ * . placeholder for decimal separator
+ * , placeholder for grouping separator.
+ * ; separates formats.
+ * - default negative prefix.
+ * % divide by 100 and show as percentage
+ * X any other characters can be used in the prefix or suffix
+ * ' used to quote special characters in a prefix or suffix.
+ * \endcode
+ * </pre>
+ * [Notes]
+ * <P>
+ * If there is no explicit negative subpattern, - is prefixed to the
+ * positive form. That is, "0.00" alone is equivalent to "0.00;-0.00".
+ * <P>
+ * The grouping separator is commonly used for thousands, but in some
+ * countries for ten-thousands. The interval is a constant number of
+ * digits between the grouping characters, such as 100,000,000 or 1,0000,0000.
+ * If you supply a pattern with multiple grouping characters, the interval
+ * between the last one and the end of the integer is the one that is
+ * used. So "#,##,###,####" == "######,####" == "##,####,####".
+ * <P>
+ * This class only handles localized digits where the 10 digits are
+ * contiguous in Unicode, from 0 to 9. Other digits sets (such as
+ * superscripts) would need a different subclass.
+ */
+class U_I18N_API DecimalFormatSymbols : public UObject {
+public:
+ /**
+ * Constants for specifying a number format symbol.
+ * @stable ICU 2.0
+ */
+ enum ENumberFormatSymbol {
+ /** The decimal separator */
+ kDecimalSeparatorSymbol,
+ /** The grouping separator */
+ kGroupingSeparatorSymbol,
+ /** The pattern separator */
+ kPatternSeparatorSymbol,
+ /** The percent sign */
+ kPercentSymbol,
+ /** Zero*/
+ kZeroDigitSymbol,
+ /** Character representing a digit in the pattern */
+ kDigitSymbol,
+ /** The minus sign */
+ kMinusSignSymbol,
+ /** The plus sign */
+ kPlusSignSymbol,
+ /** The currency symbol */
+ kCurrencySymbol,
+ /** The international currency symbol */
+ kIntlCurrencySymbol,
+ /** The monetary separator */
+ kMonetarySeparatorSymbol,
+ /** The exponential symbol */
+ kExponentialSymbol,
+ /** Per mill symbol - replaces kPermillSymbol */
+ kPerMillSymbol,
+ /** Escape padding character */
+ kPadEscapeSymbol,
+ /** Infinity symbol */
+ kInfinitySymbol,
+ /** Nan symbol */
+ kNaNSymbol,
+ /** Significant digit symbol
+ * @stable ICU 3.0 */
+ kSignificantDigitSymbol,
+ /** The monetary grouping separator
+ * @stable ICU 3.6
+ */
+ kMonetaryGroupingSeparatorSymbol,
+ /** count symbol constants */
+ kFormatSymbolCount
+ };
+
+ /**
+ * Create a DecimalFormatSymbols object for the given locale.
+ *
+ * @param locale The locale to get symbols for.
+ * @param status Input/output parameter, set to success or
+ * failure code upon return.
+ * @stable ICU 2.0
+ */
+ DecimalFormatSymbols(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Create a DecimalFormatSymbols object for the default locale.
+ * This constructor will not fail. If the resource file data is
+ * not available, it will use hard-coded last-resort data and
+ * set status to U_USING_FALLBACK_ERROR.
+ *
+ * @param status Input/output parameter, set to success or
+ * failure code upon return.
+ * @stable ICU 2.0
+ */
+ DecimalFormatSymbols( UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ * @stable ICU 2.0
+ */
+ DecimalFormatSymbols(const DecimalFormatSymbols&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 2.0
+ */
+ DecimalFormatSymbols& operator=(const DecimalFormatSymbols&);
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~DecimalFormatSymbols();
+
+ /**
+ * Return true if another object is semantically equal to this one.
+ *
+ * @param other the object to be compared with.
+ * @return true if another object is semantically equal to this one.
+ * @stable ICU 2.0
+ */
+ UBool operator==(const DecimalFormatSymbols& other) const;
+
+ /**
+ * Return true if another object is semantically unequal to this one.
+ *
+ * @param other the object to be compared with.
+ * @return true if another object is semantically unequal to this one.
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const DecimalFormatSymbols& other) const { return !operator==(other); }
+
+ /**
+ * Get one of the format symbols by its enum constant.
+ * Each symbol is stored as a string so that graphemes
+ * (characters with modifyer letters) can be used.
+ *
+ * @param symbol Constant to indicate a number format symbol.
+ * @return the format symbols by the param 'symbol'
+ * @stable ICU 2.0
+ */
+ inline UnicodeString getSymbol(ENumberFormatSymbol symbol) const;
+
+ /**
+ * Set one of the format symbols by its enum constant.
+ * Each symbol is stored as a string so that graphemes
+ * (characters with modifyer letters) can be used.
+ *
+ * @param symbol Constant to indicate a number format symbol.
+ * @param value value of the format sybmol
+ * @stable ICU 2.0
+ */
+ void setSymbol(ENumberFormatSymbol symbol, const UnicodeString &value);
+
+ /**
+ * Returns the locale for which this object was constructed.
+ * @stable ICU 2.6
+ */
+ inline Locale getLocale() const;
+
+ /**
+ * Returns the locale for this object. Two flavors are available:
+ * valid and actual locale.
+ * @stable ICU 2.8
+ */
+ Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+ DecimalFormatSymbols(); // default constructor not implemented
+
+ /**
+ * Initializes the symbols from the LocaleElements resource bundle.
+ * Note: The organization of LocaleElements badly needs to be
+ * cleaned up.
+ *
+ * @param locale The locale to get symbols for.
+ * @param success Input/output parameter, set to success or
+ * failure code upon return.
+ * @param useLastResortData determine if use last resort data
+ */
+ void initialize(const Locale& locale, UErrorCode& success, UBool useLastResortData = FALSE);
+
+ /**
+ * Initialize the symbols from the given array of UnicodeStrings.
+ * The array must be of the correct size.
+ *
+ * @param numberElements the number format symbols
+ * @param numberElementsLength length of numberElements
+ */
+ void initialize(const UChar** numberElements, int32_t *numberElementsStrLen, int32_t numberElementsLength);
+
+ /**
+ * Initialize the symbols with default values.
+ */
+ void initialize();
+
+ void setCurrencyForSymbols();
+
+public:
+ /**
+ * _Internal_ function - more efficient version of getSymbol,
+ * returning a const reference to one of the symbol strings.
+ * The returned reference becomes invalid when the symbol is changed
+ * or when the DecimalFormatSymbols are destroyed.
+ * ### TODO markus 2002oct11: Consider proposing getConstSymbol() to be really public.
+ *
+ * @param symbol Constant to indicate a number format symbol.
+ * @return the format symbol by the param 'symbol'
+ * @internal
+ */
+ inline const UnicodeString &getConstSymbol(ENumberFormatSymbol symbol) const;
+
+ /**
+ * Returns that pattern stored in currecy info. Internal API for use by NumberFormat API.
+ * @internal
+ */
+ inline const UChar* getCurrencyPattern(void) const;
+
+private:
+ /**
+ * Private symbol strings.
+ * They are either loaded from a resource bundle or otherwise owned.
+ * setSymbol() clones the symbol string.
+ * Readonly aliases can only come from a resource bundle, so that we can always
+ * use fastCopyFrom() with them.
+ *
+ * If DecimalFormatSymbols becomes subclassable and the status of fSymbols changes
+ * from private to protected,
+ * or when fSymbols can be set any other way that allows them to be readonly aliases
+ * to non-resource bundle strings,
+ * then regular UnicodeString copies must be used instead of fastCopyFrom().
+ *
+ * @internal
+ */
+ UnicodeString fSymbols[kFormatSymbolCount];
+
+ /**
+ * Non-symbol variable for getConstSymbol(). Always empty.
+ * @internal
+ */
+ UnicodeString fNoSymbol;
+
+ Locale locale;
+
+ char actualLocale[ULOC_FULLNAME_CAPACITY];
+ char validLocale[ULOC_FULLNAME_CAPACITY];
+ const UChar* currPattern;
+};
+
+// -------------------------------------
+
+inline UnicodeString
+DecimalFormatSymbols::getSymbol(ENumberFormatSymbol symbol) const {
+ const UnicodeString *strPtr;
+ if(symbol < kFormatSymbolCount) {
+ strPtr = &fSymbols[symbol];
+ } else {
+ strPtr = &fNoSymbol;
+ }
+ return *strPtr;
+}
+
+inline const UnicodeString &
+DecimalFormatSymbols::getConstSymbol(ENumberFormatSymbol symbol) const {
+ const UnicodeString *strPtr;
+ if(symbol < kFormatSymbolCount) {
+ strPtr = &fSymbols[symbol];
+ } else {
+ strPtr = &fNoSymbol;
+ }
+ return *strPtr;
+}
+
+// -------------------------------------
+
+inline void
+DecimalFormatSymbols::setSymbol(ENumberFormatSymbol symbol, const UnicodeString &value) {
+ if(symbol<kFormatSymbolCount) {
+ fSymbols[symbol]=value;
+ }
+}
+
+// -------------------------------------
+
+inline Locale
+DecimalFormatSymbols::getLocale() const {
+ return locale;
+}
+
+inline const UChar*
+DecimalFormatSymbols::getCurrencyPattern() const {
+ return currPattern;
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DCFMTSYM
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/decimfmt.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/decimfmt.h
new file mode 100644
index 00000000000..296906fb7d7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/decimfmt.h
@@ -0,0 +1,1902 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File DECIMFMT.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/20/97 clhuang Updated per C++ implementation.
+* 04/03/97 aliu Rewrote parsing and formatting completely, and
+* cleaned up and debugged. Actually works now.
+* 04/17/97 aliu Changed DigitCount to int per code review.
+* 07/10/97 helena Made ParsePosition a class and get rid of the function
+* hiding problems.
+* 09/09/97 aliu Ported over support for exponential formats.
+* 07/20/98 stephen Changed documentation
+********************************************************************************
+*/
+
+#ifndef DECIMFMT_H
+#define DECIMFMT_H
+
+#include "unicode/utypes.h"
+/**
+ * \file
+ * \brief C++ API: Formats decimal numbers.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/dcfmtsym.h"
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+
+U_NAMESPACE_BEGIN
+
+class DigitList;
+class ChoiceFormat;
+
+/**
+ * DecimalFormat is a concrete subclass of NumberFormat that formats decimal
+ * numbers. It has a variety of features designed to make it possible to parse
+ * and format numbers in any locale, including support for Western, Arabic, or
+ * Indic digits. It also supports different flavors of numbers, including
+ * integers ("123"), fixed-point numbers ("123.4"), scientific notation
+ * ("1.23E4"), percentages ("12%"), and currency amounts ("$123"). All of these
+ * flavors can be easily localized.
+ *
+ * <p>To obtain a NumberFormat for a specific locale (including the default
+ * locale) call one of NumberFormat's factory methods such as
+ * createInstance(). Do not call the DecimalFormat constructors directly, unless
+ * you know what you are doing, since the NumberFormat factory methods may
+ * return subclasses other than DecimalFormat.
+ *
+ * <p><strong>Example Usage</strong>
+ *
+ * \code
+ * // Normally we would have a GUI with a menu for this
+ * int32_t locCount;
+ * const Locale* locales = NumberFormat::getAvailableLocales(locCount);
+ *
+ * double myNumber = -1234.56;
+ * UErrorCode success = U_ZERO_ERROR;
+ * NumberFormat* form;
+ *
+ * // Print out a number with the localized number, currency and percent
+ * // format for each locale.
+ * UnicodeString countryName;
+ * UnicodeString displayName;
+ * UnicodeString str;
+ * UnicodeString pattern;
+ * Formattable fmtable;
+ * for (int32_t j = 0; j < 3; ++j) {
+ * cout << endl << "FORMAT " << j << endl;
+ * for (int32_t i = 0; i < locCount; ++i) {
+ * if (locales[i].getCountry(countryName).size() == 0) {
+ * // skip language-only
+ * continue;
+ * }
+ * switch (j) {
+ * case 0:
+ * form = NumberFormat::createInstance(locales[i], success ); break;
+ * case 1:
+ * form = NumberFormat::createCurrencyInstance(locales[i], success ); break;
+ * default:
+ * form = NumberFormat::createPercentInstance(locales[i], success ); break;
+ * }
+ * if (form) {
+ * str.remove();
+ * pattern = ((DecimalFormat*)form)->toPattern(pattern);
+ * cout << locales[i].getDisplayName(displayName) << ": " << pattern;
+ * cout << " -> " << form->format(myNumber,str) << endl;
+ * form->parse(form->format(myNumber,str), fmtable, success);
+ * delete form;
+ * }
+ * }
+ * }
+ * \endcode
+ *
+ * <p><strong>Patterns</strong>
+ *
+ * <p>A DecimalFormat consists of a <em>pattern</em> and a set of
+ * <em>symbols</em>. The pattern may be set directly using
+ * applyPattern(), or indirectly using other API methods which
+ * manipulate aspects of the pattern, such as the minimum number of integer
+ * digits. The symbols are stored in a DecimalFormatSymbols
+ * object. When using the NumberFormat factory methods, the
+ * pattern and symbols are read from ICU's locale data.
+ *
+ * <p><strong>Special Pattern Characters</strong>
+ *
+ * <p>Many characters in a pattern are taken literally; they are matched during
+ * parsing and output unchanged during formatting. Special characters, on the
+ * other hand, stand for other characters, strings, or classes of characters.
+ * For example, the '#' character is replaced by a localized digit. Often the
+ * replacement character is the same as the pattern character; in the U.S. locale,
+ * the ',' grouping character is replaced by ','. However, the replacement is
+ * still happening, and if the symbols are modified, the grouping character
+ * changes. Some special characters affect the behavior of the formatter by
+ * their presence; for example, if the percent character is seen, then the
+ * value is multiplied by 100 before being displayed.
+ *
+ * <p>To insert a special character in a pattern as a literal, that is, without
+ * any special meaning, the character must be quoted. There are some exceptions to
+ * this which are noted below.
+ *
+ * <p>The characters listed here are used in non-localized patterns. Localized
+ * patterns use the corresponding characters taken from this formatter's
+ * DecimalFormatSymbols object instead, and these characters lose
+ * their special status. Two exceptions are the currency sign and quote, which
+ * are not localized.
+ *
+ * <table border=0 cellspacing=3 cellpadding=0>
+ * <tr bgcolor="#ccccff">
+ * <td align=left><strong>Symbol</strong>
+ * <td align=left><strong>Location</strong>
+ * <td align=left><strong>Localized?</strong>
+ * <td align=left><strong>Meaning</strong>
+ * <tr valign=top>
+ * <td><code>0</code>
+ * <td>Number
+ * <td>Yes
+ * <td>Digit
+ * <tr valign=top bgcolor="#eeeeff">
+ * <td><code>1-9</code>
+ * <td>Number
+ * <td>Yes
+ * <td>'1' through '9' indicate rounding.
+ * <tr valign=top>
+ * <td><code>\htmlonly&#x40;\endhtmlonly</code> <!--doxygen doesn't like @-->
+ * <td>Number
+ * <td>No
+ * <td>Significant digit
+ * <tr valign=top bgcolor="#eeeeff">
+ * <td><code>#</code>
+ * <td>Number
+ * <td>Yes
+ * <td>Digit, zero shows as absent
+ * <tr valign=top>
+ * <td><code>.</code>
+ * <td>Number
+ * <td>Yes
+ * <td>Decimal separator or monetary decimal separator
+ * <tr valign=top bgcolor="#eeeeff">
+ * <td><code>-</code>
+ * <td>Number
+ * <td>Yes
+ * <td>Minus sign
+ * <tr valign=top>
+ * <td><code>,</code>
+ * <td>Number
+ * <td>Yes
+ * <td>Grouping separator
+ * <tr valign=top bgcolor="#eeeeff">
+ * <td><code>E</code>
+ * <td>Number
+ * <td>Yes
+ * <td>Separates mantissa and exponent in scientific notation.
+ * <em>Need not be quoted in prefix or suffix.</em>
+ * <tr valign=top>
+ * <td><code>+</code>
+ * <td>Exponent
+ * <td>Yes
+ * <td>Prefix positive exponents with localized plus sign.
+ * <em>Need not be quoted in prefix or suffix.</em>
+ * <tr valign=top bgcolor="#eeeeff">
+ * <td><code>;</code>
+ * <td>Subpattern boundary
+ * <td>Yes
+ * <td>Separates positive and negative subpatterns
+ * <tr valign=top>
+ * <td><code>\%</code>
+ * <td>Prefix or suffix
+ * <td>Yes
+ * <td>Multiply by 100 and show as percentage
+ * <tr valign=top bgcolor="#eeeeff">
+ * <td><code>\\u2030</code>
+ * <td>Prefix or suffix
+ * <td>Yes
+ * <td>Multiply by 1000 and show as per mille
+ * <tr valign=top>
+ * <td><code>\htmlonly&curren;\endhtmlonly</code> (<code>\\u00A4</code>)
+ * <td>Prefix or suffix
+ * <td>No
+ * <td>Currency sign, replaced by currency symbol. If
+ * doubled, replaced by international currency symbol.
+ * If present in a pattern, the monetary decimal separator
+ * is used instead of the decimal separator.
+ * <tr valign=top bgcolor="#eeeeff">
+ * <td><code>'</code>
+ * <td>Prefix or suffix
+ * <td>No
+ * <td>Used to quote special characters in a prefix or suffix,
+ * for example, <code>"'#'#"</code> formats 123 to
+ * <code>"#123"</code>. To create a single quote
+ * itself, use two in a row: <code>"# o''clock"</code>.
+ * <tr valign=top>
+ * <td><code>*</code>
+ * <td>Prefix or suffix boundary
+ * <td>Yes
+ * <td>Pad escape, precedes pad character
+ * </table>
+ *
+ * <p>A DecimalFormat pattern contains a postive and negative
+ * subpattern, for example, "#,##0.00;(#,##0.00)". Each subpattern has a
+ * prefix, a numeric part, and a suffix. If there is no explicit negative
+ * subpattern, the negative subpattern is the localized minus sign prefixed to the
+ * positive subpattern. That is, "0.00" alone is equivalent to "0.00;-0.00". If there
+ * is an explicit negative subpattern, it serves only to specify the negative
+ * prefix and suffix; the number of digits, minimal digits, and other
+ * characteristics are ignored in the negative subpattern. That means that
+ * "#,##0.0#;(#)" has precisely the same result as "#,##0.0#;(#,##0.0#)".
+ *
+ * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
+ * thousands separators, decimal separators, etc. may be set to arbitrary
+ * values, and they will appear properly during formatting. However, care must
+ * be taken that the symbols and strings do not conflict, or parsing will be
+ * unreliable. For example, either the positive and negative prefixes or the
+ * suffixes must be distinct for parse() to be able
+ * to distinguish positive from negative values. Another example is that the
+ * decimal separator and thousands separator should be distinct characters, or
+ * parsing will be impossible.
+ *
+ * <p>The <em>grouping separator</em> is a character that separates clusters of
+ * integer digits to make large numbers more legible. It commonly used for
+ * thousands, but in some locales it separates ten-thousands. The <em>grouping
+ * size</em> is the number of digits between the grouping separators, such as 3
+ * for "100,000,000" or 4 for "1 0000 0000". There are actually two different
+ * grouping sizes: One used for the least significant integer digits, the
+ * <em>primary grouping size</em>, and one used for all others, the
+ * <em>secondary grouping size</em>. In most locales these are the same, but
+ * sometimes they are different. For example, if the primary grouping interval
+ * is 3, and the secondary is 2, then this corresponds to the pattern
+ * "#,##,##0", and the number 123456789 is formatted as "12,34,56,789". If a
+ * pattern contains multiple grouping separators, the interval between the last
+ * one and the end of the integer defines the primary grouping size, and the
+ * interval between the last two defines the secondary grouping size. All others
+ * are ignored, so "#,##,###,####" == "###,###,####" == "##,#,###,####".
+ *
+ * <p>Illegal patterns, such as "#.#.#" or "#.###,###", will cause
+ * DecimalFormat to set a failing UErrorCode.
+ *
+ * <p><strong>Pattern BNF</strong>
+ *
+ * <pre>
+ * pattern := subpattern (';' subpattern)?
+ * subpattern := prefix? number exponent? suffix?
+ * number := (integer ('.' fraction)?) | sigDigits
+ * prefix := '\\u0000'..'\\uFFFD' - specialCharacters
+ * suffix := '\\u0000'..'\\uFFFD' - specialCharacters
+ * integer := '#'* '0'* '0'
+ * fraction := '0'* '#'*
+ * sigDigits := '#'* '@' '@'* '#'*
+ * exponent := 'E' '+'? '0'* '0'
+ * padSpec := '*' padChar
+ * padChar := '\\u0000'..'\\uFFFD' - quote
+ * &nbsp;
+ * Notation:
+ * X* 0 or more instances of X
+ * X? 0 or 1 instances of X
+ * X|Y either X or Y
+ * C..D any character from C up to D, inclusive
+ * S-T characters in S, except those in T
+ * </pre>
+ * The first subpattern is for positive numbers. The second (optional)
+ * subpattern is for negative numbers.
+ *
+ * <p>Not indicated in the BNF syntax above:
+ *
+ * <ul><li>The grouping separator ',' can occur inside the integer and
+ * sigDigits elements, between any two pattern characters of that
+ * element, as long as the integer or sigDigits element is not
+ * followed by the exponent element.
+ *
+ * <li>Two grouping intervals are recognized: That between the
+ * decimal point and the first grouping symbol, and that
+ * between the first and second grouping symbols. These
+ * intervals are identical in most locales, but in some
+ * locales they differ. For example, the pattern
+ * &quot;#,##,###&quot; formats the number 123456789 as
+ * &quot;12,34,56,789&quot;.</li>
+ *
+ * <li>The pad specifier <code>padSpec</code> may appear before the prefix,
+ * after the prefix, before the suffix, after the suffix, or not at all.
+ *
+ * <li>In place of '0', the digits '1' through '9' may be used to
+ * indicate a rounding increment.
+ * </ul>
+ *
+ * <p><strong>Parsing</strong>
+ *
+ * <p>DecimalFormat parses all Unicode characters that represent
+ * decimal digits, as defined by u_charDigitValue(). In addition,
+ * DecimalFormat also recognizes as digits the ten consecutive
+ * characters starting with the localized zero digit defined in the
+ * DecimalFormatSymbols object. During formatting, the
+ * DecimalFormatSymbols-based digits are output.
+ *
+ * <p>During parsing, grouping separators are ignored.
+ *
+ * <p>If parse(UnicodeString&,Formattable&,ParsePosition&)
+ * fails to parse a string, it leaves the parse position unchanged.
+ * The convenience method parse(UnicodeString&,Formattable&,UErrorCode&)
+ * indicates parse failure by setting a failing
+ * UErrorCode.
+ *
+ * <p><strong>Formatting</strong>
+ *
+ * <p>Formatting is guided by several parameters, all of which can be
+ * specified either using a pattern or using the API. The following
+ * description applies to formats that do not use <a href="#sci">scientific
+ * notation</a> or <a href="#sigdig">significant digits</a>.
+ *
+ * <ul><li>If the number of actual integer digits exceeds the
+ * <em>maximum integer digits</em>, then only the least significant
+ * digits are shown. For example, 1997 is formatted as "97" if the
+ * maximum integer digits is set to 2.
+ *
+ * <li>If the number of actual integer digits is less than the
+ * <em>minimum integer digits</em>, then leading zeros are added. For
+ * example, 1997 is formatted as "01997" if the minimum integer digits
+ * is set to 5.
+ *
+ * <li>If the number of actual fraction digits exceeds the <em>maximum
+ * fraction digits</em>, then half-even rounding it performed to the
+ * maximum fraction digits. For example, 0.125 is formatted as "0.12"
+ * if the maximum fraction digits is 2. This behavior can be changed
+ * by specifying a rounding increment and a rounding mode.
+ *
+ * <li>If the number of actual fraction digits is less than the
+ * <em>minimum fraction digits</em>, then trailing zeros are added.
+ * For example, 0.125 is formatted as "0.1250" if the mimimum fraction
+ * digits is set to 4.
+ *
+ * <li>Trailing fractional zeros are not displayed if they occur
+ * <em>j</em> positions after the decimal, where <em>j</em> is less
+ * than the maximum fraction digits. For example, 0.10004 is
+ * formatted as "0.1" if the maximum fraction digits is four or less.
+ * </ul>
+ *
+ * <p><strong>Special Values</strong>
+ *
+ * <p><code>NaN</code> is represented as a single character, typically
+ * <code>\\uFFFD</code>. This character is determined by the
+ * DecimalFormatSymbols object. This is the only value for which
+ * the prefixes and suffixes are not used.
+ *
+ * <p>Infinity is represented as a single character, typically
+ * <code>\\u221E</code>, with the positive or negative prefixes and suffixes
+ * applied. The infinity character is determined by the
+ * DecimalFormatSymbols object.
+ *
+ * <a name="sci"><strong>Scientific Notation</strong></a>
+ *
+ * <p>Numbers in scientific notation are expressed as the product of a mantissa
+ * and a power of ten, for example, 1234 can be expressed as 1.234 x 10<sup>3</sup>. The
+ * mantissa is typically in the half-open interval [1.0, 10.0) or sometimes [0.0, 1.0),
+ * but it need not be. DecimalFormat supports arbitrary mantissas.
+ * DecimalFormat can be instructed to use scientific
+ * notation through the API or through the pattern. In a pattern, the exponent
+ * character immediately followed by one or more digit characters indicates
+ * scientific notation. Example: "0.###E0" formats the number 1234 as
+ * "1.234E3".
+ *
+ * <ul>
+ * <li>The number of digit characters after the exponent character gives the
+ * minimum exponent digit count. There is no maximum. Negative exponents are
+ * formatted using the localized minus sign, <em>not</em> the prefix and suffix
+ * from the pattern. This allows patterns such as "0.###E0 m/s". To prefix
+ * positive exponents with a localized plus sign, specify '+' between the
+ * exponent and the digits: "0.###E+0" will produce formats "1E+1", "1E+0",
+ * "1E-1", etc. (In localized patterns, use the localized plus sign rather than
+ * '+'.)
+ *
+ * <li>The minimum number of integer digits is achieved by adjusting the
+ * exponent. Example: 0.00123 formatted with "00.###E0" yields "12.3E-4". This
+ * only happens if there is no maximum number of integer digits. If there is a
+ * maximum, then the minimum number of integer digits is fixed at one.
+ *
+ * <li>The maximum number of integer digits, if present, specifies the exponent
+ * grouping. The most common use of this is to generate <em>engineering
+ * notation</em>, in which the exponent is a multiple of three, e.g.,
+ * "##0.###E0". The number 12345 is formatted using "##0.####E0" as "12.345E3".
+ *
+ * <li>When using scientific notation, the formatter controls the
+ * digit counts using significant digits logic. The maximum number of
+ * significant digits limits the total number of integer and fraction
+ * digits that will be shown in the mantissa; it does not affect
+ * parsing. For example, 12345 formatted with "##0.##E0" is "12.3E3".
+ * See the section on significant digits for more details.
+ *
+ * <li>The number of significant digits shown is determined as
+ * follows: If areSignificantDigitsUsed() returns false, then the
+ * minimum number of significant digits shown is one, and the maximum
+ * number of significant digits shown is the sum of the <em>minimum
+ * integer</em> and <em>maximum fraction</em> digits, and is
+ * unaffected by the maximum integer digits. If this sum is zero,
+ * then all significant digits are shown. If
+ * areSignificantDigitsUsed() returns true, then the significant digit
+ * counts are specified by getMinimumSignificantDigits() and
+ * getMaximumSignificantDigits(). In this case, the number of
+ * integer digits is fixed at one, and there is no exponent grouping.
+ *
+ * <li>Exponential patterns may not contain grouping separators.
+ * </ul>
+ *
+ * <a name="sigdig"><strong>Significant Digits</strong></a>
+ *
+ * <code>DecimalFormat</code> has two ways of controlling how many
+ * digits are shows: (a) significant digits counts, or (b) integer and
+ * fraction digit counts. Integer and fraction digit counts are
+ * described above. When a formatter is using significant digits
+ * counts, the number of integer and fraction digits is not specified
+ * directly, and the formatter settings for these counts are ignored.
+ * Instead, the formatter uses however many integer and fraction
+ * digits are required to display the specified number of significant
+ * digits. Examples:
+ *
+ * <table border=0 cellspacing=3 cellpadding=0>
+ * <tr bgcolor="#ccccff">
+ * <td align=left>Pattern
+ * <td align=left>Minimum significant digits
+ * <td align=left>Maximum significant digits
+ * <td align=left>Number
+ * <td align=left>Output of format()
+ * <tr valign=top>
+ * <td><code>\@\@\@</code>
+ * <td>3
+ * <td>3
+ * <td>12345
+ * <td><code>12300</code>
+ * <tr valign=top bgcolor="#eeeeff">
+ * <td><code>\@\@\@</code>
+ * <td>3
+ * <td>3
+ * <td>0.12345
+ * <td><code>0.123</code>
+ * <tr valign=top>
+ * <td><code>\@\@##</code>
+ * <td>2
+ * <td>4
+ * <td>3.14159
+ * <td><code>3.142</code>
+ * <tr valign=top bgcolor="#eeeeff">
+ * <td><code>\@\@##</code>
+ * <td>2
+ * <td>4
+ * <td>1.23004
+ * <td><code>1.23</code>
+ * </table>
+ *
+ * <ul>
+ * <li>Significant digit counts may be expressed using patterns that
+ * specify a minimum and maximum number of significant digits. These
+ * are indicated by the <code>'@'</code> and <code>'#'</code>
+ * characters. The minimum number of significant digits is the number
+ * of <code>'@'</code> characters. The maximum number of significant
+ * digits is the number of <code>'@'</code> characters plus the number
+ * of <code>'#'</code> characters following on the right. For
+ * example, the pattern <code>"@@@"</code> indicates exactly 3
+ * significant digits. The pattern <code>"@##"</code> indicates from
+ * 1 to 3 significant digits. Trailing zero digits to the right of
+ * the decimal separator are suppressed after the minimum number of
+ * significant digits have been shown. For example, the pattern
+ * <code>"@##"</code> formats the number 0.1203 as
+ * <code>"0.12"</code>.
+ *
+ * <li>If a pattern uses significant digits, it may not contain a
+ * decimal separator, nor the <code>'0'</code> pattern character.
+ * Patterns such as <code>"@00"</code> or <code>"@.###"</code> are
+ * disallowed.
+ *
+ * <li>Any number of <code>'#'</code> characters may be prepended to
+ * the left of the leftmost <code>'@'</code> character. These have no
+ * effect on the minimum and maximum significant digits counts, but
+ * may be used to position grouping separators. For example,
+ * <code>"#,#@#"</code> indicates a minimum of one significant digits,
+ * a maximum of two significant digits, and a grouping size of three.
+ *
+ * <li>In order to enable significant digits formatting, use a pattern
+ * containing the <code>'@'</code> pattern character. Alternatively,
+ * call setSignificantDigitsUsed(TRUE).
+ *
+ * <li>In order to disable significant digits formatting, use a
+ * pattern that does not contain the <code>'@'</code> pattern
+ * character. Alternatively, call setSignificantDigitsUsed(FALSE).
+ *
+ * <li>The number of significant digits has no effect on parsing.
+ *
+ * <li>Significant digits may be used together with exponential notation. Such
+ * patterns are equivalent to a normal exponential pattern with a minimum and
+ * maximum integer digit count of one, a minimum fraction digit count of
+ * <code>getMinimumSignificantDigits() - 1</code>, and a maximum fraction digit
+ * count of <code>getMaximumSignificantDigits() - 1</code>. For example, the
+ * pattern <code>"@@###E0"</code> is equivalent to <code>"0.0###E0"</code>.
+ *
+ * <li>If signficant digits are in use, then the integer and fraction
+ * digit counts, as set via the API, are ignored. If significant
+ * digits are not in use, then the signficant digit counts, as set via
+ * the API, are ignored.
+ *
+ * </ul>
+ *
+ * <p><strong>Padding</strong>
+ *
+ * <p>DecimalFormat supports padding the result of
+ * format() to a specific width. Padding may be specified either
+ * through the API or through the pattern syntax. In a pattern the pad escape
+ * character, followed by a single pad character, causes padding to be parsed
+ * and formatted. The pad escape character is '*' in unlocalized patterns, and
+ * can be localized using DecimalFormatSymbols::setSymbol() with a
+ * DecimalFormatSymbols::kPadEscapeSymbol
+ * selector. For example, <code>"$*x#,##0.00"</code> formats 123 to
+ * <code>"$xx123.00"</code>, and 1234 to <code>"$1,234.00"</code>.
+ *
+ * <ul>
+ * <li>When padding is in effect, the width of the positive subpattern,
+ * including prefix and suffix, determines the format width. For example, in
+ * the pattern <code>"* #0 o''clock"</code>, the format width is 10.
+ *
+ * <li>The width is counted in 16-bit code units (UChars).
+ *
+ * <li>Some parameters which usually do not matter have meaning when padding is
+ * used, because the pattern width is significant with padding. In the pattern
+ * "* ##,##,#,##0.##", the format width is 14. The initial characters "##,##,"
+ * do not affect the grouping size or maximum integer digits, but they do affect
+ * the format width.
+ *
+ * <li>Padding may be inserted at one of four locations: before the prefix,
+ * after the prefix, before the suffix, or after the suffix. If padding is
+ * specified in any other location, applyPattern()
+ * sets a failing UErrorCode. If there is no prefix,
+ * before the prefix and after the prefix are equivalent, likewise for the
+ * suffix.
+ *
+ * <li>When specified in a pattern, the 32-bit code point immediately
+ * following the pad escape is the pad character. This may be any character,
+ * including a special pattern character. That is, the pad escape
+ * <em>escapes</em> the following character. If there is no character after
+ * the pad escape, then the pattern is illegal.
+ *
+ * </ul>
+ *
+ * <p><strong>Rounding</strong>
+ *
+ * <p>DecimalFormat supports rounding to a specific increment. For
+ * example, 1230 rounded to the nearest 50 is 1250. 1.234 rounded to the
+ * nearest 0.65 is 1.3. The rounding increment may be specified through the API
+ * or in a pattern. To specify a rounding increment in a pattern, include the
+ * increment in the pattern itself. "#,#50" specifies a rounding increment of
+ * 50. "#,##0.05" specifies a rounding increment of 0.05.
+ *
+ * <ul>
+ * <li>Rounding only affects the string produced by formatting. It does
+ * not affect parsing or change any numerical values.
+ *
+ * <li>A <em>rounding mode</em> determines how values are rounded; see
+ * DecimalFormat::ERoundingMode. Rounding increments specified in
+ * patterns use the default mode, DecimalFormat::kRoundHalfEven.
+ *
+ * <li>Some locales use rounding in their currency formats to reflect the
+ * smallest currency denomination.
+ *
+ * <li>In a pattern, digits '1' through '9' specify rounding, but otherwise
+ * behave identically to digit '0'.
+ * </ul>
+ *
+ * <p><strong>Synchronization</strong>
+ *
+ * <p>DecimalFormat objects are not synchronized. Multiple
+ * threads should not access one formatter concurrently.
+ *
+ * <p><strong>Subclassing</strong>
+ *
+ * <p><em>User subclasses are not supported.</em> While clients may write
+ * subclasses, such code will not necessarily work and will not be
+ * guaranteed to work stably from release to release.
+ */
+class U_I18N_API DecimalFormat: public NumberFormat {
+public:
+ /**
+ * Rounding mode.
+ * @stable ICU 2.4
+ */
+ enum ERoundingMode {
+ kRoundCeiling, /**< Round towards positive infinity */
+ kRoundFloor, /**< Round towards negative infinity */
+ kRoundDown, /**< Round towards zero */
+ kRoundUp, /**< Round away from zero */
+ kRoundHalfEven, /**< Round towards the nearest integer, or
+ towards the nearest even integer if equidistant */
+ kRoundHalfDown, /**< Round towards the nearest integer, or
+ towards zero if equidistant */
+ kRoundHalfUp /**< Round towards the nearest integer, or
+ away from zero if equidistant */
+ // We don't support ROUND_UNNECESSARY
+ };
+
+ /**
+ * Pad position.
+ * @stable ICU 2.4
+ */
+ enum EPadPosition {
+ kPadBeforePrefix,
+ kPadAfterPrefix,
+ kPadBeforeSuffix,
+ kPadAfterSuffix
+ };
+
+ /**
+ * Create a DecimalFormat using the default pattern and symbols
+ * for the default locale. This is a convenient way to obtain a
+ * DecimalFormat when internationalization is not the main concern.
+ * <P>
+ * To obtain standard formats for a given locale, use the factory methods
+ * on NumberFormat such as createInstance. These factories will
+ * return the most appropriate sub-class of NumberFormat for a given
+ * locale.
+ * @param status Output param set to success/failure code. If the
+ * pattern is invalid this will be set to a failure code.
+ * @stable ICU 2.0
+ */
+ DecimalFormat(UErrorCode& status);
+
+ /**
+ * Create a DecimalFormat from the given pattern and the symbols
+ * for the default locale. This is a convenient way to obtain a
+ * DecimalFormat when internationalization is not the main concern.
+ * <P>
+ * To obtain standard formats for a given locale, use the factory methods
+ * on NumberFormat such as createInstance. These factories will
+ * return the most appropriate sub-class of NumberFormat for a given
+ * locale.
+ * @param pattern A non-localized pattern string.
+ * @param status Output param set to success/failure code. If the
+ * pattern is invalid this will be set to a failure code.
+ * @stable ICU 2.0
+ */
+ DecimalFormat(const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Create a DecimalFormat from the given pattern and symbols.
+ * Use this constructor when you need to completely customize the
+ * behavior of the format.
+ * <P>
+ * To obtain standard formats for a given
+ * locale, use the factory methods on NumberFormat such as
+ * createInstance or createCurrencyInstance. If you need only minor adjustments
+ * to a standard format, you can modify the format returned by
+ * a NumberFormat factory method.
+ *
+ * @param pattern a non-localized pattern string
+ * @param symbolsToAdopt the set of symbols to be used. The caller should not
+ * delete this object after making this call.
+ * @param status Output param set to success/failure code. If the
+ * pattern is invalid this will be set to a failure code.
+ * @stable ICU 2.0
+ */
+ DecimalFormat( const UnicodeString& pattern,
+ DecimalFormatSymbols* symbolsToAdopt,
+ UErrorCode& status);
+
+ /**
+ * Create a DecimalFormat from the given pattern and symbols.
+ * Use this constructor when you need to completely customize the
+ * behavior of the format.
+ * <P>
+ * To obtain standard formats for a given
+ * locale, use the factory methods on NumberFormat such as
+ * createInstance or createCurrencyInstance. If you need only minor adjustments
+ * to a standard format, you can modify the format returned by
+ * a NumberFormat factory method.
+ *
+ * @param pattern a non-localized pattern string
+ * @param symbolsToAdopt the set of symbols to be used. The caller should not
+ * delete this object after making this call.
+ * @param parseError Output param to receive errors occured during parsing
+ * @param status Output param set to success/failure code. If the
+ * pattern is invalid this will be set to a failure code.
+ * @stable ICU 2.0
+ */
+ DecimalFormat( const UnicodeString& pattern,
+ DecimalFormatSymbols* symbolsToAdopt,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Create a DecimalFormat from the given pattern and symbols.
+ * Use this constructor when you need to completely customize the
+ * behavior of the format.
+ * <P>
+ * To obtain standard formats for a given
+ * locale, use the factory methods on NumberFormat such as
+ * createInstance or createCurrencyInstance. If you need only minor adjustments
+ * to a standard format, you can modify the format returned by
+ * a NumberFormat factory method.
+ *
+ * @param pattern a non-localized pattern string
+ * @param symbols the set of symbols to be used
+ * @param status Output param set to success/failure code. If the
+ * pattern is invalid this will be set to a failure code.
+ * @stable ICU 2.0
+ */
+ DecimalFormat( const UnicodeString& pattern,
+ const DecimalFormatSymbols& symbols,
+ UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ *
+ * @param source the DecimalFormat object to be copied from.
+ * @stable ICU 2.0
+ */
+ DecimalFormat(const DecimalFormat& source);
+
+ /**
+ * Assignment operator.
+ *
+ * @param rhs the DecimalFormat object to be copied.
+ * @stable ICU 2.0
+ */
+ DecimalFormat& operator=(const DecimalFormat& rhs);
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~DecimalFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the
+ * result and should delete it when done.
+ *
+ * @return a polymorphic copy of this DecimalFormat.
+ * @stable ICU 2.0
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Return true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ *
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Format a double or long number using base-10 representation.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+ /**
+ * Format a long number using base-10 representation.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+ /**
+ * Format an int64 number using base-10 representation.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.8
+ */
+ virtual UnicodeString& format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format a Formattable using base-10 representation.
+ *
+ * @param obj The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Error code indicating success or failure.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * Formats an object to produce a string.
+ *
+ * @param obj The object to format.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Output parameter filled in with success or failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * Format a double number.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(double number,
+ UnicodeString& appendTo) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * Format a long number. These methods call the NumberFormat
+ * pure virtual format() methods with the default FieldPosition.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(int32_t number,
+ UnicodeString& appendTo) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * Format an int64 number. These methods call the NumberFormat
+ * pure virtual format() methods with the default FieldPosition.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.8
+ */
+ UnicodeString& format(int64_t number,
+ UnicodeString& appendTo) const;
+ /**
+ * Parse the given string using this object's choices. The method
+ * does string comparisons to try to find an optimal match.
+ * If no object can be parsed, index is unchanged, and NULL is
+ * returned. The result is returned as the most parsimonious
+ * type of Formattable that will accomodate all of the
+ * necessary precision. For example, if the result is exactly 12,
+ * it will be returned as a long. However, if it is 1.5, it will
+ * be returned as a double.
+ *
+ * @param text The text to be parsed.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param parsePosition The position to start parsing at on input.
+ * On output, moved to after the last successfully
+ * parse character. On parse failure, does not change.
+ * @see Formattable
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& parsePosition) const;
+
+ // Declare here again to get rid of function hiding problems.
+ /**
+ * Parse the given string using this object's choices.
+ *
+ * @param text The text to be parsed.
+ * @param result Formattable to be set to the parse result.
+ * @param status Output parameter filled in with success or failure status.
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const;
+
+ /**
+ * Parses text from the given string as a currency amount. Unlike
+ * the parse() method, this method will attempt to parse a generic
+ * currency name, searching for a match of this object's locale's
+ * currency display names, or for a 3-letter ISO currency code.
+ * This method will fail if this format is not a currency format,
+ * that is, if it does not contain the currency pattern symbol
+ * (U+00A4) in its prefix or suffix.
+ *
+ * @param text the string to parse
+ * @param result output parameter to receive result. This will have
+ * its currency set to the parsed ISO currency code.
+ * @param pos input-output position; on input, the position within
+ * text to match; must have 0 <= pos.getIndex() < text.length();
+ * on output, the position after the last matched character. If
+ * the parse fails, the position in unchanged upon output.
+ * @return a reference to result
+ * @internal
+ */
+ virtual Formattable& parseCurrency(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& pos) const;
+
+ /**
+ * Returns the decimal format symbols, which is generally not changed
+ * by the programmer or user.
+ * @return desired DecimalFormatSymbols
+ * @see DecimalFormatSymbols
+ * @stable ICU 2.0
+ */
+ virtual const DecimalFormatSymbols* getDecimalFormatSymbols(void) const;
+
+ /**
+ * Sets the decimal format symbols, which is generally not changed
+ * by the programmer or user.
+ * @param symbolsToAdopt DecimalFormatSymbols to be adopted.
+ * @stable ICU 2.0
+ */
+ virtual void adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt);
+
+ /**
+ * Sets the decimal format symbols, which is generally not changed
+ * by the programmer or user.
+ * @param symbols DecimalFormatSymbols.
+ * @stable ICU 2.0
+ */
+ virtual void setDecimalFormatSymbols(const DecimalFormatSymbols& symbols);
+
+
+ /**
+ * Get the positive prefix.
+ *
+ * @param result Output param which will receive the positive prefix.
+ * @return A reference to 'result'.
+ * Examples: +123, $123, sFr123
+ * @stable ICU 2.0
+ */
+ UnicodeString& getPositivePrefix(UnicodeString& result) const;
+
+ /**
+ * Set the positive prefix.
+ *
+ * @param newValue the new value of the the positive prefix to be set.
+ * Examples: +123, $123, sFr123
+ * @stable ICU 2.0
+ */
+ virtual void setPositivePrefix(const UnicodeString& newValue);
+
+ /**
+ * Get the negative prefix.
+ *
+ * @param result Output param which will receive the negative prefix.
+ * @return A reference to 'result'.
+ * Examples: -123, ($123) (with negative suffix), sFr-123
+ * @stable ICU 2.0
+ */
+ UnicodeString& getNegativePrefix(UnicodeString& result) const;
+
+ /**
+ * Set the negative prefix.
+ *
+ * @param newValue the new value of the the negative prefix to be set.
+ * Examples: -123, ($123) (with negative suffix), sFr-123
+ * @stable ICU 2.0
+ */
+ virtual void setNegativePrefix(const UnicodeString& newValue);
+
+ /**
+ * Get the positive suffix.
+ *
+ * @param result Output param which will receive the positive suffix.
+ * @return A reference to 'result'.
+ * Example: 123%
+ * @stable ICU 2.0
+ */
+ UnicodeString& getPositiveSuffix(UnicodeString& result) const;
+
+ /**
+ * Set the positive suffix.
+ *
+ * @param newValue the new value of the positive suffix to be set.
+ * Example: 123%
+ * @stable ICU 2.0
+ */
+ virtual void setPositiveSuffix(const UnicodeString& newValue);
+
+ /**
+ * Get the negative suffix.
+ *
+ * @param result Output param which will receive the negative suffix.
+ * @return A reference to 'result'.
+ * Examples: -123%, ($123) (with positive suffixes)
+ * @stable ICU 2.0
+ */
+ UnicodeString& getNegativeSuffix(UnicodeString& result) const;
+
+ /**
+ * Set the negative suffix.
+ *
+ * @param newValue the new value of the negative suffix to be set.
+ * Examples: 123%
+ * @stable ICU 2.0
+ */
+ virtual void setNegativeSuffix(const UnicodeString& newValue);
+
+ /**
+ * Get the multiplier for use in percent, permill, etc.
+ * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
+ * (For Arabic, use arabic percent symbol).
+ * For a permill, set the suffixes to have "\\u2031" and the multiplier to be 1000.
+ *
+ * @return the multiplier for use in percent, permill, etc.
+ * Examples: with 100, 1.23 -> "123", and "123" -> 1.23
+ * @stable ICU 2.0
+ */
+ int32_t getMultiplier(void) const;
+
+ /**
+ * Set the multiplier for use in percent, permill, etc.
+ * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
+ * (For Arabic, use arabic percent symbol).
+ * For a permill, set the suffixes to have "\\u2031" and the multiplier to be 1000.
+ *
+ * @param newValue the new value of the multiplier for use in percent, permill, etc.
+ * Examples: with 100, 1.23 -> "123", and "123" -> 1.23
+ * @stable ICU 2.0
+ */
+ virtual void setMultiplier(int32_t newValue);
+
+ /**
+ * Get the rounding increment.
+ * @return A positive rounding increment, or 0.0 if rounding
+ * is not in effect.
+ * @see #setRoundingIncrement
+ * @see #getRoundingMode
+ * @see #setRoundingMode
+ * @stable ICU 2.0
+ */
+ virtual double getRoundingIncrement(void) const;
+
+ /**
+ * Set the rounding increment. This method also controls whether
+ * rounding is enabled.
+ * @param newValue A positive rounding increment, or 0.0 to disable rounding.
+ * Negative increments are equivalent to 0.0.
+ * @see #getRoundingIncrement
+ * @see #getRoundingMode
+ * @see #setRoundingMode
+ * @stable ICU 2.0
+ */
+ virtual void setRoundingIncrement(double newValue);
+
+ /**
+ * Get the rounding mode.
+ * @return A rounding mode
+ * @see #setRoundingIncrement
+ * @see #getRoundingIncrement
+ * @see #setRoundingMode
+ * @stable ICU 2.0
+ */
+ virtual ERoundingMode getRoundingMode(void) const;
+
+ /**
+ * Set the rounding mode. This has no effect unless the rounding
+ * increment is greater than zero.
+ * @param roundingMode A rounding mode
+ * @see #setRoundingIncrement
+ * @see #getRoundingIncrement
+ * @see #getRoundingMode
+ * @stable ICU 2.0
+ */
+ virtual void setRoundingMode(ERoundingMode roundingMode);
+
+ /**
+ * Get the width to which the output of format() is padded.
+ * The width is counted in 16-bit code units.
+ * @return the format width, or zero if no padding is in effect
+ * @see #setFormatWidth
+ * @see #getPadCharacterString
+ * @see #setPadCharacter
+ * @see #getPadPosition
+ * @see #setPadPosition
+ * @stable ICU 2.0
+ */
+ virtual int32_t getFormatWidth(void) const;
+
+ /**
+ * Set the width to which the output of format() is padded.
+ * The width is counted in 16-bit code units.
+ * This method also controls whether padding is enabled.
+ * @param width the width to which to pad the result of
+ * format(), or zero to disable padding. A negative
+ * width is equivalent to 0.
+ * @see #getFormatWidth
+ * @see #getPadCharacterString
+ * @see #setPadCharacter
+ * @see #getPadPosition
+ * @see #setPadPosition
+ * @stable ICU 2.0
+ */
+ virtual void setFormatWidth(int32_t width);
+
+ /**
+ * Get the pad character used to pad to the format width. The
+ * default is ' '.
+ * @return a string containing the pad character. This will always
+ * have a length of one 32-bit code point.
+ * @see #setFormatWidth
+ * @see #getFormatWidth
+ * @see #setPadCharacter
+ * @see #getPadPosition
+ * @see #setPadPosition
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString getPadCharacterString() const;
+
+ /**
+ * Set the character used to pad to the format width. If padding
+ * is not enabled, then this will take effect if padding is later
+ * enabled.
+ * @param padChar a string containing the pad charcter. If the string
+ * has length 0, then the pad characer is set to ' '. Otherwise
+ * padChar.char32At(0) will be used as the pad character.
+ * @see #setFormatWidth
+ * @see #getFormatWidth
+ * @see #getPadCharacterString
+ * @see #getPadPosition
+ * @see #setPadPosition
+ * @stable ICU 2.0
+ */
+ virtual void setPadCharacter(const UnicodeString &padChar);
+
+ /**
+ * Get the position at which padding will take place. This is the location
+ * at which padding will be inserted if the result of format()
+ * is shorter than the format width.
+ * @return the pad position, one of kPadBeforePrefix,
+ * kPadAfterPrefix, kPadBeforeSuffix, or
+ * kPadAfterSuffix.
+ * @see #setFormatWidth
+ * @see #getFormatWidth
+ * @see #setPadCharacter
+ * @see #getPadCharacterString
+ * @see #setPadPosition
+ * @see #kPadBeforePrefix
+ * @see #kPadAfterPrefix
+ * @see #kPadBeforeSuffix
+ * @see #kPadAfterSuffix
+ * @stable ICU 2.0
+ */
+ virtual EPadPosition getPadPosition(void) const;
+
+ /**
+ * Set the position at which padding will take place. This is the location
+ * at which padding will be inserted if the result of format()
+ * is shorter than the format width. This has no effect unless padding is
+ * enabled.
+ * @param padPos the pad position, one of kPadBeforePrefix,
+ * kPadAfterPrefix, kPadBeforeSuffix, or
+ * kPadAfterSuffix.
+ * @see #setFormatWidth
+ * @see #getFormatWidth
+ * @see #setPadCharacter
+ * @see #getPadCharacterString
+ * @see #getPadPosition
+ * @see #kPadBeforePrefix
+ * @see #kPadAfterPrefix
+ * @see #kPadBeforeSuffix
+ * @see #kPadAfterSuffix
+ * @stable ICU 2.0
+ */
+ virtual void setPadPosition(EPadPosition padPos);
+
+ /**
+ * Return whether or not scientific notation is used.
+ * @return TRUE if this object formats and parses scientific notation
+ * @see #setScientificNotation
+ * @see #getMinimumExponentDigits
+ * @see #setMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ * @see #setExponentSignAlwaysShown
+ * @stable ICU 2.0
+ */
+ virtual UBool isScientificNotation(void);
+
+ /**
+ * Set whether or not scientific notation is used. When scientific notation
+ * is used, the effective maximum number of integer digits is <= 8. If the
+ * maximum number of integer digits is set to more than 8, the effective
+ * maximum will be 1. This allows this call to generate a 'default' scientific
+ * number format without additional changes.
+ * @param useScientific TRUE if this object formats and parses scientific
+ * notation
+ * @see #isScientificNotation
+ * @see #getMinimumExponentDigits
+ * @see #setMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ * @see #setExponentSignAlwaysShown
+ * @stable ICU 2.0
+ */
+ virtual void setScientificNotation(UBool useScientific);
+
+ /**
+ * Return the minimum exponent digits that will be shown.
+ * @return the minimum exponent digits that will be shown
+ * @see #setScientificNotation
+ * @see #isScientificNotation
+ * @see #setMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ * @see #setExponentSignAlwaysShown
+ * @stable ICU 2.0
+ */
+ virtual int8_t getMinimumExponentDigits(void) const;
+
+ /**
+ * Set the minimum exponent digits that will be shown. This has no
+ * effect unless scientific notation is in use.
+ * @param minExpDig a value >= 1 indicating the fewest exponent digits
+ * that will be shown. Values less than 1 will be treated as 1.
+ * @see #setScientificNotation
+ * @see #isScientificNotation
+ * @see #getMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ * @see #setExponentSignAlwaysShown
+ * @stable ICU 2.0
+ */
+ virtual void setMinimumExponentDigits(int8_t minExpDig);
+
+ /**
+ * Return whether the exponent sign is always shown.
+ * @return TRUE if the exponent is always prefixed with either the
+ * localized minus sign or the localized plus sign, false if only negative
+ * exponents are prefixed with the localized minus sign.
+ * @see #setScientificNotation
+ * @see #isScientificNotation
+ * @see #setMinimumExponentDigits
+ * @see #getMinimumExponentDigits
+ * @see #setExponentSignAlwaysShown
+ * @stable ICU 2.0
+ */
+ virtual UBool isExponentSignAlwaysShown(void);
+
+ /**
+ * Set whether the exponent sign is always shown. This has no effect
+ * unless scientific notation is in use.
+ * @param expSignAlways TRUE if the exponent is always prefixed with either
+ * the localized minus sign or the localized plus sign, false if only
+ * negative exponents are prefixed with the localized minus sign.
+ * @see #setScientificNotation
+ * @see #isScientificNotation
+ * @see #setMinimumExponentDigits
+ * @see #getMinimumExponentDigits
+ * @see #isExponentSignAlwaysShown
+ * @stable ICU 2.0
+ */
+ virtual void setExponentSignAlwaysShown(UBool expSignAlways);
+
+ /**
+ * Return the grouping size. Grouping size is the number of digits between
+ * grouping separators in the integer portion of a number. For example,
+ * in the number "123,456.78", the grouping size is 3.
+ *
+ * @return the grouping size.
+ * @see setGroupingSize
+ * @see NumberFormat::isGroupingUsed
+ * @see DecimalFormatSymbols::getGroupingSeparator
+ * @stable ICU 2.0
+ */
+ int32_t getGroupingSize(void) const;
+
+ /**
+ * Set the grouping size. Grouping size is the number of digits between
+ * grouping separators in the integer portion of a number. For example,
+ * in the number "123,456.78", the grouping size is 3.
+ *
+ * @param newValue the new value of the grouping size.
+ * @see getGroupingSize
+ * @see NumberFormat::setGroupingUsed
+ * @see DecimalFormatSymbols::setGroupingSeparator
+ * @stable ICU 2.0
+ */
+ virtual void setGroupingSize(int32_t newValue);
+
+ /**
+ * Return the secondary grouping size. In some locales one
+ * grouping interval is used for the least significant integer
+ * digits (the primary grouping size), and another is used for all
+ * others (the secondary grouping size). A formatter supporting a
+ * secondary grouping size will return a positive integer unequal
+ * to the primary grouping size returned by
+ * getGroupingSize(). For example, if the primary
+ * grouping size is 4, and the secondary grouping size is 2, then
+ * the number 123456789 formats as "1,23,45,6789", and the pattern
+ * appears as "#,##,###0".
+ * @return the secondary grouping size, or a value less than
+ * one if there is none
+ * @see setSecondaryGroupingSize
+ * @see NumberFormat::isGroupingUsed
+ * @see DecimalFormatSymbols::getGroupingSeparator
+ * @stable ICU 2.4
+ */
+ int32_t getSecondaryGroupingSize(void) const;
+
+ /**
+ * Set the secondary grouping size. If set to a value less than 1,
+ * then secondary grouping is turned off, and the primary grouping
+ * size is used for all intervals, not just the least significant.
+ *
+ * @param newValue the new value of the secondary grouping size.
+ * @see getSecondaryGroupingSize
+ * @see NumberFormat#setGroupingUsed
+ * @see DecimalFormatSymbols::setGroupingSeparator
+ * @stable ICU 2.4
+ */
+ virtual void setSecondaryGroupingSize(int32_t newValue);
+
+ /**
+ * Allows you to get the behavior of the decimal separator with integers.
+ * (The decimal separator will always appear with decimals.)
+ *
+ * @return TRUE if the decimal separator always appear with decimals.
+ * Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
+ * @stable ICU 2.0
+ */
+ UBool isDecimalSeparatorAlwaysShown(void) const;
+
+ /**
+ * Allows you to set the behavior of the decimal separator with integers.
+ * (The decimal separator will always appear with decimals.)
+ *
+ * @param newValue set TRUE if the decimal separator will always appear with decimals.
+ * Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
+ * @stable ICU 2.0
+ */
+ virtual void setDecimalSeparatorAlwaysShown(UBool newValue);
+
+ /**
+ * Synthesizes a pattern string that represents the current state
+ * of this Format object.
+ *
+ * @param result Output param which will receive the pattern.
+ * Previous contents are deleted.
+ * @return A reference to 'result'.
+ * @see applyPattern
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toPattern(UnicodeString& result) const;
+
+ /**
+ * Synthesizes a localized pattern string that represents the current
+ * state of this Format object.
+ *
+ * @param result Output param which will receive the localized pattern.
+ * Previous contents are deleted.
+ * @return A reference to 'result'.
+ * @see applyPattern
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toLocalizedPattern(UnicodeString& result) const;
+
+ /**
+ * Apply the given pattern to this Format object. A pattern is a
+ * short-hand specification for the various formatting properties.
+ * These properties can also be changed individually through the
+ * various setter methods.
+ * <P>
+ * There is no limit to integer digits are set
+ * by this routine, since that is the typical end-user desire;
+ * use setMaximumInteger if you want to set a real value.
+ * For negative numbers, use a second pattern, separated by a semicolon
+ * <pre>
+ * . Example "#,#00.0#" -> 1,234.56
+ * </pre>
+ * This means a minimum of 2 integer digits, 1 fraction digit, and
+ * a maximum of 2 fraction digits.
+ * <pre>
+ * . Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
+ * </pre>
+ * In negative patterns, the minimum and maximum counts are ignored;
+ * these are presumed to be set in the positive pattern.
+ *
+ * @param pattern The pattern to be applied.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Sets the pattern.
+ * @param pattern The pattern to be applied.
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Apply the given pattern to this Format object. The pattern
+ * is assumed to be in a localized notation. A pattern is a
+ * short-hand specification for the various formatting properties.
+ * These properties can also be changed individually through the
+ * various setter methods.
+ * <P>
+ * There is no limit to integer digits are set
+ * by this routine, since that is the typical end-user desire;
+ * use setMaximumInteger if you want to set a real value.
+ * For negative numbers, use a second pattern, separated by a semicolon
+ * <pre>
+ * . Example "#,#00.0#" -> 1,234.56
+ * </pre>
+ * This means a minimum of 2 integer digits, 1 fraction digit, and
+ * a maximum of 2 fraction digits.
+ *
+ * Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
+ *
+ * In negative patterns, the minimum and maximum counts are ignored;
+ * these are presumed to be set in the positive pattern.
+ *
+ * @param pattern The localized pattern to be applied.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+ virtual void applyLocalizedPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ /**
+ * Apply the given pattern to this Format object.
+ *
+ * @param pattern The localized pattern to be applied.
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+ virtual void applyLocalizedPattern(const UnicodeString& pattern,
+ UErrorCode& status);
+
+
+ /**
+ * Sets the maximum number of digits allowed in the integer portion of a
+ * number. This override limits the integer digit count to 309.
+ *
+ * @param newValue the new value of the maximum number of digits
+ * allowed in the integer portion of a number.
+ * @see NumberFormat#setMaximumIntegerDigits
+ * @stable ICU 2.0
+ */
+ virtual void setMaximumIntegerDigits(int32_t newValue);
+
+ /**
+ * Sets the minimum number of digits allowed in the integer portion of a
+ * number. This override limits the integer digit count to 309.
+ *
+ * @param newValue the new value of the minimum number of digits
+ * allowed in the integer portion of a number.
+ * @see NumberFormat#setMinimumIntegerDigits
+ * @stable ICU 2.0
+ */
+ virtual void setMinimumIntegerDigits(int32_t newValue);
+
+ /**
+ * Sets the maximum number of digits allowed in the fraction portion of a
+ * number. This override limits the fraction digit count to 340.
+ *
+ * @param newValue the new value of the maximum number of digits
+ * allowed in the fraction portion of a number.
+ * @see NumberFormat#setMaximumFractionDigits
+ * @stable ICU 2.0
+ */
+ virtual void setMaximumFractionDigits(int32_t newValue);
+
+ /**
+ * Sets the minimum number of digits allowed in the fraction portion of a
+ * number. This override limits the fraction digit count to 340.
+ *
+ * @param newValue the new value of the minimum number of digits
+ * allowed in the fraction portion of a number.
+ * @see NumberFormat#setMinimumFractionDigits
+ * @stable ICU 2.0
+ */
+ virtual void setMinimumFractionDigits(int32_t newValue);
+
+ /**
+ * Returns the minimum number of significant digits that will be
+ * displayed. This value has no effect unless areSignificantDigitsUsed()
+ * returns true.
+ * @return the fewest significant digits that will be shown
+ * @stable ICU 3.0
+ */
+ int32_t getMinimumSignificantDigits() const;
+
+ /**
+ * Returns the maximum number of significant digits that will be
+ * displayed. This value has no effect unless areSignificantDigitsUsed()
+ * returns true.
+ * @return the most significant digits that will be shown
+ * @stable ICU 3.0
+ */
+ int32_t getMaximumSignificantDigits() const;
+
+ /**
+ * Sets the minimum number of significant digits that will be
+ * displayed. If <code>min</code> is less than one then it is set
+ * to one. If the maximum significant digits count is less than
+ * <code>min</code>, then it is set to <code>min</code>. This
+ * value has no effect unless areSignificantDigits() returns true.
+ * @param min the fewest significant digits to be shown
+ * @stable ICU 3.0
+ */
+ void setMinimumSignificantDigits(int32_t min);
+
+ /**
+ * Sets the maximum number of significant digits that will be
+ * displayed. If <code>max</code> is less than one then it is set
+ * to one. If the minimum significant digits count is greater
+ * than <code>max</code>, then it is set to <code>max</code>.
+ * This value has no effect unless areSignificantDigits() returns
+ * true.
+ * @param max the most significant digits to be shown
+ * @stable ICU 3.0
+ */
+ void setMaximumSignificantDigits(int32_t max);
+
+ /**
+ * Returns true if significant digits are in use, or false if
+ * integer and fraction digit counts are in use.
+ * @return true if significant digits are in use
+ * @stable ICU 3.0
+ */
+ UBool areSignificantDigitsUsed() const;
+
+ /**
+ * Sets whether significant digits are in use, or integer and
+ * fraction digit counts are in use.
+ * @param useSignificantDigits true to use significant digits, or
+ * false to use integer and fraction digit counts
+ * @stable ICU 3.0
+ */
+ void setSignificantDigitsUsed(UBool useSignificantDigits);
+
+ public:
+ /**
+ * Sets the currency used to display currency
+ * amounts. This takes effect immediately, if this format is a
+ * currency format. If this format is not a currency format, then
+ * the currency is used if and when this object becomes a
+ * currency format through the application of a new pattern.
+ * @param theCurrency a 3-letter ISO code indicating new currency
+ * to use. It need not be null-terminated. May be the empty
+ * string or NULL to indicate no currency.
+ * @param ec input-output error code
+ * @stable ICU 3.0
+ */
+ virtual void setCurrency(const UChar* theCurrency, UErrorCode& ec);
+
+ /**
+ * Sets the currency used to display currency amounts. See
+ * setCurrency(const UChar*, UErrorCode&).
+ * @deprecated ICU 3.0. Use setCurrency(const UChar*, UErrorCode&).
+ */
+ virtual void setCurrency(const UChar* theCurrency);
+
+ /**
+ * The resource tags we use to retrieve decimal format data from
+ * locale resource bundles.
+ * @deprecated ICU 3.4. This string has no public purpose. Please don't use it.
+ */
+ static const char fgNumberPatterns[];
+
+public:
+
+ /**
+ * Return the class ID for this class. This is useful only for
+ * comparing to a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . Derived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override.
+ * This method is to implement a simple version of RTTI, since not all
+ * C++ compilers support genuine RTTI. Polymorphic operator==() and
+ * clone() methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+private:
+ DecimalFormat(); // default constructor not implemented
+
+ int32_t precision(UBool isIntegral) const;
+
+ /**
+ * Do real work of constructing a new DecimalFormat.
+ */
+ void construct(UErrorCode& status,
+ UParseError& parseErr,
+ const UnicodeString* pattern = 0,
+ DecimalFormatSymbols* symbolsToAdopt = 0
+ );
+
+ /**
+ * Does the real work of generating a pattern.
+ *
+ * @param result Output param which will receive the pattern.
+ * Previous contents are deleted.
+ * @param localized TRUE return localized pattern.
+ * @return A reference to 'result'.
+ */
+ UnicodeString& toPattern(UnicodeString& result, UBool localized) const;
+
+ /**
+ * Does the real work of applying a pattern.
+ * @param pattern The pattern to be applied.
+ * @param localized If true, the pattern is localized; else false.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ */
+ void applyPattern(const UnicodeString& pattern,
+ UBool localized,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Do the work of formatting a number, either a double or a long.
+ *
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param fieldPosition On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param digits the digits to be formatted.
+ * @param isInteger if TRUE format the digits as Integer.
+ * @return Reference to 'appendTo' parameter.
+ */
+ UnicodeString& subformat(UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ DigitList& digits,
+ UBool isInteger) const;
+
+ void parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& pos,
+ UBool parseCurrency) const;
+
+ enum {
+ fgStatusInfinite,
+ fgStatusLength // Leave last in list.
+ } StatusFlags;
+
+ UBool subparse(const UnicodeString& text, ParsePosition& parsePosition,
+ DigitList& digits, UBool* status,
+ UChar* currency) const;
+
+ int32_t skipPadding(const UnicodeString& text, int32_t position) const;
+
+ int32_t compareAffix(const UnicodeString& input,
+ int32_t pos,
+ UBool isNegative,
+ UBool isPrefix,
+ UChar* currency) const;
+
+ static int32_t compareSimpleAffix(const UnicodeString& affix,
+ const UnicodeString& input,
+ int32_t pos);
+
+ static int32_t skipRuleWhiteSpace(const UnicodeString& text, int32_t pos);
+
+ static int32_t skipUWhiteSpace(const UnicodeString& text, int32_t pos);
+
+ int32_t compareComplexAffix(const UnicodeString& affixPat,
+ const UnicodeString& input,
+ int32_t pos,
+ UChar* currency) const;
+
+ static int32_t match(const UnicodeString& text, int32_t pos, UChar32 ch);
+
+ static int32_t match(const UnicodeString& text, int32_t pos, const UnicodeString& str);
+
+ /**
+ * Get a decimal format symbol.
+ * Returns a const reference to the symbol string.
+ * @internal
+ */
+ inline const UnicodeString &getConstSymbol(DecimalFormatSymbols::ENumberFormatSymbol symbol) const;
+
+ int32_t appendAffix(UnicodeString& buf, double number,
+ UBool isNegative, UBool isPrefix) const;
+
+ /**
+ * Append an affix to the given UnicodeString, using quotes if
+ * there are special characters. Single quotes themselves must be
+ * escaped in either case.
+ */
+ void appendAffixPattern(UnicodeString& appendTo, const UnicodeString& affix,
+ UBool localized) const;
+
+ void appendAffixPattern(UnicodeString& appendTo,
+ const UnicodeString* affixPattern,
+ const UnicodeString& expAffix, UBool localized) const;
+
+ void expandAffix(const UnicodeString& pattern,
+ UnicodeString& affix,
+ double number,
+ UBool doFormat) const;
+
+ void expandAffixes();
+
+ static double round(double a, ERoundingMode mode, UBool isNegative);
+
+ void addPadding(UnicodeString& appendTo,
+ FieldPosition& fieldPosition,
+ int32_t prefixLen, int32_t suffixLen) const;
+
+ UBool isGroupingPosition(int32_t pos) const;
+
+ void setCurrencyForSymbols();
+
+ /**
+ * Constants.
+ */
+ //static const int8_t fgMaxDigit; // The largest digit, in this case 9
+
+ /*transient*/ //DigitList* fDigitList;
+
+ UnicodeString fPositivePrefix;
+ UnicodeString fPositiveSuffix;
+ UnicodeString fNegativePrefix;
+ UnicodeString fNegativeSuffix;
+ UnicodeString* fPosPrefixPattern;
+ UnicodeString* fPosSuffixPattern;
+ UnicodeString* fNegPrefixPattern;
+ UnicodeString* fNegSuffixPattern;
+
+ /**
+ * Formatter for ChoiceFormat-based currency names. If this field
+ * is not null, then delegate to it to format currency symbols.
+ * @since ICU 2.6
+ */
+ ChoiceFormat* fCurrencyChoice;
+
+ int32_t fMultiplier;
+ int32_t fGroupingSize;
+ int32_t fGroupingSize2;
+ UBool fDecimalSeparatorAlwaysShown;
+ /*transient*/ UBool fIsCurrencyFormat;
+ DecimalFormatSymbols* fSymbols;
+
+ UBool fUseSignificantDigits;
+ int32_t fMinSignificantDigits;
+ int32_t fMaxSignificantDigits;
+
+ UBool fUseExponentialNotation;
+ int8_t fMinExponentDigits;
+ UBool fExponentSignAlwaysShown;
+
+ /* If fRoundingIncrement is NULL, there is no rounding. Otherwise, round to
+ * fRoundingIncrement.getDouble(). Since this operation may be expensive,
+ * we cache the result in fRoundingDouble. All methods that update
+ * fRoundingIncrement also update fRoundingDouble. */
+ DigitList* fRoundingIncrement;
+ /*transient*/ double fRoundingDouble;
+ ERoundingMode fRoundingMode;
+
+ UChar32 fPad;
+ int32_t fFormatWidth;
+ EPadPosition fPadPosition;
+
+protected:
+
+ /**
+ * Returns the currency in effect for this formatter. Subclasses
+ * should override this method as needed. Unlike getCurrency(),
+ * this method should never return "".
+ * @result output parameter for null-terminated result, which must
+ * have a capacity of at least 4
+ * @internal
+ */
+ virtual void getEffectiveCurrency(UChar* result, UErrorCode& ec) const;
+
+ /** number of integer digits
+ * @stable ICU 2.4
+ */
+ static const int32_t kDoubleIntegerDigits;
+ /** number of fraction digits
+ * @stable ICU 2.4
+ */
+ static const int32_t kDoubleFractionDigits;
+
+ /**
+ * When someone turns on scientific mode, we assume that more than this
+ * number of digits is due to flipping from some other mode that didn't
+ * restrict the maximum, and so we force 1 integer digit. We don't bother
+ * to track and see if someone is using exponential notation with more than
+ * this number, it wouldn't make sense anyway, and this is just to make sure
+ * that someone turning on scientific mode with default settings doesn't
+ * end up with lots of zeroes.
+ * @stable ICU 2.8
+ */
+ static const int32_t kMaxScientificIntegerDigits;
+};
+
+inline UnicodeString&
+DecimalFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ // Don't use Format:: - use immediate base class only,
+ // in case immediate base modifies behavior later.
+ return NumberFormat::format(obj, appendTo, status);
+}
+
+inline UnicodeString&
+DecimalFormat::format(double number,
+ UnicodeString& appendTo) const {
+ FieldPosition pos(0);
+ return format(number, appendTo, pos);
+}
+
+inline UnicodeString&
+DecimalFormat::format(int32_t number,
+ UnicodeString& appendTo) const {
+ FieldPosition pos(0);
+ return format((int64_t)number, appendTo, pos);
+}
+
+inline const UnicodeString &
+DecimalFormat::getConstSymbol(DecimalFormatSymbols::ENumberFormatSymbol symbol) const {
+ return fSymbols->getConstSymbol(symbol);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DECIMFMT
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/dtfmtsym.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/dtfmtsym.h
new file mode 100644
index 00000000000..5bc73fef829
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/dtfmtsym.h
@@ -0,0 +1,698 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File DTFMTSYM.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 07/21/98 stephen Added getZoneIndex()
+* Changed to match C++ conventions
+********************************************************************************
+*/
+
+#ifndef DTFMTSYM_H
+#define DTFMTSYM_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/uobject.h"
+#include "unicode/locid.h"
+#include "unicode/ures.h"
+
+/**
+ * \file
+ * \brief C++ API: Symbols for formatting dates.
+ */
+
+U_NAMESPACE_BEGIN
+
+/* forward declaration */
+class SimpleDateFormat;
+class Hashtable;
+class ZoneStringFormat;
+class SafeZoneStringFormatPtr;
+
+/**
+ * DateFormatSymbols is a public class for encapsulating localizable date-time
+ * formatting data -- including timezone data. DateFormatSymbols is used by
+ * DateFormat and SimpleDateFormat.
+ * <P>
+ * Rather than first creating a DateFormatSymbols to get a date-time formatter
+ * by using a SimpleDateFormat constructor, clients are encouraged to create a
+ * date-time formatter using the getTimeInstance(), getDateInstance(), or
+ * getDateTimeInstance() method in DateFormat. Each of these methods can return a
+ * date/time formatter initialized with a default format pattern along with the
+ * date-time formatting data for a given or default locale. After a formatter is
+ * created, clients may modify the format pattern using the setPattern function
+ * as so desired. For more information on using these formatter factory
+ * functions, see DateFormat.
+ * <P>
+ * If clients decide to create a date-time formatter with a particular format
+ * pattern and locale, they can do so with new SimpleDateFormat(aPattern,
+ * new DateFormatSymbols(aLocale)). This will load the appropriate date-time
+ * formatting data from the locale.
+ * <P>
+ * DateFormatSymbols objects are clonable. When clients obtain a
+ * DateFormatSymbols object, they can feel free to modify the date-time
+ * formatting data as necessary. For instance, clients can
+ * replace the localized date-time format pattern characters with the ones that
+ * they feel easy to remember. Or they can change the representative cities
+ * originally picked by default to using their favorite ones.
+ * <P>
+ * DateFormatSymbols are not expected to be subclassed. Data for a calendar is
+ * loaded out of resource bundles. The 'type' parameter indicates the type of
+ * calendar, for example, "gregorian" or "japanese". If the type is not gregorian
+ * (or NULL, or an empty string) then the type is appended to the resource name,
+ * for example, 'Eras_japanese' instead of 'Eras'. If the resource 'Eras_japanese' did
+ * not exist (even in root), then this class will fall back to just 'Eras', that is,
+ * Gregorian data. Therefore, the calendar implementor MUST ensure that the root
+ * locale at least contains any resources that are to be particularized for the
+ * calendar type.
+ */
+class U_I18N_API DateFormatSymbols : public UObject {
+public:
+ /**
+ * Construct a DateFormatSymbols object by loading format data from
+ * resources for the default locale, in the default calendar (Gregorian).
+ * <P>
+ * NOTE: This constructor will never fail; if it cannot get resource
+ * data for the default locale, it will return a last-resort object
+ * based on hard-coded strings.
+ *
+ * @param status Status code. Failure
+ * results if the resources for the default cannot be
+ * found or cannot be loaded
+ * @stable ICU 2.0
+ */
+ DateFormatSymbols(UErrorCode& status);
+
+ /**
+ * Construct a DateFormatSymbols object by loading format data from
+ * resources for the given locale, in the default calendar (Gregorian).
+ *
+ * @param locale Locale to load format data from.
+ * @param status Status code. Failure
+ * results if the resources for the locale cannot be
+ * found or cannot be loaded
+ * @stable ICU 2.0
+ */
+ DateFormatSymbols(const Locale& locale,
+ UErrorCode& status);
+
+ /**
+ * Construct a DateFormatSymbols object by loading format data from
+ * resources for the default locale, in the default calendar (Gregorian).
+ * <P>
+ * NOTE: This constructor will never fail; if it cannot get resource
+ * data for the default locale, it will return a last-resort object
+ * based on hard-coded strings.
+ *
+ * @param type Type of calendar (as returned by Calendar::getType).
+ * Will be used to access the correct set of strings.
+ * (NULL or empty string defaults to "gregorian".)
+ * @param status Status code. Failure
+ * results if the resources for the default cannot be
+ * found or cannot be loaded
+ * @internal
+ */
+ DateFormatSymbols(const char *type, UErrorCode& status);
+
+ /**
+ * Construct a DateFormatSymbols object by loading format data from
+ * resources for the given locale, in the default calendar (Gregorian).
+ *
+ * @param locale Locale to load format data from.
+ * @param type Type of calendar (as returned by Calendar::getType).
+ * Will be used to access the correct set of strings.
+ * (NULL or empty string defaults to "gregorian".)
+ * @param status Status code. Failure
+ * results if the resources for the locale cannot be
+ * found or cannot be loaded
+ * @internal
+ */
+ DateFormatSymbols(const Locale& locale,
+ const char *type,
+ UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ * @stable ICU 2.0
+ */
+ DateFormatSymbols(const DateFormatSymbols&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 2.0
+ */
+ DateFormatSymbols& operator=(const DateFormatSymbols&);
+
+ /**
+ * Destructor. This is nonvirtual because this class is not designed to be
+ * subclassed.
+ * @stable ICU 2.0
+ */
+ virtual ~DateFormatSymbols();
+
+ /**
+ * Return true if another object is semantically equal to this one.
+ *
+ * @param other the DateFormatSymbols object to be compared with.
+ * @return true if other is semantically equal to this.
+ * @stable ICU 2.0
+ */
+ UBool operator==(const DateFormatSymbols& other) const;
+
+ /**
+ * Return true if another object is semantically unequal to this one.
+ *
+ * @param other the DateFormatSymbols object to be compared with.
+ * @return true if other is semantically unequal to this.
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const DateFormatSymbols& other) const { return !operator==(other); }
+
+ /**
+ * Gets era strings. For example: "AD" and "BC".
+ *
+ * @param count Filled in with length of the array.
+ * @return the era strings.
+ * @stable ICU 2.0
+ */
+ const UnicodeString* getEras(int32_t& count) const;
+
+ /**
+ * Sets era strings. For example: "AD" and "BC".
+ * @param eras Array of era strings (DateFormatSymbols retains ownership.)
+ * @param count Filled in with length of the array.
+ * @stable ICU 2.0
+ */
+ void setEras(const UnicodeString* eras, int32_t count);
+
+ /**
+ * Gets era name strings. For example: "Anno Domini" and "Before Christ".
+ *
+ * @param count Filled in with length of the array.
+ * @return the era name strings.
+ * @stable ICU 3.4
+ */
+ const UnicodeString* getEraNames(int32_t& count) const;
+
+ /**
+ * Sets era name strings. For example: "Anno Domini" and "Before Christ".
+ * @param eraNames Array of era name strings (DateFormatSymbols retains ownership.)
+ * @param count Filled in with length of the array.
+ * @stable ICU 3.6
+ */
+ void setEraNames(const UnicodeString* eraNames, int32_t count);
+
+ /**
+ * Gets month strings. For example: "January", "February", etc.
+ * @param count Filled in with length of the array.
+ * @return the month strings. (DateFormatSymbols retains ownership.)
+ * @stable ICU 2.0
+ */
+ const UnicodeString* getMonths(int32_t& count) const;
+
+ /**
+ * Sets month strings. For example: "January", "February", etc.
+ *
+ * @param months the new month strings. (not adopted; caller retains ownership)
+ * @param count Filled in with length of the array.
+ * @stable ICU 2.0
+ */
+ void setMonths(const UnicodeString* months, int32_t count);
+
+ /**
+ * Gets short month strings. For example: "Jan", "Feb", etc.
+ *
+ * @param count Filled in with length of the array.
+ * @return the short month strings. (DateFormatSymbols retains ownership.)
+ * @stable ICU 2.0
+ */
+ const UnicodeString* getShortMonths(int32_t& count) const;
+
+ /**
+ * Sets short month strings. For example: "Jan", "Feb", etc.
+ * @param count Filled in with length of the array.
+ * @param shortMonths the new short month strings. (not adopted; caller retains ownership)
+ * @stable ICU 2.0
+ */
+ void setShortMonths(const UnicodeString* shortMonths, int32_t count);
+
+ /**
+ * Selector for date formatting context
+ * @stable ICU 3.6
+ */
+ enum DtContextType {
+ FORMAT,
+ STANDALONE,
+ DT_CONTEXT_COUNT
+ };
+
+ /**
+ * Selector for date formatting width
+ * @stable ICU 3.6
+ */
+ enum DtWidthType {
+ ABBREVIATED,
+ WIDE,
+ NARROW,
+ DT_WIDTH_COUNT
+ };
+
+ /**
+ * Gets month strings by width and context. For example: "January", "February", etc.
+ * @param count Filled in with length of the array.
+ * @param context The formatting context, either FORMAT or STANDALONE
+ * @param width The width of returned strings, either WIDE, ABBREVIATED, or NARROW.
+ * @return the month strings. (DateFormatSymbols retains ownership.)
+ * @stable ICU 3.4
+ */
+ const UnicodeString* getMonths(int32_t& count, DtContextType context, DtWidthType width) const;
+
+ /**
+ * Sets month strings by width and context. For example: "January", "February", etc.
+ *
+ * @param months The new month strings. (not adopted; caller retains ownership)
+ * @param count Filled in with length of the array.
+ * @param context The formatting context, either FORMAT or STANDALONE
+ * @param width The width of returned strings, either WIDE, ABBREVIATED, or NARROW.
+ * @stable ICU 3.6
+ */
+ void setMonths(const UnicodeString* months, int32_t count, DtContextType context, DtWidthType width);
+
+ /**
+ * Gets weekday strings. For example: "Sunday", "Monday", etc.
+ * @param count Filled in with length of the array.
+ * @return the weekday strings. (DateFormatSymbols retains ownership.)
+ * @stable ICU 2.0
+ */
+ const UnicodeString* getWeekdays(int32_t& count) const;
+
+
+ /**
+ * Sets weekday strings. For example: "Sunday", "Monday", etc.
+ * @param weekdays the new weekday strings. (not adopted; caller retains ownership)
+ * @param count Filled in with length of the array.
+ * @stable ICU 2.0
+ */
+ void setWeekdays(const UnicodeString* weekdays, int32_t count);
+
+ /**
+ * Gets short weekday strings. For example: "Sun", "Mon", etc.
+ * @param count Filled in with length of the array.
+ * @return the short weekday strings. (DateFormatSymbols retains ownership.)
+ * @stable ICU 2.0
+ */
+ const UnicodeString* getShortWeekdays(int32_t& count) const;
+
+ /**
+ * Sets short weekday strings. For example: "Sun", "Mon", etc.
+ * @param shortWeekdays the new short weekday strings. (not adopted; caller retains ownership)
+ * @param count Filled in with length of the array.
+ * @stable ICU 2.0
+ */
+ void setShortWeekdays(const UnicodeString* shortWeekdays, int32_t count);
+
+ /**
+ * Gets weekday strings by width and context. For example: "Sunday", "Monday", etc.
+ * @param count Filled in with length of the array.
+ * @param context The formatting context, either FORMAT or STANDALONE
+ * @param width The width of returned strings, either WIDE, ABBREVIATED, or NARROW
+ * @return the month strings. (DateFormatSymbols retains ownership.)
+ * @stable ICU 3.4
+ */
+ const UnicodeString* getWeekdays(int32_t& count, DtContextType context, DtWidthType width) const;
+
+ /**
+ * Sets weekday strings by width and context. For example: "Sunday", "Monday", etc.
+ * @param weekdays The new weekday strings. (not adopted; caller retains ownership)
+ * @param count Filled in with length of the array.
+ * @param context The formatting context, either FORMAT or STANDALONE
+ * @param width The width of returned strings, either WIDE, ABBREVIATED, or NARROW
+ * @stable ICU 3.6
+ */
+ void setWeekdays(const UnicodeString* weekdays, int32_t count, DtContextType context, DtWidthType width);
+
+ /**
+ * Gets quarter strings by width and context. For example: "1st Quarter", "2nd Quarter", etc.
+ * @param count Filled in with length of the array.
+ * @param context The formatting context, either FORMAT or STANDALONE
+ * @param width The width of returned strings, either WIDE or ABBREVIATED. There
+ * are no NARROW quarters.
+ * @return the quarter strings. (DateFormatSymbols retains ownership.)
+ * @stable ICU 3.6
+ */
+ const UnicodeString* getQuarters(int32_t& count, DtContextType context, DtWidthType width) const;
+
+ /**
+ * Sets quarter strings by width and context. For example: "1st Quarter", "2nd Quarter", etc.
+ *
+ * @param quarters The new quarter strings. (not adopted; caller retains ownership)
+ * @param count Filled in with length of the array.
+ * @param context The formatting context, either FORMAT or STANDALONE
+ * @param width The width of returned strings, either WIDE or ABBREVIATED. There
+ * are no NARROW quarters.
+ * @stable ICU 3.6
+ */
+ void setQuarters(const UnicodeString* quarters, int32_t count, DtContextType context, DtWidthType width);
+
+ /**
+ * Gets AM/PM strings. For example: "AM" and "PM".
+ * @param count Filled in with length of the array.
+ * @return the weekday strings. (DateFormatSymbols retains ownership.)
+ * @stable ICU 2.0
+ */
+ const UnicodeString* getAmPmStrings(int32_t& count) const;
+
+ /**
+ * Sets ampm strings. For example: "AM" and "PM".
+ * @param ampms the new ampm strings. (not adopted; caller retains ownership)
+ * @param count Filled in with length of the array.
+ * @stable ICU 2.0
+ */
+ void setAmPmStrings(const UnicodeString* ampms, int32_t count);
+
+ /**
+ * Gets timezone strings. These strings are stored in a 2-dimensional array.
+ * @param rowCount Output param to receive number of rows.
+ * @param columnCount Output param to receive number of columns.
+ * @return The timezone strings as a 2-d array. (DateFormatSymbols retains ownership.)
+ * @deprecated ICU 3.6
+ */
+ const UnicodeString** getZoneStrings(int32_t& rowCount, int32_t& columnCount) const;
+
+ /**
+ * Sets timezone strings. These strings are stored in a 2-dimensional array.
+ * @param strings The timezone strings as a 2-d array to be copied. (not adopted; caller retains ownership)
+ * @param rowCount The number of rows (count of first index).
+ * @param columnCount The number of columns (count of second index).
+ * @stable ICU 2.0
+ */
+ void setZoneStrings(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount);
+
+ /**
+ * Get the non-localized date-time pattern characters.
+ * @return the non-localized date-time pattern characters
+ * @stable ICU 2.0
+ */
+ static const UChar * U_EXPORT2 getPatternUChars(void);
+
+ /**
+ * Gets localized date-time pattern characters. For example: 'u', 't', etc.
+ * <p>
+ * Note: ICU no longer provides localized date-time pattern characters for a locale
+ * starting ICU 3.8. This method returns the non-localized date-time pattern
+ * characters unless user defined localized data is set by setLocalPatternChars.
+ * @param result Output param which will receive the localized date-time pattern characters.
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ UnicodeString& getLocalPatternChars(UnicodeString& result) const;
+
+ /**
+ * Sets localized date-time pattern characters. For example: 'u', 't', etc.
+ * @param newLocalPatternChars the new localized date-time
+ * pattern characters.
+ * @stable ICU 2.0
+ */
+ void setLocalPatternChars(const UnicodeString& newLocalPatternChars);
+
+ /**
+ * Returns the locale for this object. Two flavors are available:
+ * valid and actual locale.
+ * @stable ICU 2.8
+ */
+ Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+
+ friend class SimpleDateFormat;
+ friend class DateFormatSymbolsSingleSetter; // see udat.cpp
+
+ /**
+ * Era strings. For example: "AD" and "BC".
+ */
+ UnicodeString* fEras;
+ int32_t fErasCount;
+
+ /**
+ * Era name strings. For example: "Anno Domini" and "Before Christ".
+ */
+ UnicodeString* fEraNames;
+ int32_t fEraNamesCount;
+
+ /**
+ * Month strings. For example: "January", "February", etc.
+ */
+ UnicodeString* fMonths;
+ int32_t fMonthsCount;
+
+ /**
+ * Short month strings. For example: "Jan", "Feb", etc.
+ */
+ UnicodeString* fShortMonths;
+ int32_t fShortMonthsCount;
+
+ /**
+ * Narrow month strings. For example: "J", "F", etc.
+ */
+ UnicodeString* fNarrowMonths;
+ int32_t fNarrowMonthsCount;
+
+ /**
+ * Standalone Month strings. For example: "January", "February", etc.
+ */
+ UnicodeString* fStandaloneMonths;
+ int32_t fStandaloneMonthsCount;
+
+ /**
+ * Standalone Short month strings. For example: "Jan", "Feb", etc.
+ */
+ UnicodeString* fStandaloneShortMonths;
+ int32_t fStandaloneShortMonthsCount;
+
+ /**
+ * Standalone Narrow month strings. For example: "J", "F", etc.
+ */
+ UnicodeString* fStandaloneNarrowMonths;
+ int32_t fStandaloneNarrowMonthsCount;
+
+ /**
+ * Weekday strings. For example: "Sunday", "Monday", etc.
+ */
+ UnicodeString* fWeekdays;
+ int32_t fWeekdaysCount;
+
+ /**
+ * Short weekday strings. For example: "Sun", "Mon", etc.
+ */
+ UnicodeString* fShortWeekdays;
+ int32_t fShortWeekdaysCount;
+
+ /**
+ * Narrow weekday strings. For example: "Sun", "Mon", etc.
+ */
+ UnicodeString* fNarrowWeekdays;
+ int32_t fNarrowWeekdaysCount;
+
+ /**
+ * Standalone Weekday strings. For example: "Sunday", "Monday", etc.
+ */
+ UnicodeString* fStandaloneWeekdays;
+ int32_t fStandaloneWeekdaysCount;
+
+ /**
+ * Standalone Short weekday strings. For example: "Sun", "Mon", etc.
+ */
+ UnicodeString* fStandaloneShortWeekdays;
+ int32_t fStandaloneShortWeekdaysCount;
+
+ /**
+ * Standalone Narrow weekday strings. For example: "Sun", "Mon", etc.
+ */
+ UnicodeString* fStandaloneNarrowWeekdays;
+ int32_t fStandaloneNarrowWeekdaysCount;
+
+ /**
+ * Ampm strings. For example: "AM" and "PM".
+ */
+ UnicodeString* fAmPms;
+ int32_t fAmPmsCount;
+
+ /**
+ * Quarter strings. For example: "1st quarter", "2nd quarter", etc.
+ */
+ UnicodeString *fQuarters;
+ int32_t fQuartersCount;
+
+ /**
+ * Short quarters. For example: "Q1", "Q2", etc.
+ */
+ UnicodeString *fShortQuarters;
+ int32_t fShortQuartersCount;
+
+ /**
+ * Standalone quarter strings. For example: "1st quarter", "2nd quarter", etc.
+ */
+ UnicodeString *fStandaloneQuarters;
+ int32_t fStandaloneQuartersCount;
+
+ /**
+ * Standalone short quarter strings. For example: "Q1", "Q2", etc.
+ */
+ UnicodeString *fStandaloneShortQuarters;
+ int32_t fStandaloneShortQuartersCount;
+
+ /**
+ * The format data of all the timezones in this locale.
+ */
+ UnicodeString **fZoneStrings; // Zone string array set by setZoneStrings
+ UnicodeString **fLocaleZoneStrings; // Zone string array created by the locale
+ int32_t fZoneStringsRowCount;
+ int32_t fZoneStringsColCount;
+
+ const ZoneStringFormat *fZoneStringFormat;
+ ZoneStringFormat *fZSFLocal; // Local ZoneStringFormat instance
+ SafeZoneStringFormatPtr *fZSFCachePtr; // Cached ZoneStringFormat
+ Locale fZSFLocale; // Locale used for getting ZoneStringFormat
+
+ /**
+ * Pattern string used for localized time zone GMT format. For example, "GMT{0}"
+ */
+ UnicodeString fGmtFormat;
+
+ /**
+ * Pattern strings used for formatting zone offset in a localized time zone GMT string.
+ */
+ UnicodeString *fGmtHourFormats;
+ int32_t fGmtHourFormatsCount;
+
+ enum GMTHourType {
+ GMT_NEGATIVE_HMS = 0,
+ GMT_NEGATIVE_HM,
+ GMT_POSITIVE_HMS,
+ GMT_POSITIVE_HM,
+ GMT_HOUR_COUNT
+ };
+
+ /**
+ * Localized date-time pattern characters. For example: use 'u' as 'y'.
+ */
+ UnicodeString fLocalPatternChars;
+
+private:
+ /** valid/actual locale information
+ * these are always ICU locales, so the length should not be a problem
+ */
+ char validLocale[ULOC_FULLNAME_CAPACITY];
+ char actualLocale[ULOC_FULLNAME_CAPACITY];
+
+ DateFormatSymbols(); // default constructor not implemented
+
+ /**
+ * Called by the constructors to actually load data from the resources
+ *
+ * @param locale The locale to get symbols for.
+ * @param type Calendar Type (as from Calendar::getType())
+ * @param status Input/output parameter, set to success or
+ * failure code upon return.
+ * @param useLastResortData determine if use last resort data
+ */
+ void initializeData(const Locale&, const char *type, UErrorCode& status, UBool useLastResortData = FALSE);
+
+ /**
+ * Copy or alias an array in another object, as appropriate.
+ *
+ * @param dstArray the copy destination array.
+ * @param dstCount fill in with the lenth of 'dstArray'.
+ * @param srcArray the source array to be copied.
+ * @param srcCount the length of items to be copied from the 'srcArray'.
+ */
+ static void assignArray(UnicodeString*& dstArray,
+ int32_t& dstCount,
+ const UnicodeString* srcArray,
+ int32_t srcCount);
+
+ /**
+ * Return true if the given arrays' contents are equal, or if the arrays are
+ * identical (pointers are equal).
+ *
+ * @param array1 one array to be compared with.
+ * @param array2 another array to be compared with.
+ * @param count the length of items to be copied.
+ * @return true if the given arrays' contents are equal, or if the arrays are
+ * identical (pointers are equal).
+ */
+ static UBool arrayCompare(const UnicodeString* array1,
+ const UnicodeString* array2,
+ int32_t count);
+
+ /**
+ * Create a copy, in fZoneStrings, of the given zone strings array. The
+ * member variables fZoneStringsRowCount and fZoneStringsColCount should be
+ * set already by the caller.
+ */
+ void createZoneStrings(const UnicodeString *const * otherStrings);
+
+ /**
+ * Delete all the storage owned by this object.
+ */
+ void dispose(void);
+
+ /**
+ * Copy all of the other's data to this.
+ * @param other the object to be copied.
+ */
+ void copyData(const DateFormatSymbols& other);
+
+
+ /**
+ * Returns a ZoneStringFormat, used only by SimpleDateFormat for now.
+ */
+ const ZoneStringFormat* getZoneStringFormat(void) const;
+
+ /**
+ * Create a ZoneStringFormat by locale if not yet availble
+ */
+ void initZoneStringFormat(void);
+
+ /**
+ * Create zone strings array by locale if not yet available
+ */
+ void initZoneStringsArray(void);
+
+ /**
+ * Delete just the zone strings.
+ */
+ void disposeZoneStrings(void);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DTFMTSYM
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/dtptngen.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/dtptngen.h
new file mode 100644
index 00000000000..09f6b84590c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/dtptngen.h
@@ -0,0 +1,416 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*
+* File DTPTNGEN.H
+*
+*******************************************************************************
+*/
+
+#ifndef __DTPTNGEN_H__
+#define __DTPTNGEN_H__
+
+#include "unicode/datefmt.h"
+#include "unicode/locid.h"
+#include "unicode/udat.h"
+#include "unicode/udatpg.h"
+
+U_NAMESPACE_BEGIN
+
+class Hashtable;
+class FormatParser;
+class DateTimeMatcher;
+class DistanceInfo;
+class PatternMap;
+
+/**
+ * This class provides flexible generation of date format patterns, like "yy-MM-dd".
+ * The user can build up the generator by adding successive patterns. Once that
+ * is done, a query can be made using a "skeleton", which is a pattern which just
+ * includes the desired fields and lengths. The generator will return the "best fit"
+ * pattern corresponding to that skeleton.
+ * <p>The main method people will use is getBestPattern(String skeleton),
+ * since normally this class is pre-built with data from a particular locale.
+ * However, generators can be built directly from other data as well.
+ * <p><i>Issue: may be useful to also have a function that returns the list of
+ * fields in a pattern, in order, since we have that internally.
+ * That would be useful for getting the UI order of field elements.</i>
+ * @draft ICU 3.8
+**/
+class U_I18N_API DateTimePatternGenerator : public UObject {
+public:
+ /**
+ * Construct a flexible generator according to default locale.
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @draft ICU 3.8
+ */
+ static DateTimePatternGenerator* U_EXPORT2 createInstance(UErrorCode& status);
+
+ /**
+ * Construct a flexible generator according to data for a given locale.
+ * @param uLocale
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @draft ICU 3.8
+ */
+ static DateTimePatternGenerator* U_EXPORT2 createInstance(const Locale& uLocale, UErrorCode& status);
+
+ /**
+ * Create an empty generator, to be constructed with addPattern(...) etc.
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @draft ICU 3.8
+ */
+ static DateTimePatternGenerator* U_EXPORT2 createEmptyInstance(UErrorCode& status);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~DateTimePatternGenerator();
+
+ /**
+ * Clone DateTimePatternGenerator object. Clients are responsible for
+ * deleting the DateTimePatternGenerator object cloned.
+ * @draft ICU 3.8
+ */
+ DateTimePatternGenerator* clone() const;
+
+ /**
+ * Return true if another object is semantically equal to this one.
+ *
+ * @param other the DateTimePatternGenerator object to be compared with.
+ * @return true if other is semantically equal to this.
+ * @draft ICU 3.8
+ */
+ UBool operator==(const DateTimePatternGenerator& other) const;
+
+ /**
+ * Return true if another object is semantically unequal to this one.
+ *
+ * @param other the DateTimePatternGenerator object to be compared with.
+ * @return true if other is semantically unequal to this.
+ * @draft ICU 3.8
+ */
+ UBool operator!=(const DateTimePatternGenerator& other) const;
+
+ /**
+ * Utility to return a unique skeleton from a given pattern. For example,
+ * both "MMM-dd" and "dd/MMM" produce the skeleton "MMMdd".
+ *
+ * @param pattern Input pattern, such as "dd/MMM"
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @return skeleton such as "MMMdd"
+ * @draft ICU 3.8
+ */
+ UnicodeString getSkeleton(const UnicodeString& pattern, UErrorCode& status);
+
+ /**
+ * Utility to return a unique base skeleton from a given pattern. This is
+ * the same as the skeleton, except that differences in length are minimized
+ * so as to only preserve the difference between string and numeric form. So
+ * for example, both "MMM-dd" and "d/MMM" produce the skeleton "MMMd"
+ * (notice the single d).
+ *
+ * @param pattern Input pattern, such as "dd/MMM"
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @return base skeleton, such as "Md"
+ * @draft ICU 3.8
+ */
+ UnicodeString getBaseSkeleton(const UnicodeString& pattern, UErrorCode& status);
+
+ /**
+ * Adds a pattern to the generator. If the pattern has the same skeleton as
+ * an existing pattern, and the override parameter is set, then the previous
+ * value is overriden. Otherwise, the previous value is retained. In either
+ * case, the conflicting status is set and previous vale is stored in
+ * conflicting pattern.
+ * <p>
+ * Note that single-field patterns (like "MMM") are automatically added, and
+ * don't need to be added explicitly!
+ *
+ * @param pattern Input pattern, such as "dd/MMM"
+ * @param override When existing values are to be overridden use true,
+ * otherwise use false.
+ * @param conflictingPattern Previous pattern with the same skeleton.
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @return conflicting status. The value could be UDATPG_NO_CONFLICT,
+ * UDATPG_BASE_CONFLICT or UDATPG_CONFLICT.
+ * @draft ICU 3.8
+ */
+ UDateTimePatternConflict addPattern(const UnicodeString& pattern,
+ UBool override,
+ UnicodeString& conflictingPattern,
+ UErrorCode& status);
+
+ /**
+ * An AppendItem format is a pattern used to append a field if there is no
+ * good match. For example, suppose that the input skeleton is "GyyyyMMMd",
+ * and there is no matching pattern internally, but there is a pattern
+ * matching "yyyyMMMd", say "d-MM-yyyy". Then that pattern is used, plus the
+ * G. The way these two are conjoined is by using the AppendItemFormat for G
+ * (era). So if that value is, say "{0}, {1}" then the final resulting
+ * pattern is "d-MM-yyyy, G".
+ * <p>
+ * There are actually three available variables: {0} is the pattern so far,
+ * {1} is the element we are adding, and {2} is the name of the element.
+ * <p>
+ * This reflects the way that the CLDR data is organized.
+ *
+ * @param field such as UDATPG_ERA_FIELD.
+ * @param value pattern, such as "{0}, {1}"
+ * @draft ICU 3.8
+ */
+ void setAppendItemFormat(UDateTimePatternField field, const UnicodeString& value);
+
+ /**
+ * Getter corresponding to setAppendItemFormat. Values below 0 or at or
+ * above UDATPG_FIELD_COUNT are illegal arguments.
+ *
+ * @param field such as UDATPG_ERA_FIELD.
+ * @return append pattern for field
+ * @draft ICU 3.8
+ */
+ const UnicodeString& getAppendItemFormat(UDateTimePatternField field) const;
+
+ /**
+ * Sets the names of field, eg "era" in English for ERA. These are only
+ * used if the corresponding AppendItemFormat is used, and if it contains a
+ * {2} variable.
+ * <p>
+ * This reflects the way that the CLDR data is organized.
+ *
+ * @param field such as UDATPG_ERA_FIELD.
+ * @param value name of the field
+ * @draft ICU 3.8
+ */
+ void setAppendItemName(UDateTimePatternField field, const UnicodeString& value);
+
+ /**
+ * Getter corresponding to setAppendItemNames. Values below 0 or at or above
+ * UDATPG_FIELD_COUNT are illegal arguments.
+ *
+ * @param field such as UDATPG_ERA_FIELD.
+ * @return name for field
+ * @draft ICU 3.8
+ */
+ const UnicodeString& getAppendItemName(UDateTimePatternField field) const;
+
+ /**
+ * The date time format is a message format pattern used to compose date and
+ * time patterns. The default value is "{0} {1}", where {0} will be replaced
+ * by the date pattern and {1} will be replaced by the time pattern.
+ * <p>
+ * This is used when the input skeleton contains both date and time fields,
+ * but there is not a close match among the added patterns. For example,
+ * suppose that this object was created by adding "dd-MMM" and "hh:mm", and
+ * its datetimeFormat is the default "{0} {1}". Then if the input skeleton
+ * is "MMMdhmm", there is not an exact match, so the input skeleton is
+ * broken up into two components "MMMd" and "hmm". There are close matches
+ * for those two skeletons, so the result is put together with this pattern,
+ * resulting in "d-MMM h:mm".
+ *
+ * @param dateTimeFormat
+ * message format pattern, here {0} will be replaced by the date
+ * pattern and {1} will be replaced by the time pattern.
+ * @draft ICU 3.8
+ */
+ void setDateTimeFormat(const UnicodeString& dateTimeFormat);
+
+ /**
+ * Getter corresponding to setDateTimeFormat.
+ * @return DateTimeFormat.
+ * @draft ICU 3.8
+ */
+ const UnicodeString& getDateTimeFormat() const;
+
+ /**
+ * Return the best pattern matching the input skeleton. It is guaranteed to
+ * have all of the fields in the skeleton.
+ *
+ * @param skeleton
+ * The skeleton is a pattern containing only the variable fields.
+ * For example, "MMMdd" and "mmhh" are skeletons.
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @return bestPattern
+ * The best pattern found from the given skeleton.
+ * @draft ICU 3.8
+ */
+ UnicodeString getBestPattern(const UnicodeString& skeleton, UErrorCode& status);
+
+
+ /**
+ * Adjusts the field types (width and subtype) of a pattern to match what is
+ * in a skeleton. That is, if you supply a pattern like "d-M H:m", and a
+ * skeleton of "MMMMddhhmm", then the input pattern is adjusted to be
+ * "dd-MMMM hh:mm". This is used internally to get the best match for the
+ * input skeleton, but can also be used externally.
+ *
+ * @param pattern Input pattern
+ * @param skeleton
+ * The skeleton is a pattern containing only the variable fields.
+ * For example, "MMMdd" and "mmhh" are skeletons.
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @return pattern adjusted to match the skeleton fields widths and subtypes.
+ * @draft ICU 3.8
+ */
+ UnicodeString replaceFieldTypes(const UnicodeString& pattern,
+ const UnicodeString& skeleton,
+ UErrorCode& status);
+
+ /**
+ * Return a list of all the skeletons (in canonical form) from this class.
+ *
+ * Call getPatternForSkeleton() to get the corresponding pattern.
+ *
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @return StringEnumeration with the skeletons.
+ * The caller must delete the object.
+ * @draft ICU 3.8
+ */
+ StringEnumeration* getSkeletons(UErrorCode& status) const;
+
+ /**
+ * Get the pattern corresponding to a given skeleton.
+ * @param skeleton
+ * @return pattern corresponding to a given skeleton.
+ * @draft ICU 3.8
+ */
+ const UnicodeString& getPatternForSkeleton(const UnicodeString& skeleton) const;
+
+ /**
+ * Return a list of all the base skeletons (in canonical form) from this class.
+ *
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @return a StringEnumeration with the base skeletons.
+ * The caller must delete the object.
+ * @draft ICU 3.8
+ */
+ StringEnumeration* getBaseSkeletons(UErrorCode& status) const;
+
+ /**
+ * Return a list of redundant patterns are those which if removed, make no
+ * difference in the resulting getBestPattern values. This method returns a
+ * list of them, to help check the consistency of the patterns used to build
+ * this generator.
+ *
+ * @param status Output param set to success/failure code on exit,
+ * which must not indicate a failure before the function call.
+ * @return a StringEnumeration with the redundant pattern.
+ * The caller must delete the object.
+ * @internal ICU 3.8
+ */
+ StringEnumeration* getRedundants(UErrorCode& status);
+
+ /**
+ * The decimal value is used in formatting fractions of seconds. If the
+ * skeleton contains fractional seconds, then this is used with the
+ * fractional seconds. For example, suppose that the input pattern is
+ * "hhmmssSSSS", and the best matching pattern internally is "H:mm:ss", and
+ * the decimal string is ",". Then the resulting pattern is modified to be
+ * "H:mm:ss,SSSS"
+ *
+ * @param decimal
+ * @draft ICU 3.8
+ */
+ void setDecimal(const UnicodeString& decimal);
+
+ /**
+ * Getter corresponding to setDecimal.
+ * @return UnicodeString corresponding to the decimal point
+ * @draft ICU 3.8
+ */
+ const UnicodeString& getDecimal() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 3.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+private:
+ /**
+ * Constructor.
+ * @draft ICU 3.8
+ */
+ DateTimePatternGenerator(UErrorCode & status);
+
+ /**
+ * Constructor.
+ * @draft ICU 3.8
+ */
+ DateTimePatternGenerator(const Locale& locale, UErrorCode & status);
+
+ /**
+ * Copy constructor.
+ * @param other DateTimePatternGenerator to copy
+ * @draft ICU 3.8
+ */
+ DateTimePatternGenerator(const DateTimePatternGenerator& other);
+
+ /**
+ * Default assignment operator.
+ * @param other DateTimePatternGenerator to copy
+ * @draft ICU 3.8
+ */
+ DateTimePatternGenerator& operator=(const DateTimePatternGenerator& other);
+
+ Locale pLocale; // pattern locale
+ FormatParser *fp;
+ DateTimeMatcher* dtMatcher;
+ DistanceInfo *distanceInfo;
+ PatternMap *patternMap;
+ UnicodeString appendItemFormats[UDATPG_FIELD_COUNT];
+ UnicodeString appendItemNames[UDATPG_FIELD_COUNT];
+ UnicodeString dateTimeFormat;
+ UnicodeString decimal;
+ DateTimeMatcher *skipMatcher;
+ Hashtable *fAvailableFormatKeyHash;
+ UnicodeString hackPattern;
+ UErrorCode fStatus;
+ UnicodeString emptyString;
+
+ void initData(const Locale &locale);
+ void addCanonicalItems();
+ void addICUPatterns(const Locale& locale, UErrorCode& status);
+ void hackTimes(const UnicodeString& hackPattern, UErrorCode& status);
+ void addCLDRData(const Locale& locale);
+ void initHashtable(UErrorCode& status);
+ void setDateTimeFromCalendar(const Locale& locale, UErrorCode& status);
+ void setDecimalSymbols(const Locale& locale, UErrorCode& status);
+ UDateTimePatternField getAppendFormatNumber(const char* field) const;
+ UDateTimePatternField getAppendNameNumber(const char* field) const;
+ void getAppendName(UDateTimePatternField field, UnicodeString& value);
+ int32_t getCanonicalIndex(const UnicodeString& field);
+ const UnicodeString* getBestRaw(DateTimeMatcher& source, int32_t includeMask, DistanceInfo* missingFields);
+ UnicodeString adjustFieldTypes(const UnicodeString& pattern, UBool fixFractionalSeconds);
+ UnicodeString getBestAppending(int32_t missingFields);
+ int32_t getTopBitNumber(int32_t foundMask);
+ void setAvailableFormat(const UnicodeString &key, UErrorCode& status);
+ UBool isAvailableFormatSet(const UnicodeString &key) const;
+ void copyHashtable(Hashtable *other);
+ UBool isCanonicalItem(const UnicodeString& item) const;
+ UErrorCode getStatus() const { return fStatus; } ;
+} ;// end class DateTimePatternGenerator
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/dtrule.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/dtrule.h
new file mode 100644
index 00000000000..7bdacd06aea
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/dtrule.h
@@ -0,0 +1,250 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef DTRULE_H
+#define DTRULE_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Rule for specifying date and time in an year
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+
+U_NAMESPACE_BEGIN
+/**
+ * <code>DateTimeRule</code> is a class representing a time in a year by
+ * a rule specified by month, day of month, day of week and
+ * time in the day.
+ *
+ * @draft ICU 3.8
+ */
+class U_I18N_API DateTimeRule : public UObject {
+public:
+
+ /**
+ * Date rule type constants.
+ * @draft ICU 3.8
+ */
+ enum DateRuleType {
+ DOM = 0, /**< The exact day of month,
+ for example, March 11. */
+ DOW, /**< The Nth occurence of the day of week,
+ for example, 2nd Sunday in March. */
+ DOW_GEQ_DOM, /**< The first occurence of the day of week on or after the day of monnth,
+ for example, first Sunday on or after March 8. */
+ DOW_LEQ_DOM /**< The last occurence of the day of week on or before the day of month,
+ for example, first Sunday on or before March 14. */
+ };
+
+ /**
+ * Time rule type constants.
+ * @draft ICU 3.8
+ */
+ enum TimeRuleType {
+ WALL_TIME = 0, /**< The local wall clock time */
+ STANDARD_TIME, /**< The local standard time */
+ UTC_TIME /**< The UTC time */
+ };
+
+ /**
+ * Constructs a <code>DateTimeRule</code> by the day of month and
+ * the time rule. The date rule type for an instance created by
+ * this constructor is <code>DOM</code>.
+ *
+ * @param month The rule month, for example, <code>Calendar::JANUARY</code>
+ * @param dayOfMonth The day of month, 1-based.
+ * @param millisInDay The milliseconds in the rule date.
+ * @param timeType The time type, <code>WALL_TIME</code> or <code>STANDARD_TIME</code>
+ * or <code>UTC_TIME</code>.
+ * @draft ICU 3.8
+ */
+ DateTimeRule(int32_t month, int32_t dayOfMonth,
+ int32_t millisInDay, TimeRuleType timeType);
+
+ /**
+ * Constructs a <code>DateTimeRule</code> by the day of week and its oridinal
+ * number and the time rule. The date rule type for an instance created
+ * by this constructor is <code>DOW</code>.
+ *
+ * @param month The rule month, for example, <code>Calendar::JANUARY</code>.
+ * @param weekInMonth The ordinal number of the day of week. Negative number
+ * may be used for specifying a rule date counted from the
+ * end of the rule month.
+ * @param dayOfWeek The day of week, for example, <code>Calendar::SUNDAY</code>.
+ * @param millisInDay The milliseconds in the rule date.
+ * @param timeType The time type, <code>WALL_TIME</code> or <code>STANDARD_TIME</code>
+ * or <code>UTC_TIME</code>.
+ * @draft ICU 3.8
+ */
+ DateTimeRule(int32_t month, int32_t weekInMonth, int32_t dayOfWeek,
+ int32_t millisInDay, TimeRuleType timeType);
+
+ /**
+ * Constructs a <code>DateTimeRule</code> by the first/last day of week
+ * on or after/before the day of month and the time rule. The date rule
+ * type for an instance created by this constructor is either
+ * <code>DOM_GEQ_DOM</code> or <code>DOM_LEQ_DOM</code>.
+ *
+ * @param month The rule month, for example, <code>Calendar::JANUARY</code>
+ * @param dayOfMonth The day of month, 1-based.
+ * @param dayOfWeek The day of week, for example, <code>Calendar::SUNDAY</code>.
+ * @param after true if the rule date is on or after the day of month.
+ * @param millisInDay The milliseconds in the rule date.
+ * @param timeType The time type, <code>WALL_TIME</code> or <code>STANDARD_TIME</code>
+ * or <code>UTC_TIME</code>.
+ * @draft ICU 3.8
+ */
+ DateTimeRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek, UBool after,
+ int32_t millisInDay, TimeRuleType timeType);
+
+ /**
+ * Copy constructor.
+ * @param source The DateTimeRule object to be copied.
+ * @draft ICU 3.8
+ */
+ DateTimeRule(const DateTimeRule& source);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ ~DateTimeRule();
+
+ /**
+ * Clone this DateTimeRule object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @draft ICU 3.8
+ */
+ DateTimeRule* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @draft ICU 3.8
+ */
+ DateTimeRule& operator=(const DateTimeRule& right);
+
+ /**
+ * Return true if the given DateTimeRule objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given DateTimeRule objects are semantically equal.
+ * @draft ICU 3.8
+ */
+ UBool operator==(const DateTimeRule& that) const;
+
+ /**
+ * Return true if the given DateTimeRule objects are semantically unequal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given DateTimeRule objects are semantically unequal.
+ * @draft ICU 3.8
+ */
+ UBool operator!=(const DateTimeRule& that) const;
+
+ /**
+ * Gets the date rule type, such as <code>DOM</code>
+ * @return The date rule type.
+ * @draft ICU 3.8
+ */
+ DateRuleType getDateRuleType(void) const;
+
+ /**
+ * Gets the time rule type
+ * @return The time rule type, either <code>WALL_TIME</code> or <code>STANDARD_TIME</code>
+ * or <code>UTC_TIME</code>.
+ * @draft ICU 3.8
+ */
+ TimeRuleType getTimeRuleType(void) const;
+
+ /**
+ * Gets the rule month.
+ * @return The rule month.
+ * @draft ICU 3.8
+ */
+ int32_t getRuleMonth(void) const;
+
+ /**
+ * Gets the rule day of month. When the date rule type
+ * is <code>DOW</code>, the value is always 0.
+ * @return The rule day of month
+ * @draft ICU 3.8
+ */
+ int32_t getRuleDayOfMonth(void) const;
+
+ /**
+ * Gets the rule day of week. When the date rule type
+ * is <code>DOM</code>, the value is always 0.
+ * @return The rule day of week.
+ * @draft ICU 3.8
+ */
+ int32_t getRuleDayOfWeek(void) const;
+
+ /**
+ * Gets the ordinal number of the occurence of the day of week
+ * in the month. When the date rule type is not <code>DOW</code>,
+ * the value is always 0.
+ * @return The rule day of week ordinal number in the month.
+ * @draft ICU 3.8
+ */
+ int32_t getRuleWeekInMonth(void) const;
+
+ /**
+ * Gets the rule time in the rule day.
+ * @return The time in the rule day in milliseconds.
+ * @draft ICU 3.8
+ */
+ int32_t getRuleMillisInDay(void) const;
+
+private:
+ int32_t fMonth;
+ int32_t fDayOfMonth;
+ int32_t fDayOfWeek;
+ int32_t fWeekInMonth;
+ int32_t fMillisInDay;
+ DateRuleType fDateRuleType;
+ TimeRuleType fTimeRuleType;
+
+public:
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // DTRULE_H
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/fieldpos.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/fieldpos.h
new file mode 100644
index 00000000000..38a9576e782
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/fieldpos.h
@@ -0,0 +1,291 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 1997-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************************
+ *
+ * File FIELDPOS.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 02/25/97 aliu Converted from java.
+ * 03/17/97 clhuang Updated per Format implementation.
+ * 07/17/98 stephen Added default/copy ctors, and operators =, ==, !=
+ ********************************************************************************
+ */
+
+// *****************************************************************************
+// This file was generated from the java source file FieldPosition.java
+// *****************************************************************************
+
+#ifndef FIELDPOS_H
+#define FIELDPOS_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: FieldPosition identifies the fields in a formatted output.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * <code>FieldPosition</code> is a simple class used by <code>Format</code>
+ * and its subclasses to identify fields in formatted output. Fields are
+ * identified by constants, whose names typically end with <code>_FIELD</code>,
+ * defined in the various subclasses of <code>Format</code>. See
+ * <code>ERA_FIELD</code> and its friends in <code>DateFormat</code> for
+ * an example.
+ *
+ * <p>
+ * <code>FieldPosition</code> keeps track of the position of the
+ * field within the formatted output with two indices: the index
+ * of the first character of the field and the index of the last
+ * character of the field.
+ *
+ * <p>
+ * One version of the <code>format</code> method in the various
+ * <code>Format</code> classes requires a <code>FieldPosition</code>
+ * object as an argument. You use this <code>format</code> method
+ * to perform partial formatting or to get information about the
+ * formatted output (such as the position of a field).
+ *
+ * The FieldPosition class is not suitable for subclassing.
+ *
+ * <p>
+ * Below is an example of using <code>FieldPosition</code> to aid
+ * alignment of an array of formatted floating-point numbers on
+ * their decimal points:
+ * <pre>
+ * \code
+ * double doubleNum[] = {123456789.0, -12345678.9, 1234567.89, -123456.789,
+ * 12345.6789, -1234.56789, 123.456789, -12.3456789, 1.23456789};
+ * int dNumSize = (int)(sizeof(doubleNum)/sizeof(double));
+ *
+ * UErrorCode status = U_ZERO_ERROR;
+ * DecimalFormat* fmt = (DecimalFormat*) NumberFormat::createInstance(status);
+ * fmt->setDecimalSeparatorAlwaysShown(true);
+ *
+ * const int tempLen = 20;
+ * char temp[tempLen];
+ *
+ * for (int i=0; i<dNumSize; i++) {
+ * FieldPosition pos(NumberFormat::INTEGER_FIELD);
+ * UnicodeString buf;
+ * char fmtText[tempLen];
+ * ToCharString(fmt->format(doubleNum[i], buf, pos), fmtText);
+ * for (int j=0; j<tempLen; j++) temp[j] = ' '; // clear with spaces
+ * temp[__min(tempLen, tempLen-pos.getEndIndex())] = '\0';
+ * cout << temp << fmtText << endl;
+ * }
+ * delete fmt;
+ * \endcode
+ * </pre>
+ * <p>
+ * The code will generate the following output:
+ * <pre>
+ * \code
+ * 123,456,789.000
+ * -12,345,678.900
+ * 1,234,567.880
+ * -123,456.789
+ * 12,345.678
+ * -1,234.567
+ * 123.456
+ * -12.345
+ * 1.234
+ * \endcode
+ * </pre>
+ */
+class U_I18N_API FieldPosition : public UObject {
+public:
+ /**
+ * DONT_CARE may be specified as the field to indicate that the
+ * caller doesn't need to specify a field. Do not subclass.
+ */
+ enum { DONT_CARE = -1 };
+
+ /**
+ * Creates a FieldPosition object with a non-specified field.
+ * @stable ICU 2.0
+ */
+ FieldPosition()
+ : UObject(), fField(DONT_CARE), fBeginIndex(0), fEndIndex(0) {}
+
+ /**
+ * Creates a FieldPosition object for the given field. Fields are
+ * identified by constants, whose names typically end with _FIELD,
+ * in the various subclasses of Format.
+ *
+ * @see NumberFormat#INTEGER_FIELD
+ * @see NumberFormat#FRACTION_FIELD
+ * @see DateFormat#YEAR_FIELD
+ * @see DateFormat#MONTH_FIELD
+ * @stable ICU 2.0
+ */
+ FieldPosition(int32_t field)
+ : UObject(), fField(field), fBeginIndex(0), fEndIndex(0) {}
+
+ /**
+ * Copy constructor
+ * @param copy the object to be copied from.
+ * @stable ICU 2.0
+ */
+ FieldPosition(const FieldPosition& copy)
+ : UObject(copy), fField(copy.fField), fBeginIndex(copy.fBeginIndex), fEndIndex(copy.fEndIndex) {}
+
+ /**
+ * Destructor
+ * @stable ICU 2.0
+ */
+ virtual ~FieldPosition();
+
+ /**
+ * Assignment operator
+ * @param copy the object to be copied from.
+ * @stable ICU 2.0
+ */
+ FieldPosition& operator=(const FieldPosition& copy);
+
+ /**
+ * Equality operator.
+ * @param that the object to be compared with.
+ * @return TRUE if the two field positions are equal, FALSE otherwise.
+ * @stable ICU 2.0
+ */
+ UBool operator==(const FieldPosition& that) const;
+
+ /**
+ * Equality operator.
+ * @param that the object to be compared with.
+ * @return TRUE if the two field positions are not equal, FALSE otherwise.
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const FieldPosition& that) const;
+
+ /**
+ * Clone this object.
+ * Clones can be used concurrently in multiple threads.
+ * If an error occurs, then NULL is returned.
+ * The caller must delete the clone.
+ *
+ * @return a clone of this object
+ *
+ * @see getDynamicClassID
+ * @stable ICU 2.8
+ */
+ FieldPosition *clone() const;
+
+ /**
+ * Retrieve the field identifier.
+ * @return the field identifier.
+ * @stable ICU 2.0
+ */
+ int32_t getField(void) const { return fField; }
+
+ /**
+ * Retrieve the index of the first character in the requested field.
+ * @return the index of the first character in the requested field.
+ * @stable ICU 2.0
+ */
+ int32_t getBeginIndex(void) const { return fBeginIndex; }
+
+ /**
+ * Retrieve the index of the character following the last character in the
+ * requested field.
+ * @return the index of the character following the last character in the
+ * requested field.
+ * @stable ICU 2.0
+ */
+ int32_t getEndIndex(void) const { return fEndIndex; }
+
+ /**
+ * Set the field.
+ * @param f the new value of the field.
+ * @stable ICU 2.0
+ */
+ void setField(int32_t f) { fField = f; }
+
+ /**
+ * Set the begin index. For use by subclasses of Format.
+ * @param bi the new value of the begin index
+ * @stable ICU 2.0
+ */
+ void setBeginIndex(int32_t bi) { fBeginIndex = bi; }
+
+ /**
+ * Set the end index. For use by subclasses of Format.
+ * @param ei the new value of the end index
+ * @stable ICU 2.0
+ */
+ void setEndIndex(int32_t ei) { fEndIndex = ei; }
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+ /**
+ * Input: Desired field to determine start and end offsets for.
+ * The meaning depends on the subclass of Format.
+ */
+ int32_t fField;
+
+ /**
+ * Output: Start offset of field in text.
+ * If the field does not occur in the text, 0 is returned.
+ */
+ int32_t fBeginIndex;
+
+ /**
+ * Output: End offset of field in text.
+ * If the field does not occur in the text, 0 is returned.
+ */
+ int32_t fEndIndex;
+};
+
+inline FieldPosition&
+FieldPosition::operator=(const FieldPosition& copy)
+{
+ fField = copy.fField;
+ fEndIndex = copy.fEndIndex;
+ fBeginIndex = copy.fBeginIndex;
+ return *this;
+}
+
+inline UBool
+FieldPosition::operator==(const FieldPosition& copy) const
+{
+ return (fField == copy.fField &&
+ fEndIndex == copy.fEndIndex &&
+ fBeginIndex == copy.fBeginIndex);
+}
+
+inline UBool
+FieldPosition::operator!=(const FieldPosition& copy) const
+{
+ return !operator==(copy);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _FIELDPOS
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/fmtable.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/fmtable.h
new file mode 100644
index 00000000000..94ee32843f5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/fmtable.h
@@ -0,0 +1,591 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File FMTABLE.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/29/97 aliu Creation.
+********************************************************************************
+*/
+#ifndef FMTABLE_H
+#define FMTABLE_H
+
+#include "unicode/utypes.h"
+#include "unicode/unistr.h"
+/**
+ * \file
+ * \brief C++ API: Formattable is a thin wrapper for primitive numeric types.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Formattable objects can be passed to the Format class or
+ * its subclasses for formatting. Formattable is a thin wrapper
+ * class which interconverts between the primitive numeric types
+ * (double, long, etc.) as well as UDate and UnicodeString.
+ *
+ * <p>Internally, a Formattable object is a union of primitive types.
+ * As such, it can only store one flavor of data at a time. To
+ * determine what flavor of data it contains, use the getType method.
+ *
+ * <p>As of ICU 3.0, Formattable may also wrap a UObject pointer,
+ * which it owns. This allows an instance of any ICU class to be
+ * encapsulated in a Formattable. For legacy reasons and for
+ * efficiency, primitive numeric types are still stored directly
+ * within a Formattable.
+ *
+ * <p>The Formattable class is not suitable for subclassing.
+ */
+class U_I18N_API Formattable : public UObject {
+public:
+ /**
+ * This enum is only used to let callers distinguish between
+ * the Formattable(UDate) constructor and the Formattable(double)
+ * constructor; the compiler cannot distinguish the signatures,
+ * since UDate is currently typedefed to be either double or long.
+ * If UDate is changed later to be a bonafide class
+ * or struct, then we no longer need this enum.
+ * @stable ICU 2.4
+ */
+ enum ISDATE { kIsDate };
+
+ /**
+ * Default constructor
+ * @stable ICU 2.4
+ */
+ Formattable(); // Type kLong, value 0
+
+ /**
+ * Creates a Formattable object with a UDate instance.
+ * @param d the UDate instance.
+ * @param flag the flag to indicate this is a date. Always set it to kIsDate
+ * @stable ICU 2.0
+ */
+ Formattable(UDate d, ISDATE flag);
+
+ /**
+ * Creates a Formattable object with a double number.
+ * @param d the double number.
+ * @stable ICU 2.0
+ */
+ Formattable(double d);
+
+ /**
+ * Creates a Formattable object with a long number.
+ * @param l the long number.
+ * @stable ICU 2.0
+ */
+ Formattable(int32_t l);
+
+ /**
+ * Creates a Formattable object with an int64_t number
+ * @param ll the int64_t number.
+ * @stable ICU 2.8
+ */
+ Formattable(int64_t ll);
+
+#if !UCONFIG_NO_CONVERSION
+ /**
+ * Creates a Formattable object with a char string pointer.
+ * Assumes that the char string is null terminated.
+ * @param strToCopy the char string.
+ * @stable ICU 2.0
+ */
+ Formattable(const char* strToCopy);
+#endif
+
+ /**
+ * Creates a Formattable object with a UnicodeString object to copy from.
+ * @param strToCopy the UnicodeString string.
+ * @stable ICU 2.0
+ */
+ Formattable(const UnicodeString& strToCopy);
+
+ /**
+ * Creates a Formattable object with a UnicodeString object to adopt from.
+ * @param strToAdopt the UnicodeString string.
+ * @stable ICU 2.0
+ */
+ Formattable(UnicodeString* strToAdopt);
+
+ /**
+ * Creates a Formattable object with an array of Formattable objects.
+ * @param arrayToCopy the Formattable object array.
+ * @param count the array count.
+ * @stable ICU 2.0
+ */
+ Formattable(const Formattable* arrayToCopy, int32_t count);
+
+ /**
+ * Creates a Formattable object that adopts the given UObject.
+ * @param objectToAdopt the UObject to set this object to
+ * @stable ICU 3.0
+ */
+ Formattable(UObject* objectToAdopt);
+
+ /**
+ * Copy constructor.
+ * @stable ICU 2.0
+ */
+ Formattable(const Formattable&);
+
+ /**
+ * Assignment operator.
+ * @param rhs The Formattable object to copy into this object.
+ * @stable ICU 2.0
+ */
+ Formattable& operator=(const Formattable &rhs);
+
+ /**
+ * Equality comparison.
+ * @param other the object to be compared with.
+ * @return TRUE if other are equal to this, FALSE otherwise.
+ * @stable ICU 2.0
+ */
+ UBool operator==(const Formattable &other) const;
+
+ /**
+ * Equality operator.
+ * @param other the object to be compared with.
+ * @return TRUE if other are unequal to this, FALSE otherwise.
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const Formattable& other) const
+ { return !operator==(other); }
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~Formattable();
+
+ /**
+ * Clone this object.
+ * Clones can be used concurrently in multiple threads.
+ * If an error occurs, then NULL is returned.
+ * The caller must delete the clone.
+ *
+ * @return a clone of this object
+ *
+ * @see getDynamicClassID
+ * @stable ICU 2.8
+ */
+ Formattable *clone() const;
+
+ /**
+ * Selector for flavor of data type contained within a
+ * Formattable object. Formattable is a union of several
+ * different types, and at any time contains exactly one type.
+ * @stable ICU 2.4
+ */
+ enum Type {
+ /**
+ * Selector indicating a UDate value. Use getDate to retrieve
+ * the value.
+ * @stable ICU 2.4
+ */
+ kDate,
+
+ /**
+ * Selector indicating a double value. Use getDouble to
+ * retrieve the value.
+ * @stable ICU 2.4
+ */
+ kDouble,
+
+ /**
+ * Selector indicating a 32-bit integer value. Use getLong to
+ * retrieve the value.
+ * @stable ICU 2.4
+ */
+ kLong,
+
+ /**
+ * Selector indicating a UnicodeString value. Use getString
+ * to retrieve the value.
+ * @stable ICU 2.4
+ */
+ kString,
+
+ /**
+ * Selector indicating an array of Formattables. Use getArray
+ * to retrieve the value.
+ * @stable ICU 2.4
+ */
+ kArray,
+
+ /**
+ * Selector indicating a 64-bit integer value. Use getInt64
+ * to retrieve the value.
+ * @stable ICU 2.8
+ */
+ kInt64,
+
+ /**
+ * Selector indicating a UObject value. Use getObject to
+ * retrieve the value.
+ * @stable ICU 3.0
+ */
+ kObject
+ };
+
+ /**
+ * Gets the data type of this Formattable object.
+ * @return the data type of this Formattable object.
+ * @stable ICU 2.0
+ */
+ Type getType(void) const;
+
+ /**
+ * Returns TRUE if the data type of this Formattable object
+ * is kDouble, kLong, or kInt64.
+ * @return TRUE if this is a pure numeric object
+ * @stable ICU 3.0
+ */
+ UBool isNumeric() const;
+
+ /**
+ * Gets the double value of this object. If this object is not of type
+ * kDouble then the result is undefined.
+ * @return the double value of this object.
+ * @stable ICU 2.0
+ */
+ double getDouble(void) const { return fValue.fDouble; }
+
+ /**
+ * Gets the double value of this object. If this object is of type
+ * long or int64 then a casting conversion is peformed, with
+ * possible loss of precision. If the type is kObject and the
+ * object is a Measure, then the result of
+ * getNumber().getDouble(status) is returned. If this object is
+ * neither a numeric type nor a Measure, then 0 is returned and
+ * the status is set to U_INVALID_FORMAT_ERROR.
+ * @param status the error code
+ * @return the double value of this object.
+ * @stable ICU 3.0
+ */
+ double getDouble(UErrorCode& status) const;
+
+ /**
+ * Gets the long value of this object. If this object is not of type
+ * kLong then the result is undefined.
+ * @return the long value of this object.
+ * @stable ICU 2.0
+ */
+ int32_t getLong(void) const { return (int32_t)fValue.fInt64; }
+
+ /**
+ * Gets the long value of this object. If the magnitude is too
+ * large to fit in a long, then the maximum or minimum long value,
+ * as appropriate, is returned and the status is set to
+ * U_INVALID_FORMAT_ERROR. If this object is of type kInt64 and
+ * it fits within a long, then no precision is lost. If it is of
+ * type kDouble, then a casting conversion is peformed, with
+ * truncation of any fractional part. If the type is kObject and
+ * the object is a Measure, then the result of
+ * getNumber().getLong(status) is returned. If this object is
+ * neither a numeric type nor a Measure, then 0 is returned and
+ * the status is set to U_INVALID_FORMAT_ERROR.
+ * @param status the error code
+ * @return the long value of this object.
+ * @stable ICU 3.0
+ */
+ int32_t getLong(UErrorCode& status) const;
+
+ /**
+ * Gets the int64 value of this object. If this object is not of type
+ * kInt64 then the result is undefined.
+ * @return the int64 value of this object.
+ * @stable ICU 2.8
+ */
+ int64_t getInt64(void) const { return fValue.fInt64; }
+
+ /**
+ * Gets the int64 value of this object. If this object is of type
+ * kDouble and the magnitude is too large to fit in an int64, then
+ * the maximum or minimum int64 value, as appropriate, is returned
+ * and the status is set to U_INVALID_FORMAT_ERROR. If the
+ * magnitude fits in an int64, then a casting conversion is
+ * peformed, with truncation of any fractional part. If the type
+ * is kObject and the object is a Measure, then the result of
+ * getNumber().getDouble(status) is returned. If this object is
+ * neither a numeric type nor a Measure, then 0 is returned and
+ * the status is set to U_INVALID_FORMAT_ERROR.
+ * @param status the error code
+ * @return the int64 value of this object.
+ * @stable ICU 3.0
+ */
+ int64_t getInt64(UErrorCode& status) const;
+
+ /**
+ * Gets the Date value of this object. If this object is not of type
+ * kDate then the result is undefined.
+ * @return the Date value of this object.
+ * @stable ICU 2.0
+ */
+ UDate getDate() const { return fValue.fDate; }
+
+ /**
+ * Gets the Date value of this object. If the type is not a date,
+ * status is set to U_INVALID_FORMAT_ERROR and the return value is
+ * undefined.
+ * @param status the error code.
+ * @return the Date value of this object.
+ * @stable ICU 3.0
+ */
+ UDate getDate(UErrorCode& status) const;
+
+ /**
+ * Gets the string value of this object. If this object is not of type
+ * kString then the result is undefined.
+ * @param result Output param to receive the Date value of this object.
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ UnicodeString& getString(UnicodeString& result) const
+ { result=*fValue.fString; return result; }
+
+ /**
+ * Gets the string value of this object. If the type is not a
+ * string, status is set to U_INVALID_FORMAT_ERROR and a bogus
+ * string is returned.
+ * @param result Output param to receive the Date value of this object.
+ * @param status the error code.
+ * @return A reference to 'result'.
+ * @stable ICU 3.0
+ */
+ UnicodeString& getString(UnicodeString& result, UErrorCode& status) const;
+
+ /**
+ * Gets a const reference to the string value of this object. If
+ * this object is not of type kString then the result is
+ * undefined.
+ * @return a const reference to the string value of this object.
+ * @stable ICU 2.0
+ */
+ inline const UnicodeString& getString(void) const;
+
+ /**
+ * Gets a const reference to the string value of this object. If
+ * the type is not a string, status is set to
+ * U_INVALID_FORMAT_ERROR and the result is a bogus string.
+ * @param status the error code.
+ * @return a const reference to the string value of this object.
+ * @stable ICU 3.0
+ */
+ const UnicodeString& getString(UErrorCode& status) const;
+
+ /**
+ * Gets a reference to the string value of this object. If this
+ * object is not of type kString then the result is undefined.
+ * @return a reference to the string value of this object.
+ * @stable ICU 2.0
+ */
+ inline UnicodeString& getString(void);
+
+ /**
+ * Gets a reference to the string value of this object. If the
+ * type is not a string, status is set to U_INVALID_FORMAT_ERROR
+ * and the result is a bogus string.
+ * @param status the error code.
+ * @return a reference to the string value of this object.
+ * @stable ICU 3.0
+ */
+ UnicodeString& getString(UErrorCode& status);
+
+ /**
+ * Gets the array value and count of this object. If this object
+ * is not of type kArray then the result is undefined.
+ * @param count fill-in with the count of this object.
+ * @return the array value of this object.
+ * @stable ICU 2.0
+ */
+ const Formattable* getArray(int32_t& count) const
+ { count=fValue.fArrayAndCount.fCount; return fValue.fArrayAndCount.fArray; }
+
+ /**
+ * Gets the array value and count of this object. If the type is
+ * not an array, status is set to U_INVALID_FORMAT_ERROR, count is
+ * set to 0, and the result is NULL.
+ * @param count fill-in with the count of this object.
+ * @param status the error code.
+ * @return the array value of this object.
+ * @stable ICU 3.0
+ */
+ const Formattable* getArray(int32_t& count, UErrorCode& status) const;
+
+ /**
+ * Accesses the specified element in the array value of this
+ * Formattable object. If this object is not of type kArray then
+ * the result is undefined.
+ * @param index the specified index.
+ * @return the accessed element in the array.
+ * @stable ICU 2.0
+ */
+ Formattable& operator[](int32_t index) { return fValue.fArrayAndCount.fArray[index]; }
+
+ /**
+ * Returns a pointer to the UObject contained within this
+ * formattable, or NULL if this object does not contain a UObject.
+ * @return a UObject pointer, or NULL
+ * @stable ICU 3.0
+ */
+ const UObject* getObject() const;
+
+ /**
+ * Sets the double value of this object and changes the type to
+ * kDouble.
+ * @param d the new double value to be set.
+ * @stable ICU 2.0
+ */
+ void setDouble(double d);
+
+ /**
+ * Sets the long value of this object and changes the type to
+ * kLong.
+ * @param l the new long value to be set.
+ * @stable ICU 2.0
+ */
+ void setLong(int32_t l);
+
+ /**
+ * Sets the int64 value of this object and changes the type to
+ * kInt64.
+ * @param ll the new int64 value to be set.
+ * @stable ICU 2.8
+ */
+ void setInt64(int64_t ll);
+
+ /**
+ * Sets the Date value of this object and changes the type to
+ * kDate.
+ * @param d the new Date value to be set.
+ * @stable ICU 2.0
+ */
+ void setDate(UDate d);
+
+ /**
+ * Sets the string value of this object and changes the type to
+ * kString.
+ * @param stringToCopy the new string value to be set.
+ * @stable ICU 2.0
+ */
+ void setString(const UnicodeString& stringToCopy);
+
+ /**
+ * Sets the array value and count of this object and changes the
+ * type to kArray.
+ * @param array the array value.
+ * @param count the number of array elements to be copied.
+ * @stable ICU 2.0
+ */
+ void setArray(const Formattable* array, int32_t count);
+
+ /**
+ * Sets and adopts the string value and count of this object and
+ * changes the type to kArray.
+ * @param stringToAdopt the new string value to be adopted.
+ * @stable ICU 2.0
+ */
+ void adoptString(UnicodeString* stringToAdopt);
+
+ /**
+ * Sets and adopts the array value and count of this object and
+ * changes the type to kArray.
+ * @stable ICU 2.0
+ */
+ void adoptArray(Formattable* array, int32_t count);
+
+ /**
+ * Sets and adopts the UObject value of this object and changes
+ * the type to kObject. After this call, the caller must not
+ * delete the given object.
+ * @param objectToAdopt the UObject value to be adopted
+ * @stable ICU 3.0
+ */
+ void adoptObject(UObject* objectToAdopt);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * Deprecated variant of getLong(UErrorCode&).
+ * @param status the error code
+ * @return the long value of this object.
+ * @deprecated ICU 3.0 use getLong(UErrorCode&) instead
+ */
+ inline int32_t getLong(UErrorCode* status) const;
+
+private:
+ /**
+ * Cleans up the memory for unwanted values. For example, the adopted
+ * string or array objects.
+ */
+ void dispose(void);
+
+ UnicodeString* getBogus() const;
+
+ union {
+ UObject* fObject;
+ UnicodeString* fString;
+ double fDouble;
+ int64_t fInt64;
+ UDate fDate;
+ struct {
+ Formattable* fArray;
+ int32_t fCount;
+ } fArrayAndCount;
+ } fValue;
+
+ Type fType;
+ UnicodeString fBogus; // Bogus string when it's needed.
+};
+
+inline UDate Formattable::getDate(UErrorCode& status) const {
+ if (fType != kDate) {
+ if (U_SUCCESS(status)) {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ return 0;
+ }
+ return fValue.fDate;
+}
+
+inline const UnicodeString& Formattable::getString(void) const {
+ return *fValue.fString;
+}
+
+inline UnicodeString& Formattable::getString(void) {
+ return *fValue.fString;
+}
+
+inline int32_t Formattable::getLong(UErrorCode* status) const {
+ return getLong(*status);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif //_FMTABLE
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/format.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/format.h
new file mode 100644
index 00000000000..7f17b52f00a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/format.h
@@ -0,0 +1,296 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2006, International Business Machines Corporation and others.
+* All Rights Reserved.
+********************************************************************************
+*
+* File FORMAT.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/17/97 clhuang Updated per C++ implementation.
+* 03/27/97 helena Updated to pass the simple test after code review.
+********************************************************************************
+*/
+// *****************************************************************************
+// This file was generated from the java source file Format.java
+// *****************************************************************************
+
+#ifndef FORMAT_H
+#define FORMAT_H
+
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Base class for all formats.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/fmtable.h"
+#include "unicode/fieldpos.h"
+#include "unicode/parsepos.h"
+#include "unicode/parseerr.h"
+#include "unicode/locid.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Base class for all formats. This is an abstract base class which
+ * specifies the protocol for classes which convert other objects or
+ * values, such as numeric values and dates, and their string
+ * representations. In some cases these representations may be
+ * localized or contain localized characters or strings. For example,
+ * a numeric formatter such as DecimalFormat may convert a numeric
+ * value such as 12345 to the string "$12,345". It may also parse
+ * the string back into a numeric value. A date and time formatter
+ * like SimpleDateFormat may represent a specific date, encoded
+ * numerically, as a string such as "Wednesday, February 26, 1997 AD".
+ * <P>
+ * Many of the concrete subclasses of Format employ the notion of
+ * a pattern. A pattern is a string representation of the rules which
+ * govern the interconversion between values and strings. For example,
+ * a DecimalFormat object may be associated with the pattern
+ * "$#,##0.00;($#,##0.00)", which is a common US English format for
+ * currency values, yielding strings such as "$1,234.45" for 1234.45,
+ * and "($987.65)" for 987.6543. The specific syntax of a pattern
+ * is defined by each subclass.
+ * <P>
+ * Even though many subclasses use patterns, the notion of a pattern
+ * is not inherent to Format classes in general, and is not part of
+ * the explicit base class protocol.
+ * <P>
+ * Two complex formatting classes bear mentioning. These are
+ * MessageFormat and ChoiceFormat. ChoiceFormat is a subclass of
+ * NumberFormat which allows the user to format different number ranges
+ * as strings. For instance, 0 may be represented as "no files", 1 as
+ * "one file", and any number greater than 1 as "many files".
+ * MessageFormat is a formatter which utilizes other Format objects to
+ * format a string containing with multiple values. For instance,
+ * A MessageFormat object might produce the string "There are no files
+ * on the disk MyDisk on February 27, 1997." given the arguments 0,
+ * "MyDisk", and the date value of 2/27/97. See the ChoiceFormat
+ * and MessageFormat headers for further information.
+ * <P>
+ * If formatting is unsuccessful, a failing UErrorCode is returned when
+ * the Format cannot format the type of object, otherwise if there is
+ * something illformed about the the Unicode replacement character
+ * 0xFFFD is returned.
+ * <P>
+ * If there is no match when parsing, a parse failure UErrorCode is
+ * retured for methods which take no ParsePosition. For the method
+ * that takes a ParsePosition, the index parameter is left unchanged.
+ * <P>
+ * <em>User subclasses are not supported.</em> While clients may write
+ * subclasses, such code will not necessarily work and will not be
+ * guaranteed to work stably from release to release.
+ */
+class U_I18N_API Format : public UObject {
+public:
+
+ /** Destructor
+ * @stable ICU 2.4
+ */
+ virtual ~Format();
+
+ /**
+ * Return true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return Return true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Format& other) const = 0;
+
+ /**
+ * Return true if the given Format objects are not semantically
+ * equal.
+ * @param other the object to be compared with.
+ * @return Return true if the given Format objects are not semantically.
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const Format& other) const { return !operator==(other); }
+
+ /**
+ * Clone this object polymorphically. The caller is responsible
+ * for deleting the result when done.
+ * @return A copy of the object
+ * @stable ICU 2.0
+ */
+ virtual Format* clone() const = 0;
+
+ /**
+ * Formats an object to produce a string.
+ *
+ * @param obj The object to format.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Output parameter filled in with success or failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const;
+
+ /**
+ * Format an object to produce a string. This is a pure virtual method which
+ * subclasses must implement. This method allows polymorphic formatting
+ * of Formattable objects. If a subclass of Format receives a Formattable
+ * object type it doesn't handle (e.g., if a numeric Formattable is passed
+ * to a DateFormat object) then it returns a failing UErrorCode.
+ *
+ * @param obj The object to format.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const = 0;
+
+ /**
+ * Parse a string to produce an object. This is a pure virtual
+ * method which subclasses must implement. This method allows
+ * polymorphic parsing of strings into Formattable objects.
+ * <P>
+ * Before calling, set parse_pos.index to the offset you want to
+ * start parsing at in the source. After calling, parse_pos.index
+ * is the end of the text you parsed. If error occurs, index is
+ * unchanged.
+ * <P>
+ * When parsing, leading whitespace is discarded (with successful
+ * parse), while trailing whitespace is left as is.
+ * <P>
+ * Example:
+ * <P>
+ * Parsing "_12_xy" (where _ represents a space) for a number,
+ * with index == 0 will result in the number 12, with
+ * parse_pos.index updated to 3 (just before the second space).
+ * Parsing a second time will result in a failing UErrorCode since
+ * "xy" is not a number, and leave index at 3.
+ * <P>
+ * Subclasses will typically supply specific parse methods that
+ * return different types of values. Since methods can't overload
+ * on return types, these will typically be named "parse", while
+ * this polymorphic method will always be called parseObject. Any
+ * parse method that does not take a parse_pos should set status
+ * to an error value when no text in the required format is at the
+ * start position.
+ *
+ * @param source The string to be parsed into an object.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param parse_pos The position to start parsing at. Upon return
+ * this param is set to the position after the
+ * last character successfully parsed. If the
+ * source is not parsed successfully, this param
+ * will remain unchanged.
+ * @stable ICU 2.0
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& parse_pos) const = 0;
+
+ /**
+ * Parses a string to produce an object. This is a convenience method
+ * which calls the pure virtual parseObject() method, and returns a
+ * failure UErrorCode if the ParsePosition indicates failure.
+ *
+ * @param source The string to be parsed into an object.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param status Output param to be filled with success/failure
+ * result code.
+ * @stable ICU 2.0
+ */
+ void parseObject(const UnicodeString& source,
+ Formattable& result,
+ UErrorCode& status) const;
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual method.
+ * This method is to implement a simple version of RTTI, since not all
+ * C++ compilers support genuine RTTI. Polymorphic operator==() and
+ * clone() methods call this method.
+ * Concrete subclasses of Format must implement getDynamicClassID()
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID() const = 0;
+
+ /** Get the locale for this format object. You can choose between valid and actual locale.
+ * @param type type of the locale we're looking for (valid or actual)
+ * @param status error code for the operation
+ * @return the locale
+ * @stable ICU 2.8
+ */
+ Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
+
+ /** Get the locale for this format object. You can choose between valid and actual locale.
+ * @param type type of the locale we're looking for (valid or actual)
+ * @param status error code for the operation
+ * @return the locale
+ * @internal
+ */
+ const char* getLocaleID(ULocDataLocaleType type, UErrorCode &status) const;
+
+ protected:
+ /** @stable ICU 2.8 */
+ void setLocaleIDs(const char* valid, const char* actual);
+
+protected:
+ /**
+ * Default constructor for subclass use only. Does nothing.
+ * @stable ICU 2.0
+ */
+ Format();
+
+ /**
+ * @stable ICU 2.0
+ */
+ Format(const Format&); // Does nothing; for subclasses only
+
+ /**
+ * @stable ICU 2.0
+ */
+ Format& operator=(const Format&); // Does nothing; for subclasses
+
+
+ /**
+ * Simple function for initializing a UParseError from a UnicodeString.
+ *
+ * @param pattern The pattern to copy into the parseError
+ * @param pos The position in pattern where the error occured
+ * @param parseError The UParseError object to fill in
+ * @stable ICU 2.4
+ */
+ static void syntaxError(const UnicodeString& pattern,
+ int32_t pos,
+ UParseError& parseError);
+
+ private:
+ char actualLocale[ULOC_FULLNAME_CAPACITY];
+ char validLocale[ULOC_FULLNAME_CAPACITY];
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _FORMAT
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/gregocal.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/gregocal.h
new file mode 100644
index 00000000000..f2d1b0b17d5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/gregocal.h
@@ -0,0 +1,823 @@
+/*
+* Copyright (C) 1997-2006, International Business Machines Corporation and others.
+* All Rights Reserved.
+********************************************************************************
+*
+* File GREGOCAL.H
+*
+* Modification History:
+*
+* Date Name Description
+* 04/22/97 aliu Overhauled header.
+* 07/28/98 stephen Sync with JDK 1.2
+* 09/04/98 stephen Re-sync with JDK 8/31 putback
+* 09/14/98 stephen Changed type of kOneDay, kOneWeek to double.
+* Fixed bug in roll()
+* 10/15/99 aliu Fixed j31, incorrect WEEK_OF_YEAR computation.
+* Added documentation of WEEK_OF_YEAR computation.
+* 10/15/99 aliu Fixed j32, cannot set date to Feb 29 2000 AD.
+* {JDK bug 4210209 4209272}
+* 11/07/2003 srl Update, clean up documentation.
+********************************************************************************
+*/
+
+#ifndef GREGOCAL_H
+#define GREGOCAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+
+/**
+ * \file
+ * \brief C++ API: Concrete class which provides the standard calendar.
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Concrete class which provides the standard calendar used by most of the world.
+ * <P>
+ * The standard (Gregorian) calendar has 2 eras, BC and AD.
+ * <P>
+ * This implementation handles a single discontinuity, which corresponds by default to
+ * the date the Gregorian calendar was originally instituted (October 15, 1582). Not all
+ * countries adopted the Gregorian calendar then, so this cutover date may be changed by
+ * the caller.
+ * <P>
+ * Prior to the institution of the Gregorian Calendar, New Year's Day was March 25. To
+ * avoid confusion, this Calendar always uses January 1. A manual adjustment may be made
+ * if desired for dates that are prior to the Gregorian changeover and which fall
+ * between January 1 and March 24.
+ *
+ * <p>Values calculated for the <code>WEEK_OF_YEAR</code> field range from 1 to
+ * 53. Week 1 for a year is the first week that contains at least
+ * <code>getMinimalDaysInFirstWeek()</code> days from that year. It thus
+ * depends on the values of <code>getMinimalDaysInFirstWeek()</code>,
+ * <code>getFirstDayOfWeek()</code>, and the day of the week of January 1.
+ * Weeks between week 1 of one year and week 1 of the following year are
+ * numbered sequentially from 2 to 52 or 53 (as needed).
+ *
+ * <p>For example, January 1, 1998 was a Thursday. If
+ * <code>getFirstDayOfWeek()</code> is <code>MONDAY</code> and
+ * <code>getMinimalDaysInFirstWeek()</code> is 4 (these are the values
+ * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts
+ * on December 29, 1997, and ends on January 4, 1998. If, however,
+ * <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>, then week 1 of 1998
+ * starts on January 4, 1998, and ends on January 10, 1998; the first three days
+ * of 1998 then are part of week 53 of 1997.
+ *
+ * <p>Example for using GregorianCalendar:
+ * <pre>
+ * \code
+ * // get the supported ids for GMT-08:00 (Pacific Standard Time)
+ * UErrorCode success = U_ZERO_ERROR;
+ * const StringEnumeration *ids = TimeZone::createEnumeration(-8 * 60 * 60 * 1000);
+ * // if no ids were returned, something is wrong. get out.
+ * if (ids == 0 || ids->count(success) == 0) {
+ * return;
+ * }
+ *
+ * // begin output
+ * cout << "Current Time" << endl;
+ *
+ * // create a Pacific Standard Time time zone
+ * SimpleTimeZone* pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids->unext(NULL, success)));
+ *
+ * // set up rules for daylight savings time
+ * pdt->setStartRule(Calendar::APRIL, 1, Calendar::SUNDAY, 2 * 60 * 60 * 1000);
+ * pdt->setEndRule(Calendar::OCTOBER, -1, Calendar::SUNDAY, 2 * 60 * 60 * 1000);
+ *
+ * // create a GregorianCalendar with the Pacific Daylight time zone
+ * // and the current date and time
+ * Calendar* calendar = new GregorianCalendar( pdt, success );
+ *
+ * // print out a bunch of interesting things
+ * cout << "ERA: " << calendar->get( Calendar::ERA, success ) << endl;
+ * cout << "YEAR: " << calendar->get( Calendar::YEAR, success ) << endl;
+ * cout << "MONTH: " << calendar->get( Calendar::MONTH, success ) << endl;
+ * cout << "WEEK_OF_YEAR: " << calendar->get( Calendar::WEEK_OF_YEAR, success ) << endl;
+ * cout << "WEEK_OF_MONTH: " << calendar->get( Calendar::WEEK_OF_MONTH, success ) << endl;
+ * cout << "DATE: " << calendar->get( Calendar::DATE, success ) << endl;
+ * cout << "DAY_OF_MONTH: " << calendar->get( Calendar::DAY_OF_MONTH, success ) << endl;
+ * cout << "DAY_OF_YEAR: " << calendar->get( Calendar::DAY_OF_YEAR, success ) << endl;
+ * cout << "DAY_OF_WEEK: " << calendar->get( Calendar::DAY_OF_WEEK, success ) << endl;
+ * cout << "DAY_OF_WEEK_IN_MONTH: " << calendar->get( Calendar::DAY_OF_WEEK_IN_MONTH, success ) << endl;
+ * cout << "AM_PM: " << calendar->get( Calendar::AM_PM, success ) << endl;
+ * cout << "HOUR: " << calendar->get( Calendar::HOUR, success ) << endl;
+ * cout << "HOUR_OF_DAY: " << calendar->get( Calendar::HOUR_OF_DAY, success ) << endl;
+ * cout << "MINUTE: " << calendar->get( Calendar::MINUTE, success ) << endl;
+ * cout << "SECOND: " << calendar->get( Calendar::SECOND, success ) << endl;
+ * cout << "MILLISECOND: " << calendar->get( Calendar::MILLISECOND, success ) << endl;
+ * cout << "ZONE_OFFSET: " << (calendar->get( Calendar::ZONE_OFFSET, success )/(60*60*1000)) << endl;
+ * cout << "DST_OFFSET: " << (calendar->get( Calendar::DST_OFFSET, success )/(60*60*1000)) << endl;
+ *
+ * cout << "Current Time, with hour reset to 3" << endl;
+ * calendar->clear(Calendar::HOUR_OF_DAY); // so doesn't override
+ * calendar->set(Calendar::HOUR, 3);
+ * cout << "ERA: " << calendar->get( Calendar::ERA, success ) << endl;
+ * cout << "YEAR: " << calendar->get( Calendar::YEAR, success ) << endl;
+ * cout << "MONTH: " << calendar->get( Calendar::MONTH, success ) << endl;
+ * cout << "WEEK_OF_YEAR: " << calendar->get( Calendar::WEEK_OF_YEAR, success ) << endl;
+ * cout << "WEEK_OF_MONTH: " << calendar->get( Calendar::WEEK_OF_MONTH, success ) << endl;
+ * cout << "DATE: " << calendar->get( Calendar::DATE, success ) << endl;
+ * cout << "DAY_OF_MONTH: " << calendar->get( Calendar::DAY_OF_MONTH, success ) << endl;
+ * cout << "DAY_OF_YEAR: " << calendar->get( Calendar::DAY_OF_YEAR, success ) << endl;
+ * cout << "DAY_OF_WEEK: " << calendar->get( Calendar::DAY_OF_WEEK, success ) << endl;
+ * cout << "DAY_OF_WEEK_IN_MONTH: " << calendar->get( Calendar::DAY_OF_WEEK_IN_MONTH, success ) << endl;
+ * cout << "AM_PM: " << calendar->get( Calendar::AM_PM, success ) << endl;
+ * cout << "HOUR: " << calendar->get( Calendar::HOUR, success ) << endl;
+ * cout << "HOUR_OF_DAY: " << calendar->get( Calendar::HOUR_OF_DAY, success ) << endl;
+ * cout << "MINUTE: " << calendar->get( Calendar::MINUTE, success ) << endl;
+ * cout << "SECOND: " << calendar->get( Calendar::SECOND, success ) << endl;
+ * cout << "MILLISECOND: " << calendar->get( Calendar::MILLISECOND, success ) << endl;
+ * cout << "ZONE_OFFSET: " << (calendar->get( Calendar::ZONE_OFFSET, success )/(60*60*1000)) << endl; // in hours
+ * cout << "DST_OFFSET: " << (calendar->get( Calendar::DST_OFFSET, success )/(60*60*1000)) << endl; // in hours
+ *
+ * if (U_FAILURE(success)) {
+ * cout << "An error occured. success=" << u_errorName(success) << endl;
+ * }
+ *
+ * delete ids;
+ * delete calendar; // also deletes pdt
+ * \endcode
+ * </pre>
+ * @stable ICU 2.0
+ */
+class U_I18N_API GregorianCalendar: public Calendar {
+public:
+
+ /**
+ * Useful constants for GregorianCalendar and TimeZone.
+ * @stable ICU 2.0
+ */
+ enum EEras {
+ BC,
+ AD
+ };
+
+ /**
+ * Constructs a default GregorianCalendar using the current time in the default time
+ * zone with the default locale.
+ *
+ * @param success Indicates the status of GregorianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(UErrorCode& success);
+
+ /**
+ * Constructs a GregorianCalendar based on the current time in the given time zone
+ * with the default locale. Clients are no longer responsible for deleting the given
+ * time zone object after it's adopted.
+ *
+ * @param zoneToAdopt The given timezone.
+ * @param success Indicates the status of GregorianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(TimeZone* zoneToAdopt, UErrorCode& success);
+
+ /**
+ * Constructs a GregorianCalendar based on the current time in the given time zone
+ * with the default locale.
+ *
+ * @param zone The given timezone.
+ * @param success Indicates the status of GregorianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(const TimeZone& zone, UErrorCode& success);
+
+ /**
+ * Constructs a GregorianCalendar based on the current time in the default time zone
+ * with the given locale.
+ *
+ * @param aLocale The given locale.
+ * @param success Indicates the status of GregorianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Constructs a GregorianCalendar based on the current time in the given time zone
+ * with the given locale. Clients are no longer responsible for deleting the given
+ * time zone object after it's adopted.
+ *
+ * @param zoneToAdopt The given timezone.
+ * @param aLocale The given locale.
+ * @param success Indicates the status of GregorianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(TimeZone* zoneToAdopt, const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Constructs a GregorianCalendar based on the current time in the given time zone
+ * with the given locale.
+ *
+ * @param zone The given timezone.
+ * @param aLocale The given locale.
+ * @param success Indicates the status of GregorianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(const TimeZone& zone, const Locale& aLocale, UErrorCode& success);
+
+ /**
+ * Constructs a GregorianCalendar with the given AD date set in the default time
+ * zone with the default locale.
+ *
+ * @param year The value used to set the YEAR time field in the calendar.
+ * @param month The value used to set the MONTH time field in the calendar. Month
+ * value is 0-based. e.g., 0 for January.
+ * @param date The value used to set the DATE time field in the calendar.
+ * @param success Indicates the status of GregorianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(int32_t year, int32_t month, int32_t date, UErrorCode& success);
+
+ /**
+ * Constructs a GregorianCalendar with the given AD date and time set for the
+ * default time zone with the default locale.
+ *
+ * @param year The value used to set the YEAR time field in the calendar.
+ * @param month The value used to set the MONTH time field in the calendar. Month
+ * value is 0-based. e.g., 0 for January.
+ * @param date The value used to set the DATE time field in the calendar.
+ * @param hour The value used to set the HOUR_OF_DAY time field in the calendar.
+ * @param minute The value used to set the MINUTE time field in the calendar.
+ * @param success Indicates the status of GregorianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute, UErrorCode& success);
+
+ /**
+ * Constructs a GregorianCalendar with the given AD date and time set for the
+ * default time zone with the default locale.
+ *
+ * @param year The value used to set the YEAR time field in the calendar.
+ * @param month The value used to set the MONTH time field in the calendar. Month
+ * value is 0-based. e.g., 0 for January.
+ * @param date The value used to set the DATE time field in the calendar.
+ * @param hour The value used to set the HOUR_OF_DAY time field in the calendar.
+ * @param minute The value used to set the MINUTE time field in the calendar.
+ * @param second The value used to set the SECOND time field in the calendar.
+ * @param success Indicates the status of GregorianCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t minute, int32_t second, UErrorCode& success);
+
+ /**
+ * Destructor
+ * @stable ICU 2.0
+ */
+ virtual ~GregorianCalendar();
+
+ /**
+ * Copy constructor
+ * @param source the object to be copied.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar(const GregorianCalendar& source);
+
+ /**
+ * Default assignment operator
+ * @param right the object to be copied.
+ * @stable ICU 2.0
+ */
+ GregorianCalendar& operator=(const GregorianCalendar& right);
+
+ /**
+ * Create and return a polymorphic copy of this calendar.
+ * @return return a polymorphic copy of this calendar.
+ * @stable ICU 2.0
+ */
+ virtual Calendar* clone(void) const;
+
+ /**
+ * Sets the GregorianCalendar change date. This is the point when the switch from
+ * Julian dates to Gregorian dates occurred. Default is 00:00:00 local time, October
+ * 15, 1582. Previous to this time and date will be Julian dates.
+ *
+ * @param date The given Gregorian cutover date.
+ * @param success Output param set to success/failure code on exit.
+ * @stable ICU 2.0
+ */
+ void setGregorianChange(UDate date, UErrorCode& success);
+
+ /**
+ * Gets the Gregorian Calendar change date. This is the point when the switch from
+ * Julian dates to Gregorian dates occurred. Default is 00:00:00 local time, October
+ * 15, 1582. Previous to this time and date will be Julian dates.
+ *
+ * @return The Gregorian cutover time for this calendar.
+ * @stable ICU 2.0
+ */
+ UDate getGregorianChange(void) const;
+
+ /**
+ * Return true if the given year is a leap year. Determination of whether a year is
+ * a leap year is actually very complicated. We do something crude and mostly
+ * correct here, but for a real determination you need a lot of contextual
+ * information. For example, in Sweden, the change from Julian to Gregorian happened
+ * in a complex way resulting in missed leap years and double leap years between
+ * 1700 and 1753. Another example is that after the start of the Julian calendar in
+ * 45 B.C., the leap years did not regularize until 8 A.D. This method ignores these
+ * quirks, and pays attention only to the Julian onset date and the Gregorian
+ * cutover (which can be changed).
+ *
+ * @param year The given year.
+ * @return True if the given year is a leap year; false otherwise.
+ * @stable ICU 2.0
+ */
+ UBool isLeapYear(int32_t year) const;
+
+ /**
+ * Returns TRUE if the given Calendar object is equivalent to this
+ * one. Calendar override.
+ *
+ * @param other the Calendar to be compared with this Calendar
+ * @stable ICU 2.4
+ */
+ virtual UBool isEquivalentTo(const Calendar& other) const;
+
+ /**
+ * (Overrides Calendar) Rolls up or down by the given amount in the specified field.
+ * For more information, see the documentation for Calendar::roll().
+ *
+ * @param field The time field.
+ * @param amount Indicates amount to roll.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ * @deprecated ICU 2.6. Use roll(UCalendarDateFields field, int32_t amount, UErrorCode& status) instead.
+ */
+ virtual void roll(EDateFields field, int32_t amount, UErrorCode& status);
+
+ /**
+ * (Overrides Calendar) Rolls up or down by the given amount in the specified field.
+ * For more information, see the documentation for Calendar::roll().
+ *
+ * @param field The time field.
+ * @param amount Indicates amount to roll.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ * @stable ICU 2.6.
+ */
+ virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode& status);
+
+ /**
+ * Return the minimum value that this field could have, given the current date.
+ * For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
+ * @param field the time field.
+ * @return the minimum value that this field could have, given the current date.
+ * @deprecated ICU 2.6. Use getActualMinimum(UCalendarDateFields field) instead.
+ */
+ int32_t getActualMinimum(EDateFields field) const;
+
+ /**
+ * Return the minimum value that this field could have, given the current date.
+ * For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
+ * @param field the time field.
+ * @param status
+ * @return the minimum value that this field could have, given the current date.
+ * @deprecated ICU 2.6. Use getActualMinimum(UCalendarDateFields field) instead. (Added to ICU 3.0 for signature consistency)
+ */
+ int32_t getActualMinimum(EDateFields field, UErrorCode& status) const;
+
+ /**
+ * Return the minimum value that this field could have, given the current date.
+ * For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum().
+ * @param field the time field.
+ * @param status error result.
+ * @return the minimum value that this field could have, given the current date.
+ * @stable ICU 3.0
+ */
+ int32_t getActualMinimum(UCalendarDateFields field, UErrorCode &status) const;
+
+ /**
+ * Return the maximum value that this field could have, given the current date.
+ * For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field, the actual
+ * maximum would be 28; for "Feb 3, 1996" it s 29. Similarly for a Hebrew calendar,
+ * for some years the actual maximum for MONTH is 12, and for others 13.
+ * @param field the time field.
+ * @return the maximum value that this field could have, given the current date.
+ * @deprecated ICU 2.6. Use getActualMaximum(UCalendarDateFields field) instead.
+ */
+ int32_t getActualMaximum(EDateFields field) const;
+
+ /**
+ * Return the maximum value that this field could have, given the current date.
+ * For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field, the actual
+ * maximum would be 28; for "Feb 3, 1996" it s 29. Similarly for a Hebrew calendar,
+ * for some years the actual maximum for MONTH is 12, and for others 13.
+ * @param field the time field.
+ * @param status returns any errors that may result from this function call.
+ * @return the maximum value that this field could have, given the current date.
+ * @stable ICU 2.6
+ */
+ virtual int32_t getActualMaximum(UCalendarDateFields field, UErrorCode& status) const;
+
+ /**
+ * (Overrides Calendar) Return true if the current date for this Calendar is in
+ * Daylight Savings Time. Recognizes DST_OFFSET, if it is set.
+ *
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return True if the current date for this Calendar is in Daylight Savings Time,
+ * false, otherwise.
+ * @stable ICU 2.0
+ */
+ virtual UBool inDaylightTime(UErrorCode& status) const;
+
+public:
+
+ /**
+ * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
+ * override. This method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
+ * this method.
+ *
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to a return
+ * value from getDynamicClassID(). For example:
+ *
+ * Base* polymorphic_pointer = createPolymorphicObject();
+ * if (polymorphic_pointer->getDynamicClassID() ==
+ * Derived::getStaticClassID()) ...
+ *
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Get the calendar type, "gregorian", for use in DateFormatSymbols.
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+protected:
+
+ /**
+ * (Overrides Calendar) Converts GMT as milliseconds to time field values.
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @stable ICU 2.0
+ */
+
+ private:
+ GregorianCalendar(); // default constructor not implemented
+
+ protected:
+ /**
+ * Return the ERA. We need a special method for this because the
+ * default ERA is AD, but a zero (unset) ERA is BC.
+ * @return the ERA.
+ * @internal
+ */
+ virtual int32_t internalGetEra() const;
+
+ /**
+ * Return the Julian day number of day before the first day of the
+ * given month in the given extended year. Subclasses should override
+ * this method to implement their calendar system.
+ * @param eyear the extended year
+ * @param month the zero-based month, or 0 if useMonth is false
+ * @param useMonth if false, compute the day before the first day of
+ * the given year, otherwise, compute the day before the first day of
+ * the given month
+ * @return the Julian day number of the day before the first
+ * day of the given month and year
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month,
+ UBool useMonth) const;
+
+ /**
+ * Subclasses may override this. This method calls
+ * handleGetMonthLength() to obtain the calendar-specific month
+ * length.
+ * @param bestField which field to use to calculate the date
+ * @return julian day specified by calendar fields.
+ * @internal
+ */
+ virtual int32_t handleComputeJulianDay(UCalendarDateFields bestField) ;
+
+ /**
+ * Return the number of days in the given month of the given extended
+ * year of this calendar system. Subclasses should override this
+ * method if they can provide a more correct or more efficient
+ * implementation than the default implementation in Calendar.
+ * @internal
+ */
+ virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const;
+
+ /**
+ * Return the number of days in the given extended year of this
+ * calendar system. Subclasses should override this method if they can
+ * provide a more correct or more efficient implementation than the
+ * default implementation in Calendar.
+ * @stable ICU 2.0
+ */
+ virtual int32_t handleGetYearLength(int32_t eyear) const;
+
+ /**
+ * return the length of the given month.
+ * @param month the given month.
+ * @return the length of the given month.
+ * @internal
+ */
+ virtual int32_t monthLength(int32_t month) const;
+
+ /**
+ * return the length of the month according to the given year.
+ * @param month the given month.
+ * @param year the given year.
+ * @return the length of the month
+ * @internal
+ */
+ virtual int32_t monthLength(int32_t month, int32_t year) const;
+
+ /**
+ * return the length of the given year.
+ * @param year the given year.
+ * @return the length of the given year.
+ * @internal
+ */
+ int32_t yearLength(int32_t year) const;
+
+ /**
+ * return the length of the year field.
+ * @return the length of the year field
+ * @internal
+ */
+ int32_t yearLength(void) const;
+
+ /**
+ * After adjustments such as add(MONTH), add(YEAR), we don't want the
+ * month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar
+ * 3, we want it to go to Feb 28. Adjustments which might run into this
+ * problem call this method to retain the proper month.
+ * @internal
+ */
+ void pinDayOfMonth(void);
+
+ /**
+ * Return the day number with respect to the epoch. January 1, 1970 (Gregorian)
+ * is day zero.
+ * @param status Fill-in parameter which receives the status of this operation.
+ * @return the day number with respect to the epoch.
+ * @internal
+ */
+ virtual UDate getEpochDay(UErrorCode& status);
+
+ /**
+ * Subclass API for defining limits of different types.
+ * Subclasses must implement this method to return limits for the
+ * following fields:
+ *
+ * <pre>UCAL_ERA
+ * UCAL_YEAR
+ * UCAL_MONTH
+ * UCAL_WEEK_OF_YEAR
+ * UCAL_WEEK_OF_MONTH
+ * UCAL_DATE (DAY_OF_MONTH on Java)
+ * UCAL_DAY_OF_YEAR
+ * UCAL_DAY_OF_WEEK_IN_MONTH
+ * UCAL_YEAR_WOY
+ * UCAL_EXTENDED_YEAR</pre>
+ *
+ * @param field one of the above field numbers
+ * @param limitType one of <code>MINIMUM</code>, <code>GREATEST_MINIMUM</code>,
+ * <code>LEAST_MAXIMUM</code>, or <code>MAXIMUM</code>
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+
+ /**
+ * Return the extended year defined by the current fields. This will
+ * use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
+ * as UCAL_ERA) specific to the calendar system, depending on which set of
+ * fields is newer.
+ * @return the extended year
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+
+ /**
+ * Subclasses may override this to convert from week fields
+ * (YEAR_WOY and WEEK_OF_YEAR) to an extended year in the case
+ * where YEAR, EXTENDED_YEAR are not set.
+ * The Gregorian implementation assumes a yearWoy in gregorian format, according to the current era.
+ * @return the extended year, UCAL_EXTENDED_YEAR
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy);
+
+
+ /**
+ * Subclasses may override this method to compute several fields
+ * specific to each calendar system. These are:
+ *
+ * <ul><li>ERA
+ * <li>YEAR
+ * <li>MONTH
+ * <li>DAY_OF_MONTH
+ * <li>DAY_OF_YEAR
+ * <li>EXTENDED_YEAR</ul>
+ *
+ * <p>The GregorianCalendar implementation implements
+ * a calendar with the specified Julian/Gregorian cutover date.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status);
+
+ private:
+ /**
+ * Compute the julian day number of the given year.
+ * @param isGregorian if true, using Gregorian calendar, otherwise using Julian calendar
+ * @param year the given year.
+ * @param isLeap true if the year is a leap year.
+ * @return
+ */
+ static double computeJulianDayOfYear(UBool isGregorian, int32_t year,
+ UBool& isLeap);
+
+ /**
+ * Validates the values of the set time fields. True if they're all valid.
+ * @return True if the set time fields are all valid.
+ */
+ UBool validateFields(void) const;
+
+ /**
+ * Validates the value of the given time field. True if it's valid.
+ */
+ UBool boundsCheck(int32_t value, UCalendarDateFields field) const;
+
+ /**
+ * Return the pseudo-time-stamp for two fields, given their
+ * individual pseudo-time-stamps. If either of the fields
+ * is unset, then the aggregate is unset. Otherwise, the
+ * aggregate is the later of the two stamps.
+ * @param stamp_a One given field.
+ * @param stamp_b Another given field.
+ * @return the pseudo-time-stamp for two fields
+ */
+ int32_t aggregateStamp(int32_t stamp_a, int32_t stamp_b);
+
+ /**
+ * The point at which the Gregorian calendar rules are used, measured in
+ * milliseconds from the standard epoch. Default is October 15, 1582
+ * (Gregorian) 00:00:00 UTC, that is, October 4, 1582 (Julian) is followed
+ * by October 15, 1582 (Gregorian). This corresponds to Julian day number
+ * 2299161. This is measured from the standard epoch, not in Julian Days.
+ * @internal
+ */
+ UDate fGregorianCutover;
+
+ /**
+ * Julian day number of the Gregorian cutover
+ */
+ int32_t fCutoverJulianDay;
+
+ /**
+ * Midnight, local time (using this Calendar's TimeZone) at or before the
+ * gregorianCutover. This is a pure date value with no time of day or
+ * timezone component.
+ */
+ UDate fNormalizedGregorianCutover;// = gregorianCutover;
+
+ /**
+ * The year of the gregorianCutover, with 0 representing
+ * 1 BC, -1 representing 2 BC, etc.
+ */
+ int32_t fGregorianCutoverYear;// = 1582;
+
+ /**
+ * The year of the gregorianCutover, with 0 representing
+ * 1 BC, -1 representing 2 BC, etc.
+ */
+ int32_t fGregorianCutoverJulianDay;// = 2299161;
+
+ /**
+ * Converts time as milliseconds to Julian date. The Julian date used here is not a
+ * true Julian date, since it is measured from midnight, not noon.
+ *
+ * @param millis The given milliseconds.
+ * @return The Julian date number.
+ */
+ static double millisToJulianDay(UDate millis);
+
+ /**
+ * Converts Julian date to time as milliseconds. The Julian date used here is not a
+ * true Julian date, since it is measured from midnight, not noon.
+ *
+ * @param julian The given Julian date number.
+ * @return Time as milliseconds.
+ */
+ static UDate julianDayToMillis(double julian);
+
+ /**
+ * Used by handleComputeJulianDay() and handleComputeMonthStart().
+ * Temporary field indicating whether the calendar is currently Gregorian as opposed to Julian.
+ */
+ UBool fIsGregorian;
+
+ /**
+ * Used by handleComputeJulianDay() and handleComputeMonthStart().
+ * Temporary field indicating that the sense of the gregorian cutover should be inverted
+ * to handle certain calculations on and around the cutover date.
+ */
+ UBool fInvertGregorian;
+
+
+ public: // internal implementation
+
+ /**
+ * @internal
+ * @return TRUE if this calendar has the notion of a default century
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * @internal
+ * @return the start of the default century
+ */
+ virtual UDate defaultCenturyStart() const;
+
+ /**
+ * @internal
+ * @return the beginning year of the default century
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+ private:
+ /**
+ * The system maintains a static default century start date. This is initialized
+ * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
+ * indicate an uninitialized state. Once the system default century date and year
+ * are set, they do not change.
+ */
+ static UDate fgSystemDefaultCenturyStart;
+
+ /**
+ * See documentation for systemDefaultCenturyStart.
+ */
+ static int32_t fgSystemDefaultCenturyStartYear;
+
+ /**
+ * Default value that indicates the defaultCenturyStartYear is unitialized
+ */
+ static const int32_t fgSystemDefaultCenturyYear;
+
+ /**
+ * Default value that indicates the UDate of the beginning of the system default century
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * Returns the beginning date of the 100-year window that dates with 2-digit years
+ * are considered to fall within.
+ * @return the beginning date of the 100-year window that dates with 2-digit years
+ * are considered to fall within.
+ */
+ UDate internalGetDefaultCenturyStart(void) const;
+
+ /**
+ * Returns the first year of the 100-year window that dates with 2-digit years
+ * are considered to fall within.
+ * @return the first year of the 100-year window that dates with 2-digit years
+ * are considered to fall within.
+ */
+ int32_t internalGetDefaultCenturyStartYear(void) const;
+
+ /**
+ * Initializes the 100-year window that dates with 2-digit years are considered
+ * to fall within so that its start date is 80 years before the current time.
+ */
+ static void initializeSystemDefaultCentury(void);
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _GREGOCAL
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/measfmt.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/measfmt.h
new file mode 100644
index 00000000000..a5af55e9d53
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/measfmt.h
@@ -0,0 +1,77 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 20, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#ifndef MEASUREFORMAT_H
+#define MEASUREFORMAT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+
+/**
+ * \file
+ * \brief C++ API: Formatter for measure objects.
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ *
+ * A formatter for measure objects. This is an abstract base class.
+ *
+ * <p>To format or parse a measure object, first create a formatter
+ * object using a MeasureFormat factory method. Then use that
+ * object's format and parse methods.
+ *
+ * <p>This is an abstract class.
+ *
+ * @see Format
+ * @author Alan Liu
+ * @stable ICU 3.0
+ */
+class U_I18N_API MeasureFormat : public Format {
+
+ public:
+
+ /**
+ * Return a formatter for CurrencyAmount objects in the given
+ * locale.
+ * @param locale desired locale
+ * @param ec input-output error code
+ * @return a formatter object, or NULL upon error
+ * @stable ICU 3.0
+ */
+ static MeasureFormat* U_EXPORT2 createCurrencyFormat(const Locale& locale,
+ UErrorCode& ec);
+
+ /**
+ * Return a formatter for CurrencyAmount objects in the default
+ * locale.
+ * @param ec input-output error code
+ * @return a formatter object, or NULL upon error
+ * @stable ICU 3.0
+ */
+ static MeasureFormat* U_EXPORT2 createCurrencyFormat(UErrorCode& ec);
+
+ protected:
+
+ /**
+ * Default constructor.
+ * @stable ICU 3.0
+ */
+ MeasureFormat();
+};
+
+U_NAMESPACE_END
+
+#endif // #if !UCONFIG_NO_FORMATTING
+#endif // #ifndef MEASUREFORMAT_H
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/measunit.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/measunit.h
new file mode 100644
index 00000000000..9a210e65957
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/measunit.h
@@ -0,0 +1,71 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 26, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#ifndef __MEASUREUNIT_H__
+#define __MEASUREUNIT_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/fmtable.h"
+
+/**
+ * \file
+ * \brief C++ API: A unit for measuring a quantity.
+ */
+
+U_NAMESPACE_BEGIN
+
+/**
+ * A unit such as length, mass, volume, currency, etc. A unit is
+ * coupled with a numeric amount to produce a Measure.
+ *
+ * <p>This is an abstract class.
+ *
+ * @author Alan Liu
+ * @stable ICU 3.0
+ */
+class U_I18N_API MeasureUnit: public UObject {
+ public:
+ /**
+ * Return a polymorphic clone of this object. The result will
+ * have the same class as returned by getDynamicClassID().
+ * @stable ICU 3.0
+ */
+ virtual UObject* clone() const = 0;
+
+ /**
+ * Destructor
+ * @stable ICU 3.0
+ */
+ virtual ~MeasureUnit();
+
+ /**
+ * Equality operator. Return true if this object is equal
+ * to the given object.
+ * @stable ICU 3.0
+ */
+ virtual UBool operator==(const UObject& other) const = 0;
+
+ protected:
+ /**
+ * Default constructor.
+ * @stable ICU 3.0
+ */
+ MeasureUnit();
+};
+
+U_NAMESPACE_END
+
+// NOTE: There is no measunit.cpp. For implementation, see measure.cpp. [alan]
+
+#endif // !UCONFIG_NO_FORMATTING
+#endif // __MEASUREUNIT_H__
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/measure.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/measure.h
new file mode 100644
index 00000000000..6b7a0497b47
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/measure.h
@@ -0,0 +1,137 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: April 26, 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#ifndef __MEASURE_H__
+#define __MEASURE_H__
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: MeasureUnit object.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/fmtable.h"
+
+U_NAMESPACE_BEGIN
+
+class MeasureUnit;
+
+/**
+ * An amount of a specified unit, consisting of a number and a Unit.
+ * For example, a length measure consists of a number and a length
+ * unit, such as feet or meters. This is an abstract class.
+ * Subclasses specify a concrete Unit type.
+ *
+ * <p>Measure objects are parsed and formatted by subclasses of
+ * MeasureFormat.
+ *
+ * <p>Measure objects are immutable.
+ *
+ * <p>This is an abstract class.
+ *
+ * @author Alan Liu
+ * @stable ICU 3.0
+ */
+class U_I18N_API Measure: public UObject {
+ public:
+ /**
+ * Construct an object with the given numeric amount and the given
+ * unit. After this call, the caller must not delete the given
+ * unit object.
+ * @param number a numeric object; amount.isNumeric() must be TRUE
+ * @param adoptedUnit the unit object, which must not be NULL
+ * @param ec input-output error code. If the amount or the unit
+ * is invalid, then this will be set to a failing value.
+ * @stable ICU 3.0
+ */
+ Measure(const Formattable& number, MeasureUnit* adoptedUnit,
+ UErrorCode& ec);
+
+ /**
+ * Copy constructor
+ * @stable ICU 3.0
+ */
+ Measure(const Measure& other);
+
+ /**
+ * Assignment operator
+ * @stable ICU 3.0
+ */
+ Measure& operator=(const Measure& other);
+
+ /**
+ * Return a polymorphic clone of this object. The result will
+ * have the same class as returned by getDynamicClassID().
+ * @stable ICU 3.0
+ */
+ virtual UObject* clone() const = 0;
+
+ /**
+ * Destructor
+ * @stable ICU 3.0
+ */
+ virtual ~Measure();
+
+ /**
+ * Equality operator. Return true if this object is equal
+ * to the given object.
+ * @stable ICU 3.0
+ */
+ UBool operator==(const UObject& other) const;
+
+ /**
+ * Return a reference to the numeric value of this object. The
+ * numeric value may be of any numeric type supported by
+ * Formattable.
+ * @stable ICU 3.0
+ */
+ inline const Formattable& getNumber() const;
+
+ /**
+ * Return a reference to the unit of this object.
+ * @stable ICU 3.0
+ */
+ inline const MeasureUnit& getUnit() const;
+
+ protected:
+ /**
+ * Default constructor.
+ * @stable ICU 3.0
+ */
+ Measure();
+
+ private:
+ /**
+ * The numeric value of this object, e.g. 2.54 or 100.
+ */
+ Formattable number;
+
+ /**
+ * The unit of this object, e.g., "millimeter" or "JPY". This is
+ * owned by this object.
+ */
+ MeasureUnit* unit;
+};
+
+inline const Formattable& Measure::getNumber() const {
+ return number;
+}
+
+inline const MeasureUnit& Measure::getUnit() const {
+ return *unit;
+}
+
+U_NAMESPACE_END
+
+#endif // !UCONFIG_NO_FORMATTING
+#endif // __MEASURE_H__
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/msgfmt.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/msgfmt.h
new file mode 100644
index 00000000000..815cabbb944
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/msgfmt.h
@@ -0,0 +1,829 @@
+/*
+* Copyright (C) 1997-2006, International Business Machines Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File MSGFMT.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/20/97 helena Finished first cut of implementation.
+* 07/22/98 stephen Removed operator!= (defined in Format)
+* 08/19/2002 srl Removing Javaisms
+********************************************************************************
+*/
+
+#ifndef MSGFMT_H
+#define MSGFMT_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Formats messages in a language-neutral way.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+#include "unicode/locid.h"
+#include "unicode/parseerr.h"
+
+U_NAMESPACE_BEGIN
+
+class NumberFormat;
+class DateFormat;
+
+/**
+ *
+ * A MessageFormat produces concatenated messages in a
+ * language-neutral way. It should be used for all string
+ * concatenations that are visible to end users.
+ * <P>
+ * A MessageFormat contains an array of <EM>subformats</EM> arranged
+ * within a <EM>template string</EM>. Together, the subformats and
+ * template string determine how the MessageFormat will operate during
+ * formatting and parsing.
+ * <P>
+ * Typically, both the subformats and the template string are
+ * specified at once in a <EM>pattern</EM>. By using different
+ * patterns for different locales, messages may be localized.
+ * <P>
+ * During formatting, the MessageFormat takes an array of arguments
+ * and produces a user-readable string. Each argument is a
+ * Formattable object; they may be passed in in an array, or as a
+ * single Formattable object which itself contains an array. Each
+ * argument is matched up with its corresponding subformat, which then
+ * formats it into a string. The resultant strings are then assembled
+ * within the string template of the MessageFormat to produce the
+ * final output string.
+ * <P>
+ * During parsing, an input string is matched against the string
+ * template of the MessageFormat to produce an array of Formattable
+ * objects. Plain text of the template string is matched directly
+ * against intput text. At each position in the template string where
+ * a subformat is located, the subformat is called to parse the
+ * corresponding segment of input text to produce an output argument.
+ * In this way, an array of arguments is created which together
+ * constitute the parse result.
+ * <P>
+ * Parsing may fail or produce unexpected results in a number of
+ * circumstances.
+ * <UL>
+ * <LI>If one of the arguments does not occur in the pattern, it
+ * will be returned as a default Formattable.
+ * <LI>If the format of an argument is loses information, such as with
+ * a choice format where a large number formats to "many", then the
+ * parse may not correspond to the originally formatted argument.
+ * <LI>MessageFormat does not handle ChoiceFormat recursion during
+ * parsing; such parses will fail.
+ * <LI>Parsing will not always find a match (or the correct match) if
+ * some part of the parse is ambiguous. For example, if the pattern
+ * "{1},{2}" is used with the string arguments {"a,b", "c"}, it will
+ * format as "a,b,c". When the result is parsed, it will return {"a",
+ * "b,c"}.
+ * <LI>If a single argument is formatted more than once in the string,
+ * then the rightmost subformat in the pattern string will produce the
+ * parse result; prior subformats with the same argument index will
+ * have no effect.
+ * </UL>
+ * Here are some examples of usage:
+ * <P>
+ * Example 1:
+ * <pre>
+ * \code
+ * UErrorCode success = U_ZERO_ERROR;
+ * GregorianCalendar cal(success);
+ * Formattable arguments[] = {
+ * 7L,
+ * Formattable( (Date) cal.getTime(success), Formattable::kIsDate),
+ * "a disturbance in the Force"
+ * };
+ *
+ * UnicodeString result;
+ * MessageFormat::format(
+ * "At {1,time} on {1,date}, there was {2} on planet {0,number}.",
+ * arguments, 3, result, success );
+ *
+ * cout << "result: " << result << endl;
+ * //<output>: At 4:34:20 PM on 23-Mar-98, there was a disturbance
+ * // in the Force on planet 7.
+ * \endcode
+ * </pre>
+ * Typically, the message format will come from resources, and the
+ * arguments will be dynamically set at runtime.
+ * <P>
+ * Example 2:
+ * <pre>
+ * \code
+ * success = U_ZERO_ERROR;
+ * Formattable testArgs[] = {3L, "MyDisk"};
+ *
+ * MessageFormat form(
+ * "The disk \"{1}\" contains {0} file(s).", success );
+ *
+ * UnicodeString string;
+ * FieldPosition fpos = 0;
+ * cout << "format: " << form.format(testArgs, 2, string, fpos, success ) << endl;
+ *
+ * // output, with different testArgs:
+ * // output: The disk "MyDisk" contains 0 file(s).
+ * // output: The disk "MyDisk" contains 1 file(s).
+ * // output: The disk "MyDisk" contains 1,273 file(s).
+ * \endcode
+ * </pre>
+ *
+ * The pattern is of the following form. Legend:
+ * <pre>
+ * \code
+ * {optional item}
+ * (group that may be repeated)*
+ * \endcode
+ * </pre>
+ * Do not confuse optional items with items inside quotes braces, such
+ * as this: "{". Quoted braces are literals.
+ * <pre>
+ * \code
+ * messageFormatPattern := string ( "{" messageFormatElement "}" string )*
+ *
+ * messageFormatElement := argumentIndex { "," elementFormat }
+ *
+ * elementFormat := "time" { "," datetimeStyle }
+ * | "date" { "," datetimeStyle }
+ * | "number" { "," numberStyle }
+ * | "choice" "," choiceStyle
+ *
+ * datetimeStyle := "short"
+ * | "medium"
+ * | "long"
+ * | "full"
+ * | dateFormatPattern
+ *
+ * numberStyle := "currency"
+ * | "percent"
+ * | "integer"
+ * | numberFormatPattern
+ *
+ * choiceStyle := choiceFormatPattern
+ * \endcode
+ * </pre>
+ * If there is no elementFormat, then the argument must be a string,
+ * which is substituted. If there is no dateTimeStyle or numberStyle,
+ * then the default format is used (e.g. NumberFormat::createInstance(),
+ * DateFormat::createTimeInstance(DateFormat::kDefault, ...) or DateFormat::createDateInstance(DateFormat::kDefault, ...). For
+ * a ChoiceFormat, the pattern must always be specified, since there
+ * is no default.
+ * <P>
+ * In strings, single quotes can be used to quote syntax characters.
+ * A literal single quote is represented by '', both within and outside
+ * of single-quoted segments. Inside a
+ * messageFormatElement, quotes are <EM>not</EM> removed. For example,
+ * {1,number,$'#',##} will produce a number format with the pound-sign
+ * quoted, with a result such as: "$#31,45".
+ * <P>
+ * If a pattern is used, then unquoted braces in the pattern, if any,
+ * must match: that is, "ab {0} de" and "ab '}' de" are ok, but "ab
+ * {0'}' de" and "ab } de" are not.
+ * <p>
+ * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
+ * format patterns unfortunately have shown to be somewhat confusing.
+ * In particular, it isn't always obvious to localizers whether single
+ * quotes need to be doubled or not. Make sure to inform localizers about
+ * the rules, and tell them (for example, by using comments in resource
+ * bundle source files) which strings will be processed by MessageFormat.
+ * Note that localizers may need to use single quotes in translated
+ * strings where the original version doesn't have them.
+ * <br>Note also that the simplest way to avoid the problem is to
+ * use the real apostrophe (single quote) character U+2019 (') for
+ * human-readable text, and to use the ASCII apostrophe (U+0027 ' )
+ * only in program syntax, like quoting in MessageFormat.
+ * See the annotations for U+0027 Apostrophe in The Unicode Standard.</p>
+ * </dl>
+ * <P>
+ * The argumentIndex is a non-negative integer, which corresponds to the
+ * index of the arguments presented in an array to be formatted. The
+ * first argument has argumentIndex 0.
+ * <P>
+ * It is acceptable to have unused arguments in the array. With missing
+ * arguments or arguments that are not of the right class for the
+ * specified format, a failing UErrorCode result is set.
+ * <P>
+ * For more sophisticated patterns, you can use a ChoiceFormat to get
+ * output:
+ * <pre>
+ * \code
+ * UErrorCode success = U_ZERO_ERROR;
+ * MessageFormat* form("The disk \"{1}\" contains {0}.", success);
+ * double filelimits[] = {0,1,2};
+ * UnicodeString filepart[] = {"no files","one file","{0,number} files"};
+ * ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3);
+ * form.setFormat(1, *fileform); // NOT zero, see below
+ *
+ * Formattable testArgs[] = {1273L, "MyDisk"};
+ *
+ * UnicodeString string;
+ * FieldPosition fpos = 0;
+ * cout << form.format(testArgs, 2, string, fpos, success) << endl;
+ *
+ * // output, with different testArgs
+ * // output: The disk "MyDisk" contains no files.
+ * // output: The disk "MyDisk" contains one file.
+ * // output: The disk "MyDisk" contains 1,273 files.
+ * \endcode
+ * </pre>
+ * You can either do this programmatically, as in the above example,
+ * or by using a pattern (see ChoiceFormat for more information) as in:
+ * <pre>
+ * \code
+ * form.applyPattern(
+ * "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.");
+ * \endcode
+ * </pre>
+ * <P>
+ * <EM>Note:</EM> As we see above, the string produced by a ChoiceFormat in
+ * MessageFormat is treated specially; occurences of '{' are used to
+ * indicated subformats, and cause recursion. If you create both a
+ * MessageFormat and ChoiceFormat programmatically (instead of using
+ * the string patterns), then be careful not to produce a format that
+ * recurses on itself, which will cause an infinite loop.
+ * <P>
+ * <EM>Note:</EM> Subformats are numbered by their order in the pattern.
+ * This is <EM>not</EM> the same as the argumentIndex.
+ * <pre>
+ * \code
+ * For example: with "abc{2}def{3}ghi{0}...",
+ *
+ * format0 affects the first variable {2}
+ * format1 affects the second variable {3}
+ * format2 affects the second variable {0}
+ * \endcode
+ * </pre>
+ *
+ * <p><em>User subclasses are not supported.</em> While clients may write
+ * subclasses, such code will not necessarily work and will not be
+ * guaranteed to work stably from release to release.
+ */
+class U_I18N_API MessageFormat : public Format {
+public:
+ /**
+ * Enum type for kMaxFormat.
+ * @obsolete ICU 3.0. The 10-argument limit was removed as of ICU 2.6,
+ * rendering this enum type obsolete.
+ */
+ enum EFormatNumber {
+ /**
+ * The maximum number of arguments.
+ * @obsolete ICU 3.0. The 10-argument limit was removed as of ICU 2.6,
+ * rendering this constant obsolete.
+ */
+ kMaxFormat = 10
+ };
+
+ /**
+ * Constructs a new MessageFormat using the given pattern and the
+ * default locale.
+ *
+ * @param pattern Pattern used to construct object.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ MessageFormat(const UnicodeString& pattern,
+ UErrorCode &status);
+
+ /**
+ * Constructs a new MessageFormat using the given pattern and locale.
+ * @param pattern Pattern used to construct object.
+ * @param newLocale The locale to use for formatting dates and numbers.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UErrorCode& status);
+ /**
+ * Constructs a new MessageFormat using the given pattern and locale.
+ * @param pattern Pattern used to construct object.
+ * @param newLocale The locale to use for formatting dates and numbers.
+ * @param parseError Struct to recieve information on position
+ * of error within the pattern.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ MessageFormat(const UnicodeString& pattern,
+ const Locale& newLocale,
+ UParseError& parseError,
+ UErrorCode& status);
+ /**
+ * Constructs a new MessageFormat from an existing one.
+ * @stable ICU 2.0
+ */
+ MessageFormat(const MessageFormat&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 2.0
+ */
+ const MessageFormat& operator=(const MessageFormat&);
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~MessageFormat();
+
+ /**
+ * Clones this Format object polymorphically. The caller owns the
+ * result and should delete it when done.
+ * @stable ICU 2.0
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Returns true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Sets the locale. This locale is used for fetching default number or date
+ * format information.
+ * @param theLocale the new locale value to be set.
+ * @stable ICU 2.0
+ */
+ virtual void setLocale(const Locale& theLocale);
+
+ /**
+ * Gets the locale. This locale is used for fetching default number or date
+ * format information.
+ * @return the locale of the object.
+ * @stable ICU 2.0
+ */
+ virtual const Locale& getLocale(void) const;
+
+ /**
+ * Applies the given pattern string to this message format.
+ *
+ * @param pattern The pattern to be applied.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UErrorCode& status);
+ /**
+ * Applies the given pattern string to this message format.
+ *
+ * @param pattern The pattern to be applied.
+ * @param parseError Struct to recieve information on position
+ * of error within pattern.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ /**
+ * Returns a pattern that can be used to recreate this object.
+ *
+ * @param appendTo Output parameter to receive the pattern.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toPattern(UnicodeString& appendTo) const;
+
+ /**
+ * Sets subformats.
+ * See the class description about format numbering.
+ * The caller should not delete the Format objects after this call.
+ * <EM>The array formatsToAdopt is not itself adopted.</EM> Its
+ * ownership is retained by the caller. If the call fails because
+ * memory cannot be allocated, then the formats will be deleted
+ * by this method, and this object will remain unchanged.
+ *
+ * @stable ICU 2.0
+ * @param formatsToAdopt the format to be adopted.
+ * @param count the size of the array.
+ */
+ virtual void adoptFormats(Format** formatsToAdopt, int32_t count);
+
+ /**
+ * Sets subformats.
+ * See the class description about format numbering.
+ * Each item in the array is cloned into the internal array.
+ * If the call fails because memory cannot be allocated, then this
+ * object will remain unchanged.
+ *
+ * @stable ICU 2.0
+ * @param newFormats the new format to be set.
+ * @param cnt the size of the array.
+ */
+ virtual void setFormats(const Format** newFormats,int32_t cnt);
+
+
+ /**
+ * Sets one subformat.
+ * See the class description about format numbering.
+ * The caller should not delete the Format object after this call.
+ * If the number is over the number of formats already set,
+ * the item will be deleted and ignored.
+ * @stable ICU 2.0
+ * @param formatNumber index of the subformat.
+ * @param formatToAdopt the format to be adopted.
+ */
+ virtual void adoptFormat(int32_t formatNumber, Format* formatToAdopt);
+
+ /**
+ * Sets one subformat.
+ * See the class description about format numbering.
+ * If the number is over the number of formats already set,
+ * the item will be ignored.
+ * @param formatNumber index of the subformat.
+ * @param format the format to be set.
+ * @stable ICU 2.0
+ */
+ virtual void setFormat(int32_t formatNumber, const Format& format);
+
+ /**
+ * Gets an array of subformats of this object. The returned array
+ * should not be deleted by the caller, nor should the pointers
+ * within the array. The array and its contents remain valid only
+ * until the next call to any method of this class is made with
+ * this object. See the class description about format numbering.
+ * @param count output parameter to receive the size of the array
+ * @return an array of count Format* objects, or NULL if out of
+ * memory. Any or all of the array elements may be NULL.
+ * @stable ICU 2.0
+ */
+ virtual const Format** getFormats(int32_t& count) const;
+
+ /**
+ * Formats the given array of arguments into a user-readable string.
+ * Does not take ownership of the Formattable* array or its contents.
+ *
+ * @param source An array of objects to be formatted.
+ * @param count The number of elements of 'source'.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param ignore Not used; inherited from base class API.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format( const Formattable* source,
+ int32_t count,
+ UnicodeString& appendTo,
+ FieldPosition& ignore,
+ UErrorCode& status) const;
+
+ /**
+ * Formats the given array of arguments into a user-readable string
+ * using the given pattern.
+ *
+ * @param pattern The pattern.
+ * @param arguments An array of objects to be formatted.
+ * @param count The number of elements of 'source'.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ static UnicodeString& format( const UnicodeString& pattern,
+ const Formattable* arguments,
+ int32_t count,
+ UnicodeString& appendTo,
+ UErrorCode& status);
+
+ /**
+ * Formats the given array of arguments into a user-readable
+ * string. The array must be stored within a single Formattable
+ * object of type kArray. If the Formattable object type is not of
+ * type kArray, then returns a failing UErrorCode.
+ *
+ * @param obj A Formattable of type kArray containing
+ * arguments to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Formats the given array of arguments into a user-readable
+ * string. The array must be stored within a single Formattable
+ * object of type kArray. If the Formattable object type is not of
+ * type kArray, then returns a failing UErrorCode.
+ *
+ * @param obj The object to format
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const;
+
+ /**
+ * Parses the given string into an array of output arguments.
+ *
+ * @param source String to be parsed.
+ * @param pos On input, starting position for parse. On output,
+ * final position after parse. Unchanged if parse
+ * fails.
+ * @param count Output parameter to receive the number of arguments
+ * parsed.
+ * @return an array of parsed arguments. The caller owns both
+ * the array and its contents.
+ * @stable ICU 2.0
+ */
+ virtual Formattable* parse( const UnicodeString& source,
+ ParsePosition& pos,
+ int32_t& count) const;
+
+ /**
+ * Parses the given string into an array of output arguments.
+ *
+ * @param source String to be parsed.
+ * @param count Output param to receive size of returned array.
+ * @param status Input/output error code. If the
+ * pattern cannot be parsed, set to failure code.
+ * @return an array of parsed arguments. The caller owns both
+ * the array and its contents.
+ * @stable ICU 2.0
+ */
+ virtual Formattable* parse( const UnicodeString& source,
+ int32_t& count,
+ UErrorCode& status) const;
+
+ /**
+ * Parses the given string into an array of output arguments
+ * stored within a single Formattable of type kArray.
+ *
+ * @param source The string to be parsed into an object.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param pos On input, starting position for parse. On output,
+ * final position after parse. Unchanged if parse
+ * fails.
+ * @stable ICU 2.0
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& pos) const;
+
+ /**
+ * Convert an 'apostrophe-friendly' pattern into a standard
+ * pattern. Standard patterns treat all apostrophes as
+ * quotes, which is problematic in some languages, e.g.
+ * French, where apostrophe is commonly used. This utility
+ * assumes that only an unpaired apostrophe immediately before
+ * a brace is a true quote. Other unpaired apostrophes are paired,
+ * and the resulting standard pattern string is returned.
+ *
+ * <p><b>Note</b> it is not guaranteed that the returned pattern
+ * is indeed a valid pattern. The only effect is to convert
+ * between patterns having different quoting semantics.
+ *
+ * @param pattern the 'apostrophe-friendly' patttern to convert
+ * @param status Input/output error code. If the pattern
+ * cannot be parsed, the failure code is set.
+ * @return the standard equivalent of the original pattern
+ * @stable ICU 3.4
+ */
+ static UnicodeString autoQuoteApostrophe(const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override.
+ * This method is to implement a simple version of RTTI, since not all
+ * C++ compilers support genuine RTTI. Polymorphic operator==() and
+ * clone() methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for
+ * comparing to a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . Derived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+private:
+
+ Locale fLocale;
+ UnicodeString fPattern;
+ Format** formatAliases; // see getFormats
+ int32_t formatAliasesCapacity;
+
+ MessageFormat(); // default constructor not implemented
+
+ /*
+ * A structure representing one subformat of this MessageFormat.
+ * Each subformat has a Format object, an offset into the plain
+ * pattern text fPattern, and an argument number. The argument
+ * number corresponds to the array of arguments to be formatted.
+ * @internal
+ */
+ class Subformat {
+ public:
+ /**
+ * @internal
+ */
+ Format* format; // formatter
+ /**
+ * @internal
+ */
+ int32_t offset; // offset into fPattern
+ /**
+ * @internal
+ */
+ int32_t arg; // 0-based argument number
+
+ /**
+ * Clone that.format and assign it to this.format
+ * Do NOT delete this.format
+ * @internal
+ */
+ Subformat& operator=(const Subformat& that) {
+ format = that.format ? that.format->clone() : NULL;
+ offset = that.offset;
+ arg = that.arg;
+ return *this;
+ }
+
+ /**
+ * @internal
+ */
+ UBool operator==(const Subformat& that) const {
+ // Do cheap comparisons first
+ return offset == that.offset &&
+ arg == that.arg &&
+ ((format == that.format) || // handles NULL
+ (*format == *that.format));
+ }
+
+ /**
+ * @internal
+ */
+ UBool operator!=(const Subformat& that) const {
+ return !operator==(that);
+ }
+ };
+
+ /**
+ * A MessageFormat contains an array of subformats. This array
+ * needs to grow dynamically if the MessageFormat is modified.
+ */
+ Subformat* subformats;
+ int32_t subformatCount;
+ int32_t subformatCapacity;
+
+ /**
+ * A MessageFormat formats an array of arguments. Each argument
+ * has an expected type, based on the pattern. For example, if
+ * the pattern contains the subformat "{3,number,integer}", then
+ * we expect argument 3 to have type Formattable::kLong. This
+ * array needs to grow dynamically if the MessageFormat is
+ * modified.
+ */
+ Formattable::Type* argTypes;
+ int32_t argTypeCount;
+ int32_t argTypeCapacity;
+
+ // Variable-size array management
+ UBool allocateSubformats(int32_t capacity);
+ UBool allocateArgTypes(int32_t capacity);
+
+ /**
+ * Default Format objects used when no format is specified and a
+ * numeric or date argument is formatted. These are volatile
+ * cache objects maintained only for performance. They do not
+ * participate in operator=(), copy constructor(), nor
+ * operator==().
+ */
+ NumberFormat* defaultNumberFormat;
+ DateFormat* defaultDateFormat;
+
+ /**
+ * Method to retrieve default formats (or NULL on failure).
+ * These are semantically const, but may modify *this.
+ */
+ const NumberFormat* getDefaultNumberFormat(UErrorCode&) const;
+ const DateFormat* getDefaultDateFormat(UErrorCode&) const;
+
+ /**
+ * Finds the word s, in the keyword list and returns the located index.
+ * @param s the keyword to be searched for.
+ * @param list the list of keywords to be searched with.
+ * @return the index of the list which matches the keyword s.
+ */
+ static int32_t findKeyword( const UnicodeString& s,
+ const UChar * const *list);
+
+ /**
+ * Formats the array of arguments and copies the result into the
+ * result buffer, updates the field position.
+ *
+ * @param arguments The formattable objects array.
+ * @param cnt The array count.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Field position status.
+ * @param recursionProtection
+ * Initially zero. Bits 0..9 are used to indicate
+ * that a parameter has already been seen, to
+ * avoid recursion. Currently unused.
+ * @param success The error code status.
+ * @return Reference to 'appendTo' parameter.
+ */
+ UnicodeString& format( const Formattable* arguments,
+ int32_t cnt,
+ UnicodeString& appendTo,
+ FieldPosition& status,
+ int32_t recursionProtection,
+ UErrorCode& success) const;
+
+ void makeFormat(int32_t offsetNumber,
+ UnicodeString* segments,
+ UParseError& parseError,
+ UErrorCode& success);
+
+ /**
+ * Convenience method that ought to be in NumberFormat
+ */
+ NumberFormat* createIntegerFormat(const Locale& locale, UErrorCode& status) const;
+
+ /**
+ * Checks the range of the source text to quote the special
+ * characters, { and ' and copy to target buffer.
+ * @param source
+ * @param start the text offset to start the process of in the source string
+ * @param end the text offset to end the process of in the source string
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ */
+ static void copyAndFixQuotes(const UnicodeString& appendTo, int32_t start, int32_t end, UnicodeString& target);
+
+ /**
+ * Returns array of argument types in the parsed pattern
+ * for use in C API. Only for the use of umsg_vformat(). Not
+ * for public consumption.
+ * @param listCount Output parameter to receive the size of array
+ * @return The array of formattable types in the pattern
+ * @internal
+ */
+ const Formattable::Type* getArgTypeList(int32_t& listCount) const {
+ listCount = argTypeCount;
+ return argTypes;
+ }
+
+ friend class MessageFormatAdapter; // getFormatTypeList() access
+};
+
+inline UnicodeString&
+MessageFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ return Format::format(obj, appendTo, status);
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _MSGFMT
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/numfmt.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/numfmt.h
new file mode 100644
index 00000000000..b27ed470819
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/numfmt.h
@@ -0,0 +1,861 @@
+/*
+********************************************************************************
+* Copyright (C) 1997-2006, International Business Machines Corporation and others.
+* All Rights Reserved.
+********************************************************************************
+*
+* File NUMFMT.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 03/18/97 clhuang Updated per C++ implementation.
+* 04/17/97 aliu Changed DigitCount to int per code review.
+* 07/20/98 stephen JDK 1.2 sync up. Added scientific support.
+* Changed naming conventions to match C++ guidelines
+* Derecated Java style constants (eg, INTEGER_FIELD)
+********************************************************************************
+*/
+
+#ifndef NUMFMT_H
+#define NUMFMT_H
+
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Abstract base class for all number formats.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/format.h"
+#include "unicode/unum.h" // UNumberFormatStyle
+#include "unicode/locid.h"
+
+U_NAMESPACE_BEGIN
+
+#if !UCONFIG_NO_SERVICE
+class NumberFormatFactory;
+class StringEnumeration;
+#endif
+
+/**
+ *
+ * Abstract base class for all number formats. Provides interface for
+ * formatting and parsing a number. Also provides methods for
+ * determining which locales have number formats, and what their names
+ * are.
+ * <P>
+ * NumberFormat helps you to format and parse numbers for any locale.
+ * Your code can be completely independent of the locale conventions
+ * for decimal points, thousands-separators, or even the particular
+ * decimal digits used, or whether the number format is even decimal.
+ * <P>
+ * To format a number for the current Locale, use one of the static
+ * factory methods:
+ * <pre>
+ * \code
+ * double myNumber = 7.0;
+ * UnicodeString myString;
+ * UErrorCode success = U_ZERO_ERROR;
+ * NumberFormat* nf = NumberFormat::createInstance(success)
+ * nf->format(myNumber, myString);
+ * cout << " Example 1: " << myString << endl;
+ * \endcode
+ * </pre>
+ * If you are formatting multiple numbers, it is more efficient to get
+ * the format and use it multiple times so that the system doesn't
+ * have to fetch the information about the local language and country
+ * conventions multiple times.
+ * <pre>
+ * \code
+ * UnicodeString myString;
+ * UErrorCode success = U_ZERO_ERROR;
+ * nf = NumberFormat::createInstance( success );
+ * int32_t a[] = { 123, 3333, -1234567 };
+ * const int32_t a_len = sizeof(a) / sizeof(a[0]);
+ * myString.remove();
+ * for (int32_t i = 0; i < a_len; i++) {
+ * nf->format(a[i], myString);
+ * myString += " ; ";
+ * }
+ * cout << " Example 2: " << myString << endl;
+ * \endcode
+ * </pre>
+ * To format a number for a different Locale, specify it in the
+ * call to createInstance().
+ * <pre>
+ * \code
+ * nf = NumberFormat::createInstance( Locale::FRENCH, success );
+ * \endcode
+ * </pre>
+ * You can use a NumberFormat to parse also.
+ * <pre>
+ * \code
+ * UErrorCode success;
+ * Formattable result(-999); // initialized with error code
+ * nf->parse(myString, result, success);
+ * \endcode
+ * </pre>
+ * Use createInstance to get the normal number format for that country.
+ * There are other static factory methods available. Use getCurrency
+ * to get the currency number format for that country. Use getPercent
+ * to get a format for displaying percentages. With this format, a
+ * fraction from 0.53 is displayed as 53%.
+ * <P>
+ * You can also control the display of numbers with such methods as
+ * getMinimumFractionDigits. If you want even more control over the
+ * format or parsing, or want to give your users more control, you can
+ * try casting the NumberFormat you get from the factory methods to a
+ * DecimalNumberFormat. This will work for the vast majority of
+ * countries; just remember to put it in a try block in case you
+ * encounter an unusual one.
+ * <P>
+ * You can also use forms of the parse and format methods with
+ * ParsePosition and FieldPosition to allow you to:
+ * <ul type=round>
+ * <li>(a) progressively parse through pieces of a string.
+ * <li>(b) align the decimal point and other areas.
+ * </ul>
+ * For example, you can align numbers in two ways.
+ * <P>
+ * If you are using a monospaced font with spacing for alignment, you
+ * can pass the FieldPosition in your format call, with field =
+ * INTEGER_FIELD. On output, getEndIndex will be set to the offset
+ * between the last character of the integer and the decimal. Add
+ * (desiredSpaceCount - getEndIndex) spaces at the front of the
+ * string.
+ * <P>
+ * If you are using proportional fonts, instead of padding with
+ * spaces, measure the width of the string in pixels from the start to
+ * getEndIndex. Then move the pen by (desiredPixelWidth -
+ * widthToAlignmentPoint) before drawing the text. It also works
+ * where there is no decimal, but possibly additional characters at
+ * the end, e.g. with parentheses in negative numbers: "(12)" for -12.
+ * <p>
+ * <em>User subclasses are not supported.</em> While clients may write
+ * subclasses, such code will not necessarily work and will not be
+ * guaranteed to work stably from release to release.
+ *
+ * @stable ICU 2.0
+ */
+class U_I18N_API NumberFormat : public Format {
+public:
+
+ /**
+ * Alignment Field constants used to construct a FieldPosition object.
+ * Signifies that the position of the integer part or fraction part of
+ * a formatted number should be returned.
+ *
+ * @see FieldPosition
+ * @stable ICU 2.0
+ */
+ enum EAlignmentFields {
+ kIntegerField,
+ kFractionField,
+
+
+ /**
+ * These constants are provided for backwards compatibility only.
+ * Please use the C++ style constants defined above.
+ * @stable ICU 2.0
+ */
+ INTEGER_FIELD = kIntegerField,
+ FRACTION_FIELD = kFractionField
+ };
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~NumberFormat();
+
+ /**
+ * Return true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ * @return true if the given Format objects are semantically equal.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Format an object to produce a string. This method handles
+ * Formattable objects with numeric types. If the Formattable
+ * object type is not a numeric type, then it returns a failing
+ * UErrorCode.
+ *
+ * @param obj The object to format.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @param status Output param filled with success/failure status.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Parse a string to produce an object. This methods handles
+ * parsing of numeric strings into Formattable objects with numeric
+ * types.
+ * <P>
+ * Before calling, set parse_pos.index to the offset you want to
+ * start parsing at in the source. After calling, parse_pos.index
+ * indicates the position after the successfully parsed text. If
+ * an error occurs, parse_pos.index is unchanged.
+ * <P>
+ * When parsing, leading whitespace is discarded (with successful
+ * parse), while trailing whitespace is left as is.
+ * <P>
+ * See Format::parseObject() for more.
+ *
+ * @param source The string to be parsed into an object.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param parse_pos The position to start parsing at. Upon return
+ * this param is set to the position after the
+ * last character successfully parsed. If the
+ * source is not parsed successfully, this param
+ * will remain unchanged.
+ * @return A newly created Formattable* object, or NULL
+ * on failure. The caller owns this and should
+ * delete it when done.
+ * @stable ICU 2.0
+ */
+ virtual void parseObject(const UnicodeString& source,
+ Formattable& result,
+ ParsePosition& parse_pos) const;
+
+ /**
+ * Format a double number. These methods call the NumberFormat
+ * pure virtual format() methods with the default FieldPosition.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format( double number,
+ UnicodeString& appendTo) const;
+
+ /**
+ * Format a long number. These methods call the NumberFormat
+ * pure virtual format() methods with the default FieldPosition.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format( int32_t number,
+ UnicodeString& appendTo) const;
+
+ /**
+ * Format an int64 number. These methods call the NumberFormat
+ * pure virtual format() methods with the default FieldPosition.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.8
+ */
+ UnicodeString& format( int64_t number,
+ UnicodeString& appendTo) const;
+
+ /**
+ * Format a double number. Concrete subclasses must implement
+ * these pure virtual methods.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const = 0;
+ /**
+ * Format a long number. Concrete subclasses must implement
+ * these pure virtual methods.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const = 0;
+
+ /**
+ * Format an int64 number. (Not abstract to retain compatibility
+ * with earlier releases, however subclasses should override this
+ * method as it just delegates to format(int32_t number...);
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.8
+ */
+ virtual UnicodeString& format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+ /**
+ * Redeclared Format method.
+ * @param obj The object to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Output parameter set to a failure error code
+ * when a failure occurs.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const;
+
+ /**
+ * Return a long if possible (e.g. within range LONG_MAX,
+ * LONG_MAX], and with no decimals), otherwise a double. If
+ * IntegerOnly is set, will stop at a decimal point (or equivalent;
+ * e.g. for rational numbers "1 2/3", will stop after the 1).
+ * <P>
+ * If no object can be parsed, index is unchanged, and NULL is
+ * returned.
+ * <P>
+ * This is a pure virtual which concrete subclasses must implement.
+ *
+ * @param text The text to be parsed.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param parsePosition The position to start parsing at on input.
+ * On output, moved to after the last successfully
+ * parse character. On parse failure, does not change.
+ * @return A Formattable object of numeric type. The caller
+ * owns this an must delete it. NULL on failure.
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& parsePosition) const = 0;
+
+ /**
+ * Parse a string as a numeric value, and return a Formattable
+ * numeric object. This method parses integers only if IntegerOnly
+ * is set.
+ *
+ * @param text The text to be parsed.
+ * @param result Formattable to be set to the parse result.
+ * If parse fails, return contents are undefined.
+ * @param status Output parameter set to a failure error code
+ * when a failure occurs.
+ * @return A Formattable object of numeric type. The caller
+ * owns this an must delete it. NULL on failure.
+ * @see NumberFormat::isParseIntegerOnly
+ * @stable ICU 2.0
+ */
+ virtual void parse( const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const;
+
+ /**
+ * Parses text from the given string as a currency amount. Unlike
+ * the parse() method, this method will attempt to parse a generic
+ * currency name, searching for a match of this object's locale's
+ * currency display names, or for a 3-letter ISO currency code.
+ * This method will fail if this format is not a currency format,
+ * that is, if it does not contain the currency pattern symbol
+ * (U+00A4) in its prefix or suffix.
+ *
+ * @param text the string to parse
+ * @param result output parameter to receive result. This will have
+ * its currency set to the parsed ISO currency code.
+ * @param pos input-output position; on input, the position within
+ * text to match; must have 0 <= pos.getIndex() < text.length();
+ * on output, the position after the last matched character. If
+ * the parse fails, the position in unchanged upon output.
+ * @return a reference to result
+ * @internal
+ */
+ virtual Formattable& parseCurrency(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& pos) const;
+
+ /**
+ * Return true if this format will parse numbers as integers
+ * only. For example in the English locale, with ParseIntegerOnly
+ * true, the string "1234." would be parsed as the integer value
+ * 1234 and parsing would stop at the "." character. Of course,
+ * the exact format accepted by the parse operation is locale
+ * dependant and determined by sub-classes of NumberFormat.
+ * @return true if this format will parse numbers as integers
+ * only.
+ * @stable ICU 2.0
+ */
+ UBool isParseIntegerOnly(void) const;
+
+ /**
+ * Sets whether or not numbers should be parsed as integers only.
+ * @param value set True, this format will parse numbers as integers
+ * only.
+ * @see isParseIntegerOnly
+ * @stable ICU 2.0
+ */
+ virtual void setParseIntegerOnly(UBool value);
+
+ /**
+ * Returns the default number format for the current default
+ * locale. The default format is one of the styles provided by
+ * the other factory methods: getNumberInstance,
+ * getCurrencyInstance or getPercentInstance. Exactly which one
+ * is locale dependant.
+ * @stable ICU 2.0
+ */
+ static NumberFormat* U_EXPORT2 createInstance(UErrorCode&);
+
+ /**
+ * Returns the default number format for the specified locale.
+ * The default format is one of the styles provided by the other
+ * factory methods: getNumberInstance, getCurrencyInstance or
+ * getPercentInstance. Exactly which one is locale dependant.
+ * @param inLocale the given locale.
+ * @stable ICU 2.0
+ */
+ static NumberFormat* U_EXPORT2 createInstance(const Locale& inLocale,
+ UErrorCode&);
+
+ /**
+ * Returns a currency format for the current default locale.
+ * @stable ICU 2.0
+ */
+ static NumberFormat* U_EXPORT2 createCurrencyInstance(UErrorCode&);
+
+ /**
+ * Returns a currency format for the specified locale.
+ * @param inLocale the given locale.
+ * @stable ICU 2.0
+ */
+ static NumberFormat* U_EXPORT2 createCurrencyInstance(const Locale& inLocale,
+ UErrorCode&);
+
+ /**
+ * Returns a percentage format for the current default locale.
+ * @stable ICU 2.0
+ */
+ static NumberFormat* U_EXPORT2 createPercentInstance(UErrorCode&);
+
+ /**
+ * Returns a percentage format for the specified locale.
+ * @param inLocale the given locale.
+ * @stable ICU 2.0
+ */
+ static NumberFormat* U_EXPORT2 createPercentInstance(const Locale& inLocale,
+ UErrorCode&);
+
+ /**
+ * Returns a scientific format for the current default locale.
+ * @stable ICU 2.0
+ */
+ static NumberFormat* U_EXPORT2 createScientificInstance(UErrorCode&);
+
+ /**
+ * Returns a scientific format for the specified locale.
+ * @param inLocale the given locale.
+ * @stable ICU 2.0
+ */
+ static NumberFormat* U_EXPORT2 createScientificInstance(const Locale& inLocale,
+ UErrorCode&);
+
+ /**
+ * Get the set of Locales for which NumberFormats are installed.
+ * @param count Output param to receive the size of the locales
+ * @stable ICU 2.0
+ */
+ static const Locale* U_EXPORT2 getAvailableLocales(int32_t& count);
+
+#if !UCONFIG_NO_SERVICE
+ /**
+ * Register a new NumberFormatFactory. The factory will be adopted.
+ * @param toAdopt the NumberFormatFactory instance to be adopted
+ * @param status the in/out status code, no special meanings are assigned
+ * @return a registry key that can be used to unregister this factory
+ * @stable ICU 2.6
+ */
+ static URegistryKey U_EXPORT2 registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status);
+
+ /**
+ * Unregister a previously-registered NumberFormatFactory using the key returned from the
+ * register call. Key becomes invalid after a successful call and should not be used again.
+ * The NumberFormatFactory corresponding to the key will be deleted.
+ * @param key the registry key returned by a previous call to registerFactory
+ * @param status the in/out status code, no special meanings are assigned
+ * @return TRUE if the factory for the key was successfully unregistered
+ * @stable ICU 2.6
+ */
+ static UBool U_EXPORT2 unregister(URegistryKey key, UErrorCode& status);
+
+ /**
+ * Return a StringEnumeration over the locales available at the time of the call,
+ * including registered locales.
+ * @return a StringEnumeration over the locales available at the time of the call
+ * @stable ICU 2.6
+ */
+ static StringEnumeration* U_EXPORT2 getAvailableLocales(void);
+#endif /* UCONFIG_NO_SERVICE */
+
+ /**
+ * Returns true if grouping is used in this format. For example,
+ * in the English locale, with grouping on, the number 1234567
+ * might be formatted as "1,234,567". The grouping separator as
+ * well as the size of each group is locale dependant and is
+ * determined by sub-classes of NumberFormat.
+ * @see setGroupingUsed
+ * @stable ICU 2.0
+ */
+ UBool isGroupingUsed(void) const;
+
+ /**
+ * Set whether or not grouping will be used in this format.
+ * @param newValue True, grouping will be used in this format.
+ * @see getGroupingUsed
+ * @stable ICU 2.0
+ */
+ virtual void setGroupingUsed(UBool newValue);
+
+ /**
+ * Returns the maximum number of digits allowed in the integer portion of a
+ * number.
+ * @return the maximum number of digits allowed in the integer portion of a
+ * number.
+ * @see setMaximumIntegerDigits
+ * @stable ICU 2.0
+ */
+ int32_t getMaximumIntegerDigits(void) const;
+
+ /**
+ * Sets the maximum number of digits allowed in the integer portion of a
+ * number. maximumIntegerDigits must be >= minimumIntegerDigits. If the
+ * new value for maximumIntegerDigits is less than the current value
+ * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
+ * the new value.
+ *
+ * @param newValue the new value for the maximum number of digits
+ * allowed in the integer portion of a number.
+ * @see getMaximumIntegerDigits
+ * @stable ICU 2.0
+ */
+ virtual void setMaximumIntegerDigits(int32_t newValue);
+
+ /**
+ * Returns the minimum number of digits allowed in the integer portion of a
+ * number.
+ * @return the minimum number of digits allowed in the integer portion of a
+ * number.
+ * @see setMinimumIntegerDigits
+ * @stable ICU 2.0
+ */
+ int32_t getMinimumIntegerDigits(void) const;
+
+ /**
+ * Sets the minimum number of digits allowed in the integer portion of a
+ * number. minimumIntegerDigits must be &lt;= maximumIntegerDigits. If the
+ * new value for minimumIntegerDigits exceeds the current value
+ * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
+ * the new value.
+ * @param newValue the new value to be set.
+ * @see getMinimumIntegerDigits
+ * @stable ICU 2.0
+ */
+ virtual void setMinimumIntegerDigits(int32_t newValue);
+
+ /**
+ * Returns the maximum number of digits allowed in the fraction portion of a
+ * number.
+ * @return the maximum number of digits allowed in the fraction portion of a
+ * number.
+ * @see setMaximumFractionDigits
+ * @stable ICU 2.0
+ */
+ int32_t getMaximumFractionDigits(void) const;
+
+ /**
+ * Sets the maximum number of digits allowed in the fraction portion of a
+ * number. maximumFractionDigits must be >= minimumFractionDigits. If the
+ * new value for maximumFractionDigits is less than the current value
+ * of minimumFractionDigits, then minimumFractionDigits will also be set to
+ * the new value.
+ * @param newValue the new value to be set.
+ * @see getMaximumFractionDigits
+ * @stable ICU 2.0
+ */
+ virtual void setMaximumFractionDigits(int32_t newValue);
+
+ /**
+ * Returns the minimum number of digits allowed in the fraction portion of a
+ * number.
+ * @return the minimum number of digits allowed in the fraction portion of a
+ * number.
+ * @see setMinimumFractionDigits
+ * @stable ICU 2.0
+ */
+ int32_t getMinimumFractionDigits(void) const;
+
+ /**
+ * Sets the minimum number of digits allowed in the fraction portion of a
+ * number. minimumFractionDigits must be &lt;= maximumFractionDigits. If the
+ * new value for minimumFractionDigits exceeds the current value
+ * of maximumFractionDigits, then maximumIntegerDigits will also be set to
+ * the new value
+ * @param newValue the new value to be set.
+ * @see getMinimumFractionDigits
+ * @stable ICU 2.0
+ */
+ virtual void setMinimumFractionDigits(int32_t newValue);
+
+ /**
+ * Sets the currency used to display currency
+ * amounts. This takes effect immediately, if this format is a
+ * currency format. If this format is not a currency format, then
+ * the currency is used if and when this object becomes a
+ * currency format.
+ * @param theCurrency a 3-letter ISO code indicating new currency
+ * to use. It need not be null-terminated. May be the empty
+ * string or NULL to indicate no currency.
+ * @param ec input-output error code
+ * @stable ICU 3.0
+ */
+ virtual void setCurrency(const UChar* theCurrency, UErrorCode& ec);
+
+ /**
+ * Gets the currency used to display currency
+ * amounts. This may be an empty string for some subclasses.
+ * @return a 3-letter null-terminated ISO code indicating
+ * the currency in use, or a pointer to the empty string.
+ * @stable ICU 2.6
+ */
+ const UChar* getCurrency() const;
+
+public:
+
+ /**
+ * Return the class ID for this class. This is useful for
+ * comparing to a return value from getDynamicClassID(). Note that,
+ * because NumberFormat is an abstract base class, no fully constructed object
+ * will have the class ID returned by NumberFormat::getStaticClassID().
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override.
+ * This method is to implement a simple version of RTTI, since not all
+ * C++ compilers support genuine RTTI. Polymorphic operator==() and
+ * clone() methods call this method.
+ * <P>
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const = 0;
+
+protected:
+
+ /**
+ * Default constructor for subclass use only.
+ * @stable ICU 2.0
+ */
+ NumberFormat();
+
+ /**
+ * Copy constructor.
+ * @stable ICU 2.0
+ */
+ NumberFormat(const NumberFormat&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 2.0
+ */
+ NumberFormat& operator=(const NumberFormat&);
+
+ /**
+ * Returns the currency in effect for this formatter. Subclasses
+ * should override this method as needed. Unlike getCurrency(),
+ * this method should never return "".
+ * @result output parameter for null-terminated result, which must
+ * have a capacity of at least 4
+ * @internal
+ */
+ virtual void getEffectiveCurrency(UChar* result, UErrorCode& ec) const;
+
+private:
+
+ enum EStyles {
+ kNumberStyle,
+ kCurrencyStyle,
+ kPercentStyle,
+ kScientificStyle,
+ kStyleCount // ALWAYS LAST ENUM: number of styles
+ };
+
+ /**
+ * Creates the specified decimal format style of the desired locale.
+ * Hook for service registration, uses makeInstance directly if no services
+ * registered.
+ * @param desiredLocale the given locale.
+ * @param choice the given style.
+ * @param success Output param filled with success/failure status.
+ * @return A new NumberFormat instance.
+ */
+ static NumberFormat* U_EXPORT2 createInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
+
+ /**
+ * Creates the specified decimal format style of the desired locale.
+ * @param desiredLocale the given locale.
+ * @param choice the given style.
+ * @param success Output param filled with success/failure status.
+ * @return A new NumberFormat instance.
+ */
+ static NumberFormat* makeInstance(const Locale& desiredLocale, EStyles choice, UErrorCode& success);
+
+ UBool fGroupingUsed;
+ int32_t fMaxIntegerDigits;
+ int32_t fMinIntegerDigits;
+ int32_t fMaxFractionDigits;
+ int32_t fMinFractionDigits;
+ UBool fParseIntegerOnly;
+
+ // ISO currency code
+ UChar fCurrency[4];
+
+ friend class ICUNumberFormatFactory; // access to makeInstance, EStyles
+ friend class ICUNumberFormatService;
+};
+
+#if !UCONFIG_NO_SERVICE
+/**
+ * A NumberFormatFactory is used to register new number formats. The factory
+ * should be able to create any of the predefined formats for each locale it
+ * supports. When registered, the locales it supports extend or override the
+ * locale already supported by ICU.
+ *
+ * @stable ICU 2.6
+ */
+class U_I18N_API NumberFormatFactory : public UObject {
+public:
+
+ /**
+ * Destructor
+ * @stable ICU 3.0
+ */
+ virtual ~NumberFormatFactory();
+
+ /**
+ * Return true if this factory will be visible. Default is true.
+ * If not visible, the locales supported by this factory will not
+ * be listed by getAvailableLocales.
+ * @stable ICU 2.6
+ */
+ virtual UBool visible(void) const = 0;
+
+ /**
+ * Return the locale names directly supported by this factory. The number of names
+ * is returned in count;
+ * @stable ICU 2.6
+ */
+ virtual const UnicodeString * getSupportedIDs(int32_t &count, UErrorCode& status) const = 0;
+
+ /**
+ * Return a number format of the appropriate type. If the locale
+ * is not supported, return null. If the locale is supported, but
+ * the type is not provided by this service, return null. Otherwise
+ * return an appropriate instance of NumberFormat.
+ * @stable ICU 2.6
+ */
+ virtual NumberFormat* createFormat(const Locale& loc, UNumberFormatStyle formatType) = 0;
+};
+
+/**
+ * A NumberFormatFactory that supports a single locale. It can be visible or invisible.
+ * @stable ICU 2.6
+ */
+class U_I18N_API SimpleNumberFormatFactory : public NumberFormatFactory {
+protected:
+ /**
+ * True if the locale supported by this factory is visible.
+ * @stable ICU 2.6
+ */
+ const UBool _visible;
+
+ /**
+ * The locale supported by this factory, as a UnicodeString.
+ * @stable ICU 2.6
+ */
+ UnicodeString _id;
+
+public:
+ /**
+ * @stable ICU 2.6
+ */
+ SimpleNumberFormatFactory(const Locale& locale, UBool visible = TRUE);
+
+ /**
+ * @stable ICU 3.0
+ */
+ virtual ~SimpleNumberFormatFactory();
+
+ /**
+ * @stable ICU 2.6
+ */
+ virtual UBool visible(void) const;
+
+ /**
+ * @stable ICU 2.6
+ */
+ virtual const UnicodeString * getSupportedIDs(int32_t &count, UErrorCode& status) const;
+};
+#endif /* #if !UCONFIG_NO_SERVICE */
+
+// -------------------------------------
+
+inline UBool
+NumberFormat::isParseIntegerOnly() const
+{
+ return fParseIntegerOnly;
+}
+
+inline UnicodeString&
+NumberFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ return Format::format(obj, appendTo, status);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _NUMFMT
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/rbnf.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/rbnf.h
new file mode 100644
index 00000000000..030565eb284
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/rbnf.h
@@ -0,0 +1,1049 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2006, International Business Machines Corporation and others.
+* All Rights Reserved.
+*******************************************************************************
+*/
+
+#ifndef RBNF_H
+#define RBNF_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Rule Based Number Format
+ */
+
+/**
+ * \def U_HAVE_RBNF
+ * This will be 0 if RBNF support is not included in ICU
+ * and 1 if it is.
+ *
+ * @stable ICU 2.4
+ */
+#if UCONFIG_NO_FORMATTING
+#define U_HAVE_RBNF 0
+#else
+#define U_HAVE_RBNF 1
+
+#include "unicode/coll.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/fmtable.h"
+#include "unicode/locid.h"
+#include "unicode/numfmt.h"
+#include "unicode/unistr.h"
+#include "unicode/strenum.h"
+
+U_NAMESPACE_BEGIN
+
+class NFRuleSet;
+class LocalizationInfo;
+
+/**
+ * Tags for the predefined rulesets.
+ *
+ * @stable ICU 2.2
+ */
+enum URBNFRuleSetTag {
+ URBNF_SPELLOUT,
+ URBNF_ORDINAL,
+ URBNF_DURATION,
+ URBNF_COUNT
+};
+
+#if UCONFIG_NO_COLLATION
+class Collator;
+#endif
+
+/**
+ * The RuleBasedNumberFormat class formats numbers according to a set of rules. This number formatter is
+ * typically used for spelling out numeric values in words (e.g., 25,3476 as
+ * &quot;twenty-five thousand three hundred seventy-six&quot; or &quot;vingt-cinq mille trois
+ * cents soixante-seize&quot; or
+ * &quot;f&uuml;nfundzwanzigtausenddreihundertsechsundsiebzig&quot;), but can also be used for
+ * other complicated formatting tasks, such as formatting a number of seconds as hours,
+ * minutes and seconds (e.g., 3,730 as &quot;1:02:10&quot;).
+ *
+ * <p>The resources contain three predefined formatters for each locale: spellout, which
+ * spells out a value in words (123 is &quot;one hundred twenty-three&quot;); ordinal, which
+ * appends an ordinal suffix to the end of a numeral (123 is &quot;123rd&quot;); and
+ * duration, which shows a duration in seconds as hours, minutes, and seconds (123 is
+ * &quot;2:03&quot;).&nbsp; The client can also define more specialized <tt>RuleBasedNumberFormat</tt>s
+ * by supplying programmer-defined rule sets.</p>
+ *
+ * <p>The behavior of a <tt>RuleBasedNumberFormat</tt> is specified by a textual description
+ * that is either passed to the constructor as a <tt>String</tt> or loaded from a resource
+ * bundle. In its simplest form, the description consists of a semicolon-delimited list of <em>rules.</em>
+ * Each rule has a string of output text and a value or range of values it is applicable to.
+ * In a typical spellout rule set, the first twenty rules are the words for the numbers from
+ * 0 to 19:</p>
+ *
+ * <pre>zero; one; two; three; four; five; six; seven; eight; nine;
+ * ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen; seventeen; eighteen; nineteen;</pre>
+ *
+ * <p>For larger numbers, we can use the preceding set of rules to format the ones place, and
+ * we only have to supply the words for the multiples of 10:</p>
+ *
+ * <pre> 20: twenty[-&gt;&gt;];
+ * 30: thirty[-&gt;&gt;];
+ * 40: forty[-&gt;&gt;];
+ * 50: fifty[-&gt;&gt;];
+ * 60: sixty[-&gt;&gt;];
+ * 70: seventy[-&gt;&gt;];
+ * 80: eighty[-&gt;&gt;];
+ * 90: ninety[-&gt;&gt;];</pre>
+ *
+ * <p>In these rules, the <em>base value</em> is spelled out explicitly and set off from the
+ * rule's output text with a colon. The rules are in a sorted list, and a rule is applicable
+ * to all numbers from its own base value to one less than the next rule's base value. The
+ * &quot;&gt;&gt;&quot; token is called a <em>substitution</em> and tells the fomatter to
+ * isolate the number's ones digit, format it using this same set of rules, and place the
+ * result at the position of the &quot;&gt;&gt;&quot; token. Text in brackets is omitted if
+ * the number being formatted is an even multiple of 10 (the hyphen is a literal hyphen; 24
+ * is &quot;twenty-four,&quot; not &quot;twenty four&quot;).</p>
+ *
+ * <p>For even larger numbers, we can actually look up several parts of the number in the
+ * list:</p>
+ *
+ * <pre>100: &lt;&lt; hundred[ &gt;&gt;];</pre>
+ *
+ * <p>The &quot;&lt;&lt;&quot; represents a new kind of substitution. The &lt;&lt; isolates
+ * the hundreds digit (and any digits to its left), formats it using this same rule set, and
+ * places the result where the &quot;&lt;&lt;&quot; was. Notice also that the meaning of
+ * &gt;&gt; has changed: it now refers to both the tens and the ones digits. The meaning of
+ * both substitutions depends on the rule's base value. The base value determines the rule's <em>divisor,</em>
+ * which is the highest power of 10 that is less than or equal to the base value (the user
+ * can change this). To fill in the substitutions, the formatter divides the number being
+ * formatted by the divisor. The integral quotient is used to fill in the &lt;&lt;
+ * substitution, and the remainder is used to fill in the &gt;&gt; substitution. The meaning
+ * of the brackets changes similarly: text in brackets is omitted if the value being
+ * formatted is an even multiple of the rule's divisor. The rules are applied recursively, so
+ * if a substitution is filled in with text that includes another substitution, that
+ * substitution is also filled in.</p>
+ *
+ * <p>This rule covers values up to 999, at which point we add another rule:</p>
+ *
+ * <pre>1000: &lt;&lt; thousand[ &gt;&gt;];</pre>
+ *
+ * <p>Again, the meanings of the brackets and substitution tokens shift because the rule's
+ * base value is a higher power of 10, changing the rule's divisor. This rule can actually be
+ * used all the way up to 999,999. This allows us to finish out the rules as follows:</p>
+ *
+ * <pre> 1,000,000: &lt;&lt; million[ &gt;&gt;];
+ * 1,000,000,000: &lt;&lt; billion[ &gt;&gt;];
+ * 1,000,000,000,000: &lt;&lt; trillion[ &gt;&gt;];
+ * 1,000,000,000,000,000: OUT OF RANGE!;</pre>
+ *
+ * <p>Commas, periods, and spaces can be used in the base values to improve legibility and
+ * are ignored by the rule parser. The last rule in the list is customarily treated as an
+ * &quot;overflow rule,&quot; applying to everything from its base value on up, and often (as
+ * in this example) being used to print out an error message or default representation.
+ * Notice also that the size of the major groupings in large numbers is controlled by the
+ * spacing of the rules: because in English we group numbers by thousand, the higher rules
+ * are separated from each other by a factor of 1,000.</p>
+ *
+ * <p>To see how these rules actually work in practice, consider the following example:
+ * Formatting 25,430 with this rule set would work like this:</p>
+ *
+ * <table border="0" width="100%">
+ * <tr>
+ * <td><strong>&lt;&lt; thousand &gt;&gt;</strong></td>
+ * <td>[the rule whose base value is 1,000 is applicable to 25,340]</td>
+ * </tr>
+ * <tr>
+ * <td><strong>twenty-&gt;&gt;</strong> thousand &gt;&gt;</td>
+ * <td>[25,340 over 1,000 is 25. The rule for 20 applies.]</td>
+ * </tr>
+ * <tr>
+ * <td>twenty-<strong>five</strong> thousand &gt;&gt;</td>
+ * <td>[25 mod 10 is 5. The rule for 5 is &quot;five.&quot;</td>
+ * </tr>
+ * <tr>
+ * <td>twenty-five thousand <strong>&lt;&lt; hundred &gt;&gt;</strong></td>
+ * <td>[25,340 mod 1,000 is 340. The rule for 100 applies.]</td>
+ * </tr>
+ * <tr>
+ * <td>twenty-five thousand <strong>three</strong> hundred &gt;&gt;</td>
+ * <td>[340 over 100 is 3. The rule for 3 is &quot;three.&quot;]</td>
+ * </tr>
+ * <tr>
+ * <td>twenty-five thousand three hundred <strong>forty</strong></td>
+ * <td>[340 mod 100 is 40. The rule for 40 applies. Since 40 divides
+ * evenly by 10, the hyphen and substitution in the brackets are omitted.]</td>
+ * </tr>
+ * </table>
+ *
+ * <p>The above syntax suffices only to format positive integers. To format negative numbers,
+ * we add a special rule:</p>
+ *
+ * <pre>-x: minus &gt;&gt;;</pre>
+ *
+ * <p>This is called a <em>negative-number rule,</em> and is identified by &quot;-x&quot;
+ * where the base value would be. This rule is used to format all negative numbers. the
+ * &gt;&gt; token here means &quot;find the number's absolute value, format it with these
+ * rules, and put the result here.&quot;</p>
+ *
+ * <p>We also add a special rule called a <em>fraction rule </em>for numbers with fractional
+ * parts:</p>
+ *
+ * <pre>x.x: &lt;&lt; point &gt;&gt;;</pre>
+ *
+ * <p>This rule is used for all positive non-integers (negative non-integers pass through the
+ * negative-number rule first and then through this rule). Here, the &lt;&lt; token refers to
+ * the number's integral part, and the &gt;&gt; to the number's fractional part. The
+ * fractional part is formatted as a series of single-digit numbers (e.g., 123.456 would be
+ * formatted as &quot;one hundred twenty-three point four five six&quot;).</p>
+ *
+ * <p>To see how this rule syntax is applied to various languages, examine the resource data.</p>
+ *
+ * <p>There is actually much more flexibility built into the rule language than the
+ * description above shows. A formatter may own multiple rule sets, which can be selected by
+ * the caller, and which can use each other to fill in their substitutions. Substitutions can
+ * also be filled in with digits, using a DecimalFormat object. There is syntax that can be
+ * used to alter a rule's divisor in various ways. And there is provision for much more
+ * flexible fraction handling. A complete description of the rule syntax follows:</p>
+ *
+ * <hr>
+ *
+ * <p>The description of a <tt>RuleBasedNumberFormat</tt>'s behavior consists of one or more <em>rule
+ * sets.</em> Each rule set consists of a name, a colon, and a list of <em>rules.</em> A rule
+ * set name must begin with a % sign. Rule sets with names that begin with a single % sign
+ * are <em>public:</em> the caller can specify that they be used to format and parse numbers.
+ * Rule sets with names that begin with %% are <em>private:</em> they exist only for the use
+ * of other rule sets. If a formatter only has one rule set, the name may be omitted.</p>
+ *
+ * <p>The user can also specify a special &quot;rule set&quot; named <tt>%%lenient-parse</tt>.
+ * The body of <tt>%%lenient-parse</tt> isn't a set of number-formatting rules, but a <tt>RuleBasedCollator</tt>
+ * description which is used to define equivalences for lenient parsing. For more information
+ * on the syntax, see <tt>RuleBasedCollator</tt>. For more information on lenient parsing,
+ * see <tt>setLenientParse()</tt>. <em>Note:</em> symbols that have syntactic meaning
+ * in collation rules, such as '&amp;', have no particular meaning when appearing outside
+ * of the <tt>lenient-parse</tt> rule set.</p>
+ *
+ * <p>The body of a rule set consists of an ordered, semicolon-delimited list of <em>rules.</em>
+ * Internally, every rule has a base value, a divisor, rule text, and zero, one, or two <em>substitutions.</em>
+ * These parameters are controlled by the description syntax, which consists of a <em>rule
+ * descriptor,</em> a colon, and a <em>rule body.</em></p>
+ *
+ * <p>A rule descriptor can take one of the following forms (text in <em>italics</em> is the
+ * name of a token):</p>
+ *
+ * <table border="0" width="100%">
+ * <tr>
+ * <td><em>bv</em>:</td>
+ * <td><em>bv</em> specifies the rule's base value. <em>bv</em> is a decimal
+ * number expressed using ASCII digits. <em>bv</em> may contain spaces, period, and commas,
+ * which are ignored. The rule's divisor is the highest power of 10 less than or equal to
+ * the base value.</td>
+ * </tr>
+ * <tr>
+ * <td><em>bv</em>/<em>rad</em>:</td>
+ * <td><em>bv</em> specifies the rule's base value. The rule's divisor is the
+ * highest power of <em>rad</em> less than or equal to the base value.</td>
+ * </tr>
+ * <tr>
+ * <td><em>bv</em>&gt;:</td>
+ * <td><em>bv</em> specifies the rule's base value. To calculate the divisor,
+ * let the radix be 10, and the exponent be the highest exponent of the radix that yields a
+ * result less than or equal to the base value. Every &gt; character after the base value
+ * decreases the exponent by 1. If the exponent is positive or 0, the divisor is the radix
+ * raised to the power of the exponent; otherwise, the divisor is 1.</td>
+ * </tr>
+ * <tr>
+ * <td><em>bv</em>/<em>rad</em>&gt;:</td>
+ * <td><em>bv</em> specifies the rule's base value. To calculate the divisor,
+ * let the radix be <em>rad</em>, and the exponent be the highest exponent of the radix that
+ * yields a result less than or equal to the base value. Every &gt; character after the radix
+ * decreases the exponent by 1. If the exponent is positive or 0, the divisor is the radix
+ * raised to the power of the exponent; otherwise, the divisor is 1.</td>
+ * </tr>
+ * <tr>
+ * <td>-x:</td>
+ * <td>The rule is a negative-number rule.</td>
+ * </tr>
+ * <tr>
+ * <td>x.x:</td>
+ * <td>The rule is an <em>improper fraction rule.</em></td>
+ * </tr>
+ * <tr>
+ * <td>0.x:</td>
+ * <td>The rule is a <em>proper fraction rule.</em></td>
+ * </tr>
+ * <tr>
+ * <td>x.0:</td>
+ * <td>The rule is a <em>master rule.</em></td>
+ * </tr>
+ * <tr>
+ * <td><em>nothing</em></td>
+ * <td>If the rule's rule descriptor is left out, the base value is one plus the
+ * preceding rule's base value (or zero if this is the first rule in the list) in a normal
+ * rule set.&nbsp; In a fraction rule set, the base value is the same as the preceding rule's
+ * base value.</td>
+ * </tr>
+ * </table>
+ *
+ * <p>A rule set may be either a regular rule set or a <em>fraction rule set,</em> depending
+ * on whether it is used to format a number's integral part (or the whole number) or a
+ * number's fractional part. Using a rule set to format a rule's fractional part makes it a
+ * fraction rule set.</p>
+ *
+ * <p>Which rule is used to format a number is defined according to one of the following
+ * algorithms: If the rule set is a regular rule set, do the following:
+ *
+ * <ul>
+ * <li>If the rule set includes a master rule (and the number was passed in as a <tt>double</tt>),
+ * use the master rule.&nbsp; (If the number being formatted was passed in as a <tt>long</tt>,
+ * the master rule is ignored.)</li>
+ * <li>If the number is negative, use the negative-number rule.</li>
+ * <li>If the number has a fractional part and is greater than 1, use the improper fraction
+ * rule.</li>
+ * <li>If the number has a fractional part and is between 0 and 1, use the proper fraction
+ * rule.</li>
+ * <li>Binary-search the rule list for the rule with the highest base value less than or equal
+ * to the number. If that rule has two substitutions, its base value is not an even multiple
+ * of its divisor, and the number <em>is</em> an even multiple of the rule's divisor, use the
+ * rule that precedes it in the rule list. Otherwise, use the rule itself.</li>
+ * </ul>
+ *
+ * <p>If the rule set is a fraction rule set, do the following:
+ *
+ * <ul>
+ * <li>Ignore negative-number and fraction rules.</li>
+ * <li>For each rule in the list, multiply the number being formatted (which will always be
+ * between 0 and 1) by the rule's base value. Keep track of the distance between the result
+ * the nearest integer.</li>
+ * <li>Use the rule that produced the result closest to zero in the above calculation. In the
+ * event of a tie or a direct hit, use the first matching rule encountered. (The idea here is
+ * to try each rule's base value as a possible denominator of a fraction. Whichever
+ * denominator produces the fraction closest in value to the number being formatted wins.) If
+ * the rule following the matching rule has the same base value, use it if the numerator of
+ * the fraction is anything other than 1; if the numerator is 1, use the original matching
+ * rule. (This is to allow singular and plural forms of the rule text without a lot of extra
+ * hassle.)</li>
+ * </ul>
+ *
+ * <p>A rule's body consists of a string of characters terminated by a semicolon. The rule
+ * may include zero, one, or two <em>substitution tokens,</em> and a range of text in
+ * brackets. The brackets denote optional text (and may also include one or both
+ * substitutions). The exact meanings of the substitution tokens, and under what conditions
+ * optional text is omitted, depend on the syntax of the substitution token and the context.
+ * The rest of the text in a rule body is literal text that is output when the rule matches
+ * the number being formatted.</p>
+ *
+ * <p>A substitution token begins and ends with a <em>token character.</em> The token
+ * character and the context together specify a mathematical operation to be performed on the
+ * number being formatted. An optional <em>substitution descriptor </em>specifies how the
+ * value resulting from that operation is used to fill in the substitution. The position of
+ * the substitution token in the rule body specifies the location of the resultant text in
+ * the original rule text.</p>
+ *
+ * <p>The meanings of the substitution token characters are as follows:</p>
+ *
+ * <table border="0" width="100%">
+ * <tr>
+ * <td>&gt;&gt;</td>
+ * <td>in normal rule</td>
+ * <td>Divide the number by the rule's divisor and format the remainder</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in negative-number rule</td>
+ * <td>Find the absolute value of the number and format the result</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in fraction or master rule</td>
+ * <td>Isolate the number's fractional part and format it.</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in rule in fraction rule set</td>
+ * <td>Not allowed.</td>
+ * </tr>
+ * <tr>
+ * <td>&gt;&gt;&gt;</td>
+ * <td>in normal rule</td>
+ * <td>Divide the number by the rule's divisor and format the remainder,
+ * but bypass the normal rule-selection process and just use the
+ * rule that precedes this one in this rule list.</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in all other rules</td>
+ * <td>Not allowed.</td>
+ * </tr>
+ * <tr>
+ * <td>&lt;&lt;</td>
+ * <td>in normal rule</td>
+ * <td>Divide the number by the rule's divisor and format the quotient</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in negative-number rule</td>
+ * <td>Not allowed.</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in fraction or master rule</td>
+ * <td>Isolate the number's integral part and format it.</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in rule in fraction rule set</td>
+ * <td>Multiply the number by the rule's base value and format the result.</td>
+ * </tr>
+ * <tr>
+ * <td>==</td>
+ * <td>in all rule sets</td>
+ * <td>Format the number unchanged</td>
+ * </tr>
+ * <tr>
+ * <td>[]</td>
+ * <td>in normal rule</td>
+ * <td>Omit the optional text if the number is an even multiple of the rule's divisor</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in negative-number rule</td>
+ * <td>Not allowed.</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in improper-fraction rule</td>
+ * <td>Omit the optional text if the number is between 0 and 1 (same as specifying both an
+ * x.x rule and a 0.x rule)</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in master rule</td>
+ * <td>Omit the optional text if the number is an integer (same as specifying both an x.x
+ * rule and an x.0 rule)</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in proper-fraction rule</td>
+ * <td>Not allowed.</td>
+ * </tr>
+ * <tr>
+ * <td></td>
+ * <td>in rule in fraction rule set</td>
+ * <td>Omit the optional text if multiplying the number by the rule's base value yields 1.</td>
+ * </tr>
+ * </table>
+ *
+ * <p>The substitution descriptor (i.e., the text between the token characters) may take one
+ * of three forms:</p>
+ *
+ * <table border="0" width="100%">
+ * <tr>
+ * <td>a rule set name</td>
+ * <td>Perform the mathematical operation on the number, and format the result using the
+ * named rule set.</td>
+ * </tr>
+ * <tr>
+ * <td>a DecimalFormat pattern</td>
+ * <td>Perform the mathematical operation on the number, and format the result using a
+ * DecimalFormat with the specified pattern.&nbsp; The pattern must begin with 0 or #.</td>
+ * </tr>
+ * <tr>
+ * <td>nothing</td>
+ * <td>Perform the mathematical operation on the number, and format the result using the rule
+ * set containing the current rule, except:
+ * <ul>
+ * <li>You can't have an empty substitution descriptor with a == substitution.</li>
+ * <li>If you omit the substitution descriptor in a &gt;&gt; substitution in a fraction rule,
+ * format the result one digit at a time using the rule set containing the current rule.</li>
+ * <li>If you omit the substitution descriptor in a &lt;&lt; substitution in a rule in a
+ * fraction rule set, format the result using the default rule set for this formatter.</li>
+ * </ul>
+ * </td>
+ * </tr>
+ * </table>
+ *
+ * <p>Whitespace is ignored between a rule set name and a rule set body, between a rule
+ * descriptor and a rule body, or between rules. If a rule body begins with an apostrophe,
+ * the apostrophe is ignored, but all text after it becomes significant (this is how you can
+ * have a rule's rule text begin with whitespace). There is no escape function: the semicolon
+ * is not allowed in rule set names or in rule text, and the colon is not allowed in rule set
+ * names. The characters beginning a substitution token are always treated as the beginning
+ * of a substitution token.</p>
+ *
+ * <p>See the resource data and the demo program for annotated examples of real rule sets
+ * using these features.</p>
+ *
+ * <p><em>User subclasses are not supported.</em> While clients may write
+ * subclasses, such code will not necessarily work and will not be
+ * guaranteed to work stably from release to release.
+ *
+ * <p><b>Localizations</b></p>
+ * <p>Constructors are available that allow the specification of localizations for the
+ * public rule sets (and also allow more control over what public rule sets are available).
+ * Localization data is represented as a textual description. The description represents
+ * an array of arrays of string. The first element is an array of the public rule set names,
+ * each of these must be one of the public rule set names that appear in the rules. Only
+ * names in this array will be treated as public rule set names by the API. Each subsequent
+ * element is an array of localizations of these names. The first element of one of these
+ * subarrays is the locale name, and the remaining elements are localizations of the
+ * public rule set names, in the same order as they were listed in the first arrray.</p>
+ * <p>In the syntax, angle brackets '<', '>' are used to delimit the arrays, and comma ',' is used
+ * to separate elements of an array. Whitespace is ignored, unless quoted.</p>
+ * <p>For example:<pre>
+ * < < %foo, %bar, %baz >,
+ * < en, Foo, Bar, Baz >,
+ * < fr, 'le Foo', 'le Bar', 'le Baz' >
+ * < zh, \\u7532, \\u4e59, \\u4e19 > >
+ * </pre></p>
+ * @author Richard Gillam
+ * @see NumberFormat
+ * @see DecimalFormat
+ * @stable ICU 2.0
+ */
+class U_I18N_API RuleBasedNumberFormat : public NumberFormat {
+public:
+
+ //-----------------------------------------------------------------------
+ // constructors
+ //-----------------------------------------------------------------------
+
+ /**
+ * Creates a RuleBasedNumberFormat that behaves according to the description
+ * passed in. The formatter uses the default locale.
+ * @param rules A description of the formatter's desired behavior.
+ * See the class documentation for a complete explanation of the description
+ * syntax.
+ * @param perror The parse error if an error was encountered.
+ * @param status The status indicating whether the constructor succeeded.
+ * @stable ICU 3.2
+ */
+ RuleBasedNumberFormat(const UnicodeString& rules, UParseError& perror, UErrorCode& status);
+
+ /**
+ * Creates a RuleBasedNumberFormat that behaves according to the description
+ * passed in. The formatter uses the default locale.
+ * <p>
+ * The localizations data provides information about the public
+ * rule sets and their localized display names for different
+ * locales. The first element in the list is an array of the names
+ * of the public rule sets. The first element in this array is
+ * the initial default ruleset. The remaining elements in the
+ * list are arrays of localizations of the names of the public
+ * rule sets. Each of these is one longer than the initial array,
+ * with the first String being the ULocale ID, and the remaining
+ * Strings being the localizations of the rule set names, in the
+ * same order as the initial array. Arrays are NULL-terminated.
+ * @param rules A description of the formatter's desired behavior.
+ * See the class documentation for a complete explanation of the description
+ * syntax.
+ * @param localizations the localization information.
+ * names in the description. These will be copied by the constructor.
+ * @param perror The parse error if an error was encountered.
+ * @param status The status indicating whether the constructor succeeded.
+ * @stable ICU 3.2
+ */
+ RuleBasedNumberFormat(const UnicodeString& rules, const UnicodeString& localizations,
+ UParseError& perror, UErrorCode& status);
+
+ /**
+ * Creates a RuleBasedNumberFormat that behaves according to the rules
+ * passed in. The formatter uses the specified locale to determine the
+ * characters to use when formatting numerals, and to define equivalences
+ * for lenient parsing.
+ * @param rules The formatter rules.
+ * See the class documentation for a complete explanation of the rule
+ * syntax.
+ * @param locale A locale that governs which characters are used for
+ * formatting values in numerals and which characters are equivalent in
+ * lenient parsing.
+ * @param perror The parse error if an error was encountered.
+ * @param status The status indicating whether the constructor succeeded.
+ * @stable ICU 2.0
+ */
+ RuleBasedNumberFormat(const UnicodeString& rules, const Locale& locale,
+ UParseError& perror, UErrorCode& status);
+
+ /**
+ * Creates a RuleBasedNumberFormat that behaves according to the description
+ * passed in. The formatter uses the default locale.
+ * <p>
+ * The localizations data provides information about the public
+ * rule sets and their localized display names for different
+ * locales. The first element in the list is an array of the names
+ * of the public rule sets. The first element in this array is
+ * the initial default ruleset. The remaining elements in the
+ * list are arrays of localizations of the names of the public
+ * rule sets. Each of these is one longer than the initial array,
+ * with the first String being the ULocale ID, and the remaining
+ * Strings being the localizations of the rule set names, in the
+ * same order as the initial array. Arrays are NULL-terminated.
+ * @param rules A description of the formatter's desired behavior.
+ * See the class documentation for a complete explanation of the description
+ * syntax.
+ * @param localizations a list of localizations for the rule set
+ * names in the description. These will be copied by the constructor.
+ * @param locale A locale that governs which characters are used for
+ * formatting values in numerals and which characters are equivalent in
+ * lenient parsing.
+ * @param perror The parse error if an error was encountered.
+ * @param status The status indicating whether the constructor succeeded.
+ * @stable ICU 3.2
+ */
+ RuleBasedNumberFormat(const UnicodeString& rules, const UnicodeString& localizations,
+ const Locale& locale, UParseError& perror, UErrorCode& status);
+
+ /**
+ * Creates a RuleBasedNumberFormat from a predefined ruleset. The selector
+ * code choosed among three possible predefined formats: spellout, ordinal,
+ * and duration.
+ * @param tag A selector code specifying which kind of formatter to create for that
+ * locale. There are three legal values: URBNF_SPELLOUT, which creates a formatter that
+ * spells out a value in words in the desired language, URBNF_ORDINAL, which attaches
+ * an ordinal suffix from the desired language to the end of a number (e.g. "123rd"),
+ * and URBNF_DURATION, which formats a duration in seconds as hours, minutes, and seconds.
+ * @param locale The locale for the formatter.
+ * @param status The status indicating whether the constructor succeeded.
+ * @stable ICU 2.0
+ */
+ RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& locale, UErrorCode& status);
+
+ //-----------------------------------------------------------------------
+ // boilerplate
+ //-----------------------------------------------------------------------
+
+ /**
+ * Copy constructor
+ * @param rhs the object to be copied from.
+ * @stable ICU 2.6
+ */
+ RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs);
+
+ /**
+ * Assignment operator
+ * @param rhs the object to be copied from.
+ * @stable ICU 2.6
+ */
+ RuleBasedNumberFormat& operator=(const RuleBasedNumberFormat& rhs);
+
+ /**
+ * Release memory allocated for a RuleBasedNumberFormat when you are finished with it.
+ * @stable ICU 2.6
+ */
+ virtual ~RuleBasedNumberFormat();
+
+ /**
+ * Clone this object polymorphically. The caller is responsible
+ * for deleting the result when done.
+ * @return A copy of the object.
+ * @stable ICU 2.6
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Return true if the given Format objects are semantically equal.
+ * Objects of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ * @stable ICU 2.6
+ */
+ virtual UBool operator==(const Format& other) const;
+
+//-----------------------------------------------------------------------
+// public API functions
+//-----------------------------------------------------------------------
+
+ /**
+ * return the rules that were provided to the RuleBasedNumberFormat.
+ * @return the result String that was passed in
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString getRules() const;
+
+ /**
+ * Return the number of public rule set names.
+ * @return the number of public rule set names.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getNumberOfRuleSetNames() const;
+
+ /**
+ * Return the name of the index'th public ruleSet. If index is not valid,
+ * the function returns null.
+ * @param index the index of the ruleset
+ * @return the name of the index'th public ruleSet.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString getRuleSetName(int32_t index) const;
+
+ /**
+ * Return the number of locales for which we have localized rule set display names.
+ * @return the number of locales for which we have localized rule set display names.
+ * @stable ICU 3.2
+ */
+ virtual int32_t getNumberOfRuleSetDisplayNameLocales(void) const;
+
+ /**
+ * Return the index'th display name locale.
+ * @param index the index of the locale
+ * @param status set to a failure code when this function fails
+ * @return the locale
+ * @see #getNumberOfRuleSetDisplayNameLocales
+ * @stable ICU 3.2
+ */
+ virtual Locale getRuleSetDisplayNameLocale(int32_t index, UErrorCode& status) const;
+
+ /**
+ * Return the rule set display names for the provided locale. These are in the same order
+ * as those returned by getRuleSetName. The locale is matched against the locales for
+ * which there is display name data, using normal fallback rules. If no locale matches,
+ * the default display names are returned. (These are the internal rule set names minus
+ * the leading '%'.)
+ * @param index the index of the rule set
+ * @param locale the locale (returned by getRuleSetDisplayNameLocales) for which the localized
+ * display name is desired
+ * @return the display name for the given index, which might be bogus if there is an error
+ * @see #getRuleSetName
+ * @stable ICU 3.2
+ */
+ virtual UnicodeString getRuleSetDisplayName(int32_t index,
+ const Locale& locale = Locale::getDefault());
+
+ /**
+ * Return the rule set display name for the provided rule set and locale.
+ * The locale is matched against the locales for which there is display name data, using
+ * normal fallback rules. If no locale matches, the default display name is returned.
+ * @return the display name for the rule set
+ * @stable ICU 3.2
+ * @see #getRuleSetDisplayName
+ */
+ virtual UnicodeString getRuleSetDisplayName(const UnicodeString& ruleSetName,
+ const Locale& locale = Locale::getDefault());
+
+ /**
+ * Formats the specified 32-bit number using the default ruleset.
+ * @param number The number to format.
+ * @param toAppendTo the string that will hold the (appended) result
+ * @param pos the fieldposition
+ * @return A textual representation of the number.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Formats the specified 64-bit number using the default ruleset.
+ * @param number The number to format.
+ * @param toAppendTo the string that will hold the (appended) result
+ * @param pos the fieldposition
+ * @return A textual representation of the number.
+ * @stable ICU 2.1
+ */
+ virtual UnicodeString& format(int64_t number,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos) const;
+ /**
+ * Formats the specified number using the default ruleset.
+ * @param number The number to format.
+ * @param toAppendTo the string that will hold the (appended) result
+ * @param pos the fieldposition
+ * @return A textual representation of the number.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(double number,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Formats the specified number using the named ruleset.
+ * @param number The number to format.
+ * @param ruleSetName The name of the rule set to format the number with.
+ * This must be the name of a valid public rule set for this formatter.
+ * @param toAppendTo the string that will hold the (appended) result
+ * @param pos the fieldposition
+ * @param status the status
+ * @return A textual representation of the number.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(int32_t number,
+ const UnicodeString& ruleSetName,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+ /**
+ * Formats the specified 64-bit number using the named ruleset.
+ * @param number The number to format.
+ * @param ruleSetName The name of the rule set to format the number with.
+ * This must be the name of a valid public rule set for this formatter.
+ * @param toAppendTo the string that will hold the (appended) result
+ * @param pos the fieldposition
+ * @param status the status
+ * @return A textual representation of the number.
+ * @stable ICU 2.1
+ */
+ virtual UnicodeString& format(int64_t number,
+ const UnicodeString& ruleSetName,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+ /**
+ * Formats the specified number using the named ruleset.
+ * @param number The number to format.
+ * @param ruleSetName The name of the rule set to format the number with.
+ * This must be the name of a valid public rule set for this formatter.
+ * @param toAppendTo the string that will hold the (appended) result
+ * @param pos the fieldposition
+ * @param status the status
+ * @return A textual representation of the number.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(double number,
+ const UnicodeString& ruleSetName,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Formats the specified number using the default ruleset.
+ * @param obj The number to format.
+ * @param toAppendTo the string that will hold the (appended) result
+ * @param pos the fieldposition
+ * @param status the status
+ * @return A textual representation of the number.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+ /**
+ * Redeclared Format method.
+ * @param obj the object to be formatted.
+ * @param result Output param which will receive the formatted string.
+ * @param status Output param set to success/failure code
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& result,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * @param number the double value to be formatted.
+ * @param output Output param which will receive the formatted string.
+ * @return A reference to 'output'.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(double number,
+ UnicodeString& output) const;
+
+ /**
+ * Redeclared NumberFormat method.
+ * @param number the long value to be formatted.
+ * @param output Output param which will receive the formatted string.
+ * @return A reference to 'output'.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(int32_t number,
+ UnicodeString& output) const;
+
+ /**
+ * Parses the specfied string, beginning at the specified position, according
+ * to this formatter's rules. This will match the string against all of the
+ * formatter's public rule sets and return the value corresponding to the longest
+ * parseable substring. This function's behavior is affected by the lenient
+ * parse mode.
+ * @param text The string to parse
+ * @param result the result of the parse, either a double or a long.
+ * @param parsePosition On entry, contains the position of the first character
+ * in "text" to examine. On exit, has been updated to contain the position
+ * of the first character in "text" that wasn't consumed by the parse.
+ * @see #setLenient
+ * @stable ICU 2.0
+ */
+ virtual void parse(const UnicodeString& text,
+ Formattable& result,
+ ParsePosition& parsePosition) const;
+
+
+ /**
+ * Redeclared Format method.
+ * @param text The string to parse
+ * @param result the result of the parse, either a double or a long.
+ * @param status Output param set to failure code when a problem occurs.
+ * @stable ICU 2.0
+ */
+ virtual inline void parse(const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const;
+
+#if !UCONFIG_NO_COLLATION
+
+ /**
+ * Turns lenient parse mode on and off.
+ *
+ * When in lenient parse mode, the formatter uses a Collator for parsing the text.
+ * Only primary differences are treated as significant. This means that case
+ * differences, accent differences, alternate spellings of the same letter
+ * (e.g., ae and a-umlaut in German), ignorable characters, etc. are ignored in
+ * matching the text. In many cases, numerals will be accepted in place of words
+ * or phrases as well.
+ *
+ * For example, all of the following will correctly parse as 255 in English in
+ * lenient-parse mode:
+ * <br>"two hundred fifty-five"
+ * <br>"two hundred fifty five"
+ * <br>"TWO HUNDRED FIFTY-FIVE"
+ * <br>"twohundredfiftyfive"
+ * <br>"2 hundred fifty-5"
+ *
+ * The Collator used is determined by the locale that was
+ * passed to this object on construction. The description passed to this object
+ * on construction may supply additional collation rules that are appended to the
+ * end of the default collator for the locale, enabling additional equivalences
+ * (such as adding more ignorable characters or permitting spelled-out version of
+ * symbols; see the demo program for examples).
+ *
+ * It's important to emphasize that even strict parsing is relatively lenient: it
+ * will accept some text that it won't produce as output. In English, for example,
+ * it will correctly parse "two hundred zero" and "fifteen hundred".
+ *
+ * @param enabled If true, turns lenient-parse mode on; if false, turns it off.
+ * @see RuleBasedCollator
+ * @stable ICU 2.0
+ */
+ virtual void setLenient(UBool enabled);
+
+ /**
+ * Returns true if lenient-parse mode is turned on. Lenient parsing is off
+ * by default.
+ * @return true if lenient-parse mode is turned on.
+ * @see #setLenient
+ * @stable ICU 2.0
+ */
+ virtual inline UBool isLenient(void) const;
+
+#endif
+
+ /**
+ * Override the default rule set to use. If ruleSetName is null, reset
+ * to the initial default rule set. If the rule set is not a public rule set name,
+ * U_ILLEGAL_ARGUMENT_ERROR is returned in status.
+ * @param ruleSetName the name of the rule set, or null to reset the initial default.
+ * @param status set to failure code when a problem occurs.
+ * @stable ICU 2.6
+ */
+ virtual void setDefaultRuleSet(const UnicodeString& ruleSetName, UErrorCode& status);
+
+ /**
+ * Return the name of the current default rule set. If the current rule set is
+ * not public, returns a bogus (and empty) UnicodeString.
+ * @return the name of the current default rule set
+ * @stable ICU 3.0
+ */
+ virtual UnicodeString getDefaultRuleSetName() const;
+
+public:
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+private:
+ RuleBasedNumberFormat(); // default constructor not implemented
+
+ // this will ref the localizations if they are not NULL
+ // caller must deref to get adoption
+ RuleBasedNumberFormat(const UnicodeString& description, LocalizationInfo* localizations,
+ const Locale& locale, UParseError& perror, UErrorCode& status);
+
+ void init(const UnicodeString& rules, LocalizationInfo* localizations, UParseError& perror, UErrorCode& status);
+ void dispose();
+ void stripWhitespace(UnicodeString& src);
+ void initDefaultRuleSet();
+ void format(double number, NFRuleSet& ruleSet);
+ NFRuleSet* findRuleSet(const UnicodeString& name, UErrorCode& status) const;
+
+ /* friend access */
+ friend class NFSubstitution;
+ friend class NFRule;
+ friend class FractionalPartSubstitution;
+
+ inline NFRuleSet * getDefaultRuleSet() const;
+ Collator * getCollator() const;
+ DecimalFormatSymbols * getDecimalFormatSymbols() const;
+
+private:
+ NFRuleSet **ruleSets;
+ NFRuleSet *defaultRuleSet;
+ Locale locale;
+ Collator* collator;
+ DecimalFormatSymbols* decimalFormatSymbols;
+ UBool lenient;
+ UnicodeString* lenientParseRules;
+ LocalizationInfo* localizations;
+};
+
+// ---------------
+
+inline UnicodeString&
+RuleBasedNumberFormat::format(const Formattable& obj,
+ UnicodeString& result,
+ UErrorCode& status) const
+{
+ // Don't use Format:: - use immediate base class only,
+ // in case immediate base modifies behavior later.
+ // dlf - the above comment is bogus, if there were a reason to modify
+ // it, it would be virtual, and there's no reason because it is
+ // a one-line macro in NumberFormat anyway, just like this one.
+ return NumberFormat::format(obj, result, status);
+}
+
+inline UnicodeString&
+RuleBasedNumberFormat::format(double number, UnicodeString& output) const {
+ FieldPosition pos(0);
+ return format(number, output, pos);
+}
+
+inline UnicodeString&
+RuleBasedNumberFormat::format(int32_t number, UnicodeString& output) const {
+ FieldPosition pos(0);
+ return format(number, output, pos);
+}
+
+inline void
+RuleBasedNumberFormat::parse(const UnicodeString& text, Formattable& result, UErrorCode& status) const
+{
+ NumberFormat::parse(text, result, status);
+}
+
+#if !UCONFIG_NO_COLLATION
+
+inline UBool
+RuleBasedNumberFormat::isLenient(void) const {
+ return lenient;
+}
+
+#endif
+
+inline NFRuleSet*
+RuleBasedNumberFormat::getDefaultRuleSet() const {
+ return defaultRuleSet;
+}
+
+U_NAMESPACE_END
+
+/* U_HAVE_RBNF */
+#endif
+
+/* RBNF_H */
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/rbtz.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/rbtz.h
new file mode 100644
index 00000000000..d7f342d5f9e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/rbtz.h
@@ -0,0 +1,355 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef RBTZ_H
+#define RBTZ_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Rule based customizable time zone
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/basictz.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_BEGIN
+
+// forward declaration
+class UVector;
+struct Transition;
+
+class U_I18N_API RuleBasedTimeZone : public BasicTimeZone {
+public:
+ /**
+ * Constructs a <code>RuleBasedTimeZone</code> object with the ID and the
+ * <code>InitialTimeZoneRule</code>. The input <code>InitialTimeZoneRule</code>
+ * is adopted by this <code>RuleBasedTimeZone</code>, thus the caller must not
+ * delete it.
+ * @param id The time zone ID.
+ * @param initialRule The initial time zone rule.
+ * @draft ICU 3.8
+ */
+ RuleBasedTimeZone(const UnicodeString& id, InitialTimeZoneRule* initialRule);
+
+ /**
+ * Copy constructor.
+ * @param source The RuleBasedTimeZone object to be copied.
+ * @draft ICU 3.8
+ */
+ RuleBasedTimeZone(const RuleBasedTimeZone& source);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~RuleBasedTimeZone();
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @draft ICU 3.8
+ */
+ RuleBasedTimeZone& operator=(const RuleBasedTimeZone& right);
+
+ /**
+ * Return true if the given <code>TimeZone</code> objects are
+ * semantically equal. Objects of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZone</code> objects are
+ *semantically equal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator==(const TimeZone& that) const;
+
+ /**
+ * Return true if the given <code>TimeZone</code> objects are
+ * semantically unequal. Objects of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZone</code> objects are
+ * semantically unequal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator!=(const TimeZone& that) const;
+
+ /**
+ * Adds the <code>TimeZoneRule</code> which represents time transitions.
+ * The <code>TimeZoneRule</code> must have start times, that is, the result
+ * of isTransitionRule() must be true. Otherwise, U_ILLEGAL_ARGUMENT_ERROR
+ * is set to the error code.
+ * The input <code>TimeZoneRule</code> is adopted by this
+ * <code>RuleBasedTimeZone</code> on successful completion of this method,
+ * thus, the caller must not delete it when no error is returned.
+ * After all rules are added, the caller must call complete() method to
+ * make this <code>RuleBasedTimeZone</code> ready to handle common time
+ * zone functions.
+ * @param rule The <code>TimeZoneRule</code>.
+ * @param status Output param to filled in with a success or an error.
+ * @draft ICU 3.8
+ */
+ void addTransitionRule(TimeZoneRule* rule, UErrorCode& status);
+
+ /**
+ * Makes the <code>TimeZoneRule</code> ready to handle actual timezone
+ * calcuation APIs. This method collects time zone rules specified
+ * by the caller via the constructor and addTransitionRule() and
+ * builds internal structure for making the object ready to support
+ * time zone APIs such as getOffset(), getNextTransition() and others.
+ * @param status Output param to filled in with a success or an error.
+ * @draft ICU 3.8
+ */
+ void complete(UErrorCode& status);
+
+ /**
+ * Clones TimeZone objects polymorphically. Clients are responsible for deleting
+ * the TimeZone object cloned.
+ *
+ * @return A new copy of this TimeZone object.
+ * @draft ICU 3.8
+ */
+ virtual TimeZone* clone(void) const;
+
+ /**
+ * Returns the TimeZone's adjusted GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time in this time zone, taking daylight savings time into
+ * account) as of a particular reference date. The reference date is used to determine
+ * whether daylight savings time is in effect and needs to be figured into the offset
+ * that is returned (in other words, what is the adjusted GMT offset in this time zone
+ * at this particular date and time?). For the time zones produced by createTimeZone(),
+ * the reference data is specified according to the Gregorian calendar, and the date
+ * and time fields are local standard time.
+ *
+ * <p>Note: Don't call this method. Instead, call the getOffset(UDate...) overload,
+ * which returns both the raw and the DST offset for a given time. This method
+ * is retained only for backward compatibility.
+ *
+ * @param era The reference date's era
+ * @param year The reference date's year
+ * @param month The reference date's month (0-based; 0 is January)
+ * @param day The reference date's day-in-month (1-based)
+ * @param dayOfWeek The reference date's day-of-week (1-based; 1 is Sunday)
+ * @param millis The reference date's milliseconds in day, local standard time
+ * @param status Output param to filled in with a success or an error.
+ * @return The offset in milliseconds to add to GMT to get local time.
+ * @draft ICU 3.8
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const;
+
+ /**
+ * Gets the time zone offset, for current date, modified in case of
+ * daylight savings. This is the offset to add *to* UTC to get local time.
+ *
+ * <p>Note: Don't call this method. Instead, call the getOffset(UDate...) overload,
+ * which returns both the raw and the DST offset for a given time. This method
+ * is retained only for backward compatibility.
+ *
+ * @param era The reference date's era
+ * @param year The reference date's year
+ * @param month The reference date's month (0-based; 0 is January)
+ * @param day The reference date's day-in-month (1-based)
+ * @param dayOfWeek The reference date's day-of-week (1-based; 1 is Sunday)
+ * @param millis The reference date's milliseconds in day, local standard time
+ * @param monthLength The length of the given month in days.
+ * @param status Output param to filled in with a success or an error.
+ * @return The offset in milliseconds to add to GMT to get local time.
+ * @draft ICU 3.8
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis,
+ int32_t monthLength, UErrorCode& status) const;
+
+ /**
+ * Returns the time zone raw and GMT offset for the given moment
+ * in time. Upon return, local-millis = GMT-millis + rawOffset +
+ * dstOffset. All computations are performed in the proleptic
+ * Gregorian calendar. The default implementation in the TimeZone
+ * class delegates to the 8-argument getOffset().
+ *
+ * @param date moment in time for which to return offsets, in
+ * units of milliseconds from January 1, 1970 0:00 GMT, either GMT
+ * time or local wall time, depending on `local'.
+ * @param local if true, `date' is local wall time; otherwise it
+ * is in GMT time.
+ * @param rawOffset output parameter to receive the raw offset, that
+ * is, the offset not including DST adjustments
+ * @param dstOffset output parameter to receive the DST offset,
+ * that is, the offset to be added to `rawOffset' to obtain the
+ * total offset between local and GMT time. If DST is not in
+ * effect, this value is zero; otherwise it is a positive value,
+ * typically one hour.
+ * @param ec input-output error code
+ * @draft ICU 3.8
+ */
+ virtual void getOffset(UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& ec) const;
+
+ /**
+ * Sets the TimeZone's raw GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time, before taking daylight savings time into account).
+ *
+ * @param offsetMillis The new raw GMT offset for this time zone.
+ * @draft ICU 3.8
+ */
+ virtual void setRawOffset(int32_t offsetMillis);
+
+ /**
+ * Returns the TimeZone's raw GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time, before taking daylight savings time into account).
+ *
+ * @return The TimeZone's raw GMT offset.
+ * @draft ICU 3.8
+ */
+ virtual int32_t getRawOffset(void) const;
+
+ /**
+ * Queries if this time zone uses daylight savings time.
+ * @return true if this time zone uses daylight savings time,
+ * false, otherwise.
+ * @draft ICU 3.8
+ */
+ virtual UBool useDaylightTime(void) const;
+
+ /**
+ * Queries if the given date is in daylight savings time in
+ * this time zone.
+ * This method is wasteful since it creates a new GregorianCalendar and
+ * deletes it each time it is called. This is a deprecated method
+ * and provided only for Java compatibility.
+ *
+ * @param date the given UDate.
+ * @param status Output param filled in with success/error code.
+ * @return true if the given date is in daylight savings time,
+ * false, otherwise.
+ * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
+ */
+ virtual UBool inDaylightTime(UDate date, UErrorCode& status) const;
+
+ /**
+ * Returns true if this zone has the same rule and offset as another zone.
+ * That is, if this zone differs only in ID, if at all.
+ * @param other the <code>TimeZone</code> object to be compared with
+ * @return true if the given zone is the same as this one,
+ * with the possible exception of the ID
+ * @draft ICU 3.8
+ */
+ virtual UBool hasSameRules(const TimeZone& other) const;
+
+ /**
+ * Gets the first time zone transition after the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the first transition after the base time.
+ * @return TRUE if the transition is found.
+ * @draft ICU 3.8
+ */
+ virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * Gets the most recent time zone transition before the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the most recent transition before the base time.
+ * @return TRUE if the transition is found.
+ * @draft ICU 3.8
+ */
+ virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * Returns the number of <code>TimeZoneRule</code>s which represents time transitions,
+ * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except
+ * <code>InitialTimeZoneRule</code>. The return value range is 0 or any positive value.
+ * @param status Receives error status code.
+ * @return The number of <code>TimeZoneRule</code>s representing time transitions.
+ * @draft ICU 3.8
+ */
+ virtual int32_t countTransitionRules(UErrorCode& status) /*const*/;
+
+ /**
+ * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code>
+ * which represent time transitions for this time zone. On successful return,
+ * the argument initial points to non-NULL <code>InitialTimeZoneRule</code> and
+ * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code>
+ * instances up to the size specified by trscount. The results are referencing the
+ * rule instance held by this time zone instance. Therefore, after this time zone
+ * is destructed, they are no longer available.
+ * @param initial Receives the initial timezone rule
+ * @param trsrules Receives the timezone transition rules
+ * @param trscount On input, specify the size of the array 'transitions' receiving
+ * the timezone transition rules. On output, actual number of
+ * rules filled in the array will be set.
+ * @param status Receives error status code.
+ * @draft ICU 3.8
+ */
+ virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/;
+
+ /**
+ * Get time zone offsets from local wall time.
+ * @internal
+ */
+ virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/;
+
+private:
+ void deleteRules(void);
+ void deleteTransitions(void);
+ UVector* copyRules(UVector* source);
+ TimeZoneRule* findRuleInFinal(UDate date, UBool local,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const;
+ UBool findNext(UDate base, UBool inclusive, UDate& time, TimeZoneRule*& from, TimeZoneRule*& to) const;
+ UBool findPrev(UDate base, UBool inclusive, UDate& time, TimeZoneRule*& from, TimeZoneRule*& to) const;
+ int32_t getLocalDelta(int32_t rawBefore, int32_t dstBefore, int32_t rawAfter, int32_t dstAfter,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const;
+ UDate getTransitionTime(Transition* transition, UBool local,
+ int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const;
+ void getOffsetInternal(UDate date, UBool local, int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
+ int32_t& rawOffset, int32_t& dstOffset, UErrorCode& ec) const;
+
+ InitialTimeZoneRule *fInitialRule;
+ UVector *fHistoricRules;
+ UVector *fFinalRules;
+ UVector *fHistoricTransitions;
+ UBool fUpToDate;
+
+public:
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // RBTZ_H
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/regex.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/regex.h
new file mode 100644
index 00000000000..ce24ef5f89b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/regex.h
@@ -0,0 +1,950 @@
+/*
+**********************************************************************
+* Copyright (C) 2002-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* file name: regex.h
+* encoding: US-ASCII
+* indentation:4
+*
+* created on: 2002oct22
+* created by: Andy Heninger
+*
+* ICU Regular Expressions, API for C++
+*/
+
+#ifndef REGEX_H
+#define REGEX_H
+
+//#define REGEX_DEBUG
+
+/**
+ * \file
+ * \brief C++ API: Regular Expressions
+ *
+ * <h2>Regular Expression API</h2>
+ *
+ * <p>The ICU API for processing regular expressions consists of two classes,
+ * <code>RegexPattern</code> and <code>RegexMatcher</code>.
+ * <code>RegexPattern</code> objects represent a pre-processed, or compiled
+ * regular expression. They are created from a regular expression pattern string,
+ * and can be used to create <code>RegexMatcher</code> objects for the pattern.</p>
+ *
+ * <p>Class <code>RegexMatcher</code> bundles together a regular expression
+ * pattern and a target string to which the search pattern will be applied.
+ * <code>RegexMatcher</code> includes API for doing plain find or search
+ * operations, for search and replace operations, and for obtaining detailed
+ * information about bounds of a match. </p>
+ *
+ * <p>Note that by constructing <code>RegexMatcher</code> objects directly from regular
+ * expression pattern strings application code can be simplified and the explicit
+ * need for <code>RegexPattern</code> objects can usually be eliminated.
+ * </p>
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/parseerr.h"
+
+#include "unicode/uregex.h"
+
+U_NAMESPACE_BEGIN
+
+
+// Forward Declarations...
+
+class RegexMatcher;
+class RegexPattern;
+class UVector;
+class UVector32;
+class UnicodeSet;
+struct REStackFrame;
+struct Regex8BitSet;
+class RuleBasedBreakIterator;
+class RegexCImpl;
+
+
+
+
+/**
+ * RBBIPatternDump Debug function, displays the compiled form of a pattern.
+ * @internal
+ */
+#ifdef REGEX_DEBUG
+U_INTERNAL void U_EXPORT2
+ RegexPatternDump(const RegexPattern *pat);
+#else
+ #define RegexPatternDump(pat)
+#endif
+
+
+
+/**
+ * Class <code>RegexPattern</code> represents a compiled regular expression. It includes
+ * factory methods for creating a RegexPattern object from the source (string) form
+ * of a regular expression, methods for creating RegexMatchers that allow the pattern
+ * to be applied to input text, and a few convenience methods for simple common
+ * uses of regular expressions.
+ *
+ * <p>Class RegexPattern is not intended to be subclassed.</p>
+ *
+ * @stable ICU 2.4
+ */
+class U_I18N_API RegexPattern: public UObject {
+public:
+
+ /**
+ * default constructor. Create a RegexPattern object that refers to no actual
+ * pattern. Not normally needed; RegexPattern objects are usually
+ * created using the factory method <code>compile()</code>.
+ *
+ * @stable ICU 2.4
+ */
+ RegexPattern();
+
+ /**
+ * Copy Constructor. Create a new RegexPattern object that is equivalent
+ * to the source object.
+ * @param source the pattern object to be copied.
+ * @stable ICU 2.4
+ */
+ RegexPattern(const RegexPattern &source);
+
+ /**
+ * Destructor. Note that a RegexPattern object must persist so long as any
+ * RegexMatcher objects that were created from the RegexPattern are active.
+ * @stable ICU 2.4
+ */
+ virtual ~RegexPattern();
+
+ /**
+ * Comparison operator. Two RegexPattern objects are considered equal if they
+ * were constructed from identical source patterns using the same match flag
+ * settings.
+ * @param that a RegexPattern object to compare with "this".
+ * @return TRUE if the objects are equivalent.
+ * @stable ICU 2.4
+ */
+ UBool operator==(const RegexPattern& that) const;
+
+ /**
+ * Comparison operator. Two RegexPattern objects are considered equal if they
+ * were constructed from identical source patterns using the same match flag
+ * settings.
+ * @param that a RegexPattern object to compare with "this".
+ * @return TRUE if the objects are different.
+ * @stable ICU 2.4
+ */
+ inline UBool operator!=(const RegexPattern& that) const {return ! operator ==(that);};
+
+ /**
+ * Assignment operator. After assignment, this RegexPattern will behave identically
+ * to the source object.
+ * @stable ICU 2.4
+ */
+ RegexPattern &operator =(const RegexPattern &source);
+
+ /**
+ * Create an exact copy of this RegexPattern object. Since RegexPattern is not
+ * intended to be subclasses, <code>clone()</code> and the copy construction are
+ * equivalent operations.
+ * @return the copy of this RegexPattern
+ * @stable ICU 2.4
+ */
+ virtual RegexPattern *clone() const;
+
+
+ /**
+ * Compiles the regular expression in string form into a RegexPattern
+ * object. These compile methods, rather than the constructors, are the usual
+ * way that RegexPattern objects are created.
+ *
+ * <p>Note that RegexPattern objects must not be deleted while RegexMatcher
+ * objects created from the pattern are active. RegexMatchers keep a pointer
+ * back to their pattern, so premature deletion of the pattern is a
+ * catastrophic error.</p>
+ *
+ * <p>All pattern match mode flags are set to their default values.</p>
+ *
+ * <p>Note that it is often more convenient to construct a RegexMatcher directly
+ * from a pattern string rather than separately compiling the pattern and
+ * then creating a RegexMatcher object from the pattern.</p>
+ *
+ * @param regex The regular expression to be compiled.
+ * @param pe Receives the position (line and column nubers) of any error
+ * within the regular expression.)
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return A regexPattern object for the compiled pattern.
+ *
+ * @stable ICU 2.4
+ */
+ static RegexPattern * U_EXPORT2 compile( const UnicodeString &regex,
+ UParseError &pe,
+ UErrorCode &status);
+
+ /**
+ * Compiles the regular expression in string form into a RegexPattern
+ * object using the specified match mode flags. These compile methods,
+ * rather than the constructors, are the usual way that RegexPattern objects
+ * are created.
+ *
+ * <p>Note that RegexPattern objects must not be deleted while RegexMatcher
+ * objects created from the pattern are active. RegexMatchers keep a pointer
+ * back to their pattern, so premature deletion of the pattern is a
+ * catastrophic error.</p>
+ *
+ * <p>Note that it is often more convenient to construct a RegexMatcher directly
+ * from a pattern string instead of than separately compiling the pattern and
+ * then creating a RegexMatcher object from the pattern.</p>
+ *
+ * @param regex The regular expression to be compiled.
+ * @param flags The match mode flags to be used.
+ * @param pe Receives the position (line and column nubers) of any error
+ * within the regular expression.)
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return A regexPattern object for the compiled pattern.
+ *
+ * @stable ICU 2.4
+ */
+ static RegexPattern * U_EXPORT2 compile( const UnicodeString &regex,
+ uint32_t flags,
+ UParseError &pe,
+ UErrorCode &status);
+
+
+ /**
+ * Compiles the regular expression in string form into a RegexPattern
+ * object using the specified match mode flags. These compile methods,
+ * rather than the constructors, are the usual way that RegexPattern objects
+ * are created.
+ *
+ * <p>Note that RegexPattern objects must not be deleted while RegexMatcher
+ * objects created from the pattern are active. RegexMatchers keep a pointer
+ * back to their pattern, so premature deletion of the pattern is a
+ * catastrophic error.</p>
+ *
+ * <p>Note that it is often more convenient to construct a RegexMatcher directly
+ * from a pattern string instead of than separately compiling the pattern and
+ * then creating a RegexMatcher object from the pattern.</p>
+ *
+ * @param regex The regular expression to be compiled.
+ * @param flags The match mode flags to be used.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return A regexPattern object for the compiled pattern.
+ *
+ * @stable ICU 2.6
+ */
+ static RegexPattern * U_EXPORT2 compile( const UnicodeString &regex,
+ uint32_t flags,
+ UErrorCode &status);
+
+
+ /**
+ * Get the match mode flags that were used when compiling this pattern.
+ * @return the match mode flags
+ * @stable ICU 2.4
+ */
+ virtual uint32_t flags() const;
+
+ /**
+ * Creates a RegexMatcher that will match the given input against this pattern. The
+ * RegexMatcher can then be used to perform match, find or replace operations
+ * on the input. Note that a RegexPattern object must not be deleted while
+ * RegexMatchers created from it still exist and might possibly be used again.
+ * <p>
+ * The matcher will retain a reference to the supplied input string, and all regexp
+ * pattern matching operations happen directly on this original string. It is
+ * critical that the string not be altered or deleted before use by the regular
+ * expression operations is complete.
+ *
+ * @param input The input string to which the regular expression will be applied.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return A RegexMatcher object for this pattern and input.
+ *
+ * @stable ICU 2.4
+ */
+ virtual RegexMatcher *matcher(const UnicodeString &input,
+ UErrorCode &status) const;
+
+private:
+ /**
+ * Cause a compilation error if an application accidently attempts to
+ * create a matcher with a (UChar *) string as input rather than
+ * a UnicodeString. Avoids a dangling reference to a temporary string.
+ * <p>
+ * To efficiently work with UChar *strings, wrap the data in a UnicodeString
+ * using one of the aliasing constructors, such as
+ * <code>UnicodeString(UBool isTerminated, const UChar *text, int32_t textLength);</code>
+ *
+ * @internal
+ */
+ RegexMatcher *matcher(const UChar *input,
+ UErrorCode &status) const;
+public:
+
+
+ /**
+ * Creates a RegexMatcher that will match against this pattern. The
+ * RegexMatcher can be used to perform match, find or replace operations.
+ * Note that a RegexPattern object must not be deleted while
+ * RegexMatchers created from it still exist and might possibly be used again.
+ *
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return A RegexMatcher object for this pattern and input.
+ *
+ * @stable ICU 2.6
+ */
+ virtual RegexMatcher *matcher(UErrorCode &status) const;
+
+
+ /**
+ * Test whether a string matches a regular expression. This convenience function
+ * both compiles the reguluar expression and applies it in a single operation.
+ * Note that if the same pattern needs to be applied repeatedly, this method will be
+ * less efficient than creating and reusing a RegexMatcher object.
+ *
+ * @param regex The regular expression
+ * @param input The string data to be matched
+ * @param pe Receives the position of any syntax errors within the regular expression
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return True if the regular expression exactly matches the full input string.
+ *
+ * @stable ICU 2.4
+ */
+ static UBool U_EXPORT2 matches(const UnicodeString &regex,
+ const UnicodeString &input,
+ UParseError &pe,
+ UErrorCode &status);
+
+
+ /**
+ * Returns the regular expression from which this pattern was compiled.
+ * @stable ICU 2.4
+ */
+ virtual UnicodeString pattern() const;
+
+
+ /**
+ * Split a string into fields. Somewhat like split() from Perl.
+ * The pattern matches identify delimiters that separate the input
+ * into fields. The input data between the matches becomes the
+ * fields themselves.
+ * <p>
+ * For the best performance on split() operations,
+ * <code>RegexMatcher::split</code> is perferable to this function
+ *
+ * @param input The string to be split into fields. The field delimiters
+ * match the pattern (in the "this" object)
+ * @param dest An array of UnicodeStrings to receive the results of the split.
+ * This is an array of actual UnicodeString objects, not an
+ * array of pointers to strings. Local (stack based) arrays can
+ * work well here.
+ * @param destCapacity The number of elements in the destination array.
+ * If the number of fields found is less than destCapacity, the
+ * extra strings in the destination array are not altered.
+ * If the number of destination strings is less than the number
+ * of fields, the trailing part of the input string, including any
+ * field delimiters, is placed in the last destination string.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The number of fields into which the input string was split.
+ * @stable ICU 2.4
+ */
+ virtual int32_t split(const UnicodeString &input,
+ UnicodeString dest[],
+ int32_t destCapacity,
+ UErrorCode &status) const;
+
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.4
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.4
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+ //
+ // Implementation Data
+ //
+ UnicodeString fPattern; // The original pattern string.
+ uint32_t fFlags; // The flags used when compiling the pattern.
+ //
+ UVector32 *fCompiledPat; // The compiled pattern p-code.
+ UnicodeString fLiteralText; // Any literal string data from the pattern,
+ // after un-escaping, for use during the match.
+
+ UVector *fSets; // Any UnicodeSets referenced from the pattern.
+ Regex8BitSet *fSets8; // (and fast sets for latin-1 range.)
+
+
+ UErrorCode fDeferredStatus; // status if some prior error has left this
+ // RegexPattern in an unusable state.
+
+ int32_t fMinMatchLen; // Minimum Match Length. All matches will have length
+ // >= this value. For some patterns, this calculated
+ // value may be less than the true shortest
+ // possible match.
+
+ int32_t fFrameSize; // Size of a state stack frame in the
+ // execution engine.
+
+ int32_t fDataSize; // The size of the data needed by the pattern that
+ // does not go on the state stack, but has just
+ // a single copy per matcher.
+
+ UVector32 *fGroupMap; // Map from capture group number to position of
+ // the group's variables in the matcher stack frame.
+
+ int32_t fMaxCaptureDigits;
+
+ UnicodeSet **fStaticSets; // Ptr to static (shared) sets for predefined
+ // regex character classes, e.g. Word.
+
+ Regex8BitSet *fStaticSets8; // Ptr to the static (shared) latin-1 only
+ // sets for predefined regex classes.
+
+ int32_t fStartType; // Info on how a match must start.
+ int32_t fInitialStringIdx; //
+ int32_t fInitialStringLen;
+ UnicodeSet *fInitialChars;
+ UChar32 fInitialChar;
+ Regex8BitSet *fInitialChars8;
+
+ friend class RegexCompile;
+ friend class RegexMatcher;
+ friend class RegexCImpl;
+
+ //
+ // Implementation Methods
+ //
+ void init(); // Common initialization, for use by constructors.
+ void zap(); // Common cleanup
+#ifdef REGEX_DEBUG
+ void dumpOp(int32_t index) const;
+ friend void U_EXPORT2 RegexPatternDump(const RegexPattern *);
+#endif
+
+};
+
+
+
+/**
+ * class RegexMatcher bundles together a reular expression pattern and
+ * input text to which the expression can be applied. It includes methods
+ * for testing for matches, and for find and replace operations.
+ *
+ * <p>Class RegexMatcher is not intended to be subclassed.</p>
+ *
+ * @stable ICU 2.4
+ */
+class U_I18N_API RegexMatcher: public UObject {
+public:
+
+ /**
+ * Construct a RegexMatcher for a regular expression.
+ * This is a convenience method that avoids the need to explicitly create
+ * a RegexPattern object. Note that if several RegexMatchers need to be
+ * created for the same expression, it will be more efficient to
+ * separately create and cache a RegexPattern object, and use
+ * its matcher() method to create the RegexMatcher objects.
+ *
+ * @param regexp The Regular Expression to be compiled.
+ * @param flags Regular expression options, such as case insensitive matching.
+ * @see UREGEX_CASE_INSENSITIVE
+ * @param status Any errors are reported by setting this UErrorCode variable.
+ * @stable ICU 2.6
+ */
+ RegexMatcher(const UnicodeString &regexp, uint32_t flags, UErrorCode &status);
+
+ /**
+ * Construct a RegexMatcher for a regular expression.
+ * This is a convenience method that avoids the need to explicitly create
+ * a RegexPattern object. Note that if several RegexMatchers need to be
+ * created for the same expression, it will be more efficient to
+ * separately create and cache a RegexPattern object, and use
+ * its matcher() method to create the RegexMatcher objects.
+ * <p>
+ * The matcher will retain a reference to the supplied input string, and all regexp
+ * pattern matching operations happen directly on the original string. It is
+ * critical that the string not be altered or deleted before use by the regular
+ * expression operations is complete.
+ *
+ * @param regexp The Regular Expression to be compiled.
+ * @param input The string to match. The matcher retains a reference to the
+ * caller's string; mo copy is made.
+ * @param flags Regular expression options, such as case insensitive matching.
+ * @see UREGEX_CASE_INSENSITIVE
+ * @param status Any errors are reported by setting this UErrorCode variable.
+ * @stable ICU 2.6
+ */
+ RegexMatcher(const UnicodeString &regexp, const UnicodeString &input,
+ uint32_t flags, UErrorCode &status);
+
+private:
+ /**
+ * Cause a compilation error if an application accidently attempts to
+ * create a matcher with a (UChar *) string as input rather than
+ * a UnicodeString. Avoids a dangling reference to a temporary string.
+ * <p>
+ * To efficiently work with UChar *strings, wrap the data in a UnicodeString
+ * using one of the aliasing constructors, such as
+ * <code>UnicodeString(UBool isTerminated, const UChar *text, int32_t textLength);</code>
+ *
+ * @internal
+ */
+ RegexMatcher(const UnicodeString &regexp, const UChar *input,
+ uint32_t flags, UErrorCode &status);
+public:
+
+
+ /**
+ * Destructor.
+ *
+ * @stable ICU 2.4
+ */
+ virtual ~RegexMatcher();
+
+
+ /**
+ * Attempts to match the entire input string against the pattern.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if there is a match
+ * @stable ICU 2.4
+ */
+ virtual UBool matches(UErrorCode &status);
+
+ /**
+ * Attempts to match the input string, beginning at startIndex, against the pattern.
+ * The match must extend to the end of the input string.
+ * @param startIndex The input string index at which to begin matching.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if there is a match
+ * @stable ICU 2.8
+ */
+ virtual UBool matches(int32_t startIndex, UErrorCode &status);
+
+
+
+
+ /**
+ * Attempts to match the input string, starting from the beginning, against the pattern.
+ * Like the matches() method, this function always starts at the beginning of the input string;
+ * unlike that function, it does not require that the entire input string be matched.
+ *
+ * <p>If the match succeeds then more information can be obtained via the <code>start()</code>,
+ * <code>end()</code>, and <code>group()</code> functions.</p>
+ *
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if there is a match at the start of the input string.
+ * @stable ICU 2.4
+ */
+ virtual UBool lookingAt(UErrorCode &status);
+
+
+ /**
+ * Attempts to match the input string, starting from the specified index, against the pattern.
+ * The match may be of any length, and is not required to extend to the end
+ * of the input string. Contrast with match().
+ *
+ * <p>If the match succeeds then more information can be obtained via the <code>start()</code>,
+ * <code>end()</code>, and <code>group()</code> functions.</p>
+ *
+ * @param startIndex The input string index at which to begin matching.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if there is a match.
+ * @stable ICU 2.8
+ */
+ virtual UBool lookingAt(int32_t startIndex, UErrorCode &status);
+
+ /**
+ * Find the next pattern match in the input string.
+ * The find begins searching the input at the location following the end of
+ * the previous match, or at the start of the string if there is no previous match.
+ * If a match is found, <code>start(), end()</code> and <code>group()</code>
+ * will provide more information regarding the match.
+ * <p>Note that if the input string is changed by the application,
+ * use find(startPos, status) instead of find(), because the saved starting
+ * position may not be valid with the altered input string.</p>
+ * @return TRUE if a match is found.
+ * @stable ICU 2.4
+ */
+ virtual UBool find();
+
+
+ /**
+ * Resets this RegexMatcher and then attempts to find the next substring of the
+ * input string that matches the pattern, starting at the specified index.
+ *
+ * @param start the position in the input string to begin the search
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if a match is found.
+ * @stable ICU 2.4
+ */
+ virtual UBool find(int32_t start, UErrorCode &status);
+
+
+ /**
+ * Returns a string containing the text matched by the previous match.
+ * If the pattern can match an empty string, an empty string may be returned.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * Possible errors are U_REGEX_INVALID_STATE if no match
+ * has been attempted or the last match failed.
+ * @return a string containing the matched input text.
+ * @stable ICU 2.4
+ */
+ virtual UnicodeString group(UErrorCode &status) const;
+
+
+ /**
+ * Returns a string containing the text captured by the given group
+ * during the previous match operation. Group(0) is the entire match.
+ *
+ * @param groupNum the capture group number
+ * @param status A reference to a UErrorCode to receive any errors.
+ * Possible errors are U_REGEX_INVALID_STATE if no match
+ * has been attempted or the last match failed and
+ * U_INDEX_OUTOFBOUNDS_ERROR for a bad capture group number.
+ * @return the captured text
+ * @stable ICU 2.4
+ */
+ virtual UnicodeString group(int32_t groupNum, UErrorCode &status) const;
+
+
+ /**
+ * Returns the number of capturing groups in this matcher's pattern.
+ * @return the number of capture groups
+ * @stable ICU 2.4
+ */
+ virtual int32_t groupCount() const;
+
+
+ /**
+ * Returns the index in the input string of the start of the text matched
+ * during the previous match operation.
+ * @param status a reference to a UErrorCode to receive any errors.
+ * @return The position in the input string of the start of the last match.
+ * @stable ICU 2.4
+ */
+ virtual int32_t start(UErrorCode &status) const;
+
+
+ /**
+ * Returns the index in the input string of the start of the text matched by the
+ * specified capture group during the previous match operation. Return -1 if
+ * the capture group exists in the pattern, but was not part of the last match.
+ *
+ * @param group the capture group number
+ * @param status A reference to a UErrorCode to receive any errors. Possible
+ * errors are U_REGEX_INVALID_STATE if no match has been
+ * attempted or the last match failed, and
+ * U_INDEX_OUTOFBOUNDS_ERROR for a bad capture group number
+ * @return the start position of substring matched by the specified group.
+ * @stable ICU 2.4
+ */
+ virtual int32_t start(int32_t group, UErrorCode &status) const;
+
+
+ /**
+ * Returns the index in the input string of the first character following the
+ * text matched during the previous match operation.
+ * @param status A reference to a UErrorCode to receive any errors. Possible
+ * errors are U_REGEX_INVALID_STATE if no match has been
+ * attempted or the last match failed.
+ * @return the index of the last character matched, plus one.
+ * @stable ICU 2.4
+ */
+ virtual int32_t end(UErrorCode &status) const;
+
+
+ /**
+ * Returns the index in the input string of the character following the
+ * text matched by the specified capture group during the previous match operation.
+ * @param group the capture group number
+ * @param status A reference to a UErrorCode to receive any errors. Possible
+ * errors are U_REGEX_INVALID_STATE if no match has been
+ * attempted or the last match failed and
+ * U_INDEX_OUTOFBOUNDS_ERROR for a bad capture group number
+ * @return the index of the first character following the text
+ * captured by the specifed group during the previous match operation.
+ * Return -1 if the capture group exists in the pattern but was not part of the match.
+ * @stable ICU 2.4
+ */
+ virtual int32_t end(int32_t group, UErrorCode &status) const;
+
+
+ /**
+ * Resets this matcher. The effect is to remove any memory of previous matches,
+ * and to cause subsequent find() operations to begin at the beginning of
+ * the input string.
+ *
+ * @return this RegexMatcher.
+ * @stable ICU 2.4
+ */
+ virtual RegexMatcher &reset();
+
+
+ /**
+ * Resets this matcher, and set the current input position.
+ * The effect is to remove any memory of previous matches,
+ * and to cause subsequent find() operations to begin at
+ * the specified position in the input string.
+ *
+ * @return this RegexMatcher.
+ * @stable ICU 2.8
+ */
+ virtual RegexMatcher &reset(int32_t index, UErrorCode &status);
+
+
+ /**
+ * Resets this matcher with a new input string. This allows instances of RegexMatcher
+ * to be reused, which is more efficient than creating a new RegexMatcher for
+ * each input string to be processed.
+ * @param input The new string on which subsequent pattern matches will operate.
+ * The matcher retains a reference to the callers string, and operates
+ * directly on that. Ownership of the string remains with the caller.
+ * Because no copy of the string is made, it is essential that the
+ * caller not delete the string until after regexp operations on it
+ * are done.
+ * @return this RegexMatcher.
+ * @stable ICU 2.4
+ */
+ virtual RegexMatcher &reset(const UnicodeString &input);
+
+private:
+ /**
+ * Cause a compilation error if an application accidently attempts to
+ * reset a matcher with a (UChar *) string as input rather than
+ * a UnicodeString. Avoids a dangling reference to a temporary string.
+ * <p>
+ * To efficiently work with UChar *strings, wrap the data in a UnicodeString
+ * using one of the aliasing constructors, such as
+ * <code>UnicodeString(UBool isTerminated, const UChar *text, int32_t textLength);</code>
+ *
+ * @internal
+ */
+ RegexMatcher &reset(const UChar *input);
+public:
+
+ /**
+ * Returns the input string being matched. The returned string is not a copy,
+ * but the live input string. It should not be altered or deleted.
+ * @return the input string
+ * @stable ICU 2.4
+ */
+ virtual const UnicodeString &input() const;
+
+
+ /**
+ * Returns the pattern that is interpreted by this matcher.
+ * @return the RegexPattern for this RegexMatcher
+ * @stable ICU 2.4
+ */
+ virtual const RegexPattern &pattern() const;
+
+
+ /**
+ * Replaces every substring of the input that matches the pattern
+ * with the given replacement string. This is a convenience function that
+ * provides a complete find-and-replace-all operation.
+ *
+ * This method first resets this matcher. It then scans the input string
+ * looking for matches of the pattern. Input that is not part of any
+ * match is left unchanged; each match is replaced in the result by the
+ * replacement string. The replacement string may contain references to
+ * capture groups.
+ *
+ * @param replacement a string containing the replacement text.
+ * @param status a reference to a UErrorCode to receive any errors.
+ * @return a string containing the results of the find and replace.
+ * @stable ICU 2.4
+ */
+ virtual UnicodeString replaceAll(const UnicodeString &replacement, UErrorCode &status);
+
+
+ /**
+ * Replaces the first substring of the input that matches
+ * the pattern with the replacement string. This is a convenience
+ * function that provides a complete find-and-replace operation.
+ *
+ * <p>This function first resets this RegexMatcher. It then scans the input string
+ * looking for a match of the pattern. Input that is not part
+ * of the match is appended directly to the result string; the match is replaced
+ * in the result by the replacement string. The replacement string may contain
+ * references to captured groups.</p>
+ *
+ * <p>The state of the matcher (the position at which a subsequent find()
+ * would begin) after completing a replaceFirst() is not specified. The
+ * RegexMatcher should be reset before doing additional find() operations.</p>
+ *
+ * @param replacement a string containing the replacement text.
+ * @param status a reference to a UErrorCode to receive any errors.
+ * @return a string containing the results of the find and replace.
+ * @stable ICU 2.4
+ */
+ virtual UnicodeString replaceFirst(const UnicodeString &replacement, UErrorCode &status);
+
+ /**
+ * Implements a replace operation intended to be used as part of an
+ * incremental find-and-replace.
+ *
+ * <p>The input string, starting from the end of the previous replacement and ending at
+ * the start of the current match, is appended to the destination string. Then the
+ * replacement string is appended to the output string,
+ * including handling any substitutions of captured text.</p>
+ *
+ * <p>For simple, prepackaged, non-incremental find-and-replace
+ * operations, see replaceFirst() or replaceAll().</p>
+ *
+ * @param dest A UnicodeString to which the results of the find-and-replace are appended.
+ * @param replacement A UnicodeString that provides the text to be substituted for
+ * the input text that matched the regexp pattern. The replacement
+ * text may contain references to captured text from the
+ * input.
+ * @param status A reference to a UErrorCode to receive any errors. Possible
+ * errors are U_REGEX_INVALID_STATE if no match has been
+ * attempted or the last match failed, and U_INDEX_OUTOFBOUNDS_ERROR
+ * if the replacement text specifies a capture group that
+ * does not exist in the pattern.
+ *
+ * @return this RegexMatcher
+ * @stable ICU 2.4
+ *
+ */
+ virtual RegexMatcher &appendReplacement(UnicodeString &dest,
+ const UnicodeString &replacement, UErrorCode &status);
+
+
+ /**
+ * As the final step in a find-and-replace operation, append the remainder
+ * of the input string, starting at the position following the last appendReplacement(),
+ * to the destination string. <code>appendTail()</code> is intended to be invoked after one
+ * or more invocations of the <code>RegexMatcher::appendReplacement()</code>.
+ *
+ * @param dest A UnicodeString to which the results of the find-and-replace are appended.
+ * @return the destination string.
+ * @stable ICU 2.4
+ */
+ virtual UnicodeString &appendTail(UnicodeString &dest);
+
+
+
+ /**
+ * Split a string into fields. Somewhat like split() from Perl.
+ * The pattern matches identify delimiters that separate the input
+ * into fields. The input data between the matches becomes the
+ * fields themselves.
+ * <p>
+ *
+ * @param input The string to be split into fields. The field delimiters
+ * match the pattern (in the "this" object). This matcher
+ * will be reset to this input string.
+ * @param dest An array of UnicodeStrings to receive the results of the split.
+ * This is an array of actual UnicodeString objects, not an
+ * array of pointers to strings. Local (stack based) arrays can
+ * work well here.
+ * @param destCapacity The number of elements in the destination array.
+ * If the number of fields found is less than destCapacity, the
+ * extra strings in the destination array are not altered.
+ * If the number of destination strings is less than the number
+ * of fields, the trailing part of the input string, including any
+ * field delimiters, is placed in the last destination string.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The number of fields into which the input string was split.
+ * @stable ICU 2.6
+ */
+ virtual int32_t split(const UnicodeString &input,
+ UnicodeString dest[],
+ int32_t destCapacity,
+ UErrorCode &status);
+
+
+
+ /**
+ * setTrace Debug function, enable/disable tracing of the matching engine.
+ * For internal ICU development use only. DO NO USE!!!!
+ * @internal
+ */
+ void setTrace(UBool state);
+
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+private:
+ // Constructors and other object boilerplate are private.
+ // Instances of RegexMatcher can not be assigned, copied, cloned, etc.
+ RegexMatcher(); // default constructor not implemented
+ RegexMatcher(const RegexPattern *pat);
+ RegexMatcher(const RegexMatcher &other);
+ RegexMatcher &operator =(const RegexMatcher &rhs);
+ friend class RegexPattern;
+ friend class RegexCImpl;
+
+ //
+ // MatchAt This is the internal interface to the match engine itself.
+ // Match status comes back in matcher member variables.
+ //
+ void MatchAt(int32_t startIdx, UErrorCode &status);
+ inline void backTrack(int32_t &inputIdx, int32_t &patIdx);
+ UBool isWordBoundary(int32_t pos); // perform Perl-like \b test
+ UBool isUWordBoundary(int32_t pos); // perform RBBI based \b test
+ REStackFrame *resetStack();
+ inline REStackFrame *StateSave(REStackFrame *fp, int32_t savePatIdx,
+ int32_t frameSize, UErrorCode &status);
+
+
+ const RegexPattern *fPattern;
+ RegexPattern *fPatternOwned; // Non-NULL if this matcher owns the pattern, and
+ // should delete it when through.
+ const UnicodeString *fInput;
+
+ UBool fMatch; // True if the last match was successful.
+ int32_t fMatchStart; // Position of the start of the most recent match
+ int32_t fMatchEnd; // First position after the end of the most recent match
+ int32_t fLastMatchEnd; // First position after the end of the previous match,
+ // or -1 if there was no previous match.
+ int32_t fLastReplaceEnd; // First position after the end of the previous appendReplacement();
+
+ UVector32 *fStack;
+ REStackFrame *fFrame; // After finding a match, the last active stack
+ // frame, which will contain the capture group results.
+ // NOT valid while match engine is running.
+
+ int32_t *fData; // Data area for use by the compiled pattern.
+ int32_t fSmallData[8]; // Use this for data if it's enough.
+
+ UBool fTraceDebug; // Set true for debug tracing of match engine.
+
+ UErrorCode fDeferredStatus; // Save error state if that cannot be immediately
+ // reported, or that permanently disables this matcher.
+
+ RuleBasedBreakIterator *fWordBreakItr;
+
+
+};
+
+U_NAMESPACE_END
+#endif // UCONFIG_NO_REGULAR_EXPRESSIONS
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/search.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/search.h
new file mode 100644
index 00000000000..a2fb2a8c7a0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/search.h
@@ -0,0 +1,569 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2005 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 03/22/2000 helena Creation.
+**********************************************************************
+*/
+
+#ifndef SEARCH_H
+#define SEARCH_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: SearchIterator object.
+ */
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/chariter.h"
+#include "unicode/brkiter.h"
+#include "unicode/usearch.h"
+
+/**
+* @stable ICU 2.0
+*/
+struct USearch;
+/**
+* @stable ICU 2.0
+*/
+typedef struct USearch USearch;
+
+U_NAMESPACE_BEGIN
+
+/**
+ *
+ * <tt>SearchIterator</tt> is an abstract base class that provides
+ * methods to search for a pattern within a text string. Instances of
+ * <tt>SearchIterator</tt> maintain a current position and scans over the
+ * target text, returning the indices the pattern is matched and the length
+ * of each match.
+ * <p>
+ * <tt>SearchIterator</tt> defines a protocol for text searching.
+ * Subclasses provide concrete implementations of various search algorithms.
+ * For example, <tt>StringSearch</tt> implements language-sensitive pattern
+ * matching based on the comparison rules defined in a
+ * <tt>RuleBasedCollator</tt> object.
+ * <p>
+ * Other options for searching includes using a BreakIterator to restrict
+ * the points at which matches are detected.
+ * <p>
+ * <tt>SearchIterator</tt> provides an API that is similar to that of
+ * other text iteration classes such as <tt>BreakIterator</tt>. Using
+ * this class, it is easy to scan through text looking for all occurances of
+ * a given pattern. The following example uses a <tt>StringSearch</tt>
+ * object to find all instances of "fox" in the target string. Any other
+ * subclass of <tt>SearchIterator</tt> can be used in an identical
+ * manner.
+ * <pre><code>
+ * UnicodeString target("The quick brown fox jumped over the lazy fox");
+ * UnicodeString pattern("fox");
+ *
+ * SearchIterator *iter = new StringSearch(pattern, target);
+ * UErrorCode error = U_ZERO_ERROR;
+ * for (int pos = iter->first(error); pos != USEARCH_DONE;
+ * pos = iter->next(error)) {
+ * printf("Found match at %d pos, length is %d\n", pos,
+ * iter.getMatchLength());
+ * }
+ * </code></pre>
+ *
+ * @see StringSearch
+ * @see RuleBasedCollator
+ */
+class U_I18N_API SearchIterator : public UObject {
+
+public:
+
+ // public constructors and destructors -------------------------------
+
+ /**
+ * Copy constructor that creates a SearchIterator instance with the same
+ * behavior, and iterating over the same text.
+ * @param other the SearchIterator instance to be copied.
+ * @stable ICU 2.0
+ */
+ SearchIterator(const SearchIterator &other);
+
+ /**
+ * Destructor. Cleans up the search iterator data struct.
+ * @stable ICU 2.0
+ */
+ virtual ~SearchIterator();
+
+ // public get and set methods ----------------------------------------
+
+ /**
+ * Sets the index to point to the given position, and clears any state
+ * that's affected.
+ * <p>
+ * This method takes the argument index and sets the position in the text
+ * string accordingly without checking if the index is pointing to a
+ * valid starting point to begin searching.
+ * @param position within the text to be set. If position is less
+ * than or greater than the text range for searching,
+ * an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+ * @param status for errors if it occurs
+ * @stable ICU 2.0
+ */
+ virtual void setOffset(int32_t position, UErrorCode &status) = 0;
+
+ /**
+ * Return the current index in the text being searched.
+ * If the iteration has gone past the end of the text
+ * (or past the beginning for a backwards search), USEARCH_DONE
+ * is returned.
+ * @return current index in the text being searched.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getOffset(void) const = 0;
+
+ /**
+ * Sets the text searching attributes located in the enum
+ * USearchAttribute with values from the enum USearchAttributeValue.
+ * USEARCH_DEFAULT can be used for all attributes for resetting.
+ * @param attribute text attribute (enum USearchAttribute) to be set
+ * @param value text attribute value
+ * @param status for errors if it occurs
+ * @stable ICU 2.0
+ */
+ void setAttribute(USearchAttribute attribute,
+ USearchAttributeValue value,
+ UErrorCode &status);
+
+ /**
+ * Gets the text searching attributes
+ * @param attribute text attribute (enum USearchAttribute) to be retrieve
+ * @return text attribute value
+ * @stable ICU 2.0
+ */
+ USearchAttributeValue getAttribute(USearchAttribute attribute) const;
+
+ /**
+ * Returns the index to the match in the text string that was searched.
+ * This call returns a valid result only after a successful call to
+ * <tt>first</tt>, <tt>next</tt>, <tt>previous</tt>, or <tt>last</tt>.
+ * Just after construction, or after a searching method returns
+ * <tt>USEARCH_DONE</tt>, this method will return <tt>USEARCH_DONE</tt>.
+ * <p>
+ * Use getMatchedLength to get the matched string length.
+ * @return index of a substring within the text string that is being
+ * searched.
+ * @see #first
+ * @see #next
+ * @see #previous
+ * @see #last
+ * @stable ICU 2.0
+ */
+ int32_t getMatchedStart(void) const;
+
+ /**
+ * Returns the length of text in the string which matches the search
+ * pattern. This call returns a valid result only after a successful call
+ * to <tt>first</tt>, <tt>next</tt>, <tt>previous</tt>, or <tt>last</tt>.
+ * Just after construction, or after a searching method returns
+ * <tt>USEARCH_DONE</tt>, this method will return 0.
+ * @return The length of the match in the target text, or 0 if there
+ * is no match currently.
+ * @see #first
+ * @see #next
+ * @see #previous
+ * @see #last
+ * @stable ICU 2.0
+ */
+ int32_t getMatchedLength(void) const;
+
+ /**
+ * Returns the text that was matched by the most recent call to
+ * <tt>first</tt>, <tt>next</tt>, <tt>previous</tt>, or <tt>last</tt>.
+ * If the iterator is not pointing at a valid match (e.g. just after
+ * construction or after <tt>USEARCH_DONE</tt> has been returned,
+ * returns an empty string.
+ * @param result stores the matched string or an empty string if a match
+ * is not found.
+ * @see #first
+ * @see #next
+ * @see #previous
+ * @see #last
+ * @stable ICU 2.0
+ */
+ void getMatchedText(UnicodeString &result) const;
+
+ /**
+ * Set the BreakIterator that will be used to restrict the points
+ * at which matches are detected. The user is responsible for deleting
+ * the breakiterator.
+ * @param breakiter A BreakIterator that will be used to restrict the
+ * points at which matches are detected. If a match is
+ * found, but the match's start or end index is not a
+ * boundary as determined by the <tt>BreakIterator</tt>,
+ * the match will be rejected and another will be searched
+ * for. If this parameter is <tt>NULL</tt>, no break
+ * detection is attempted.
+ * @param status for errors if it occurs
+ * @see BreakIterator
+ * @stable ICU 2.0
+ */
+ void setBreakIterator(BreakIterator *breakiter, UErrorCode &status);
+
+ /**
+ * Returns the BreakIterator that is used to restrict the points at
+ * which matches are detected. This will be the same object that was
+ * passed to the constructor or to <tt>setBreakIterator</tt>.
+ * Note that <tt>NULL</tt> is a legal value; it means that break
+ * detection should not be attempted.
+ * @return BreakIterator used to restrict matchings.
+ * @see #setBreakIterator
+ * @stable ICU 2.0
+ */
+ const BreakIterator * getBreakIterator(void) const;
+
+ /**
+ * Set the string text to be searched. Text iteration will hence begin at
+ * the start of the text string. This method is useful if you want to
+ * re-use an iterator to search for the same pattern within a different
+ * body of text. The user is responsible for deleting the text.
+ * @param text string to be searched.
+ * @param status for errors. If the text length is 0,
+ * an U_ILLEGAL_ARGUMENT_ERROR is returned.
+ * @stable ICU 2.0
+ */
+ virtual void setText(const UnicodeString &text, UErrorCode &status);
+
+ /**
+ * Set the string text to be searched. Text iteration will hence begin at
+ * the start of the text string. This method is useful if you want to
+ * re-use an iterator to search for the same pattern within a different
+ * body of text.
+ * <p>
+ * Note: No parsing of the text within the <tt>CharacterIterator</tt>
+ * will be done during searching for this version. The block of text
+ * in <tt>CharacterIterator</tt> will be used as it is.
+ * The user is responsible for deleting the text.
+ * @param text string iterator to be searched.
+ * @param status for errors if any. If the text length is 0 then an
+ * U_ILLEGAL_ARGUMENT_ERROR is returned.
+ * @stable ICU 2.0
+ */
+ virtual void setText(CharacterIterator &text, UErrorCode &status);
+
+ /**
+ * Return the string text to be searched.
+ * @return text string to be searched.
+ * @stable ICU 2.0
+ */
+ const UnicodeString & getText(void) const;
+
+ // operator overloading ----------------------------------------------
+
+ /**
+ * Equality operator.
+ * @param that SearchIterator instance to be compared.
+ * @return TRUE if both BreakIterators are of the same class, have the
+ * same behavior, terates over the same text and have the same
+ * attributes. FALSE otherwise.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const SearchIterator &that) const;
+
+ /**
+ * Not-equal operator.
+ * @param that SearchIterator instance to be compared.
+ * @return FALSE if operator== returns TRUE, and vice versa.
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const SearchIterator &that) const;
+
+ // public methods ----------------------------------------------------
+
+ /**
+ * Returns a copy of SearchIterator with the same behavior, and
+ * iterating over the same text, as this one. Note that all data will be
+ * replicated, except for the text string to be searched.
+ * @return cloned object
+ * @stable ICU 2.0
+ */
+ virtual SearchIterator* safeClone(void) const = 0;
+
+ /**
+ * Returns the first index at which the string text matches the search
+ * pattern. The iterator is adjusted so that its current index (as
+ * returned by <tt>getOffset</tt>) is the match position if one
+ * was found.
+ * If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+ * the iterator will be adjusted to the index USEARCH_DONE
+ * @param status for errors if it occurs
+ * @return The character index of the first match, or
+ * <tt>USEARCH_DONE</tt> if there are no matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t first(UErrorCode &status);
+
+ /**
+ * Returns the first index greater than <tt>position</tt> at which the
+ * string text matches the search pattern. The iterator is adjusted so
+ * that its current index (as returned by <tt>getOffset</tt>) is the
+ * match position if one was found. If a match is not found,
+ * <tt>USEARCH_DONE</tt> will be returned and the iterator will be
+ * adjusted to the index USEARCH_DONE
+ * @param position where search if to start from. If position is less
+ * than or greater than the text range for searching,
+ * an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+ * @param status for errors if it occurs
+ * @return The character index of the first match following
+ * <tt>position</tt>, or <tt>USEARCH_DONE</tt> if there are no
+ * matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t following(int32_t position, UErrorCode &status);
+
+ /**
+ * Returns the last index in the target text at which it matches the
+ * search pattern. The iterator is adjusted so that its current index
+ * (as returned by <tt>getOffset</tt>) is the match position if one was
+ * found.
+ * If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+ * the iterator will be adjusted to the index USEARCH_DONE.
+ * @param status for errors if it occurs
+ * @return The index of the first match, or <tt>USEARCH_DONE</tt> if
+ * there are no matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t last(UErrorCode &status);
+
+ /**
+ * Returns the first index less than <tt>position</tt> at which the string
+ * text matches the search pattern. The iterator is adjusted so that its
+ * current index (as returned by <tt>getOffset</tt>) is the match
+ * position if one was found. If a match is not found,
+ * <tt>USEARCH_DONE</tt> will be returned and the iterator will be
+ * adjusted to the index USEARCH_DONE
+ * @param position where search is to start from. If position is less
+ * than or greater than the text range for searching,
+ * an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+ * @param status for errors if it occurs
+ * @return The character index of the first match preceding
+ * <tt>position</tt>, or <tt>USEARCH_DONE</tt> if there are
+ * no matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t preceding(int32_t position, UErrorCode &status);
+
+ /**
+ * Returns the index of the next point at which the text matches the
+ * search pattern, starting from the current position
+ * The iterator is adjusted so that its current index (as returned by
+ * <tt>getOffset</tt>) is the match position if one was found.
+ * If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+ * the iterator will be adjusted to a position after the end of the text
+ * string.
+ * @param status for errors if it occurs
+ * @return The index of the next match after the current position,
+ * or <tt>USEARCH_DONE</tt> if there are no more matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t next(UErrorCode &status);
+
+ /**
+ * Returns the index of the previous point at which the string text
+ * matches the search pattern, starting at the current position.
+ * The iterator is adjusted so that its current index (as returned by
+ * <tt>getOffset</tt>) is the match position if one was found.
+ * If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+ * the iterator will be adjusted to the index USEARCH_DONE
+ * @param status for errors if it occurs
+ * @return The index of the previous match before the current position,
+ * or <tt>USEARCH_DONE</tt> if there are no more matches.
+ * @see #getOffset
+ * @stable ICU 2.0
+ */
+ int32_t previous(UErrorCode &status);
+
+ /**
+ * Resets the iteration.
+ * Search will begin at the start of the text string if a forward
+ * iteration is initiated before a backwards iteration. Otherwise if a
+ * backwards iteration is initiated before a forwards iteration, the
+ * search will begin at the end of the text string.
+ * @stable ICU 2.0
+ */
+ virtual void reset();
+
+protected:
+ // protected data members ---------------------------------------------
+
+ /**
+ * C search data struct
+ * @stable ICU 2.0
+ */
+ USearch *m_search_;
+
+ /**
+ * Break iterator.
+ * Currently the C++ breakiterator does not have getRules etc to reproduce
+ * another in C. Hence we keep the original around and do the verification
+ * at the end of the match. The user is responsible for deleting this
+ * break iterator.
+ * @stable ICU 2.0
+ */
+ BreakIterator *m_breakiterator_;
+
+ /**
+ * Unicode string version of the search text
+ * @stable ICU 2.0
+ */
+ UnicodeString m_text_;
+
+ // protected constructors and destructors -----------------------------
+
+ /**
+ * Default constructor.
+ * Initializes data to the default values.
+ * @stable ICU 2.0
+ */
+ SearchIterator();
+
+ /**
+ * Constructor for use by subclasses.
+ * @param text The target text to be searched.
+ * @param breakiter A {@link BreakIterator} that is used to restrict the
+ * points at which matches are detected. If
+ * <tt>handleNext</tt> or <tt>handlePrev</tt> finds a
+ * match, but the match's start or end index is not a
+ * boundary as determined by the <tt>BreakIterator</tt>,
+ * the match is rejected and <tt>handleNext</tt> or
+ * <tt>handlePrev</tt> is called again. If this parameter
+ * is <tt>NULL</tt>, no break detection is attempted.
+ * @see #handleNext
+ * @see #handlePrev
+ * @stable ICU 2.0
+ */
+ SearchIterator(const UnicodeString &text,
+ BreakIterator *breakiter = NULL);
+
+ /**
+ * Constructor for use by subclasses.
+ * <p>
+ * Note: No parsing of the text within the <tt>CharacterIterator</tt>
+ * will be done during searching for this version. The block of text
+ * in <tt>CharacterIterator</tt> will be used as it is.
+ * @param text The target text to be searched.
+ * @param breakiter A {@link BreakIterator} that is used to restrict the
+ * points at which matches are detected. If
+ * <tt>handleNext</tt> or <tt>handlePrev</tt> finds a
+ * match, but the match's start or end index is not a
+ * boundary as determined by the <tt>BreakIterator</tt>,
+ * the match is rejected and <tt>handleNext</tt> or
+ * <tt>handlePrev</tt> is called again. If this parameter
+ * is <tt>NULL</tt>, no break detection is attempted.
+ * @see #handleNext
+ * @see #handlePrev
+ * @stable ICU 2.0
+ */
+ SearchIterator(CharacterIterator &text, BreakIterator *breakiter = NULL);
+
+ // protected methods --------------------------------------------------
+
+ /**
+ * Assignment operator. Sets this iterator to have the same behavior,
+ * and iterate over the same text, as the one passed in.
+ * @param that instance to be copied.
+ * @stable ICU 2.0
+ */
+ SearchIterator & operator=(const SearchIterator &that);
+
+ /**
+ * Abstract method which subclasses override to provide the mechanism
+ * for finding the next match in the target text. This allows different
+ * subclasses to provide different search algorithms.
+ * <p>
+ * If a match is found, the implementation should return the index at
+ * which the match starts and should call
+ * <tt>setMatchLength</tt> with the number of characters
+ * in the target text that make up the match. If no match is found, the
+ * method should return USEARCH_DONE.
+ * <p>
+ * @param position The index in the target text at which the search
+ * should start.
+ * @param status for error codes if it occurs.
+ * @return index at which the match starts, else if match is not found
+ * USEARCH_DONE is returned
+ * @see #setMatchLength
+ * @stable ICU 2.0
+ */
+ virtual int32_t handleNext(int32_t position, UErrorCode &status)
+ = 0;
+
+ /**
+ * Abstract method which subclasses override to provide the mechanism for
+ * finding the previous match in the target text. This allows different
+ * subclasses to provide different search algorithms.
+ * <p>
+ * If a match is found, the implementation should return the index at
+ * which the match starts and should call
+ * <tt>setMatchLength</tt> with the number of characters
+ * in the target text that make up the match. If no match is found, the
+ * method should return USEARCH_DONE.
+ * <p>
+ * @param position The index in the target text at which the search
+ * should start.
+ * @param status for error codes if it occurs.
+ * @return index at which the match starts, else if match is not found
+ * USEARCH_DONE is returned
+ * @see #setMatchLength
+ * @stable ICU 2.0
+ */
+ virtual int32_t handlePrev(int32_t position, UErrorCode &status)
+ = 0;
+
+ /**
+ * Sets the length of the currently matched string in the text string to
+ * be searched.
+ * Subclasses' <tt>handleNext</tt> and <tt>handlePrev</tt>
+ * methods should call this when they find a match in the target text.
+ * @param length length of the matched text.
+ * @see #handleNext
+ * @see #handlePrev
+ * @stable ICU 2.0
+ */
+ virtual void setMatchLength(int32_t length);
+
+ /**
+ * Sets the offset of the currently matched string in the text string to
+ * be searched.
+ * Subclasses' <tt>handleNext</tt> and <tt>handlePrev</tt>
+ * methods should call this when they find a match in the target text.
+ * @param position start offset of the matched text.
+ * @see #handleNext
+ * @see #handlePrev
+ * @stable ICU 2.0
+ */
+ virtual void setMatchStart(int32_t position);
+
+ /**
+ * sets match not found
+ * @stable ICU 2.0
+ */
+ void setMatchNotFound();
+};
+
+inline UBool SearchIterator::operator!=(const SearchIterator &that) const
+{
+ return !operator==(that);
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/simpletz.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/simpletz.h
new file mode 100644
index 00000000000..08fdd208761
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/simpletz.h
@@ -0,0 +1,927 @@
+/*
+ ********************************************************************************
+ * Copyright (C) 1997-2007, International Business Machines *
+ * Corporation and others. All Rights Reserved. *
+ ********************************************************************************
+ *
+ * File SIMPLETZ.H
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 04/21/97 aliu Overhauled header.
+ * 08/10/98 stephen JDK 1.2 sync
+ * Added setStartRule() / setEndRule() overloads
+ * Added hasSameRules()
+ * 09/02/98 stephen Added getOffset(monthLen)
+ * Changed getOffset() to take UErrorCode
+ * 07/09/99 stephen Removed millisPerHour (unused, for HP compiler)
+ * 12/02/99 aliu Added TimeMode and constructor and setStart/EndRule
+ * methods that take TimeMode. Added to docs.
+ ********************************************************************************
+ */
+
+#ifndef SIMPLETZ_H
+#define SIMPLETZ_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: SimpleTimeZone is a concrete subclass of TimeZone.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/basictz.h"
+
+U_NAMESPACE_BEGIN
+
+// forward declaration
+class InitialTimeZoneRule;
+class TimeZoneTransition;
+class AnnualTimeZoneRule;
+
+/**
+ * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
+ * that represents a time zone for use with a Gregorian calendar. This
+ * class does not handle historical changes.
+ * <P>
+ * When specifying daylight-savings-time begin and end dates, use a negative value for
+ * <code>dayOfWeekInMonth</code> to indicate that <code>SimpleTimeZone</code> should
+ * count from the end of the month backwards. For example, in the U.S., Daylight Savings
+ * Time ends at the last (dayOfWeekInMonth = -1) Sunday in October, at 2 AM in standard
+ * time.
+ *
+ * @see Calendar
+ * @see GregorianCalendar
+ * @see TimeZone
+ * @author D. Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
+ */
+class U_I18N_API SimpleTimeZone: public BasicTimeZone {
+public:
+
+ /**
+ * TimeMode is used, together with a millisecond offset after
+ * midnight, to specify a rule transition time. Most rules
+ * transition at a local wall time, that is, according to the
+ * current time in effect, either standard, or DST. However, some
+ * rules transition at local standard time, and some at a specific
+ * UTC time. Although it might seem that all times could be
+ * converted to wall time, thus eliminating the need for this
+ * parameter, this is not the case.
+ * @stable ICU 2.0
+ */
+ enum TimeMode {
+ WALL_TIME = 0,
+ STANDARD_TIME,
+ UTC_TIME
+ };
+
+ /**
+ * Copy constructor
+ * @param source the object to be copied.
+ * @stable ICU 2.0
+ */
+ SimpleTimeZone(const SimpleTimeZone& source);
+
+ /**
+ * Default assignment operator
+ * @param right the object to be copied.
+ * @stable ICU 2.0
+ */
+ SimpleTimeZone& operator=(const SimpleTimeZone& right);
+
+ /**
+ * Destructor
+ * @stable ICU 2.0
+ */
+ virtual ~SimpleTimeZone();
+
+ /**
+ * Returns true if the two TimeZone objects are equal; that is, they have
+ * the same ID, raw GMT offset, and DST rules.
+ *
+ * @param that The SimpleTimeZone object to be compared with.
+ * @return True if the given time zone is equal to this time zone; false
+ * otherwise.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const TimeZone& that) const;
+
+ /**
+ * Constructs a SimpleTimeZone with the given raw GMT offset and time zone ID,
+ * and which doesn't observe daylight savings time. Normally you should use
+ * TimeZone::createInstance() to create a TimeZone instead of creating a
+ * SimpleTimeZone directly with this constructor.
+ *
+ * @param rawOffsetGMT The given base time zone offset to GMT.
+ * @param ID The timezone ID which is obtained from
+ * TimeZone.getAvailableIDs.
+ * @stable ICU 2.0
+ */
+ SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID);
+
+ /**
+ * Construct a SimpleTimeZone with the given raw GMT offset, time zone ID,
+ * and times to start and end daylight savings time. To create a TimeZone that
+ * doesn't observe daylight savings time, don't use this constructor; use
+ * SimpleTimeZone(rawOffset, ID) instead. Normally, you should use
+ * TimeZone.createInstance() to create a TimeZone instead of creating a
+ * SimpleTimeZone directly with this constructor.
+ * <P>
+ * Various types of daylight-savings time rules can be specfied by using different
+ * values for startDay and startDayOfWeek and endDay and endDayOfWeek. For a
+ * complete explanation of how these parameters work, see the documentation for
+ * setStartRule().
+ *
+ * @param rawOffsetGMT The new SimpleTimeZone's raw GMT offset
+ * @param ID The new SimpleTimeZone's time zone ID.
+ * @param savingsStartMonth The daylight savings starting month. Month is
+ * 0-based. eg, 0 for January.
+ * @param savingsStartDayOfWeekInMonth The daylight savings starting
+ * day-of-week-in-month. See setStartRule() for a
+ * complete explanation.
+ * @param savingsStartDayOfWeek The daylight savings starting day-of-week.
+ * See setStartRule() for a complete explanation.
+ * @param savingsStartTime The daylight savings starting time, expressed as the
+ * number of milliseconds after midnight.
+ * @param savingsEndMonth The daylight savings ending month. Month is
+ * 0-based. eg, 0 for January.
+ * @param savingsEndDayOfWeekInMonth The daylight savings ending day-of-week-in-month.
+ * See setStartRule() for a complete explanation.
+ * @param savingsEndDayOfWeek The daylight savings ending day-of-week.
+ * See setStartRule() for a complete explanation.
+ * @param savingsEndTime The daylight savings ending time, expressed as the
+ * number of milliseconds after midnight.
+ * @param status An UErrorCode to receive the status.
+ * @stable ICU 2.0
+ */
+ SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
+ int8_t savingsStartMonth, int8_t savingsStartDayOfWeekInMonth,
+ int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
+ int8_t savingsEndMonth, int8_t savingsEndDayOfWeekInMonth,
+ int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
+ UErrorCode& status);
+ /**
+ * Construct a SimpleTimeZone with the given raw GMT offset, time zone ID,
+ * and times to start and end daylight savings time. To create a TimeZone that
+ * doesn't observe daylight savings time, don't use this constructor; use
+ * SimpleTimeZone(rawOffset, ID) instead. Normally, you should use
+ * TimeZone.createInstance() to create a TimeZone instead of creating a
+ * SimpleTimeZone directly with this constructor.
+ * <P>
+ * Various types of daylight-savings time rules can be specfied by using different
+ * values for startDay and startDayOfWeek and endDay and endDayOfWeek. For a
+ * complete explanation of how these parameters work, see the documentation for
+ * setStartRule().
+ *
+ * @param rawOffsetGMT The new SimpleTimeZone's raw GMT offset
+ * @param ID The new SimpleTimeZone's time zone ID.
+ * @param savingsStartMonth The daylight savings starting month. Month is
+ * 0-based. eg, 0 for January.
+ * @param savingsStartDayOfWeekInMonth The daylight savings starting
+ * day-of-week-in-month. See setStartRule() for a
+ * complete explanation.
+ * @param savingsStartDayOfWeek The daylight savings starting day-of-week.
+ * See setStartRule() for a complete explanation.
+ * @param savingsStartTime The daylight savings starting time, expressed as the
+ * number of milliseconds after midnight.
+ * @param savingsEndMonth The daylight savings ending month. Month is
+ * 0-based. eg, 0 for January.
+ * @param savingsEndDayOfWeekInMonth The daylight savings ending day-of-week-in-month.
+ * See setStartRule() for a complete explanation.
+ * @param savingsEndDayOfWeek The daylight savings ending day-of-week.
+ * See setStartRule() for a complete explanation.
+ * @param savingsEndTime The daylight savings ending time, expressed as the
+ * number of milliseconds after midnight.
+ * @param savingsDST The number of milliseconds added to standard time
+ * to get DST time. Default is one hour.
+ * @param status An UErrorCode to receive the status.
+ * @stable ICU 2.0
+ */
+ SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
+ int8_t savingsStartMonth, int8_t savingsStartDayOfWeekInMonth,
+ int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
+ int8_t savingsEndMonth, int8_t savingsEndDayOfWeekInMonth,
+ int8_t savingsEndDayOfWeek, int32_t savingsEndTime,
+ int32_t savingsDST, UErrorCode& status);
+
+ /**
+ * Construct a SimpleTimeZone with the given raw GMT offset, time zone ID,
+ * and times to start and end daylight savings time. To create a TimeZone that
+ * doesn't observe daylight savings time, don't use this constructor; use
+ * SimpleTimeZone(rawOffset, ID) instead. Normally, you should use
+ * TimeZone.createInstance() to create a TimeZone instead of creating a
+ * SimpleTimeZone directly with this constructor.
+ * <P>
+ * Various types of daylight-savings time rules can be specfied by using different
+ * values for startDay and startDayOfWeek and endDay and endDayOfWeek. For a
+ * complete explanation of how these parameters work, see the documentation for
+ * setStartRule().
+ *
+ * @param rawOffsetGMT The new SimpleTimeZone's raw GMT offset
+ * @param ID The new SimpleTimeZone's time zone ID.
+ * @param savingsStartMonth The daylight savings starting month. Month is
+ * 0-based. eg, 0 for January.
+ * @param savingsStartDayOfWeekInMonth The daylight savings starting
+ * day-of-week-in-month. See setStartRule() for a
+ * complete explanation.
+ * @param savingsStartDayOfWeek The daylight savings starting day-of-week.
+ * See setStartRule() for a complete explanation.
+ * @param savingsStartTime The daylight savings starting time, expressed as the
+ * number of milliseconds after midnight.
+ * @param savingsStartTimeMode Whether the start time is local wall time, local
+ * standard time, or UTC time. Default is local wall time.
+ * @param savingsEndMonth The daylight savings ending month. Month is
+ * 0-based. eg, 0 for January.
+ * @param savingsEndDayOfWeekInMonth The daylight savings ending day-of-week-in-month.
+ * See setStartRule() for a complete explanation.
+ * @param savingsEndDayOfWeek The daylight savings ending day-of-week.
+ * See setStartRule() for a complete explanation.
+ * @param savingsEndTime The daylight savings ending time, expressed as the
+ * number of milliseconds after midnight.
+ * @param savingsEndTimeMode Whether the end time is local wall time, local
+ * standard time, or UTC time. Default is local wall time.
+ * @param savingsDST The number of milliseconds added to standard time
+ * to get DST time. Default is one hour.
+ * @param status An UErrorCode to receive the status.
+ * @stable ICU 2.0
+ */
+ SimpleTimeZone(int32_t rawOffsetGMT, const UnicodeString& ID,
+ int8_t savingsStartMonth, int8_t savingsStartDayOfWeekInMonth,
+ int8_t savingsStartDayOfWeek, int32_t savingsStartTime,
+ TimeMode savingsStartTimeMode,
+ int8_t savingsEndMonth, int8_t savingsEndDayOfWeekInMonth,
+ int8_t savingsEndDayOfWeek, int32_t savingsEndTime, TimeMode savingsEndTimeMode,
+ int32_t savingsDST, UErrorCode& status);
+
+ /**
+ * Sets the daylight savings starting year, that is, the year this time zone began
+ * observing its specified daylight savings time rules. The time zone is considered
+ * not to observe daylight savings time prior to that year; SimpleTimeZone doesn't
+ * support historical daylight-savings-time rules.
+ * @param year the daylight savings starting year.
+ * @stable ICU 2.0
+ */
+ void setStartYear(int32_t year);
+
+ /**
+ * Sets the daylight savings starting rule. For example, in the U.S., Daylight Savings
+ * Time starts at the first Sunday in April, at 2 AM in standard time.
+ * Therefore, you can set the start rule by calling:
+ * setStartRule(TimeFields.APRIL, 1, TimeFields.SUNDAY, 2*60*60*1000);
+ * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calculate
+ * the exact starting date. Their exact meaning depend on their respective signs,
+ * allowing various types of rules to be constructed, as follows:
+ * <ul>
+ * <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the
+ * day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday
+ * of the month).</li>
+ * <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify
+ * the day of week in the month counting backward from the end of the month.
+ * (e.g., (-1, MONDAY) is the last Monday in the month)</li>
+ * <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth
+ * specifies the day of the month, regardless of what day of the week it is.
+ * (e.g., (10, 0) is the tenth day of the month)</li>
+ * <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth
+ * specifies the day of the month counting backward from the end of the
+ * month, regardless of what day of the week it is (e.g., (-2, 0) is the
+ * next-to-last day of the month).</li>
+ * <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the
+ * first specified day of the week on or after the specfied day of the month.
+ * (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month
+ * [or the 15th itself if the 15th is a Sunday].)</li>
+ * <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the
+ * last specified day of the week on or before the specified day of the month.
+ * (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month
+ * [or the 20th itself if the 20th is a Tuesday].)</li>
+ * </ul>
+ * @param month the daylight savings starting month. Month is 0-based.
+ * eg, 0 for January.
+ * @param dayOfWeekInMonth the daylight savings starting
+ * day-of-week-in-month. Please see the member description for an example.
+ * @param dayOfWeek the daylight savings starting day-of-week. Please see
+ * the member description for an example.
+ * @param time the daylight savings starting time. Please see the member
+ * description for an example.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setStartRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
+ int32_t time, UErrorCode& status);
+ /**
+ * Sets the daylight savings starting rule. For example, in the U.S., Daylight Savings
+ * Time starts at the first Sunday in April, at 2 AM in standard time.
+ * Therefore, you can set the start rule by calling:
+ * setStartRule(TimeFields.APRIL, 1, TimeFields.SUNDAY, 2*60*60*1000);
+ * The dayOfWeekInMonth and dayOfWeek parameters together specify how to calculate
+ * the exact starting date. Their exact meaning depend on their respective signs,
+ * allowing various types of rules to be constructed, as follows:
+ * <ul>
+ * <li>If both dayOfWeekInMonth and dayOfWeek are positive, they specify the
+ * day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday
+ * of the month).</li>
+ * <li>If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify
+ * the day of week in the month counting backward from the end of the month.
+ * (e.g., (-1, MONDAY) is the last Monday in the month)</li>
+ * <li>If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth
+ * specifies the day of the month, regardless of what day of the week it is.
+ * (e.g., (10, 0) is the tenth day of the month)</li>
+ * <li>If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth
+ * specifies the day of the month counting backward from the end of the
+ * month, regardless of what day of the week it is (e.g., (-2, 0) is the
+ * next-to-last day of the month).</li>
+ * <li>If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the
+ * first specified day of the week on or after the specfied day of the month.
+ * (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month
+ * [or the 15th itself if the 15th is a Sunday].)</li>
+ * <li>If dayOfWeek and DayOfWeekInMonth are both negative, they specify the
+ * last specified day of the week on or before the specified day of the month.
+ * (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month
+ * [or the 20th itself if the 20th is a Tuesday].)</li>
+ * </ul>
+ * @param month the daylight savings starting month. Month is 0-based.
+ * eg, 0 for January.
+ * @param dayOfWeekInMonth the daylight savings starting
+ * day-of-week-in-month. Please see the member description for an example.
+ * @param dayOfWeek the daylight savings starting day-of-week. Please see
+ * the member description for an example.
+ * @param time the daylight savings starting time. Please see the member
+ * description for an example.
+ * @param mode whether the time is local wall time, local standard time,
+ * or UTC time. Default is local wall time.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setStartRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
+ int32_t time, TimeMode mode, UErrorCode& status);
+
+ /**
+ * Sets the DST start rule to a fixed date within a month.
+ *
+ * @param month The month in which this rule occurs (0-based).
+ * @param dayOfMonth The date in that month (1-based).
+ * @param time The time of that day (number of millis after midnight)
+ * when DST takes effect in local wall time, which is
+ * standard time in this case.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setStartRule(int32_t month, int32_t dayOfMonth, int32_t time,
+ UErrorCode& status);
+ /**
+ * Sets the DST start rule to a fixed date within a month.
+ *
+ * @param month The month in which this rule occurs (0-based).
+ * @param dayOfMonth The date in that month (1-based).
+ * @param time The time of that day (number of millis after midnight)
+ * when DST takes effect in local wall time, which is
+ * standard time in this case.
+ * @param mode whether the time is local wall time, local standard time,
+ * or UTC time. Default is local wall time.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setStartRule(int32_t month, int32_t dayOfMonth, int32_t time,
+ TimeMode mode, UErrorCode& status);
+
+ /**
+ * Sets the DST start rule to a weekday before or after a give date within
+ * a month, e.g., the first Monday on or after the 8th.
+ *
+ * @param month The month in which this rule occurs (0-based).
+ * @param dayOfMonth A date within that month (1-based).
+ * @param dayOfWeek The day of the week on which this rule occurs.
+ * @param time The time of that day (number of millis after midnight)
+ * when DST takes effect in local wall time, which is
+ * standard time in this case.
+ * @param after If true, this rule selects the first dayOfWeek on
+ * or after dayOfMonth. If false, this rule selects
+ * the last dayOfWeek on or before dayOfMonth.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setStartRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ int32_t time, UBool after, UErrorCode& status);
+ /**
+ * Sets the DST start rule to a weekday before or after a give date within
+ * a month, e.g., the first Monday on or after the 8th.
+ *
+ * @param month The month in which this rule occurs (0-based).
+ * @param dayOfMonth A date within that month (1-based).
+ * @param dayOfWeek The day of the week on which this rule occurs.
+ * @param time The time of that day (number of millis after midnight)
+ * when DST takes effect in local wall time, which is
+ * standard time in this case.
+ * @param mode whether the time is local wall time, local standard time,
+ * or UTC time. Default is local wall time.
+ * @param after If true, this rule selects the first dayOfWeek on
+ * or after dayOfMonth. If false, this rule selects
+ * the last dayOfWeek on or before dayOfMonth.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setStartRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ int32_t time, TimeMode mode, UBool after, UErrorCode& status);
+
+ /**
+ * Sets the daylight savings ending rule. For example, in the U.S., Daylight
+ * Savings Time ends at the last (-1) Sunday in October, at 2 AM in standard time.
+ * Therefore, you can set the end rule by calling:
+ * <pre>
+ * . setEndRule(TimeFields.OCTOBER, -1, TimeFields.SUNDAY, 2*60*60*1000);
+ * </pre>
+ * Various other types of rules can be specified by manipulating the dayOfWeek
+ * and dayOfWeekInMonth parameters. For complete details, see the documentation
+ * for setStartRule().
+ *
+ * @param month the daylight savings ending month. Month is 0-based.
+ * eg, 0 for January.
+ * @param dayOfWeekInMonth the daylight savings ending
+ * day-of-week-in-month. See setStartRule() for a complete explanation.
+ * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule()
+ * for a complete explanation.
+ * @param time the daylight savings ending time. Please see the member
+ * description for an example.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setEndRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
+ int32_t time, UErrorCode& status);
+
+ /**
+ * Sets the daylight savings ending rule. For example, in the U.S., Daylight
+ * Savings Time ends at the last (-1) Sunday in October, at 2 AM in standard time.
+ * Therefore, you can set the end rule by calling:
+ * <pre>
+ * . setEndRule(TimeFields.OCTOBER, -1, TimeFields.SUNDAY, 2*60*60*1000);
+ * </pre>
+ * Various other types of rules can be specified by manipulating the dayOfWeek
+ * and dayOfWeekInMonth parameters. For complete details, see the documentation
+ * for setStartRule().
+ *
+ * @param month the daylight savings ending month. Month is 0-based.
+ * eg, 0 for January.
+ * @param dayOfWeekInMonth the daylight savings ending
+ * day-of-week-in-month. See setStartRule() for a complete explanation.
+ * @param dayOfWeek the daylight savings ending day-of-week. See setStartRule()
+ * for a complete explanation.
+ * @param time the daylight savings ending time. Please see the member
+ * description for an example.
+ * @param mode whether the time is local wall time, local standard time,
+ * or UTC time. Default is local wall time.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setEndRule(int32_t month, int32_t dayOfWeekInMonth, int32_t dayOfWeek,
+ int32_t time, TimeMode mode, UErrorCode& status);
+
+ /**
+ * Sets the DST end rule to a fixed date within a month.
+ *
+ * @param month The month in which this rule occurs (0-based).
+ * @param dayOfMonth The date in that month (1-based).
+ * @param time The time of that day (number of millis after midnight)
+ * when DST ends in local wall time, which is daylight
+ * time in this case.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setEndRule(int32_t month, int32_t dayOfMonth, int32_t time, UErrorCode& status);
+
+ /**
+ * Sets the DST end rule to a fixed date within a month.
+ *
+ * @param month The month in which this rule occurs (0-based).
+ * @param dayOfMonth The date in that month (1-based).
+ * @param time The time of that day (number of millis after midnight)
+ * when DST ends in local wall time, which is daylight
+ * time in this case.
+ * @param mode whether the time is local wall time, local standard time,
+ * or UTC time. Default is local wall time.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setEndRule(int32_t month, int32_t dayOfMonth, int32_t time,
+ TimeMode mode, UErrorCode& status);
+
+ /**
+ * Sets the DST end rule to a weekday before or after a give date within
+ * a month, e.g., the first Monday on or after the 8th.
+ *
+ * @param month The month in which this rule occurs (0-based).
+ * @param dayOfMonth A date within that month (1-based).
+ * @param dayOfWeek The day of the week on which this rule occurs.
+ * @param time The time of that day (number of millis after midnight)
+ * when DST ends in local wall time, which is daylight
+ * time in this case.
+ * @param after If true, this rule selects the first dayOfWeek on
+ * or after dayOfMonth. If false, this rule selects
+ * the last dayOfWeek on or before dayOfMonth.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setEndRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ int32_t time, UBool after, UErrorCode& status);
+
+ /**
+ * Sets the DST end rule to a weekday before or after a give date within
+ * a month, e.g., the first Monday on or after the 8th.
+ *
+ * @param month The month in which this rule occurs (0-based).
+ * @param dayOfMonth A date within that month (1-based).
+ * @param dayOfWeek The day of the week on which this rule occurs.
+ * @param time The time of that day (number of millis after midnight)
+ * when DST ends in local wall time, which is daylight
+ * time in this case.
+ * @param mode whether the time is local wall time, local standard time,
+ * or UTC time. Default is local wall time.
+ * @param after If true, this rule selects the first dayOfWeek on
+ * or after dayOfMonth. If false, this rule selects
+ * the last dayOfWeek on or before dayOfMonth.
+ * @param status An UErrorCode
+ * @stable ICU 2.0
+ */
+ void setEndRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ int32_t time, TimeMode mode, UBool after, UErrorCode& status);
+
+ /**
+ * Returns the TimeZone's adjusted GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time in this time zone, taking daylight savings time into
+ * account) as of a particular reference date. The reference date is used to determine
+ * whether daylight savings time is in effect and needs to be figured into the offset
+ * that is returned (in other words, what is the adjusted GMT offset in this time zone
+ * at this particular date and time?). For the time zones produced by createTimeZone(),
+ * the reference data is specified according to the Gregorian calendar, and the date
+ * and time fields are in GMT, NOT local time.
+ *
+ * @param era The reference date's era
+ * @param year The reference date's year
+ * @param month The reference date's month (0-based; 0 is January)
+ * @param day The reference date's day-in-month (1-based)
+ * @param dayOfWeek The reference date's day-of-week (1-based; 1 is Sunday)
+ * @param millis The reference date's milliseconds in day, UTT (NOT local time).
+ * @param status An UErrorCode to receive the status.
+ * @return The offset in milliseconds to add to GMT to get local time.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const;
+
+ /**
+ * Gets the time zone offset, for current date, modified in case of
+ * daylight savings. This is the offset to add *to* UTC to get local time.
+ * @param era the era of the given date.
+ * @param year the year in the given date.
+ * @param month the month in the given date.
+ * Month is 0-based. e.g., 0 for January.
+ * @param day the day-in-month of the given date.
+ * @param dayOfWeek the day-of-week of the given date.
+ * @param milliseconds the millis in day in <em>standard</em> local time.
+ * @param monthLength the length of the given month in days.
+ * @param status An UErrorCode to receive the status.
+ * @return the offset to add *to* GMT to get local time.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t milliseconds,
+ int32_t monthLength, UErrorCode& status) const;
+ /**
+ * Gets the time zone offset, for current date, modified in case of
+ * daylight savings. This is the offset to add *to* UTC to get local time.
+ * @param era the era of the given date.
+ * @param year the year in the given date.
+ * @param month the month in the given date.
+ * Month is 0-based. e.g., 0 for January.
+ * @param day the day-in-month of the given date.
+ * @param dayOfWeek the day-of-week of the given date.
+ * @param milliseconds the millis in day in <em>standard</em> local time.
+ * @param monthLength the length of the given month in days.
+ * @param prevMonthLength length of the previous month in days.
+ * @param status An UErrorCode to receive the status.
+ * @return the offset to add *to* GMT to get local time.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t milliseconds,
+ int32_t monthLength, int32_t prevMonthLength,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared TimeZone method. This implementation simply calls
+ * the base class method, which otherwise would be hidden.
+ * @stable ICU 2.8
+ */
+ virtual void getOffset(UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& ec) const;
+
+ /**
+ * Get time zone offsets from local wall time.
+ * @internal
+ */
+ virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/;
+
+ /**
+ * Returns the TimeZone's raw GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time, before taking daylight savings time into account).
+ *
+ * @return The TimeZone's raw GMT offset.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getRawOffset(void) const;
+
+ /**
+ * Sets the TimeZone's raw GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time, before taking daylight savings time into account).
+ *
+ * @param offsetMillis The new raw GMT offset for this time zone.
+ * @stable ICU 2.0
+ */
+ virtual void setRawOffset(int32_t offsetMillis);
+
+ /**
+ * Sets the amount of time in ms that the clock is advanced during DST.
+ * @param millisSavedDuringDST the number of milliseconds the time is
+ * advanced with respect to standard time when the daylight savings rules
+ * are in effect. A positive number, typically one hour (3600000).
+ * @param status An UErrorCode to receive the status.
+ * @stable ICU 2.0
+ */
+ void setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status);
+
+ /**
+ * Returns the amount of time in ms that the clock is advanced during DST.
+ * @return the number of milliseconds the time is
+ * advanced with respect to standard time when the daylight savings rules
+ * are in effect. A positive number, typically one hour (3600000).
+ * @stable ICU 2.0
+ */
+ virtual int32_t getDSTSavings(void) const;
+
+ /**
+ * Queries if this TimeZone uses Daylight Savings Time.
+ *
+ * @return True if this TimeZone uses Daylight Savings Time; false otherwise.
+ * @stable ICU 2.0
+ */
+ virtual UBool useDaylightTime(void) const;
+
+ /**
+ * Returns true if the given date is within the period when daylight savings time
+ * is in effect; false otherwise. If the TimeZone doesn't observe daylight savings
+ * time, this functions always returns false.
+ * This method is wasteful since it creates a new GregorianCalendar and
+ * deletes it each time it is called. This is a deprecated method
+ * and provided only for Java compatibility.
+ *
+ * @param date The date to test.
+ * @param status An UErrorCode to receive the status.
+ * @return true if the given date is in Daylight Savings Time;
+ * false otherwise.
+ * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
+ */
+ virtual UBool inDaylightTime(UDate date, UErrorCode& status) const;
+
+ /**
+ * Return true if this zone has the same rules and offset as another zone.
+ * @param other the TimeZone object to be compared with
+ * @return true if the given zone has the same rules and offset as this one
+ * @stable ICU 2.0
+ */
+ UBool hasSameRules(const TimeZone& other) const;
+
+ /**
+ * Clones TimeZone objects polymorphically. Clients are responsible for deleting
+ * the TimeZone object cloned.
+ *
+ * @return A new copy of this TimeZone object.
+ * @stable ICU 2.0
+ */
+ virtual TimeZone* clone(void) const;
+
+ /**
+ * Gets the first time zone transition after the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the first transition after the base time.
+ * @return TRUE if the transition is found.
+ * @draft ICU 3.8
+ */
+ virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * Gets the most recent time zone transition before the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the most recent transition before the base time.
+ * @return TRUE if the transition is found.
+ * @draft ICU 3.8
+ */
+ virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * Returns the number of <code>TimeZoneRule</code>s which represents time transitions,
+ * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except
+ * <code>InitialTimeZoneRule</code>. The return value range is 0 or any positive value.
+ * @param status Receives error status code.
+ * @return The number of <code>TimeZoneRule</code>s representing time transitions.
+ * @draft ICU 3.8
+ */
+ virtual int32_t countTransitionRules(UErrorCode& status) /*const*/;
+
+ /**
+ * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code>
+ * which represent time transitions for this time zone. On successful return,
+ * the argument initial points to non-NULL <code>InitialTimeZoneRule</code> and
+ * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code>
+ * instances up to the size specified by trscount. The results are referencing the
+ * rule instance held by this time zone instance. Therefore, after this time zone
+ * is destructed, they are no longer available.
+ * @param initial Receives the initial timezone rule
+ * @param trsrules Receives the timezone transition rules
+ * @param trscount On input, specify the size of the array 'transitions' receiving
+ * the timezone transition rules. On output, actual number of
+ * rules filled in the array will be set.
+ * @param status Receives error status code.
+ * @draft ICU 3.8
+ */
+ virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/;
+
+
+public:
+
+ /**
+ * Override TimeZone Returns a unique class ID POLYMORPHICALLY. Pure virtual
+ * override. This method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
+ * this method.
+ *
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to a return
+ * value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . Derived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+private:
+ /**
+ * Constants specifying values of startMode and endMode.
+ */
+ enum EMode
+ {
+ DOM_MODE = 1,
+ DOW_IN_MONTH_MODE,
+ DOW_GE_DOM_MODE,
+ DOW_LE_DOM_MODE
+ };
+
+ SimpleTimeZone(); // default constructor not implemented
+
+ /**
+ * Internal construction method.
+ * @param rawOffsetGMT The new SimpleTimeZone's raw GMT offset
+ * @param startMonth the month DST starts
+ * @param startDay the day DST starts
+ * @param startDayOfWeek the DOW DST starts
+ * @param startTime the time DST starts
+ * @param startTimeMode Whether the start time is local wall time, local
+ * standard time, or UTC time. Default is local wall time.
+ * @param endMonth the month DST ends
+ * @param endDay the day DST ends
+ * @param endDayOfWeek the DOW DST ends
+ * @param endTime the time DST ends
+ * @param endTimeMode Whether the end time is local wall time, local
+ * standard time, or UTC time. Default is local wall time.
+ * @param savingsDST The number of milliseconds added to standard time
+ * to get DST time. Default is one hour.
+ * @param status An UErrorCode to receive the status.
+ */
+ void construct(int32_t rawOffsetGMT,
+ int8_t startMonth, int8_t startDay, int8_t startDayOfWeek,
+ int32_t startTime, TimeMode startTimeMode,
+ int8_t endMonth, int8_t endDay, int8_t endDayOfWeek,
+ int32_t endTime, TimeMode endTimeMode,
+ int32_t dstSavings, UErrorCode& status);
+
+ /**
+ * Compare a given date in the year to a rule. Return 1, 0, or -1, depending
+ * on whether the date is after, equal to, or before the rule date. The
+ * millis are compared directly against the ruleMillis, so any
+ * standard-daylight adjustments must be handled by the caller.
+ *
+ * @return 1 if the date is after the rule date, -1 if the date is before
+ * the rule date, or 0 if the date is equal to the rule date.
+ */
+ static int32_t compareToRule(int8_t month, int8_t monthLen, int8_t prevMonthLen,
+ int8_t dayOfMonth,
+ int8_t dayOfWeek, int32_t millis, int32_t millisDelta,
+ EMode ruleMode, int8_t ruleMonth, int8_t ruleDayOfWeek,
+ int8_t ruleDay, int32_t ruleMillis);
+
+ /**
+ * Given a set of encoded rules in startDay and startDayOfMonth, decode
+ * them and set the startMode appropriately. Do the same for endDay and
+ * endDayOfMonth.
+ * <P>
+ * Upon entry, the day of week variables may be zero or
+ * negative, in order to indicate special modes. The day of month
+ * variables may also be negative.
+ * <P>
+ * Upon exit, the mode variables will be
+ * set, and the day of week and day of month variables will be positive.
+ * <P>
+ * This method also recognizes a startDay or endDay of zero as indicating
+ * no DST.
+ */
+ void decodeRules(UErrorCode& status);
+ void decodeStartRule(UErrorCode& status);
+ void decodeEndRule(UErrorCode& status);
+
+ int8_t startMonth, startDay, startDayOfWeek; // the month, day, DOW, and time DST starts
+ int32_t startTime;
+ TimeMode startTimeMode, endTimeMode; // Mode for startTime, endTime; see TimeMode
+ int8_t endMonth, endDay, endDayOfWeek; // the month, day, DOW, and time DST ends
+ int32_t endTime;
+ int32_t startYear; // the year these DST rules took effect
+ int32_t rawOffset; // the TimeZone's raw GMT offset
+ UBool useDaylight; // flag indicating whether this TimeZone uses DST
+ static const int8_t STATICMONTHLENGTH[12]; // lengths of the months
+ EMode startMode, endMode; // flags indicating what kind of rules the DST rules are
+
+ /**
+ * A positive value indicating the amount of time saved during DST in ms.
+ * Typically one hour; sometimes 30 minutes.
+ */
+ int32_t dstSavings;
+
+ /* Private for BasicTimeZone implementation */
+ void initTransitionRules(UErrorCode& status);
+ void clearTransitionRules(void);
+ void deleteTransitionRules(void);
+ UBool transitionRulesInitialized;
+ InitialTimeZoneRule* initialRule;
+ TimeZoneTransition* firstTransition;
+ AnnualTimeZoneRule* stdRule;
+ AnnualTimeZoneRule* dstRule;
+};
+
+inline void SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfWeekInMonth,
+ int32_t dayOfWeek,
+ int32_t time, UErrorCode& status) {
+ setStartRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME, status);
+}
+
+inline void SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth,
+ int32_t time,
+ UErrorCode& status) {
+ setStartRule(month, dayOfMonth, time, WALL_TIME, status);
+}
+
+inline void SimpleTimeZone::setStartRule(int32_t month, int32_t dayOfMonth,
+ int32_t dayOfWeek,
+ int32_t time, UBool after, UErrorCode& status) {
+ setStartRule(month, dayOfMonth, dayOfWeek, time, WALL_TIME, after, status);
+}
+
+inline void SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfWeekInMonth,
+ int32_t dayOfWeek,
+ int32_t time, UErrorCode& status) {
+ setEndRule(month, dayOfWeekInMonth, dayOfWeek, time, WALL_TIME, status);
+}
+
+inline void SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth,
+ int32_t time, UErrorCode& status) {
+ setEndRule(month, dayOfMonth, time, WALL_TIME, status);
+}
+
+inline void SimpleTimeZone::setEndRule(int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ int32_t time, UBool after, UErrorCode& status) {
+ setEndRule(month, dayOfMonth, dayOfWeek, time, WALL_TIME, after, status);
+}
+
+inline void
+SimpleTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffsetRef,
+ int32_t& dstOffsetRef, UErrorCode& ec) const {
+ TimeZone::getOffset(date, local, rawOffsetRef, dstOffsetRef, ec);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _SIMPLETZ
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/smpdtfmt.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/smpdtfmt.h
new file mode 100644
index 00000000000..2fb7c8eb0cf
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/smpdtfmt.h
@@ -0,0 +1,904 @@
+/*
+* Copyright (C) 1997-2006, International Business Machines Corporation and others. All Rights Reserved.
+*******************************************************************************
+*
+* File SMPDTFMT.H
+*
+* Modification History:
+*
+* Date Name Description
+* 02/19/97 aliu Converted from java.
+* 07/09/97 helena Make ParsePosition into a class.
+* 07/21/98 stephen Added GMT_PLUS, GMT_MINUS
+* Changed setTwoDigitStartDate to set2DigitYearStart
+* Changed getTwoDigitStartDate to get2DigitYearStart
+* Removed subParseLong
+* Removed getZoneIndex (added in DateFormatSymbols)
+* 06/14/99 stephen Removed fgTimeZoneDataSuffix
+* 10/14/99 aliu Updated class doc to describe 2-digit year parsing
+* {j28 4182066}.
+*******************************************************************************
+*/
+
+#ifndef SMPDTFMT_H
+#define SMPDTFMT_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Format and parse dates in a language-independent manner.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/datefmt.h"
+
+U_NAMESPACE_BEGIN
+
+class DateFormatSymbols;
+class DateFormat;
+class MessageFormat;
+
+/**
+ *
+ * SimpleDateFormat is a concrete class for formatting and parsing dates in a
+ * language-independent manner. It allows for formatting (millis -> text),
+ * parsing (text -> millis), and normalization. Formats/Parses a date or time,
+ * which is the standard milliseconds since 24:00 GMT, Jan 1, 1970.
+ * <P>
+ * Clients are encouraged to create a date-time formatter using DateFormat::getInstance(),
+ * getDateInstance(), getDateInstance(), or getDateTimeInstance() rather than
+ * explicitly constructing an instance of SimpleDateFormat. This way, the client
+ * is guaranteed to get an appropriate formatting pattern for whatever locale the
+ * program is running in. However, if the client needs something more unusual than
+ * the default patterns in the locales, he can construct a SimpleDateFormat directly
+ * and give it an appropriate pattern (or use one of the factory methods on DateFormat
+ * and modify the pattern after the fact with toPattern() and applyPattern().
+ * <P>
+ * Date/Time format syntax:
+ * <P>
+ * The date/time format is specified by means of a string time pattern. In this
+ * pattern, all ASCII letters are reserved as pattern letters, which are defined
+ * as the following:
+ * <pre>
+ * \code
+ * Symbol Meaning Presentation Example
+ * ------ ------- ------------ -------
+ * G era designator (Text) AD
+ * y year (Number) 1996
+ * Y year (week of year) (Number) 1997
+ * u extended year (Number) 4601
+ * M month in year (Text & Number) July & 07
+ * d day in month (Number) 10
+ * h hour in am/pm (1~12) (Number) 12
+ * H hour in day (0~23) (Number) 0
+ * m minute in hour (Number) 30
+ * s second in minute (Number) 55
+ * S fractional second (Number) 978
+ * E day of week (Text) Tuesday
+ * e day of week (local 1~7) (Number) 2
+ * D day in year (Number) 189
+ * F day of week in month (Number) 2 (2nd Wed in July)
+ * w week in year (Number) 27
+ * W week in month (Number) 2
+ * a am/pm marker (Text) PM
+ * k hour in day (1~24) (Number) 24
+ * K hour in am/pm (0~11) (Number) 0
+ * z time zone (Time) Pacific Standard Time
+ * Z time zone (RFC 822) (Number) -0800
+ * v time zone (generic) (Text) Pacific Time
+ * g Julian day (Number) 2451334
+ * A milliseconds in day (Number) 69540000
+ * ' escape for text (Delimiter) 'Date='
+ * '' single quote (Literal) 'o''clock'
+ * \endcode
+ * </pre>
+ * The count of pattern letters determine the format.
+ * <P>
+ * (Text): 4 or more, use full form, &lt;4, use short or abbreviated form if it
+ * exists. (e.g., "EEEE" produces "Monday", "EEE" produces "Mon")
+ * <P>
+ * (Number): the minimum number of digits. Shorter numbers are zero-padded to
+ * this amount (e.g. if "m" produces "6", "mm" produces "06"). Year is handled
+ * specially; that is, if the count of 'y' is 2, the Year will be truncated to 2 digits.
+ * (e.g., if "yyyy" produces "1997", "yy" produces "97".)
+ * Unlike other fields, fractional seconds are padded on the right with zero.
+ * <P>
+ * (Text & Number): 3 or over, use text, otherwise use number. (e.g., "M" produces "1",
+ * "MM" produces "01", "MMM" produces "Jan", and "MMMM" produces "January".)
+ * <P>
+ * Any characters in the pattern that are not in the ranges of ['a'..'z'] and
+ * ['A'..'Z'] will be treated as quoted text. For instance, characters
+ * like ':', '.', ' ', '#' and '@' will appear in the resulting time text
+ * even they are not embraced within single quotes.
+ * <P>
+ * A pattern containing any invalid pattern letter will result in a failing
+ * UErrorCode result during formatting or parsing.
+ * <P>
+ * Examples using the US locale:
+ * <pre>
+ * \code
+ * Format Pattern Result
+ * -------------- -------
+ * "yyyy.MM.dd G 'at' HH:mm:ss vvvv" ->> 1996.07.10 AD at 15:08:56 Pacific Time
+ * "EEE, MMM d, ''yy" ->> Wed, July 10, '96
+ * "h:mm a" ->> 12:08 PM
+ * "hh 'o''clock' a, zzzz" ->> 12 o'clock PM, Pacific Daylight Time
+ * "K:mm a, vvv" ->> 0:00 PM, PT
+ * "yyyyy.MMMMM.dd GGG hh:mm aaa" ->> 1996.July.10 AD 12:08 PM
+ * \endcode
+ * </pre>
+ * Code Sample:
+ * <pre>
+ * \code
+ * UErrorCode success = U_ZERO_ERROR;
+ * SimpleTimeZone* pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, "PST");
+ * pdt->setStartRule( Calendar::APRIL, 1, Calendar::SUNDAY, 2*60*60*1000);
+ * pdt->setEndRule( Calendar::OCTOBER, -1, Calendar::SUNDAY, 2*60*60*1000);
+ *
+ * // Format the current time.
+ * SimpleDateFormat* formatter
+ * = new SimpleDateFormat ("yyyy.MM.dd G 'at' hh:mm:ss a zzz", success );
+ * GregorianCalendar cal(success);
+ * UDate currentTime_1 = cal.getTime(success);
+ * FieldPosition fp(0);
+ * UnicodeString dateString;
+ * formatter->format( currentTime_1, dateString, fp );
+ * cout << "result: " << dateString << endl;
+ *
+ * // Parse the previous string back into a Date.
+ * ParsePosition pp(0);
+ * UDate currentTime_2 = formatter->parse(dateString, pp );
+ * \endcode
+ * </pre>
+ * In the above example, the time value "currentTime_2" obtained from parsing
+ * will be equal to currentTime_1. However, they may not be equal if the am/pm
+ * marker 'a' is left out from the format pattern while the "hour in am/pm"
+ * pattern symbol is used. This information loss can happen when formatting the
+ * time in PM.
+ *
+ * <p>
+ * When parsing a date string using the abbreviated year pattern ("y" or "yy"),
+ * SimpleDateFormat must interpret the abbreviated year
+ * relative to some century. It does this by adjusting dates to be
+ * within 80 years before and 20 years after the time the SimpleDateFormat
+ * instance is created. For example, using a pattern of "MM/dd/yy" and a
+ * SimpleDateFormat instance created on Jan 1, 1997, the string
+ * "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
+ * would be interpreted as May 4, 1964.
+ * During parsing, only strings consisting of exactly two digits, as defined by
+ * <code>Unicode::isDigit()</code>, will be parsed into the default century.
+ * Any other numeric string, such as a one digit string, a three or more digit
+ * string, or a two digit string that isn't all digits (for example, "-1"), is
+ * interpreted literally. So "01/02/3" or "01/02/003" are parsed, using the
+ * same pattern, as Jan 2, 3 AD. Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
+ *
+ * <p>
+ * If the year pattern has more than two 'y' characters, the year is
+ * interpreted literally, regardless of the number of digits. So using the
+ * pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
+ *
+ * <p>
+ * When numeric fields abut one another directly, with no intervening delimiter
+ * characters, they constitute a run of abutting numeric fields. Such runs are
+ * parsed specially. For example, the format "HHmmss" parses the input text
+ * "123456" to 12:34:56, parses the input text "12345" to 1:23:45, and fails to
+ * parse "1234". In other words, the leftmost field of the run is flexible,
+ * while the others keep a fixed width. If the parse fails anywhere in the run,
+ * then the leftmost field is shortened by one character, and the entire run is
+ * parsed again. This is repeated until either the parse succeeds or the
+ * leftmost field is one character in length. If the parse still fails at that
+ * point, the parse of the run fails.
+ *
+ * <P>
+ * For time zones that have no names, SimpleDateFormat uses strings GMT+hours:minutes or
+ * GMT-hours:minutes.
+ * <P>
+ * The calendar defines what is the first day of the week, the first week of the
+ * year, whether hours are zero based or not (0 vs 12 or 24), and the timezone.
+ * There is one common number format to handle all the numbers; the digit count
+ * is handled programmatically according to the pattern.
+ *
+ * <p><em>User subclasses are not supported.</em> While clients may write
+ * subclasses, such code will not necessarily work and will not be
+ * guaranteed to work stably from release to release.
+ */
+class U_I18N_API SimpleDateFormat: public DateFormat {
+public:
+ /**
+ * Construct a SimpleDateFormat using the default pattern for the default
+ * locale.
+ * <P>
+ * [Note:] Not all locales support SimpleDateFormat; for full generality,
+ * use the factory methods in the DateFormat class.
+ * @param status Output param set to success/failure code.
+ * @stable ICU 2.0
+ */
+ SimpleDateFormat(UErrorCode& status);
+
+ /**
+ * Construct a SimpleDateFormat using the given pattern and the default locale.
+ * The locale is used to obtain the symbols used in formatting (e.g., the
+ * names of the months), but not to provide the pattern.
+ * <P>
+ * [Note:] Not all locales support SimpleDateFormat; for full generality,
+ * use the factory methods in the DateFormat class.
+ * @param pattern the pattern for the format.
+ * @param status Output param set to success/failure code.
+ * @stable ICU 2.0
+ */
+ SimpleDateFormat(const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Construct a SimpleDateFormat using the given pattern and locale.
+ * The locale is used to obtain the symbols used in formatting (e.g., the
+ * names of the months), but not to provide the pattern.
+ * <P>
+ * [Note:] Not all locales support SimpleDateFormat; for full generality,
+ * use the factory methods in the DateFormat class.
+ * @param pattern the pattern for the format.
+ * @param locale the given locale.
+ * @param status Output param set to success/failure code.
+ * @stable ICU 2.0
+ */
+ SimpleDateFormat(const UnicodeString& pattern,
+ const Locale& locale,
+ UErrorCode& status);
+
+ /**
+ * Construct a SimpleDateFormat using the given pattern and locale-specific
+ * symbol data. The formatter takes ownership of the DateFormatSymbols object;
+ * the caller is no longer responsible for deleting it.
+ * @param pattern the given pattern for the format.
+ * @param formatDataToAdopt the symbols to be adopted.
+ * @param status Output param set to success/faulure code.
+ * @stable ICU 2.0
+ */
+ SimpleDateFormat(const UnicodeString& pattern,
+ DateFormatSymbols* formatDataToAdopt,
+ UErrorCode& status);
+
+ /**
+ * Construct a SimpleDateFormat using the given pattern and locale-specific
+ * symbol data. The DateFormatSymbols object is NOT adopted; the caller
+ * remains responsible for deleting it.
+ * @param pattern the given pattern for the format.
+ * @param formatData the formatting symbols to be use.
+ * @param status Output param set to success/faulure code.
+ * @stable ICU 2.0
+ */
+ SimpleDateFormat(const UnicodeString& pattern,
+ const DateFormatSymbols& formatData,
+ UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ * @stable ICU 2.0
+ */
+ SimpleDateFormat(const SimpleDateFormat&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 2.0
+ */
+ SimpleDateFormat& operator=(const SimpleDateFormat&);
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~SimpleDateFormat();
+
+ /**
+ * Clone this Format object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @stable ICU 2.0
+ */
+ virtual Format* clone(void) const;
+
+ /**
+ * Return true if the given Format objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param other the object to be compared with.
+ * @return true if the given Format objects are semantically equal.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Format& other) const;
+
+ /**
+ * Format a date or time, which is the standard millis since 24:00 GMT, Jan
+ * 1, 1970. Overrides DateFormat pure virtual method.
+ * <P>
+ * Example: using the US locale: "yyyy.MM.dd e 'at' HH:mm:ss zzz" ->>
+ * 1996.07.10 AD at 15:08:56 PDT
+ *
+ * @param cal Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos The formatting position. On input: an alignment field,
+ * if desired. On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.1
+ */
+ virtual UnicodeString& format( Calendar& cal,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format a date or time, which is the standard millis since 24:00 GMT, Jan
+ * 1, 1970. Overrides DateFormat pure virtual method.
+ * <P>
+ * Example: using the US locale: "yyyy.MM.dd e 'at' HH:mm:ss zzz" ->>
+ * 1996.07.10 AD at 15:08:56 PDT
+ *
+ * @param obj A Formattable containing the date-time value to be formatted
+ * into a date-time string. If the type of the Formattable
+ * is a numeric type, it is treated as if it were an
+ * instance of Date.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos The formatting position. On input: an alignment field,
+ * if desired. On output: the offsets of the alignment field.
+ * @param status Output param set to success/faulure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& format( const Formattable& obj,
+ UnicodeString& appendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared DateFormat method.
+ * @param date the Date value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param fieldPosition The formatting position. On input: an alignment field,
+ * if desired. On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.1
+ */
+ UnicodeString& format(UDate date,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition) const;
+
+ /**
+ * Redeclared DateFormat method.
+ * @param obj Object to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param status Input/output success/failure code.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const;
+
+ /**
+ * Redeclared DateFormat method.
+ * @param date Date value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @return Reference to 'appendTo' parameter.
+ * @stable ICU 2.0
+ */
+ UnicodeString& format(UDate date, UnicodeString& appendTo) const;
+
+ /**
+ * Parse a date/time string beginning at the given parse position. For
+ * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
+ * that is equivalent to Date(837039928046).
+ * <P>
+ * By default, parsing is lenient: If the input is not in the form used by
+ * this object's format method but can still be parsed as a date, then the
+ * parse succeeds. Clients may insist on strict adherence to the format by
+ * calling setLenient(false).
+ *
+ * @param text The date/time string to be parsed
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @param pos On input, the position at which to start parsing; on
+ * output, the position at which parsing terminated, or the
+ * start position if the parse failed.
+ * @return A valid UDate if the input could be parsed.
+ * @stable ICU 2.1
+ */
+ virtual void parse( const UnicodeString& text,
+ Calendar& cal,
+ ParsePosition& pos) const;
+
+ /**
+ * Parse a date/time string starting at the given parse position. For
+ * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
+ * that is equivalent to Date(837039928046).
+ * <P>
+ * By default, parsing is lenient: If the input is not in the form used by
+ * this object's format method but can still be parsed as a date, then the
+ * parse succeeds. Clients may insist on strict adherence to the format by
+ * calling setLenient(false).
+ *
+ * @see DateFormat::setLenient(boolean)
+ *
+ * @param text The date/time string to be parsed
+ * @param pos On input, the position at which to start parsing; on
+ * output, the position at which parsing terminated, or the
+ * start position if the parse failed.
+ * @return A valid UDate if the input could be parsed.
+ * @stable ICU 2.0
+ */
+ UDate parse( const UnicodeString& text,
+ ParsePosition& pos) const;
+
+
+ /**
+ * Parse a date/time string. For example, a time text "07/10/96 4:5 PM, PDT"
+ * will be parsed into a UDate that is equivalent to Date(837039928046).
+ * Parsing begins at the beginning of the string and proceeds as far as
+ * possible. Assuming no parse errors were encountered, this function
+ * doesn't return any information about how much of the string was consumed
+ * by the parsing. If you need that information, use the version of
+ * parse() that takes a ParsePosition.
+ *
+ * @param text The date/time string to be parsed
+ * @param status Filled in with U_ZERO_ERROR if the parse was successful, and with
+ * an error value if there was a parse error.
+ * @return A valid UDate if the input could be parsed.
+ * @stable ICU 2.0
+ */
+ virtual UDate parse( const UnicodeString& text,
+ UErrorCode& status) const;
+
+ /**
+ * Set the start UDate used to interpret two-digit year strings.
+ * When dates are parsed having 2-digit year strings, they are placed within
+ * a assumed range of 100 years starting on the two digit start date. For
+ * example, the string "24-Jan-17" may be in the year 1817, 1917, 2017, or
+ * some other year. SimpleDateFormat chooses a year so that the resultant
+ * date is on or after the two digit start date and within 100 years of the
+ * two digit start date.
+ * <P>
+ * By default, the two digit start date is set to 80 years before the current
+ * time at which a SimpleDateFormat object is created.
+ * @param d start UDate used to interpret two-digit year strings.
+ * @param status Filled in with U_ZERO_ERROR if the parse was successful, and with
+ * an error value if there was a parse error.
+ * @stable ICU 2.0
+ */
+ virtual void set2DigitYearStart(UDate d, UErrorCode& status);
+
+ /**
+ * Get the start UDate used to interpret two-digit year strings.
+ * When dates are parsed having 2-digit year strings, they are placed within
+ * a assumed range of 100 years starting on the two digit start date. For
+ * example, the string "24-Jan-17" may be in the year 1817, 1917, 2017, or
+ * some other year. SimpleDateFormat chooses a year so that the resultant
+ * date is on or after the two digit start date and within 100 years of the
+ * two digit start date.
+ * <P>
+ * By default, the two digit start date is set to 80 years before the current
+ * time at which a SimpleDateFormat object is created.
+ * @param status Filled in with U_ZERO_ERROR if the parse was successful, and with
+ * an error value if there was a parse error.
+ * @stable ICU 2.0
+ */
+ UDate get2DigitYearStart(UErrorCode& status) const;
+
+ /**
+ * Return a pattern string describing this date format.
+ * @param result Output param to receive the pattern.
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toPattern(UnicodeString& result) const;
+
+ /**
+ * Return a localized pattern string describing this date format.
+ * In most cases, this will return the same thing as toPattern(),
+ * but a locale can specify characters to use in pattern descriptions
+ * in place of the ones described in this class's class documentation.
+ * (Presumably, letters that would be more mnemonic in that locale's
+ * language.) This function would produce a pattern using those
+ * letters.
+ *
+ * @param result Receives the localized pattern.
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toLocalizedPattern(UnicodeString& result,
+ UErrorCode& status) const;
+
+ /**
+ * Apply the given unlocalized pattern string to this date format.
+ * (i.e., after this call, this formatter will format dates according to
+ * the new pattern)
+ *
+ * @param pattern The pattern to be applied.
+ * @stable ICU 2.0
+ */
+ virtual void applyPattern(const UnicodeString& pattern);
+
+ /**
+ * Apply the given localized pattern string to this date format.
+ * (see toLocalizedPattern() for more information on localized patterns.)
+ *
+ * @param pattern The localized pattern to be applied.
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+ virtual void applyLocalizedPattern(const UnicodeString& pattern,
+ UErrorCode& status);
+
+ /**
+ * Gets the date/time formatting symbols (this is an object carrying
+ * the various strings and other symbols used in formatting: e.g., month
+ * names and abbreviations, time zone names, AM/PM strings, etc.)
+ * @return a copy of the date-time formatting data associated
+ * with this date-time formatter.
+ * @stable ICU 2.0
+ */
+ virtual const DateFormatSymbols* getDateFormatSymbols(void) const;
+
+ /**
+ * Set the date/time formatting symbols. The caller no longer owns the
+ * DateFormatSymbols object and should not delete it after making this call.
+ * @param newFormatSymbols the given date-time formatting symbols to copy.
+ * @stable ICU 2.0
+ */
+ virtual void adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols);
+
+ /**
+ * Set the date/time formatting data.
+ * @param newFormatSymbols the given date-time formatting symbols to copy.
+ * @stable ICU 2.0
+ */
+ virtual void setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols);
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Set the calendar to be used by this date format. Initially, the default
+ * calendar for the specified or default locale is used. The caller should
+ * not delete the Calendar object after it is adopted by this call.
+ * Adopting a new calendar will change to the default symbols.
+ *
+ * @param calendarToAdopt Calendar object to be adopted.
+ * @stable ICU 2.0
+ */
+ virtual void adoptCalendar(Calendar* calendarToAdopt);
+
+private:
+ friend class DateFormat;
+
+ void initializeDefaultCentury(void);
+
+ SimpleDateFormat(); // default constructor not implemented
+
+ /**
+ * Used by the DateFormat factory methods to construct a SimpleDateFormat.
+ * @param timeStyle the time style.
+ * @param dateStyle the date style.
+ * @param locale the given locale.
+ * @param status Output param set to success/failure code on
+ * exit.
+ */
+ SimpleDateFormat(EStyle timeStyle, EStyle dateStyle, const Locale& locale, UErrorCode& status);
+
+ /**
+ * Construct a SimpleDateFormat for the given locale. If no resource data
+ * is available, create an object of last resort, using hard-coded strings.
+ * This is an internal method, called by DateFormat. It should never fail.
+ * @param locale the given locale.
+ * @param status Output param set to success/failure code on
+ * exit.
+ */
+ SimpleDateFormat(const Locale& locale, UErrorCode& status); // Use default pattern
+
+ /**
+ * Called by format() to format a single field.
+ *
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param ch The format character we encountered in the pattern.
+ * @param count Number of characters in the current pattern symbol (e.g.,
+ * "yyyy" in the pattern would result in a call to this function
+ * with ch equal to 'y' and count equal to 4)
+ * @param pos The FieldPosition being filled in by the format() call. If
+ * this function is formatting the field specfied by pos, it
+ * will fill in pos with the beginning and ending offsets of the
+ * field.
+ * @param status Receives a status code, which will be U_ZERO_ERROR if the operation
+ * succeeds.
+ */
+ void subFormat( UnicodeString &appendTo,
+ UChar ch,
+ int32_t count,
+ FieldPosition& pos,
+ Calendar& cal,
+ UErrorCode& status) const; // in case of illegal argument
+
+ /**
+ * Used by subFormat() to format a numeric value.
+ * Appends to toAppendTo a string representation of "value"
+ * having a number of digits between "minDigits" and
+ * "maxDigits". Uses the DateFormat's NumberFormat.
+ *
+ * @param appendTo Output parameter to receive result.
+ * Formatted number is appended to existing contents.
+ * @param value Value to format.
+ * @param minDigits Minimum number of digits the result should have
+ * @param maxDigits Maximum number of digits the result should have
+ */
+ void zeroPaddingNumber( UnicodeString &appendTo,
+ int32_t value,
+ int32_t minDigits,
+ int32_t maxDigits) const;
+
+ /**
+ * Return true if the given format character, occuring count
+ * times, represents a numeric field.
+ */
+ static UBool isNumeric(UChar formatChar, int32_t count);
+
+ /**
+ * initializes fCalendar from parameters. Returns fCalendar as a convenience.
+ * @param adoptZone Zone to be adopted, or NULL for TimeZone::createDefault().
+ * @param locale Locale of the calendar
+ * @param status Error code
+ * @return the newly constructed fCalendar
+ */
+ Calendar *initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status);
+
+ /**
+ * initializes fSymbols from parameters.
+ * @param locale Locale of the symbols
+ * @param calendar Alias to Calendar that will be used.
+ * @param status Error code
+ */
+ void initializeSymbols(const Locale& locale, Calendar* calendar, UErrorCode& status);
+
+ /**
+ * Called by several of the constructors to load pattern data and formatting symbols
+ * out of a resource bundle and initialize the locale based on it.
+ * @param timeStyle The time style, as passed to DateFormat::createDateInstance().
+ * @param dateStyle The date style, as passed to DateFormat::createTimeInstance().
+ * @param locale The locale to load the patterns from.
+ * @param status Filled in with an error code if loading the data from the
+ * resources fails.
+ */
+ void construct(EStyle timeStyle, EStyle dateStyle, const Locale& locale, UErrorCode& status);
+
+ /**
+ * Called by construct() and the various constructors to set up the SimpleDateFormat's
+ * Calendar and NumberFormat objects.
+ * @param locale The locale for which we want a Calendar and a NumberFormat.
+ * @param statuc Filled in with an error code if creating either subobject fails.
+ */
+ void initialize(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Private code-size reduction function used by subParse.
+ * @param text the time text being parsed.
+ * @param start where to start parsing.
+ * @param field the date field being parsed.
+ * @param stringArray the string array to parsed.
+ * @param stringArrayCount the size of the array.
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @return the new start position if matching succeeded; a negative number
+ * indicating matching failure, otherwise.
+ */
+ int32_t matchString(const UnicodeString& text, int32_t start, UCalendarDateFields field,
+ const UnicodeString* stringArray, int32_t stringArrayCount, Calendar& cal) const;
+
+ /**
+ * Private code-size reduction function used by subParse.
+ * @param text the time text being parsed.
+ * @param start where to start parsing.
+ * @param field the date field being parsed.
+ * @param stringArray the string array to parsed.
+ * @param stringArrayCount the size of the array.
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @return the new start position if matching succeeded; a negative number
+ * indicating matching failure, otherwise.
+ */
+ int32_t matchQuarterString(const UnicodeString& text, int32_t start, UCalendarDateFields field,
+ const UnicodeString* stringArray, int32_t stringArrayCount, Calendar& cal) const;
+
+ /**
+ * Private member function that converts the parsed date strings into
+ * timeFields. Returns -start (for ParsePosition) if failed.
+ * @param text the time text to be parsed.
+ * @param start where to start parsing.
+ * @param ch the pattern character for the date field text to be parsed.
+ * @param count the count of a pattern character.
+ * @param obeyCount if true then the count is strictly obeyed.
+ * @param ambiguousYear If true then the two-digit year == the default start year.
+ * @param cal a Calendar set to the date and time to be formatted
+ * into a date/time string.
+ * @return the new start position if matching succeeded; a negative number
+ * indicating matching failure, otherwise.
+ */
+ int32_t subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
+ UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], Calendar& cal) const;
+
+ void parseInt(const UnicodeString& text,
+ Formattable& number,
+ ParsePosition& pos,
+ UBool allowNegative) const;
+
+ void parseInt(const UnicodeString& text,
+ Formattable& number,
+ int32_t maxDigits,
+ ParsePosition& pos,
+ UBool allowNegative) const;
+
+ /**
+ * Translate a pattern, mapping each character in the from string to the
+ * corresponding character in the to string. Return an error if the original
+ * pattern contains an unmapped character, or if a quote is unmatched.
+ * Quoted (single quotes only) material is not translated.
+ * @param originalPattern the original pattern.
+ * @param translatedPattern Output param to receive the translited pattern.
+ * @param from the characters to be translited from.
+ * @param to the characters to be translited to.
+ * @param status Receives a status code, which will be U_ZERO_ERROR
+ * if the operation succeeds.
+ */
+ static void translatePattern(const UnicodeString& originalPattern,
+ UnicodeString& translatedPattern,
+ const UnicodeString& from,
+ const UnicodeString& to,
+ UErrorCode& status);
+
+ /**
+ * Sets the starting date of the 100-year window that dates with 2-digit years
+ * are considered to fall within.
+ * @param startDate the start date
+ * @param status Receives a status code, which will be U_ZERO_ERROR
+ * if the operation succeeds.
+ */
+ void parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status);
+
+ /**
+ * Private methods for formatting/parsing GMT string
+ */
+ void appendGMT(UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const;
+ void formatGMTDefault(UnicodeString &appendTo, int32_t offset) const;
+ int32_t parseGMT(const UnicodeString &text, ParsePosition &pos) const;
+ int32_t parseGMTDefault(const UnicodeString &text, ParsePosition &pos) const;
+ UBool isDefaultGMTFormat() const;
+
+ void formatRFC822TZ(UnicodeString &appendTo, int32_t offset) const;
+
+ /**
+ * Initialize MessageFormat instances used for GMT formatting/parsing
+ */
+ void initGMTFormatters(UErrorCode &status);
+
+ /**
+ * Used to map pattern characters to Calendar field identifiers.
+ */
+ static const UCalendarDateFields fgPatternIndexToCalendarField[];
+
+ /**
+ * Map index into pattern character string to DateFormat field number
+ */
+ static const UDateFormatField fgPatternIndexToDateFormatField[];
+
+ /**
+ * The formatting pattern for this formatter.
+ */
+ UnicodeString fPattern;
+
+ /**
+ * The original locale used (for reloading symbols)
+ */
+ Locale fLocale;
+
+ /**
+ * A pointer to an object containing the strings to use in formatting (e.g.,
+ * month and day names, AM and PM strings, time zone names, etc.)
+ */
+ DateFormatSymbols* fSymbols; // Owned
+
+ /**
+ * If dates have ambiguous years, we map them into the century starting
+ * at defaultCenturyStart, which may be any date. If defaultCenturyStart is
+ * set to SYSTEM_DEFAULT_CENTURY, which it is by default, then the system
+ * values are used. The instance values defaultCenturyStart and
+ * defaultCenturyStartYear are only used if explicitly set by the user
+ * through the API method parseAmbiguousDatesAsAfter().
+ */
+ UDate fDefaultCenturyStart;
+
+ /**
+ * See documentation for defaultCenturyStart.
+ */
+ /*transient*/ int32_t fDefaultCenturyStartYear;
+
+ enum ParsedTZType {
+ TZTYPE_UNK,
+ TZTYPE_STD,
+ TZTYPE_DST
+ };
+
+ ParsedTZType tztype; // here to avoid api change
+
+ /*
+ * MessageFormat instances used for localized GMT format
+ */
+ MessageFormat **fGMTFormatters;
+
+ UBool fHaveDefaultCentury;
+};
+
+inline UDate
+SimpleDateFormat::get2DigitYearStart(UErrorCode& /*status*/) const
+{
+ return fDefaultCenturyStart;
+}
+
+inline UnicodeString&
+SimpleDateFormat::format(const Formattable& obj,
+ UnicodeString& appendTo,
+ UErrorCode& status) const {
+ // Don't use Format:: - use immediate base class only,
+ // in case immediate base modifies behavior later.
+ return DateFormat::format(obj, appendTo, status);
+}
+
+inline UnicodeString&
+SimpleDateFormat::format(UDate date,
+ UnicodeString& appendTo,
+ FieldPosition& fieldPosition) const {
+ // Don't use Format:: - use immediate base class only,
+ // in case immediate base modifies behavior later.
+ return DateFormat::format(date, appendTo, fieldPosition);
+}
+
+inline UnicodeString&
+SimpleDateFormat::format(UDate date, UnicodeString& appendTo) const {
+ return DateFormat::format(date, appendTo);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _SMPDTFMT
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/sortkey.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/sortkey.h
new file mode 100644
index 00000000000..ef202dd9ba4
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/sortkey.h
@@ -0,0 +1,324 @@
+/*
+ *****************************************************************************
+ * Copyright (C) 1996-2006, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ *****************************************************************************
+ *
+ * File sortkey.h
+ *
+ * Created by: Helena Shih
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ *
+ * 6/20/97 helena Java class name change.
+ * 8/18/97 helena Added internal API documentation.
+ * 6/26/98 erm Changed to use byte arrays and memcmp.
+ *****************************************************************************
+ */
+
+#ifndef SORTKEY_H
+#define SORTKEY_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Keys for comparing strings multiple times.
+ */
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/coll.h"
+
+U_NAMESPACE_BEGIN
+
+/* forward declaration */
+class RuleBasedCollator;
+
+/**
+ *
+ * Collation keys are generated by the Collator class. Use the CollationKey objects
+ * instead of Collator to compare strings multiple times. A CollationKey
+ * preprocesses the comparison information from the Collator object to
+ * make the comparison faster. If you are not going to comparing strings
+ * multiple times, then using the Collator object is generally faster,
+ * since it only processes as much of the string as needed to make a
+ * comparison.
+ * <p> For example (with strength == tertiary)
+ * <p>When comparing "Abernathy" to "Baggins-Smythworthy", Collator
+ * only needs to process a couple of characters, while a comparison
+ * with CollationKeys will process all of the characters. On the other hand,
+ * if you are doing a sort of a number of fields, it is much faster to use
+ * CollationKeys, since you will be comparing strings multiple times.
+ * <p>Typical use of CollationKeys are in databases, where you store a CollationKey
+ * in a hidden field, and use it for sorting or indexing.
+ *
+ * <p>Example of use:
+ * <pre>
+ * \code
+ * UErrorCode success = U_ZERO_ERROR;
+ * Collator* myCollator = Collator::createInstance(success);
+ * CollationKey* keys = new CollationKey [3];
+ * myCollator->getCollationKey("Tom", keys[0], success );
+ * myCollator->getCollationKey("Dick", keys[1], success );
+ * myCollator->getCollationKey("Harry", keys[2], success );
+ *
+ * // Inside body of sort routine, compare keys this way:
+ * CollationKey tmp;
+ * if(keys[0].compareTo( keys[1] ) > 0 ) {
+ * tmp = keys[0]; keys[0] = keys[1]; keys[1] = tmp;
+ * }
+ * //...
+ * \endcode
+ * </pre>
+ * <p>Because Collator::compare()'s algorithm is complex, it is faster to sort
+ * long lists of words by retrieving collation keys with Collator::getCollationKey().
+ * You can then cache the collation keys and compare them using CollationKey::compareTo().
+ * <p>
+ * <strong>Note:</strong> <code>Collator</code>s with different Locale,
+ * CollationStrength and DecompositionMode settings will return different
+ * CollationKeys for the same set of strings. Locales have specific
+ * collation rules, and the way in which secondary and tertiary differences
+ * are taken into account, for example, will result in different CollationKeys
+ * for same strings.
+ * <p>
+
+ * @see Collator
+ * @see RuleBasedCollator
+ * @version 1.3 12/18/96
+ * @author Helena Shih
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+class U_I18N_API CollationKey : public UObject {
+public:
+ /**
+ * This creates an empty collation key based on the null string. An empty
+ * collation key contains no sorting information. When comparing two empty
+ * collation keys, the result is Collator::EQUAL. Comparing empty collation key
+ * with non-empty collation key is always Collator::LESS.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ CollationKey();
+
+
+ /**
+ * Creates a collation key based on the collation key values.
+ * @param values the collation key values
+ * @param count number of collation key values, including trailing nulls.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ CollationKey(const uint8_t* values,
+ int32_t count);
+
+ /**
+ * Copy constructor.
+ * @param other the object to be copied.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ CollationKey(const CollationKey& other);
+
+ /**
+ * Sort key destructor.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ virtual ~CollationKey();
+
+ /**
+ * Assignment operator
+ * @param other the object to be copied.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ const CollationKey& operator=(const CollationKey& other);
+
+ /**
+ * Compare if two collation keys are the same.
+ * @param source the collation key to compare to.
+ * @return Returns true if two collation keys are equal, false otherwise.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ UBool operator==(const CollationKey& source) const;
+
+ /**
+ * Compare if two collation keys are not the same.
+ * @param source the collation key to compare to.
+ * @return Returns TRUE if two collation keys are different, FALSE otherwise.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ UBool operator!=(const CollationKey& source) const;
+
+
+ /**
+ * Test to see if the key is in an invalid state. The key will be in an
+ * invalid state if it couldn't allocate memory for some operation.
+ * @return Returns TRUE if the key is in an invalid, FALSE otherwise.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ UBool isBogus(void) const;
+
+ /**
+ * Returns a pointer to the collation key values. The storage is owned
+ * by the collation key and the pointer will become invalid if the key
+ * is deleted.
+ * @param count the output parameter of number of collation key values,
+ * including any trailing nulls.
+ * @return a pointer to the collation key values.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ const uint8_t* getByteArray(int32_t& count) const;
+
+#ifdef U_USE_COLLATION_KEY_DEPRECATES
+ /**
+ * Extracts the collation key values into a new array. The caller owns
+ * this storage and should free it.
+ * @param count the output parameter of number of collation key values,
+ * including any trailing nulls.
+ * @obsolete ICU 2.6. Use getByteArray instead since this API will be removed in that release.
+ */
+ uint8_t* toByteArray(int32_t& count) const;
+#endif
+
+ /**
+ * Convenience method which does a string(bit-wise) comparison of the
+ * two collation keys.
+ * @param target target collation key to be compared with
+ * @return Returns Collator::LESS if sourceKey &lt; targetKey,
+ * Collator::GREATER if sourceKey > targetKey and Collator::EQUAL
+ * otherwise.
+ * @deprecated ICU 2.6 use the overload with error code
+ */
+ Collator::EComparisonResult compareTo(const CollationKey& target) const;
+
+ /**
+ * Convenience method which does a string(bit-wise) comparison of the
+ * two collation keys.
+ * @param target target collation key to be compared with
+ * @param status error code
+ * @return Returns UCOL_LESS if sourceKey &lt; targetKey,
+ * UCOL_GREATER if sourceKey > targetKey and UCOL_EQUAL
+ * otherwise.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ UCollationResult compareTo(const CollationKey& target, UErrorCode &status) const;
+
+ /**
+ * Creates an integer that is unique to the collation key. NOTE: this
+ * is not the same as String.hashCode.
+ * <p>Example of use:
+ * <pre>
+ * . UErrorCode status = U_ZERO_ERROR;
+ * . Collator *myCollation = Collator::createInstance(Locale::US, status);
+ * . if (U_FAILURE(status)) return;
+ * . CollationKey key1, key2;
+ * . UErrorCode status1 = U_ZERO_ERROR, status2 = U_ZERO_ERROR;
+ * . myCollation->getCollationKey("abc", key1, status1);
+ * . if (U_FAILURE(status1)) { delete myCollation; return; }
+ * . myCollation->getCollationKey("ABC", key2, status2);
+ * . if (U_FAILURE(status2)) { delete myCollation; return; }
+ * . // key1.hashCode() != key2.hashCode()
+ * </pre>
+ * @return the hash value based on the string's collation order.
+ * @see UnicodeString#hashCode
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ int32_t hashCode(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ * @deprecated ICU 2.8 Use Collator::getSortKey(...) instead
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+private:
+ /**
+ * Returns an array of the collation key values as 16-bit integers.
+ * The caller owns the storage and must delete it.
+ * @param values Output param of the collation key values.
+ * @param count output parameter of the number of collation key values
+ * @return a pointer to an array of 16-bit collation key values.
+ */
+ void adopt(uint8_t *values, int32_t count);
+
+ /*
+ * Creates a collation key with a string.
+ */
+
+ /**
+ * If this CollationKey has capacity less than newSize,
+ * its internal capacity will be increased to newSize.
+ * @param newSize minimum size this CollationKey has to have
+ * @return this CollationKey
+ */
+ CollationKey& ensureCapacity(int32_t newSize);
+ /**
+ * Set the CollationKey to a "bogus" or invalid state
+ * @return this CollationKey
+ */
+ CollationKey& setToBogus(void);
+ /**
+ * Resets this CollationKey to an empty state
+ * @return this CollationKey
+ */
+ CollationKey& reset(void);
+
+ /**
+ * Allow private access to RuleBasedCollator
+ */
+ friend class RuleBasedCollator;
+ /**
+ * Bogus status
+ */
+ UBool fBogus;
+ /**
+ * Size of fBytes used to store the sortkey. i.e. up till the
+ * null-termination.
+ */
+ int32_t fCount;
+ /**
+ * Full size of the fBytes
+ */
+ int32_t fCapacity;
+ /**
+ * Unique hash value of this CollationKey
+ */
+ int32_t fHashCode;
+ /**
+ * Array to store the sortkey
+ */
+ uint8_t* fBytes;
+
+};
+
+inline UBool
+CollationKey::operator!=(const CollationKey& other) const
+{
+ return !(*this == other);
+}
+
+inline UBool
+CollationKey::isBogus() const
+{
+ return fBogus;
+}
+
+inline const uint8_t*
+CollationKey::getByteArray(int32_t &count) const
+{
+ count = fCount;
+ return fBytes;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/stsearch.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/stsearch.h
new file mode 100644
index 00000000000..a3e1bd79263
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/stsearch.h
@@ -0,0 +1,518 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 03/22/2000 helena Creation.
+**********************************************************************
+*/
+
+#ifndef STSEARCH_H
+#define STSEARCH_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Service for searching text based on RuleBasedCollator.
+ */
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "unicode/search.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ *
+ * <tt>StringSearch</tt> is a <tt>SearchIterator</tt> that provides
+ * language-sensitive text searching based on the comparison rules defined
+ * in a {@link RuleBasedCollator} object.
+ * StringSearch ensures that language eccentricity can be
+ * handled, e.g. for the German collator, characters &szlig; and SS will be matched
+ * if case is chosen to be ignored.
+ * See the <a href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm">
+ * "ICU Collation Design Document"</a> for more information.
+ * <p>
+ * The algorithm implemented is a modified form of the Boyer Moore's search.
+ * For more information see
+ * <a href="http://icu-project.org/docs/papers/efficient_text_searching_in_java.html">
+ * "Efficient Text Searching in Java"</a>, published in <i>Java Report</i>
+ * in February, 1999, for further information on the algorithm.
+ * <p>
+ * There are 2 match options for selection:<br>
+ * Let S' be the sub-string of a text string S between the offsets start and
+ * end <start, end>.
+ * <br>
+ * A pattern string P matches a text string S at the offsets <start, end>
+ * if
+ * <pre>
+ * option 1. Some canonical equivalent of P matches some canonical equivalent
+ * of S'
+ * option 2. P matches S' and if P starts or ends with a combining mark,
+ * there exists no non-ignorable combining mark before or after S?
+ * in S respectively.
+ * </pre>
+ * Option 2. will be the default.
+ * <p>
+ * This search has APIs similar to that of other text iteration mechanisms
+ * such as the break iterators in <tt>BreakIterator</tt>. Using these
+ * APIs, it is easy to scan through text looking for all occurances of
+ * a given pattern. This search iterator allows changing of direction by
+ * calling a <tt>reset</tt> followed by a <tt>next</tt> or <tt>previous</tt>.
+ * Though a direction change can occur without calling <tt>reset</tt> first,
+ * this operation comes with some speed penalty.
+ * Match results in the forward direction will match the result matches in
+ * the backwards direction in the reverse order
+ * <p>
+ * <tt>SearchIterator</tt> provides APIs to specify the starting position
+ * within the text string to be searched, e.g. <tt>setOffset</tt>,
+ * <tt>preceding</tt> and <tt>following</tt>. Since the
+ * starting position will be set as it is specified, please take note that
+ * there are some danger points which the search may render incorrect
+ * results:
+ * <ul>
+ * <li> The midst of a substring that requires normalization.
+ * <li> If the following match is to be found, the position should not be the
+ * second character which requires to be swapped with the preceding
+ * character. Vice versa, if the preceding match is to be found,
+ * position to search from should not be the first character which
+ * requires to be swapped with the next character. E.g certain Thai and
+ * Lao characters require swapping.
+ * <li> If a following pattern match is to be found, any position within a
+ * contracting sequence except the first will fail. Vice versa if a
+ * preceding pattern match is to be found, a invalid starting point
+ * would be any character within a contracting sequence except the last.
+ * </ul>
+ * <p>
+ * A breakiterator can be used if only matches at logical breaks are desired.
+ * Using a breakiterator will only give you results that exactly matches the
+ * boundaries given by the breakiterator. For instance the pattern "e" will
+ * not be found in the string "\u00e9" if a character break iterator is used.
+ * <p>
+ * Options are provided to handle overlapping matches.
+ * E.g. In English, overlapping matches produces the result 0 and 2
+ * for the pattern "abab" in the text "ababab", where else mutually
+ * exclusive matches only produce the result of 0.
+ * <p>
+ * Though collator attributes will be taken into consideration while
+ * performing matches, there are no APIs here for setting and getting the
+ * attributes. These attributes can be set by getting the collator
+ * from <tt>getCollator</tt> and using the APIs in <tt>coll.h</tt>.
+ * Lastly to update StringSearch to the new collator attributes,
+ * reset() has to be called.
+ * <p>
+ * Restriction: <br>
+ * Currently there are no composite characters that consists of a
+ * character with combining class > 0 before a character with combining
+ * class == 0. However, if such a character exists in the future,
+ * StringSearch does not guarantee the results for option 1.
+ * <p>
+ * Consult the <tt>SearchIterator</tt> documentation for information on
+ * and examples of how to use instances of this class to implement text
+ * searching.
+ * <pre><code>
+ * UnicodeString target("The quick brown fox jumps over the lazy dog.");
+ * UnicodeString pattern("fox");
+ *
+ * UErrorCode error = U_ZERO_ERROR;
+ * StringSearch iter(pattern, target, Locale::getUS(), NULL, status);
+ * for (int pos = iter.first(error);
+ * pos != USEARCH_DONE;
+ * pos = iter.next(error))
+ * {
+ * printf("Found match at %d pos, length is %d\n", pos,
+ * iter.getMatchLength());
+ * }
+ * </code></pre>
+ * <p>
+ * Note, StringSearch is not to be subclassed.
+ * </p>
+ * @see SearchIterator
+ * @see RuleBasedCollator
+ * @since ICU 2.0
+ */
+
+class U_I18N_API StringSearch : public SearchIterator
+{
+public:
+
+ // public constructors and destructors --------------------------------
+
+ /**
+ * Creating a <tt>StringSearch</tt> instance using the argument locale
+ * language rule set. A collator will be created in the process, which
+ * will be owned by this instance and will be deleted during
+ * destruction
+ * @param pattern The text for which this object will search.
+ * @param text The text in which to search for the pattern.
+ * @param locale A locale which defines the language-sensitive
+ * comparison rules used to determine whether text in the
+ * pattern and target matches.
+ * @param breakiter A <tt>BreakIterator</tt> object used to constrain
+ * the matches that are found. Matches whose start and end
+ * indices in the target text are not boundaries as
+ * determined by the <tt>BreakIterator</tt> are
+ * ignored. If this behavior is not desired,
+ * <tt>NULL</tt> can be passed in instead.
+ * @param status for errors if any. If pattern or text is NULL, or if
+ * either the length of pattern or text is 0 then an
+ * U_ILLEGAL_ARGUMENT_ERROR is returned.
+ * @stable ICU 2.0
+ */
+ StringSearch(const UnicodeString &pattern, const UnicodeString &text,
+ const Locale &locale,
+ BreakIterator *breakiter,
+ UErrorCode &status);
+
+ /**
+ * Creating a <tt>StringSearch</tt> instance using the argument collator
+ * language rule set. Note, user retains the ownership of this collator,
+ * it does not get destroyed during this instance's destruction.
+ * @param pattern The text for which this object will search.
+ * @param text The text in which to search for the pattern.
+ * @param coll A <tt>RuleBasedCollator</tt> object which defines
+ * the language-sensitive comparison rules used to
+ * determine whether text in the pattern and target
+ * matches. User is responsible for the clearing of this
+ * object.
+ * @param breakiter A <tt>BreakIterator</tt> object used to constrain
+ * the matches that are found. Matches whose start and end
+ * indices in the target text are not boundaries as
+ * determined by the <tt>BreakIterator</tt> are
+ * ignored. If this behavior is not desired,
+ * <tt>NULL</tt> can be passed in instead.
+ * @param status for errors if any. If either the length of pattern or
+ * text is 0 then an U_ILLEGAL_ARGUMENT_ERROR is returned.
+ * @stable ICU 2.0
+ */
+ StringSearch(const UnicodeString &pattern,
+ const UnicodeString &text,
+ RuleBasedCollator *coll,
+ BreakIterator *breakiter,
+ UErrorCode &status);
+
+ /**
+ * Creating a <tt>StringSearch</tt> instance using the argument locale
+ * language rule set. A collator will be created in the process, which
+ * will be owned by this instance and will be deleted during
+ * destruction
+ * <p>
+ * Note: No parsing of the text within the <tt>CharacterIterator</tt>
+ * will be done during searching for this version. The block of text
+ * in <tt>CharacterIterator</tt> will be used as it is.
+ * @param pattern The text for which this object will search.
+ * @param text The text iterator in which to search for the pattern.
+ * @param locale A locale which defines the language-sensitive
+ * comparison rules used to determine whether text in the
+ * pattern and target matches. User is responsible for
+ * the clearing of this object.
+ * @param breakiter A <tt>BreakIterator</tt> object used to constrain
+ * the matches that are found. Matches whose start and end
+ * indices in the target text are not boundaries as
+ * determined by the <tt>BreakIterator</tt> are
+ * ignored. If this behavior is not desired,
+ * <tt>NULL</tt> can be passed in instead.
+ * @param status for errors if any. If either the length of pattern or
+ * text is 0 then an U_ILLEGAL_ARGUMENT_ERROR is returned.
+ * @stable ICU 2.0
+ */
+ StringSearch(const UnicodeString &pattern, CharacterIterator &text,
+ const Locale &locale,
+ BreakIterator *breakiter,
+ UErrorCode &status);
+
+ /**
+ * Creating a <tt>StringSearch</tt> instance using the argument collator
+ * language rule set. Note, user retains the ownership of this collator,
+ * it does not get destroyed during this instance's destruction.
+ * <p>
+ * Note: No parsing of the text within the <tt>CharacterIterator</tt>
+ * will be done during searching for this version. The block of text
+ * in <tt>CharacterIterator</tt> will be used as it is.
+ * @param pattern The text for which this object will search.
+ * @param text The text in which to search for the pattern.
+ * @param coll A <tt>RuleBasedCollator</tt> object which defines
+ * the language-sensitive comparison rules used to
+ * determine whether text in the pattern and target
+ * matches. User is responsible for the clearing of this
+ * object.
+ * @param breakiter A <tt>BreakIterator</tt> object used to constrain
+ * the matches that are found. Matches whose start and end
+ * indices in the target text are not boundaries as
+ * determined by the <tt>BreakIterator</tt> are
+ * ignored. If this behavior is not desired,
+ * <tt>NULL</tt> can be passed in instead.
+ * @param status for errors if any. If either the length of pattern or
+ * text is 0 then an U_ILLEGAL_ARGUMENT_ERROR is returned.
+ * @stable ICU 2.0
+ */
+ StringSearch(const UnicodeString &pattern, CharacterIterator &text,
+ RuleBasedCollator *coll,
+ BreakIterator *breakiter,
+ UErrorCode &status);
+
+ /**
+ * Copy constructor that creates a StringSearch instance with the same
+ * behavior, and iterating over the same text.
+ * @param that StringSearch instance to be copied.
+ * @stable ICU 2.0
+ */
+ StringSearch(const StringSearch &that);
+
+ /**
+ * Destructor. Cleans up the search iterator data struct.
+ * If a collator is created in the constructor, it will be destroyed here.
+ * @stable ICU 2.0
+ */
+ virtual ~StringSearch(void);
+
+ /**
+ * Clone this object.
+ * Clones can be used concurrently in multiple threads.
+ * If an error occurs, then NULL is returned.
+ * The caller must delete the clone.
+ *
+ * @return a clone of this object
+ *
+ * @see getDynamicClassID
+ * @stable ICU 2.8
+ */
+ StringSearch *clone() const;
+
+ // operator overloading ---------------------------------------------
+
+ /**
+ * Assignment operator. Sets this iterator to have the same behavior,
+ * and iterate over the same text, as the one passed in.
+ * @param that instance to be copied.
+ * @stable ICU 2.0
+ */
+ StringSearch & operator=(const StringSearch &that);
+
+ /**
+ * Equality operator.
+ * @param that instance to be compared.
+ * @return TRUE if both instances have the same attributes,
+ * breakiterators, collators and iterate over the same text
+ * while looking for the same pattern.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const SearchIterator &that) const;
+
+ // public get and set methods ----------------------------------------
+
+ /**
+ * Sets the index to point to the given position, and clears any state
+ * that's affected.
+ * <p>
+ * This method takes the argument index and sets the position in the text
+ * string accordingly without checking if the index is pointing to a
+ * valid starting point to begin searching.
+ * @param position within the text to be set. If position is less
+ * than or greater than the text range for searching,
+ * an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+ * @param status for errors if it occurs
+ * @stable ICU 2.0
+ */
+ virtual void setOffset(int32_t position, UErrorCode &status);
+
+ /**
+ * Return the current index in the text being searched.
+ * If the iteration has gone past the end of the text
+ * (or past the beginning for a backwards search), USEARCH_DONE
+ * is returned.
+ * @return current index in the text being searched.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getOffset(void) const;
+
+ /**
+ * Set the target text to be searched.
+ * Text iteration will hence begin at the start of the text string.
+ * This method is
+ * useful if you want to re-use an iterator to search for the same
+ * pattern within a different body of text.
+ * @param text text string to be searched
+ * @param status for errors if any. If the text length is 0 then an
+ * U_ILLEGAL_ARGUMENT_ERROR is returned.
+ * @stable ICU 2.0
+ */
+ virtual void setText(const UnicodeString &text, UErrorCode &status);
+
+ /**
+ * Set the target text to be searched.
+ * Text iteration will hence begin at the start of the text string.
+ * This method is
+ * useful if you want to re-use an iterator to search for the same
+ * pattern within a different body of text.
+ * Note: No parsing of the text within the <tt>CharacterIterator</tt>
+ * will be done during searching for this version. The block of text
+ * in <tt>CharacterIterator</tt> will be used as it is.
+ * @param text text string to be searched
+ * @param status for errors if any. If the text length is 0 then an
+ * U_ILLEGAL_ARGUMENT_ERROR is returned.
+ * @stable ICU 2.0
+ */
+ virtual void setText(CharacterIterator &text, UErrorCode &status);
+
+ /**
+ * Gets the collator used for the language rules.
+ * <p>
+ * Caller may modify but <b>must not</b> delete the <tt>RuleBasedCollator</tt>!
+ * Modifications to this collator will affect the original collator passed in to
+ * the <tt>StringSearch></tt> constructor or to setCollator, if any.
+ * @return collator used for string search
+ * @stable ICU 2.0
+ */
+ RuleBasedCollator * getCollator() const;
+
+ /**
+ * Sets the collator used for the language rules. User retains the
+ * ownership of this collator, thus the responsibility of deletion lies
+ * with the user. This method causes internal data such as Boyer-Moore
+ * shift tables to be recalculated, but the iterator's position is
+ * unchanged.
+ * @param coll collator
+ * @param status for errors if any
+ * @stable ICU 2.0
+ */
+ void setCollator(RuleBasedCollator *coll, UErrorCode &status);
+
+ /**
+ * Sets the pattern used for matching.
+ * Internal data like the Boyer Moore table will be recalculated, but
+ * the iterator's position is unchanged.
+ * @param pattern search pattern to be found
+ * @param status for errors if any. If the pattern length is 0 then an
+ * U_ILLEGAL_ARGUMENT_ERROR is returned.
+ * @stable ICU 2.0
+ */
+ void setPattern(const UnicodeString &pattern, UErrorCode &status);
+
+ /**
+ * Gets the search pattern.
+ * @return pattern used for matching
+ * @stable ICU 2.0
+ */
+ const UnicodeString & getPattern() const;
+
+ // public methods ----------------------------------------------------
+
+ /**
+ * Reset the iteration.
+ * Search will begin at the start of the text string if a forward
+ * iteration is initiated before a backwards iteration. Otherwise if
+ * a backwards iteration is initiated before a forwards iteration, the
+ * search will begin at the end of the text string.
+ * @stable ICU 2.0
+ */
+ virtual void reset();
+
+ /**
+ * Returns a copy of StringSearch with the same behavior, and
+ * iterating over the same text, as this one. Note that all data will be
+ * replicated, except for the user-specified collator and the
+ * breakiterator.
+ * @return cloned object
+ * @stable ICU 2.0
+ */
+ virtual SearchIterator * safeClone(void) const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+protected:
+
+ // protected method -------------------------------------------------
+
+ /**
+ * Search forward for matching text, starting at a given location.
+ * Clients should not call this method directly; instead they should
+ * call {@link SearchIterator#next }.
+ * <p>
+ * If a match is found, this method returns the index at which the match
+ * starts and calls {@link SearchIterator#setMatchLength } with the number
+ * of characters in the target text that make up the match. If no match
+ * is found, the method returns <tt>USEARCH_DONE</tt>.
+ * <p>
+ * The <tt>StringSearch</tt> is adjusted so that its current index
+ * (as returned by {@link #getOffset }) is the match position if one was
+ * found.
+ * If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+ * the <tt>StringSearch</tt> will be adjusted to the index USEARCH_DONE.
+ * @param position The index in the target text at which the search
+ * starts
+ * @param status for errors if any occurs
+ * @return The index at which the matched text in the target starts, or
+ * USEARCH_DONE if no match was found.
+ * @stable ICU 2.0
+ */
+ virtual int32_t handleNext(int32_t position, UErrorCode &status);
+
+ /**
+ * Search backward for matching text, starting at a given location.
+ * Clients should not call this method directly; instead they should call
+ * <tt>SearchIterator.previous()</tt>, which this method overrides.
+ * <p>
+ * If a match is found, this method returns the index at which the match
+ * starts and calls {@link SearchIterator#setMatchLength } with the number
+ * of characters in the target text that make up the match. If no match
+ * is found, the method returns <tt>USEARCH_DONE</tt>.
+ * <p>
+ * The <tt>StringSearch</tt> is adjusted so that its current index
+ * (as returned by {@link #getOffset }) is the match position if one was
+ * found.
+ * If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+ * the <tt>StringSearch</tt> will be adjusted to the index USEARCH_DONE.
+ * @param position The index in the target text at which the search
+ * starts.
+ * @param status for errors if any occurs
+ * @return The index at which the matched text in the target starts, or
+ * USEARCH_DONE if no match was found.
+ * @stable ICU 2.0
+ */
+ virtual int32_t handlePrev(int32_t position, UErrorCode &status);
+
+private :
+ StringSearch(); // default constructor not implemented
+
+ // private data members ----------------------------------------------
+
+ /**
+ * RuleBasedCollator, contains exactly the same UCollator * in m_strsrch_
+ * @stable ICU 2.0
+ */
+ RuleBasedCollator m_collator_;
+ /**
+ * Pattern text
+ * @stable ICU 2.0
+ */
+ UnicodeString m_pattern_;
+ /**
+ * String search struct data
+ * @stable ICU 2.0
+ */
+ UStringSearch *m_strsrch_;
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/tblcoll.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/tblcoll.h
new file mode 100644
index 00000000000..ab7d9eae21b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/tblcoll.h
@@ -0,0 +1,924 @@
+/*
+******************************************************************************
+* Copyright (C) 1996-2007, International Business Machines Corporation and
+* others. All Rights Reserved.
+******************************************************************************
+*/
+
+/**
+* File tblcoll.h
+*
+* Created by: Helena Shih
+*
+* Modification History:
+*
+* Date Name Description
+* 2/5/97 aliu Added streamIn and streamOut methods. Added
+* constructor which reads RuleBasedCollator object from
+* a binary file. Added writeToFile method which streams
+* RuleBasedCollator out to a binary file. The streamIn
+* and streamOut methods use istream and ostream objects
+* in binary mode.
+* 2/12/97 aliu Modified to use TableCollationData sub-object to
+* hold invariant data.
+* 2/13/97 aliu Moved several methods into this class from Collation.
+* Added a private RuleBasedCollator(Locale&) constructor,
+* to be used by Collator::createDefault(). General
+* clean up.
+* 2/20/97 helena Added clone, operator==, operator!=, operator=, and copy
+* constructor and getDynamicClassID.
+* 3/5/97 aliu Modified constructFromFile() to add parameter
+* specifying whether or not binary loading is to be
+* attempted. This is required for dynamic rule loading.
+* 05/07/97 helena Added memory allocation error detection.
+* 6/17/97 helena Added IDENTICAL strength for compare, changed getRules to
+* use MergeCollation::getPattern.
+* 6/20/97 helena Java class name change.
+* 8/18/97 helena Added internal API documentation.
+* 09/03/97 helena Added createCollationKeyValues().
+* 02/10/98 damiba Added compare with "length" parameter
+* 08/05/98 erm Synched with 1.2 version of RuleBasedCollator.java
+* 04/23/99 stephen Removed EDecompositionMode, merged with
+* Normalizer::EMode
+* 06/14/99 stephen Removed kResourceBundleSuffix
+* 11/02/99 helena Collator performance enhancements. Eliminates the
+* UnicodeString construction and special case for NO_OP.
+* 11/23/99 srl More performance enhancements. Updates to NormalizerIterator
+* internal state management.
+* 12/15/99 aliu Update to support Thai collation. Move NormalizerIterator
+* to implementation file.
+* 01/29/01 synwee Modified into a C++ wrapper which calls C API
+* (ucol.h)
+*/
+
+#ifndef TBLCOLL_H
+#define TBLCOLL_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: RuleBasedCollator class provides the simple implementation of Collator.
+ */
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/ucol.h"
+#include "unicode/sortkey.h"
+#include "unicode/normlzr.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+* @stable ICU 2.0
+*/
+class StringSearch;
+/**
+* @stable ICU 2.0
+*/
+class CollationElementIterator;
+
+/**
+ * The RuleBasedCollator class provides the simple implementation of
+ * Collator, using data-driven tables. The user can create a customized
+ * table-based collation.
+ * <P>
+ * <em>Important: </em>The ICU collation service has been reimplemented
+ * in order to achieve better performance and UCA compliance.
+ * For details, see the
+ * <a href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm">
+ * collation design document</a>.
+ * <p>
+ * RuleBasedCollator is a thin C++ wrapper over the C implementation.
+ * <p>
+ * For more information about the collation service see
+ * <a href="http://icu-project.org/userguide/Collate_Intro.html">the users guide</a>.
+ * <p>
+ * Collation service provides correct sorting orders for most locales supported in ICU.
+ * If specific data for a locale is not available, the orders eventually falls back
+ * to the <a href="http://www.unicode.org/unicode/reports/tr10/">UCA sort order</a>.
+ * <p>
+ * Sort ordering may be customized by providing your own set of rules. For more on
+ * this subject see the <a href="http://icu-project.org/userguide/Collate_Customization.html">
+ * Collation customization</a> section of the users guide.
+ * <p>
+ * Note, RuleBasedCollator is not to be subclassed.
+ * @see Collator
+ * @version 2.0 11/15/2001
+ */
+class U_I18N_API RuleBasedCollator : public Collator
+{
+public:
+
+ // constructor -------------------------------------------------------------
+
+ /**
+ * RuleBasedCollator constructor. This takes the table rules and builds a
+ * collation table out of them. Please see RuleBasedCollator class
+ * description for more details on the collation rule syntax.
+ * @param rules the collation rules to build the collation table from.
+ * @param status reporting a success or an error.
+ * @see Locale
+ * @stable ICU 2.0
+ */
+ RuleBasedCollator(const UnicodeString& rules, UErrorCode& status);
+
+ /**
+ * RuleBasedCollator constructor. This takes the table rules and builds a
+ * collation table out of them. Please see RuleBasedCollator class
+ * description for more details on the collation rule syntax.
+ * @param rules the collation rules to build the collation table from.
+ * @param collationStrength default strength for comparison
+ * @param status reporting a success or an error.
+ * @see Locale
+ * @stable ICU 2.0
+ */
+ RuleBasedCollator(const UnicodeString& rules,
+ ECollationStrength collationStrength,
+ UErrorCode& status);
+
+ /**
+ * RuleBasedCollator constructor. This takes the table rules and builds a
+ * collation table out of them. Please see RuleBasedCollator class
+ * description for more details on the collation rule syntax.
+ * @param rules the collation rules to build the collation table from.
+ * @param decompositionMode the normalisation mode
+ * @param status reporting a success or an error.
+ * @see Locale
+ * @stable ICU 2.0
+ */
+ RuleBasedCollator(const UnicodeString& rules,
+ UColAttributeValue decompositionMode,
+ UErrorCode& status);
+
+ /**
+ * RuleBasedCollator constructor. This takes the table rules and builds a
+ * collation table out of them. Please see RuleBasedCollator class
+ * description for more details on the collation rule syntax.
+ * @param rules the collation rules to build the collation table from.
+ * @param collationStrength default strength for comparison
+ * @param decompositionMode the normalisation mode
+ * @param status reporting a success or an error.
+ * @see Locale
+ * @stable ICU 2.0
+ */
+ RuleBasedCollator(const UnicodeString& rules,
+ ECollationStrength collationStrength,
+ UColAttributeValue decompositionMode,
+ UErrorCode& status);
+
+ /**
+ * Copy constructor.
+ * @param other the RuleBasedCollator object to be copied
+ * @see Locale
+ * @stable ICU 2.0
+ */
+ RuleBasedCollator(const RuleBasedCollator& other);
+
+
+ /** Opens a collator from a collator binary image created using
+ * cloneBinary. Binary image used in instantiation of the
+ * collator remains owned by the user and should stay around for
+ * the lifetime of the collator. The API also takes a base collator
+ * which usualy should be UCA.
+ * @param bin binary image owned by the user and required through the
+ * lifetime of the collator
+ * @param length size of the image. If negative, the API will try to
+ * figure out the length of the image
+ * @param base fallback collator, usually UCA. Base is required to be
+ * present through the lifetime of the collator. Currently
+ * it cannot be NULL.
+ * @param status for catching errors
+ * @return newly created collator
+ * @see cloneBinary
+ * @stable ICU 3.4
+ */
+ RuleBasedCollator(const uint8_t *bin, int32_t length,
+ const RuleBasedCollator *base,
+ UErrorCode &status);
+ // destructor --------------------------------------------------------------
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~RuleBasedCollator();
+
+ // public methods ----------------------------------------------------------
+
+ /**
+ * Assignment operator.
+ * @param other other RuleBasedCollator object to compare with.
+ * @stable ICU 2.0
+ */
+ RuleBasedCollator& operator=(const RuleBasedCollator& other);
+
+ /**
+ * Returns true if argument is the same as this object.
+ * @param other Collator object to be compared.
+ * @return true if arguments is the same as this object.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const Collator& other) const;
+
+ /**
+ * Returns true if argument is not the same as this object.
+ * @param other Collator object to be compared
+ * @return returns true if argument is not the same as this object.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator!=(const Collator& other) const;
+
+ /**
+ * Makes a deep copy of the object.
+ * The caller owns the returned object.
+ * @return the cloned object.
+ * @stable ICU 2.0
+ */
+ virtual Collator* clone(void) const;
+
+ /**
+ * Creates a collation element iterator for the source string. The caller of
+ * this method is responsible for the memory management of the return
+ * pointer.
+ * @param source the string over which the CollationElementIterator will
+ * iterate.
+ * @return the collation element iterator of the source string using this as
+ * the based Collator.
+ * @stable ICU 2.2
+ */
+ virtual CollationElementIterator* createCollationElementIterator(
+ const UnicodeString& source) const;
+
+ /**
+ * Creates a collation element iterator for the source. The caller of this
+ * method is responsible for the memory management of the returned pointer.
+ * @param source the CharacterIterator which produces the characters over
+ * which the CollationElementItgerator will iterate.
+ * @return the collation element iterator of the source using this as the
+ * based Collator.
+ * @stable ICU 2.2
+ */
+ virtual CollationElementIterator* createCollationElementIterator(
+ const CharacterIterator& source) const;
+
+ /**
+ * Compares a range of character data stored in two different strings based
+ * on the collation rules. Returns information about whether a string is
+ * less than, greater than or equal to another string in a language.
+ * This can be overriden in a subclass.
+ * @param source the source string.
+ * @param target the target string to be compared with the source string.
+ * @return the comparison result. GREATER if the source string is greater
+ * than the target string, LESS if the source is less than the
+ * target. Otherwise, returns EQUAL.
+ * @deprecated ICU 2.6 Use overload with UErrorCode&
+ */
+ virtual EComparisonResult compare(const UnicodeString& source,
+ const UnicodeString& target) const;
+
+
+ /**
+ * The comparison function compares the character data stored in two
+ * different strings. Returns information about whether a string is less
+ * than, greater than or equal to another string.
+ * @param source the source string to be compared with.
+ * @param target the string that is to be compared with the source string.
+ * @param status possible error code
+ * @return Returns an enum value. UCOL_GREATER if source is greater
+ * than target; UCOL_EQUAL if source is equal to target; UCOL_LESS if source is less
+ * than target
+ * @stable ICU 2.6
+ **/
+ virtual UCollationResult compare(const UnicodeString& source,
+ const UnicodeString& target,
+ UErrorCode &status) const;
+
+ /**
+ * Compares a range of character data stored in two different strings based
+ * on the collation rules up to the specified length. Returns information
+ * about whether a string is less than, greater than or equal to another
+ * string in a language. This can be overriden in a subclass.
+ * @param source the source string.
+ * @param target the target string to be compared with the source string.
+ * @param length compares up to the specified length
+ * @return the comparison result. GREATER if the source string is greater
+ * than the target string, LESS if the source is less than the
+ * target. Otherwise, returns EQUAL.
+ * @deprecated ICU 2.6 Use overload with UErrorCode&
+ */
+ virtual EComparisonResult compare(const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length) const;
+
+ /**
+ * Does the same thing as compare but limits the comparison to a specified
+ * length
+ * @param source the source string to be compared with.
+ * @param target the string that is to be compared with the source string.
+ * @param length the length the comparison is limited to
+ * @param status possible error code
+ * @return Returns an enum value. UCOL_GREATER if source (up to the specified
+ * length) is greater than target; UCOL_EQUAL if source (up to specified
+ * length) is equal to target; UCOL_LESS if source (up to the specified
+ * length) is less than target.
+ * @stable ICU 2.6
+ */
+ virtual UCollationResult compare(const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length,
+ UErrorCode &status) const;
+
+ /**
+ * The comparison function compares the character data stored in two
+ * different string arrays. Returns information about whether a string array
+ * is less than, greater than or equal to another string array.
+ * <p>Example of use:
+ * <pre>
+ * . UChar ABC[] = {0x41, 0x42, 0x43, 0}; // = "ABC"
+ * . UChar abc[] = {0x61, 0x62, 0x63, 0}; // = "abc"
+ * . UErrorCode status = U_ZERO_ERROR;
+ * . Collator *myCollation =
+ * . Collator::createInstance(Locale::US, status);
+ * . if (U_FAILURE(status)) return;
+ * . myCollation->setStrength(Collator::PRIMARY);
+ * . // result would be Collator::EQUAL ("abc" == "ABC")
+ * . // (no primary difference between "abc" and "ABC")
+ * . Collator::EComparisonResult result =
+ * . myCollation->compare(abc, 3, ABC, 3);
+ * . myCollation->setStrength(Collator::TERTIARY);
+ * . // result would be Collator::LESS ("abc" &lt;&lt;&lt; "ABC")
+ * . // (with tertiary difference between "abc" and "ABC")
+ * . result = myCollation->compare(abc, 3, ABC, 3);
+ * </pre>
+ * @param source the source string array to be compared with.
+ * @param sourceLength the length of the source string array. If this value
+ * is equal to -1, the string array is null-terminated.
+ * @param target the string that is to be compared with the source string.
+ * @param targetLength the length of the target string array. If this value
+ * is equal to -1, the string array is null-terminated.
+ * @return Returns a byte value. GREATER if source is greater than target;
+ * EQUAL if source is equal to target; LESS if source is less than
+ * target
+ * @deprecated ICU 2.6 Use overload with UErrorCode&
+ */
+ virtual EComparisonResult compare(const UChar* source, int32_t sourceLength,
+ const UChar* target, int32_t targetLength)
+ const;
+
+ /**
+ * The comparison function compares the character data stored in two
+ * different string arrays. Returns information about whether a string array
+ * is less than, greater than or equal to another string array.
+ * @param source the source string array to be compared with.
+ * @param sourceLength the length of the source string array. If this value
+ * is equal to -1, the string array is null-terminated.
+ * @param target the string that is to be compared with the source string.
+ * @param targetLength the length of the target string array. If this value
+ * is equal to -1, the string array is null-terminated.
+ * @param status possible error code
+ * @return Returns an enum value. UCOL_GREATER if source is greater
+ * than target; UCOL_EQUAL if source is equal to target; UCOL_LESS if source is less
+ * than target
+ * @stable ICU 2.6
+ */
+ virtual UCollationResult compare(const UChar* source, int32_t sourceLength,
+ const UChar* target, int32_t targetLength,
+ UErrorCode &status) const;
+
+ /**
+ * Transforms a specified region of the string into a series of characters
+ * that can be compared with CollationKey.compare. Use a CollationKey when
+ * you need to do repeated comparisions on the same string. For a single
+ * comparison the compare method will be faster.
+ * @param source the source string.
+ * @param key the transformed key of the source string.
+ * @param status the error code status.
+ * @return the transformed key.
+ * @see CollationKey
+ * @deprecated ICU 2.8 Use getSortKey(...) instead
+ */
+ virtual CollationKey& getCollationKey(const UnicodeString& source,
+ CollationKey& key,
+ UErrorCode& status) const;
+
+ /**
+ * Transforms a specified region of the string into a series of characters
+ * that can be compared with CollationKey.compare. Use a CollationKey when
+ * you need to do repeated comparisions on the same string. For a single
+ * comparison the compare method will be faster.
+ * @param source the source string.
+ * @param sourceLength the length of the source string.
+ * @param key the transformed key of the source string.
+ * @param status the error code status.
+ * @return the transformed key.
+ * @see CollationKey
+ * @deprecated ICU 2.8 Use getSortKey(...) instead
+ */
+ virtual CollationKey& getCollationKey(const UChar *source,
+ int32_t sourceLength,
+ CollationKey& key,
+ UErrorCode& status) const;
+
+ /**
+ * Generates the hash code for the rule-based collation object.
+ * @return the hash code.
+ * @stable ICU 2.0
+ */
+ virtual int32_t hashCode(void) const;
+
+ /**
+ * Gets the locale of the Collator
+ * @param type can be either requested, valid or actual locale. For more
+ * information see the definition of ULocDataLocaleType in
+ * uloc.h
+ * @param status the error code status.
+ * @return locale where the collation data lives. If the collator
+ * was instantiated from rules, locale is empty.
+ * @deprecated ICU 2.8 likely to change in ICU 3.0, based on feedback
+ */
+ virtual const Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
+
+ /**
+ * Gets the table-based rules for the collation object.
+ * @return returns the collation rules that the table collation object was
+ * created from.
+ * @stable ICU 2.0
+ */
+ const UnicodeString& getRules(void) const;
+
+ /**
+ * Gets the version information for a Collator.
+ * @param info the version # information, the result will be filled in
+ * @stable ICU 2.0
+ */
+ virtual void getVersion(UVersionInfo info) const;
+
+ /**
+ * Return the maximum length of any expansion sequences that end with the
+ * specified comparison order.
+ * @param order a collation order returned by previous or next.
+ * @return maximum size of the expansion sequences ending with the collation
+ * element or 1 if collation element does not occur at the end of
+ * any expansion sequence
+ * @see CollationElementIterator#getMaxExpansion
+ * @stable ICU 2.0
+ */
+ int32_t getMaxExpansion(int32_t order) const;
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ * @return The class ID for this object. All objects of a given class have
+ * the same class ID. Objects of other classes have different class
+ * IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Returns the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * Base* polymorphic_pointer = createPolymorphicObject();
+ * if (polymorphic_pointer->getDynamicClassID() ==
+ * Derived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns the binary format of the class's rules. The format is that of
+ * .col files.
+ * @param length Returns the length of the data, in bytes
+ * @param status the error code status.
+ * @return memory, owned by the caller, of size 'length' bytes.
+ * @stable ICU 2.2
+ */
+ uint8_t *cloneRuleData(int32_t &length, UErrorCode &status);
+
+
+ /** Creates a binary image of a collator. This binary image can be stored and
+ * later used to instantiate a collator using ucol_openBinary.
+ * This API supports preflighting.
+ * @param buffer a fill-in buffer to receive the binary image
+ * @param capacity capacity of the destination buffer
+ * @param status for catching errors
+ * @return size of the image
+ * @see ucol_openBinary
+ * @stable ICU 3.4
+ */
+ int32_t cloneBinary(uint8_t *buffer, int32_t capacity, UErrorCode &status);
+
+ /**
+ * Returns current rules. Delta defines whether full rules are returned or
+ * just the tailoring.
+ * @param delta one of UCOL_TAILORING_ONLY, UCOL_FULL_RULES.
+ * @param buffer UnicodeString to store the result rules
+ * @stable ICU 2.2
+ */
+ void getRules(UColRuleOption delta, UnicodeString &buffer);
+
+ /**
+ * Universal attribute setter
+ * @param attr attribute type
+ * @param value attribute value
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @stable ICU 2.2
+ */
+ virtual void setAttribute(UColAttribute attr, UColAttributeValue value,
+ UErrorCode &status);
+
+ /**
+ * Universal attribute getter.
+ * @param attr attribute type
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @return attribute value
+ * @stable ICU 2.2
+ */
+ virtual UColAttributeValue getAttribute(UColAttribute attr,
+ UErrorCode &status);
+
+ /**
+ * Sets the variable top to a collation element value of a string supplied.
+ * @param varTop one or more (if contraction) UChars to which the variable top should be set
+ * @param len length of variable top string. If -1 it is considered to be zero terminated.
+ * @param status error code. If error code is set, the return value is undefined. Errors set by this function are: <br>
+ * U_CE_NOT_FOUND_ERROR if more than one character was passed and there is no such a contraction<br>
+ * U_PRIMARY_TOO_LONG_ERROR if the primary for the variable top has more than two bytes
+ * @return a 32 bit value containing the value of the variable top in upper 16 bits. Lower 16 bits are undefined
+ * @stable ICU 2.0
+ */
+ virtual uint32_t setVariableTop(const UChar *varTop, int32_t len, UErrorCode &status);
+
+ /**
+ * Sets the variable top to a collation element value of a string supplied.
+ * @param varTop an UnicodeString size 1 or more (if contraction) of UChars to which the variable top should be set
+ * @param status error code. If error code is set, the return value is undefined. Errors set by this function are: <br>
+ * U_CE_NOT_FOUND_ERROR if more than one character was passed and there is no such a contraction<br>
+ * U_PRIMARY_TOO_LONG_ERROR if the primary for the variable top has more than two bytes
+ * @return a 32 bit value containing the value of the variable top in upper 16 bits. Lower 16 bits are undefined
+ * @stable ICU 2.0
+ */
+ virtual uint32_t setVariableTop(const UnicodeString varTop, UErrorCode &status);
+
+ /**
+ * Sets the variable top to a collation element value supplied. Variable top is set to the upper 16 bits.
+ * Lower 16 bits are ignored.
+ * @param varTop CE value, as returned by setVariableTop or ucol)getVariableTop
+ * @param status error code (not changed by function)
+ * @stable ICU 2.0
+ */
+ virtual void setVariableTop(const uint32_t varTop, UErrorCode &status);
+
+ /**
+ * Gets the variable top value of a Collator.
+ * Lower 16 bits are undefined and should be ignored.
+ * @param status error code (not changed by function). If error code is set, the return value is undefined.
+ * @stable ICU 2.0
+ */
+ virtual uint32_t getVariableTop(UErrorCode &status) const;
+
+ /**
+ * Get an UnicodeSet that contains all the characters and sequences tailored in
+ * this collator.
+ * @param status error code of the operation
+ * @return a pointer to a UnicodeSet object containing all the
+ * code points and sequences that may sort differently than
+ * in the UCA. The object must be disposed of by using delete
+ * @stable ICU 2.4
+ */
+ virtual UnicodeSet *getTailoredSet(UErrorCode &status) const;
+
+ /**
+ * Thread safe cloning operation.
+ * @return pointer to the new clone, user should remove it.
+ * @stable ICU 2.2
+ */
+ virtual Collator* safeClone(void);
+
+ /**
+ * Get the sort key as an array of bytes from an UnicodeString.
+ * @param source string to be processed.
+ * @param result buffer to store result in. If NULL, number of bytes needed
+ * will be returned.
+ * @param resultLength length of the result buffer. If if not enough the
+ * buffer will be filled to capacity.
+ * @return Number of bytes needed for storing the sort key
+ * @stable ICU 2.0
+ */
+ virtual int32_t getSortKey(const UnicodeString& source, uint8_t *result,
+ int32_t resultLength) const;
+
+ /**
+ * Get the sort key as an array of bytes from an UChar buffer.
+ * @param source string to be processed.
+ * @param sourceLength length of string to be processed. If -1, the string
+ * is 0 terminated and length will be decided by the function.
+ * @param result buffer to store result in. If NULL, number of bytes needed
+ * will be returned.
+ * @param resultLength length of the result buffer. If if not enough the
+ * buffer will be filled to capacity.
+ * @return Number of bytes needed for storing the sort key
+ * @stable ICU 2.2
+ */
+ virtual int32_t getSortKey(const UChar *source, int32_t sourceLength,
+ uint8_t *result, int32_t resultLength) const;
+
+ /**
+ * Determines the minimum strength that will be use in comparison or
+ * transformation.
+ * <p>E.g. with strength == SECONDARY, the tertiary difference is ignored
+ * <p>E.g. with strength == PRIMARY, the secondary and tertiary difference
+ * are ignored.
+ * @return the current comparison level.
+ * @see RuleBasedCollator#setStrength
+ * @deprecated ICU 2.6 Use getAttribute(UCOL_STRENGTH...) instead
+ */
+ virtual ECollationStrength getStrength(void) const;
+
+ /**
+ * Sets the minimum strength to be used in comparison or transformation.
+ * @see RuleBasedCollator#getStrength
+ * @param newStrength the new comparison level.
+ * @deprecated ICU 2.6 Use setAttribute(UCOL_STRENGTH...) instead
+ */
+ virtual void setStrength(ECollationStrength newStrength);
+
+private:
+
+ // private static constants -----------------------------------------------
+
+ enum {
+ /* need look up in .commit() */
+ CHARINDEX = 0x70000000,
+ /* Expand index follows */
+ EXPANDCHARINDEX = 0x7E000000,
+ /* contract indexes follows */
+ CONTRACTCHARINDEX = 0x7F000000,
+ /* unmapped character values */
+ UNMAPPED = 0xFFFFFFFF,
+ /* primary strength increment */
+ PRIMARYORDERINCREMENT = 0x00010000,
+ /* secondary strength increment */
+ SECONDARYORDERINCREMENT = 0x00000100,
+ /* tertiary strength increment */
+ TERTIARYORDERINCREMENT = 0x00000001,
+ /* mask off anything but primary order */
+ PRIMARYORDERMASK = 0xffff0000,
+ /* mask off anything but secondary order */
+ SECONDARYORDERMASK = 0x0000ff00,
+ /* mask off anything but tertiary order */
+ TERTIARYORDERMASK = 0x000000ff,
+ /* mask off ignorable char order */
+ IGNORABLEMASK = 0x0000ffff,
+ /* use only the primary difference */
+ PRIMARYDIFFERENCEONLY = 0xffff0000,
+ /* use only the primary and secondary difference */
+ SECONDARYDIFFERENCEONLY = 0xffffff00,
+ /* primary order shift */
+ PRIMARYORDERSHIFT = 16,
+ /* secondary order shift */
+ SECONDARYORDERSHIFT = 8,
+ /* starting value for collation elements */
+ COLELEMENTSTART = 0x02020202,
+ /* testing mask for primary low element */
+ PRIMARYLOWZEROMASK = 0x00FF0000,
+ /* reseting value for secondaries and tertiaries */
+ RESETSECONDARYTERTIARY = 0x00000202,
+ /* reseting value for tertiaries */
+ RESETTERTIARY = 0x00000002,
+
+ PRIMIGNORABLE = 0x0202
+ };
+
+ // private data members ---------------------------------------------------
+
+ UBool dataIsOwned;
+
+ UBool isWriteThroughAlias;
+
+ /**
+ * c struct for collation. All initialisation for it has to be done through
+ * setUCollator().
+ */
+ UCollator *ucollator;
+
+ /**
+ * Rule UnicodeString
+ */
+ UnicodeString urulestring;
+
+ // friend classes --------------------------------------------------------
+
+ /**
+ * Used to iterate over collation elements in a character source.
+ */
+ friend class CollationElementIterator;
+
+ /**
+ * Collator ONLY needs access to RuleBasedCollator(const Locale&,
+ * UErrorCode&)
+ */
+ friend class Collator;
+
+ /**
+ * Searching over collation elements in a character source
+ */
+ friend class StringSearch;
+
+ // private constructors --------------------------------------------------
+
+ /**
+ * Default constructor
+ */
+ RuleBasedCollator();
+
+ /**
+ * RuleBasedCollator constructor. This constructor takes a locale. The
+ * only caller of this class should be Collator::createInstance(). If
+ * createInstance() happens to know that the requested locale's collation is
+ * implemented as a RuleBasedCollator, it can then call this constructor.
+ * OTHERWISE IT SHOULDN'T, since this constructor ALWAYS RETURNS A VALID
+ * COLLATION TABLE. It does this by falling back to defaults.
+ * @param desiredLocale locale used
+ * @param status error code status
+ */
+ RuleBasedCollator(const Locale& desiredLocale, UErrorCode& status);
+
+ /**
+ * common constructor implementation
+ *
+ * @param rules the collation rules to build the collation table from.
+ * @param collationStrength default strength for comparison
+ * @param decompositionMode the normalisation mode
+ * @param status reporting a success or an error.
+ */
+ void
+ construct(const UnicodeString& rules,
+ UColAttributeValue collationStrength,
+ UColAttributeValue decompositionMode,
+ UErrorCode& status);
+
+ // private methods -------------------------------------------------------
+
+ /**
+ * Creates the c struct for ucollator
+ * @param locale desired locale
+ * @param status error status
+ */
+ void setUCollator(const Locale& locale, UErrorCode& status);
+
+ /**
+ * Creates the c struct for ucollator
+ * @param locale desired locale name
+ * @param status error status
+ */
+ void setUCollator(const char* locale, UErrorCode& status);
+
+ /**
+ * Creates the c struct for ucollator. This used internally by StringSearch.
+ * Hence the responsibility of cleaning up the ucollator is not done by
+ * this RuleBasedCollator. The isDataOwned flag is set to FALSE.
+ * @param collator new ucollator data
+ * @param rules corresponding collation rules
+ */
+ void setUCollator(UCollator *collator);
+
+public:
+ /**
+ * Get UCollator data struct. Used only by StringSearch & intltest.
+ * @return UCollator data struct
+ * @internal
+ */
+ const UCollator * getUCollator();
+
+protected:
+ /**
+ * Used internally by registraton to define the requested and valid locales.
+ * @param requestedLocale the requsted locale
+ * @param validLocale the valid locale
+ * @internal
+ */
+ virtual void setLocales(const Locale& requestedLocale, const Locale& validLocale);
+
+private:
+
+ // if not owned and not a write through alias, copy the ucollator
+ void checkOwned(void);
+
+ // utility to init rule string used by checkOwned and construct
+ void setRuleStringFromCollator();
+
+ /**
+ * Converts C's UCollationResult to EComparisonResult
+ * @param result member of the enum UComparisonResult
+ * @return EComparisonResult equivalent of UCollationResult
+ * @deprecated ICU 2.6. We will not need it.
+ */
+ Collator::EComparisonResult getEComparisonResult(
+ const UCollationResult &result) const;
+
+ /**
+ * Converts C's UCollationStrength to ECollationStrength
+ * @param strength member of the enum UCollationStrength
+ * @return ECollationStrength equivalent of UCollationStrength
+ */
+ Collator::ECollationStrength getECollationStrength(
+ const UCollationStrength &strength) const;
+
+ /**
+ * Converts C++'s ECollationStrength to UCollationStrength
+ * @param strength member of the enum ECollationStrength
+ * @return UCollationStrength equivalent of ECollationStrength
+ */
+ UCollationStrength getUCollationStrength(
+ const Collator::ECollationStrength &strength) const;
+};
+
+// inline method implementation ---------------------------------------------
+
+inline void RuleBasedCollator::setUCollator(const Locale &locale,
+ UErrorCode &status)
+{
+ setUCollator(locale.getName(), status);
+}
+
+
+inline void RuleBasedCollator::setUCollator(UCollator *collator)
+{
+
+ if (ucollator && dataIsOwned) {
+ ucol_close(ucollator);
+ }
+ ucollator = collator;
+ dataIsOwned = FALSE;
+ isWriteThroughAlias = TRUE;
+ setRuleStringFromCollator();
+}
+
+inline const UCollator * RuleBasedCollator::getUCollator()
+{
+ return ucollator;
+}
+
+inline Collator::EComparisonResult RuleBasedCollator::getEComparisonResult(
+ const UCollationResult &result) const
+{
+ switch (result)
+ {
+ case UCOL_LESS :
+ return Collator::LESS;
+ case UCOL_EQUAL :
+ return Collator::EQUAL;
+ default :
+ return Collator::GREATER;
+ }
+}
+
+inline Collator::ECollationStrength RuleBasedCollator::getECollationStrength(
+ const UCollationStrength &strength) const
+{
+ switch (strength)
+ {
+ case UCOL_PRIMARY :
+ return Collator::PRIMARY;
+ case UCOL_SECONDARY :
+ return Collator::SECONDARY;
+ case UCOL_TERTIARY :
+ return Collator::TERTIARY;
+ case UCOL_QUATERNARY :
+ return Collator::QUATERNARY;
+ default :
+ return Collator::IDENTICAL;
+ }
+}
+
+inline UCollationStrength RuleBasedCollator::getUCollationStrength(
+ const Collator::ECollationStrength &strength) const
+{
+ switch (strength)
+ {
+ case Collator::PRIMARY :
+ return UCOL_PRIMARY;
+ case Collator::SECONDARY :
+ return UCOL_SECONDARY;
+ case Collator::TERTIARY :
+ return UCOL_TERTIARY;
+ case Collator::QUATERNARY :
+ return UCOL_QUATERNARY;
+ default :
+ return UCOL_IDENTICAL;
+ }
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/timezone.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/timezone.h
new file mode 100644
index 00000000000..e771cb90855
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/timezone.h
@@ -0,0 +1,726 @@
+/*************************************************************************
+* Copyright (c) 1997-2007, International Business Machines Corporation
+* and others. All Rights Reserved.
+**************************************************************************
+*
+* File TIMEZONE.H
+*
+* Modification History:
+*
+* Date Name Description
+* 04/21/97 aliu Overhauled header.
+* 07/09/97 helena Changed createInstance to createDefault.
+* 08/06/97 aliu Removed dependency on internal header for Hashtable.
+* 08/10/98 stephen Changed getDisplayName() API conventions to match
+* 08/19/98 stephen Changed createTimeZone() to never return 0
+* 09/02/98 stephen Sync to JDK 1.2 8/31
+* - Added getOffset(... monthlen ...)
+* - Added hasSameRules()
+* 09/15/98 stephen Added getStaticClassID
+* 12/03/99 aliu Moved data out of static table into icudata.dll.
+* Hashtable replaced by new static data structures.
+* 12/14/99 aliu Made GMT public.
+* 08/15/01 grhoten Made GMT private and added the getGMT() function
+**************************************************************************
+*/
+
+#ifndef TIMEZONE_H
+#define TIMEZONE_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: TimeZone object
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/ures.h"
+
+U_NAMESPACE_BEGIN
+
+class StringEnumeration;
+
+/**
+ *
+ * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
+ * savings.
+ *
+ * <p>
+ * Typically, you get a <code>TimeZone</code> using <code>createDefault</code>
+ * which creates a <code>TimeZone</code> based on the time zone where the program
+ * is running. For example, for a program running in Japan, <code>createDefault</code>
+ * creates a <code>TimeZone</code> object based on Japanese Standard Time.
+ *
+ * <p>
+ * You can also get a <code>TimeZone</code> using <code>createTimeZone</code> along
+ * with a time zone ID. For instance, the time zone ID for the Pacific
+ * Standard Time zone is "PST". So, you can get a PST <code>TimeZone</code> object
+ * with:
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * TimeZone *tz = TimeZone::createTimeZone("PST");
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ * You can use <code>getAvailableIDs</code> method to iterate through
+ * all the supported time zone IDs. You can then choose a
+ * supported ID to get a <code>TimeZone</code>.
+ * If the time zone you want is not represented by one of the
+ * supported IDs, then you can create a custom time zone ID with
+ * the following syntax:
+ *
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * GMT[+|-]hh[[:]mm]
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * For example, you might specify GMT+14:00 as a custom
+ * time zone ID. The <code>TimeZone</code> that is returned
+ * when you specify a custom time zone ID does not include
+ * daylight savings time.
+ *
+ * TimeZone is an abstract class representing a time zone. A TimeZone is needed for
+ * Calendar to produce local time for a particular time zone. A TimeZone comprises
+ * three basic pieces of information:
+ * <ul>
+ * <li>A time zone offset; that, is the number of milliseconds to add or subtract
+ * from a time expressed in terms of GMT to convert it to the same time in that
+ * time zone (without taking daylight savings time into account).</li>
+ * <li>Logic necessary to take daylight savings time into account if daylight savings
+ * time is observed in that time zone (e.g., the days and hours on which daylight
+ * savings time begins and ends).</li>
+ * <li>An ID. This is a text string that uniquely identifies the time zone.</li>
+ * </ul>
+ *
+ * (Only the ID is actually implemented in TimeZone; subclasses of TimeZone may handle
+ * daylight savings time and GMT offset in different ways. Currently we only have one
+ * TimeZone subclass: SimpleTimeZone.)
+ * <P>
+ * The TimeZone class contains a static list containing a TimeZone object for every
+ * combination of GMT offset and daylight-savings time rules currently in use in the
+ * world, each with a unique ID. Each ID consists of a region (usually a continent or
+ * ocean) and a city in that region, separated by a slash, (for example, Pacific
+ * Standard Time is "America/Los_Angeles.") Because older versions of this class used
+ * three- or four-letter abbreviations instead, there is also a table that maps the older
+ * abbreviations to the newer ones (for example, "PST" maps to "America/LosAngeles").
+ * Anywhere the API requires an ID, you can use either form.
+ * <P>
+ * To create a new TimeZone, you call the factory function TimeZone::createTimeZone()
+ * and pass it a time zone ID. You can use the createEnumeration() function to
+ * obtain a list of all the time zone IDs recognized by createTimeZone().
+ * <P>
+ * You can also use TimeZone::createDefault() to create a TimeZone. This function uses
+ * platform-specific APIs to produce a TimeZone for the time zone corresponding to
+ * the client's computer's physical location. For example, if you're in Japan (assuming
+ * your machine is set up correctly), TimeZone::createDefault() will return a TimeZone
+ * for Japanese Standard Time ("Asia/Tokyo").
+ */
+class U_I18N_API TimeZone : public UObject {
+public:
+ /**
+ * @stable ICU 2.0
+ */
+ virtual ~TimeZone();
+
+ /**
+ * The GMT time zone has a raw offset of zero and does not use daylight
+ * savings time. This is a commonly used time zone.
+ * @return the GMT time zone.
+ * @stable ICU 2.0
+ */
+ static const TimeZone* U_EXPORT2 getGMT(void);
+
+ /**
+ * Creates a <code>TimeZone</code> for the given ID.
+ * @param ID the ID for a <code>TimeZone</code>, either an abbreviation such as
+ * "PST", a full name such as "America/Los_Angeles", or a custom ID
+ * such as "GMT-8:00".
+ * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
+ * cannot be understood. Return result guaranteed to be non-null. If you
+ * require that the specific zone asked for be returned, check the ID of the
+ * return result.
+ * @stable ICU 2.0
+ */
+ static TimeZone* U_EXPORT2 createTimeZone(const UnicodeString& ID);
+
+ /**
+ * Returns an enumeration over all recognized time zone IDs. (i.e.,
+ * all strings that createTimeZone() accepts)
+ *
+ * @return an enumeration object, owned by the caller.
+ * @stable ICU 2.4
+ */
+ static StringEnumeration* U_EXPORT2 createEnumeration();
+
+ /**
+ * Returns an enumeration over time zone IDs with a given raw
+ * offset from GMT. There may be several times zones with the
+ * same GMT offset that differ in the way they handle daylight
+ * savings time. For example, the state of Arizona doesn't
+ * observe daylight savings time. If you ask for the time zone
+ * IDs corresponding to GMT-7:00, you'll get back an enumeration
+ * over two time zone IDs: "America/Denver," which corresponds to
+ * Mountain Standard Time in the winter and Mountain Daylight Time
+ * in the summer, and "America/Phoenix", which corresponds to
+ * Mountain Standard Time year-round, even in the summer.
+ *
+ * @param rawOffset an offset from GMT in milliseconds, ignoring
+ * the effect of daylight savings time, if any
+ * @return an enumeration object, owned by the caller
+ * @stable ICU 2.4
+ */
+ static StringEnumeration* U_EXPORT2 createEnumeration(int32_t rawOffset);
+
+ /**
+ * Returns an enumeration over time zone IDs associated with the
+ * given country. Some zones are affiliated with no country
+ * (e.g., "UTC"); these may also be retrieved, as a group.
+ *
+ * @param country The ISO 3166 two-letter country code, or NULL to
+ * retrieve zones not affiliated with any country.
+ * @return an enumeration object, owned by the caller
+ * @stable ICU 2.4
+ */
+ static StringEnumeration* U_EXPORT2 createEnumeration(const char* country);
+
+#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
+ /**
+ * Returns a list of time zone IDs, one for each time zone with a given GMT offset.
+ * The return value is a list because there may be several times zones with the same
+ * GMT offset that differ in the way they handle daylight savings time. For example,
+ * the state of Arizona doesn't observe Daylight Savings time. So if you ask for
+ * the time zone IDs corresponding to GMT-7:00, you'll get back two time zone IDs:
+ * "America/Denver," which corresponds to Mountain Standard Time in the winter and
+ * Mountain Daylight Time in the summer, and "America/Phoenix", which corresponds to
+ * Mountain Standard Time year-round, even in the summer.
+ * <P>
+ * The caller owns the list that is returned, but does not own the strings contained
+ * in that list. Delete the array with uprv_free(), but DON'T delete the elements in the array.
+ *
+ * <p>NOTE: uprv_free() is declared in the private header source/common/cmemory.h.
+ *
+ * @param rawOffset An offset from GMT in milliseconds.
+ * @param numIDs Receives the number of items in the array that is returned.
+ * @return An array of UnicodeString pointers, where each UnicodeString is
+ * a time zone ID for a time zone with the given GMT offset. If
+ * there is no timezone that matches the GMT offset
+ * specified, NULL is returned.
+ * @obsolete ICU 2.8. Use createEnumeration(int32_t) instead since this API will be removed in that release.
+ */
+ static const UnicodeString** createAvailableIDs(int32_t rawOffset, int32_t& numIDs);
+
+ /**
+ * Returns a list of time zone IDs associated with the given
+ * country. Some zones are affiliated with no country (e.g.,
+ * "UTC"); these may also be retrieved, as a group.
+ *
+ * <P>The caller owns the list that is returned, but does not own
+ * the strings contained in that list. Delete the array with uprv_free(), but
+ * <b>DON'T</b> delete the elements in the array.
+ *
+ * <p>NOTE: uprv_free() is declared in the private header source/common/cmemory.h.
+ *
+ * @param country The ISO 3166 two-letter country code, or NULL to
+ * retrieve zones not affiliated with any country.
+ * @param numIDs Receives the number of items in the array that is
+ * returned.
+ * @return An array of UnicodeString pointers, where each
+ * UnicodeString is a time zone ID for a time zone with the given
+ * country. If there is no timezone that matches the country
+ * specified, NULL is returned.
+ * @obsolete ICU 2.8. Use createEnumeration(const char*) instead since this API will be removed in that release.
+ */
+ static const UnicodeString** createAvailableIDs(const char* country,
+ int32_t& numIDs);
+
+ /**
+ * Returns a list of all time zone IDs supported by the TimeZone class (i.e., all
+ * IDs that it's legal to pass to createTimeZone()). The caller owns the list that
+ * is returned, but does not own the strings contained in that list. Delete the array with uprv_free(),
+ * but DON'T delete the elements in the array.
+ *
+ * <p>NOTE: uprv_free() is declared in the private header source/common/cmemory.h.
+ *
+ * @param numIDs Receives the number of zone IDs returned.
+ * @return An array of UnicodeString pointers, where each is a time zone ID
+ * supported by the TimeZone class.
+ * @obsolete ICU 2.8. Use createEnumeration(void) instead since this API will be removed in that release.
+ */
+ static const UnicodeString** createAvailableIDs(int32_t& numIDs);
+#endif
+
+ /**
+ * Returns the number of IDs in the equivalency group that
+ * includes the given ID. An equivalency group contains zones
+ * that have the same GMT offset and rules.
+ *
+ * <p>The returned count includes the given ID; it is always >= 1.
+ * The given ID must be a system time zone. If it is not, returns
+ * zero.
+ * @param id a system time zone ID
+ * @return the number of zones in the equivalency group containing
+ * 'id', or zero if 'id' is not a valid system ID
+ * @see #getEquivalentID
+ * @stable ICU 2.0
+ */
+ static int32_t U_EXPORT2 countEquivalentIDs(const UnicodeString& id);
+
+ /**
+ * Returns an ID in the equivalency group that
+ * includes the given ID. An equivalency group contains zones
+ * that have the same GMT offset and rules.
+ *
+ * <p>The given index must be in the range 0..n-1, where n is the
+ * value returned by <code>countEquivalentIDs(id)</code>. For
+ * some value of 'index', the returned value will be equal to the
+ * given id. If the given id is not a valid system time zone, or
+ * if 'index' is out of range, then returns an empty string.
+ * @param id a system time zone ID
+ * @param index a value from 0 to n-1, where n is the value
+ * returned by <code>countEquivalentIDs(id)</code>
+ * @return the ID of the index-th zone in the equivalency group
+ * containing 'id', or an empty string if 'id' is not a valid
+ * system ID or 'index' is out of range
+ * @see #countEquivalentIDs
+ * @stable ICU 2.0
+ */
+ static const UnicodeString U_EXPORT2 getEquivalentID(const UnicodeString& id,
+ int32_t index);
+
+ /**
+ * Creates a new copy of the default TimeZone for this host. Unless the default time
+ * zone has already been set using adoptDefault() or setDefault(), the default is
+ * determined by querying the system using methods in TPlatformUtilities. If the
+ * system routines fail, or if they specify a TimeZone or TimeZone offset which is not
+ * recognized, the TimeZone indicated by the ID kLastResortID is instantiated
+ * and made the default.
+ *
+ * @return A default TimeZone. Clients are responsible for deleting the time zone
+ * object returned.
+ * @stable ICU 2.0
+ */
+ static TimeZone* U_EXPORT2 createDefault(void);
+
+ /**
+ * Sets the default time zone (i.e., what's returned by createDefault()) to be the
+ * specified time zone. If NULL is specified for the time zone, the default time
+ * zone is set to the default host time zone. This call adopts the TimeZone object
+ * passed in; the clent is no longer responsible for deleting it.
+ *
+ * @param zone A pointer to the new TimeZone object to use as the default.
+ * @stable ICU 2.0
+ */
+ static void U_EXPORT2 adoptDefault(TimeZone* zone);
+
+ /**
+ * Same as adoptDefault(), except that the TimeZone object passed in is NOT adopted;
+ * the caller remains responsible for deleting it.
+ *
+ * @param zone The given timezone.
+ * @system
+ */
+ static void U_EXPORT2 setDefault(const TimeZone& zone);
+
+ /**
+ * Returns the timezone data version currently used by ICU.
+ * @param status Output param to filled in with a success or an error.
+ * @return the version string, such as "2007f"
+ * @draft ICU 3.8
+ */
+ static const char* U_EXPORT2 getTZDataVersion(UErrorCode& status);
+
+ /**
+ * Returns true if the two TimeZones are equal. (The TimeZone version only compares
+ * IDs, but subclasses are expected to also compare the fields they add.)
+ *
+ * @param that The TimeZone object to be compared with.
+ * @return True if the given TimeZone is equal to this TimeZone; false
+ * otherwise.
+ * @stable ICU 2.0
+ */
+ virtual UBool operator==(const TimeZone& that) const;
+
+ /**
+ * Returns true if the two TimeZones are NOT equal; that is, if operator==() returns
+ * false.
+ *
+ * @param that The TimeZone object to be compared with.
+ * @return True if the given TimeZone is not equal to this TimeZone; false
+ * otherwise.
+ * @stable ICU 2.0
+ */
+ UBool operator!=(const TimeZone& that) const {return !operator==(that);}
+
+ /**
+ * Returns the TimeZone's adjusted GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time in this time zone, taking daylight savings time into
+ * account) as of a particular reference date. The reference date is used to determine
+ * whether daylight savings time is in effect and needs to be figured into the offset
+ * that is returned (in other words, what is the adjusted GMT offset in this time zone
+ * at this particular date and time?). For the time zones produced by createTimeZone(),
+ * the reference data is specified according to the Gregorian calendar, and the date
+ * and time fields are local standard time.
+ *
+ * <p>Note: Don't call this method. Instead, call the getOffset(UDate...) overload,
+ * which returns both the raw and the DST offset for a given time. This method
+ * is retained only for backward compatibility.
+ *
+ * @param era The reference date's era
+ * @param year The reference date's year
+ * @param month The reference date's month (0-based; 0 is January)
+ * @param day The reference date's day-in-month (1-based)
+ * @param dayOfWeek The reference date's day-of-week (1-based; 1 is Sunday)
+ * @param millis The reference date's milliseconds in day, local standard time
+ * @param status Output param to filled in with a success or an error.
+ * @return The offset in milliseconds to add to GMT to get local time.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const = 0;
+
+ /**
+ * Gets the time zone offset, for current date, modified in case of
+ * daylight savings. This is the offset to add *to* UTC to get local time.
+ *
+ * <p>Note: Don't call this method. Instead, call the getOffset(UDate...) overload,
+ * which returns both the raw and the DST offset for a given time. This method
+ * is retained only for backward compatibility.
+ *
+ * @param era the era of the given date.
+ * @param year the year in the given date.
+ * @param month the month in the given date.
+ * Month is 0-based. e.g., 0 for January.
+ * @param day the day-in-month of the given date.
+ * @param dayOfWeek the day-of-week of the given date.
+ * @param milliseconds the millis in day in <em>standard</em> local time.
+ * @param monthLength the length of the given month in days.
+ * @param status Output param to filled in with a success or an error.
+ * @return the offset to add *to* GMT to get local time.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t milliseconds,
+ int32_t monthLength, UErrorCode& status) const = 0;
+
+ /**
+ * Returns the time zone raw and GMT offset for the given moment
+ * in time. Upon return, local-millis = GMT-millis + rawOffset +
+ * dstOffset. All computations are performed in the proleptic
+ * Gregorian calendar. The default implementation in the TimeZone
+ * class delegates to the 8-argument getOffset().
+ *
+ * @param date moment in time for which to return offsets, in
+ * units of milliseconds from January 1, 1970 0:00 GMT, either GMT
+ * time or local wall time, depending on `local'.
+ * @param local if true, `date' is local wall time; otherwise it
+ * is in GMT time.
+ * @param rawOffset output parameter to receive the raw offset, that
+ * is, the offset not including DST adjustments
+ * @param dstOffset output parameter to receive the DST offset,
+ * that is, the offset to be added to `rawOffset' to obtain the
+ * total offset between local and GMT time. If DST is not in
+ * effect, this value is zero; otherwise it is a positive value,
+ * typically one hour.
+ * @param ec input-output error code
+ *
+ * @stable ICU 2.8
+ */
+ virtual void getOffset(UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& ec) const;
+
+ /**
+ * Sets the TimeZone's raw GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time, before taking daylight savings time into account).
+ *
+ * @param offsetMillis The new raw GMT offset for this time zone.
+ * @stable ICU 2.0
+ */
+ virtual void setRawOffset(int32_t offsetMillis) = 0;
+
+ /**
+ * Returns the TimeZone's raw GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time, before taking daylight savings time into account).
+ *
+ * @return The TimeZone's raw GMT offset.
+ * @stable ICU 2.0
+ */
+ virtual int32_t getRawOffset(void) const = 0;
+
+ /**
+ * Fills in "ID" with the TimeZone's ID.
+ *
+ * @param ID Receives this TimeZone's ID.
+ * @return A reference to 'ID'
+ * @stable ICU 2.0
+ */
+ UnicodeString& getID(UnicodeString& ID) const;
+
+ /**
+ * Sets the TimeZone's ID to the specified value. This doesn't affect any other
+ * fields (for example, if you say<
+ * blockquote><pre>
+ * . TimeZone* foo = TimeZone::createTimeZone("America/New_York");
+ * . foo.setID("America/Los_Angeles");
+ * </pre>\htmlonly</blockquote>\endhtmlonly
+ * the time zone's GMT offset and daylight-savings rules don't change to those for
+ * Los Angeles. They're still those for New York. Only the ID has changed.)
+ *
+ * @param ID The new timezone ID.
+ * @stable ICU 2.0
+ */
+ void setID(const UnicodeString& ID);
+
+ /**
+ * Enum for use with getDisplayName
+ * @stable ICU 2.4
+ */
+ enum EDisplayType {
+ /**
+ * Selector for short display name
+ * @stable ICU 2.4
+ */
+ SHORT = 1,
+ /**
+ * Selector for long display name
+ * @stable ICU 2.4
+ */
+ LONG
+ };
+
+ /**
+ * Returns a name of this time zone suitable for presentation to the user
+ * in the default locale.
+ * This method returns the long name, not including daylight savings.
+ * If the display name is not available for the locale,
+ * then this method returns a string in the format
+ * <code>GMT[+-]hh:mm</code>.
+ * @param result the human-readable name of this time zone in the default locale.
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ UnicodeString& getDisplayName(UnicodeString& result) const;
+
+ /**
+ * Returns a name of this time zone suitable for presentation to the user
+ * in the specified locale.
+ * This method returns the long name, not including daylight savings.
+ * If the display name is not available for the locale,
+ * then this method returns a string in the format
+ * <code>GMT[+-]hh:mm</code>.
+ * @param locale the locale in which to supply the display name.
+ * @param result the human-readable name of this time zone in the given locale
+ * or in the default locale if the given locale is not recognized.
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ UnicodeString& getDisplayName(const Locale& locale, UnicodeString& result) const;
+
+ /**
+ * Returns a name of this time zone suitable for presentation to the user
+ * in the default locale.
+ * If the display name is not available for the locale,
+ * then this method returns a string in the format
+ * <code>GMT[+-]hh:mm</code>.
+ * @param daylight if true, return the daylight savings name.
+ * @param style either <code>LONG</code> or <code>SHORT</code>
+ * @param result the human-readable name of this time zone in the default locale.
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ UnicodeString& getDisplayName(UBool daylight, EDisplayType style, UnicodeString& result) const;
+
+ /**
+ * Returns a name of this time zone suitable for presentation to the user
+ * in the specified locale.
+ * If the display name is not available for the locale,
+ * then this method returns a string in the format
+ * <code>GMT[+-]hh:mm</code>.
+ * @param daylight if true, return the daylight savings name.
+ * @param style either <code>LONG</code> or <code>SHORT</code>
+ * @param locale the locale in which to supply the display name.
+ * @param result the human-readable name of this time zone in the given locale
+ * or in the default locale if the given locale is not recognized.
+ * @return A refence to 'result'.
+ * @stable ICU 2.0
+ */
+ UnicodeString& getDisplayName(UBool daylight, EDisplayType style, const Locale& locale, UnicodeString& result) const;
+
+ /**
+ * Queries if this time zone uses daylight savings time.
+ * @return true if this time zone uses daylight savings time,
+ * false, otherwise.
+ * @stable ICU 2.0
+ */
+ virtual UBool useDaylightTime(void) const = 0;
+
+ /**
+ * Queries if the given date is in daylight savings time in
+ * this time zone.
+ * This method is wasteful since it creates a new GregorianCalendar and
+ * deletes it each time it is called. This is a deprecated method
+ * and provided only for Java compatibility.
+ *
+ * @param date the given UDate.
+ * @param status Output param filled in with success/error code.
+ * @return true if the given date is in daylight savings time,
+ * false, otherwise.
+ * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
+ */
+ virtual UBool inDaylightTime(UDate date, UErrorCode& status) const = 0;
+
+ /**
+ * Returns true if this zone has the same rule and offset as another zone.
+ * That is, if this zone differs only in ID, if at all.
+ * @param other the <code>TimeZone</code> object to be compared with
+ * @return true if the given zone is the same as this one,
+ * with the possible exception of the ID
+ * @stable ICU 2.0
+ */
+ virtual UBool hasSameRules(const TimeZone& other) const;
+
+ /**
+ * Clones TimeZone objects polymorphically. Clients are responsible for deleting
+ * the TimeZone object cloned.
+ *
+ * @return A new copy of this TimeZone object.
+ * @stable ICU 2.0
+ */
+ virtual TimeZone* clone(void) const = 0;
+
+ /**
+ * Return the class ID for this class. This is useful only for
+ * comparing to a return value from getDynamicClassID().
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. This method is to
+ * implement a simple version of RTTI, since not all C++ compilers support genuine
+ * RTTI. Polymorphic operator==() and clone() methods call this method.
+ * <P>
+ * Concrete subclasses of TimeZone must use the UOBJECT_DEFINE_RTTI_IMPLEMENTATION
+ * macro from uobject.h in their implementation to provide correct RTTI information.
+ * @return The class ID for this object. All objects of a given class have the
+ * same class ID. Objects of other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const = 0;
+
+ /**
+ * Returns the amount of time to be added to local standard time
+ * to get local wall clock time.
+ * <p>
+ * The default implementation always returns 3600000 milliseconds
+ * (i.e., one hour) if this time zone observes Daylight Saving
+ * Time. Otherwise, 0 (zero) is returned.
+ * <p>
+ * If an underlying TimeZone implementation subclass supports
+ * historical Daylight Saving Time changes, this method returns
+ * the known latest daylight saving value.
+ *
+ * @return the amount of saving time in milliseconds
+ * @stable ICU 3.6
+ */
+ virtual int32_t getDSTSavings() const;
+
+protected:
+
+ /**
+ * Default constructor. ID is initialized to the empty string.
+ * @stable ICU 2.0
+ */
+ TimeZone();
+
+ /**
+ * Construct a timezone with a given ID.
+ * @param id a system time zone ID
+ * @stable ICU 2.0
+ */
+ TimeZone(const UnicodeString &id);
+
+ /**
+ * Copy constructor.
+ * @param source the object to be copied.
+ * @stable ICU 2.0
+ */
+ TimeZone(const TimeZone& source);
+
+ /**
+ * Default assignment operator.
+ * @param right the object to be copied.
+ * @stable ICU 2.0
+ */
+ TimeZone& operator=(const TimeZone& right);
+
+ /**
+ * Utility function. For internally loading rule data.
+ * @param top Top resource bundle for tz data
+ * @param ruleid ID of rule to load
+ * @param oldbundle Old bundle to reuse or NULL
+ * @param status Status parameter
+ * @return either a new bundle or *oldbundle
+ * @internal
+ */
+ static UResourceBundle* loadRule(const UResourceBundle* top, const UnicodeString& ruleid, UResourceBundle* oldbundle, UErrorCode&status);
+
+private:
+ friend class ZoneMeta;
+
+ /**
+ * Get a canonical Olson zone ID for the given ID. If the given ID is not valid,
+ * this method returns empty string as the result. If the given ID is a link, then the
+ * referenced ID (canonical ID) is returned.
+ */
+ static UnicodeString& getOlsonCanonicalID(const UnicodeString &id, UnicodeString &canonical);
+
+ static TimeZone* createCustomTimeZone(const UnicodeString&); // Creates a time zone based on the string.
+
+ /**
+ * Responsible for setting up DEFAULT_ZONE. Uses routines in TPlatformUtilities
+ * (i.e., platform-specific calls) to get the current system time zone. Failing
+ * that, uses the platform-specific default time zone. Failing that, uses GMT.
+ */
+ static void initDefault(void);
+
+ // See source file for documentation
+ /**
+ * Lookup the given name in our system zone table. If found,
+ * instantiate a new zone of that name and return it. If not
+ * found, return 0.
+ * @param name tthe given name of a system time zone.
+ * @return the timezone indicated by the 'name'.
+ */
+ static TimeZone* createSystemTimeZone(const UnicodeString& name);
+
+ UnicodeString fID; // this time zone's ID
+};
+
+
+// -------------------------------------
+
+inline UnicodeString&
+TimeZone::getID(UnicodeString& ID) const
+{
+ ID = fID;
+ return ID;
+}
+
+// -------------------------------------
+
+inline void
+TimeZone::setID(const UnicodeString& ID)
+{
+ fID = ID;
+}
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif //_TIMEZONE
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/translit.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/translit.h
new file mode 100644
index 00000000000..1dcbb9a884d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/translit.h
@@ -0,0 +1,1323 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/17/99 aliu Creation.
+**********************************************************************
+*/
+#ifndef TRANSLIT_H
+#define TRANSLIT_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: Tranforms text from one format to another.
+ */
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/parseerr.h"
+#include "unicode/utrans.h" // UTransPosition, UTransDirection
+#include "unicode/strenum.h"
+
+U_NAMESPACE_BEGIN
+
+class UnicodeFilter;
+class UnicodeSet;
+class CompoundTransliterator;
+class TransliteratorParser;
+class NormalizationTransliterator;
+class TransliteratorIDParser;
+
+/**
+ *
+ * <code>Transliterator</code> is an abstract class that
+ * transliterates text from one format to another. The most common
+ * kind of transliterator is a script, or alphabet, transliterator.
+ * For example, a Russian to Latin transliterator changes Russian text
+ * written in Cyrillic characters to phonetically equivalent Latin
+ * characters. It does not <em>translate</em> Russian to English!
+ * Transliteration, unlike translation, operates on characters, without
+ * reference to the meanings of words and sentences.
+ *
+ * <p>Although script conversion is its most common use, a
+ * transliterator can actually perform a more general class of tasks.
+ * In fact, <code>Transliterator</code> defines a very general API
+ * which specifies only that a segment of the input text is replaced
+ * by new text. The particulars of this conversion are determined
+ * entirely by subclasses of <code>Transliterator</code>.
+ *
+ * <p><b>Transliterators are stateless</b>
+ *
+ * <p><code>Transliterator</code> objects are <em>stateless</em>; they
+ * retain no information between calls to
+ * <code>transliterate()</code>. (However, this does <em>not</em>
+ * mean that threads may share transliterators without synchronizing
+ * them. Transliterators are not immutable, so they must be
+ * synchronized when shared between threads.) This1 might seem to
+ * limit the complexity of the transliteration operation. In
+ * practice, subclasses perform complex transliterations by delaying
+ * the replacement of text until it is known that no other
+ * replacements are possible. In other words, although the
+ * <code>Transliterator</code> objects are stateless, the source text
+ * itself embodies all the needed information, and delayed operation
+ * allows arbitrary complexity.
+ *
+ * <p><b>Batch transliteration</b>
+ *
+ * <p>The simplest way to perform transliteration is all at once, on a
+ * string of existing text. This is referred to as <em>batch</em>
+ * transliteration. For example, given a string <code>input</code>
+ * and a transliterator <code>t</code>, the call
+ *
+ * \htmlonly<blockquote>\endhtmlonly<code>String result = t.transliterate(input);
+ * </code>\htmlonly</blockquote>\endhtmlonly
+ *
+ * will transliterate it and return the result. Other methods allow
+ * the client to specify a substring to be transliterated and to use
+ * {@link Replaceable } objects instead of strings, in order to
+ * preserve out-of-band information (such as text styles).
+ *
+ * <p><b>Keyboard transliteration</b>
+ *
+ * <p>Somewhat more involved is <em>keyboard</em>, or incremental
+ * transliteration. This is the transliteration of text that is
+ * arriving from some source (typically the user's keyboard) one
+ * character at a time, or in some other piecemeal fashion.
+ *
+ * <p>In keyboard transliteration, a <code>Replaceable</code> buffer
+ * stores the text. As text is inserted, as much as possible is
+ * transliterated on the fly. This means a GUI that displays the
+ * contents of the buffer may show text being modified as each new
+ * character arrives.
+ *
+ * <p>Consider the simple <code>RuleBasedTransliterator</code>:
+ *
+ * \htmlonly<blockquote>\endhtmlonly<code>
+ * th&gt;{theta}<br>
+ * t&gt;{tau}
+ * </code>\htmlonly</blockquote>\endhtmlonly
+ *
+ * When the user types 't', nothing will happen, since the
+ * transliterator is waiting to see if the next character is 'h'. To
+ * remedy this, we introduce the notion of a cursor, marked by a '|'
+ * in the output string:
+ *
+ * \htmlonly<blockquote>\endhtmlonly<code>
+ * t&gt;|{tau}<br>
+ * {tau}h&gt;{theta}
+ * </code>\htmlonly</blockquote>\endhtmlonly
+ *
+ * Now when the user types 't', tau appears, and if the next character
+ * is 'h', the tau changes to a theta. This is accomplished by
+ * maintaining a cursor position (independent of the insertion point,
+ * and invisible in the GUI) across calls to
+ * <code>transliterate()</code>. Typically, the cursor will
+ * be coincident with the insertion point, but in a case like the one
+ * above, it will precede the insertion point.
+ *
+ * <p>Keyboard transliteration methods maintain a set of three indices
+ * that are updated with each call to
+ * <code>transliterate()</code>, including the cursor, start,
+ * and limit. Since these indices are changed by the method, they are
+ * passed in an <code>int[]</code> array. The <code>START</code> index
+ * marks the beginning of the substring that the transliterator will
+ * look at. It is advanced as text becomes committed (but it is not
+ * the committed index; that's the <code>CURSOR</code>). The
+ * <code>CURSOR</code> index, described above, marks the point at
+ * which the transliterator last stopped, either because it reached
+ * the end, or because it required more characters to disambiguate
+ * between possible inputs. The <code>CURSOR</code> can also be
+ * explicitly set by rules in a <code>RuleBasedTransliterator</code>.
+ * Any characters before the <code>CURSOR</code> index are frozen;
+ * future keyboard transliteration calls within this input sequence
+ * will not change them. New text is inserted at the
+ * <code>LIMIT</code> index, which marks the end of the substring that
+ * the transliterator looks at.
+ *
+ * <p>Because keyboard transliteration assumes that more characters
+ * are to arrive, it is conservative in its operation. It only
+ * transliterates when it can do so unambiguously. Otherwise it waits
+ * for more characters to arrive. When the client code knows that no
+ * more characters are forthcoming, perhaps because the user has
+ * performed some input termination operation, then it should call
+ * <code>finishTransliteration()</code> to complete any
+ * pending transliterations.
+ *
+ * <p><b>Inverses</b>
+ *
+ * <p>Pairs of transliterators may be inverses of one another. For
+ * example, if transliterator <b>A</b> transliterates characters by
+ * incrementing their Unicode value (so "abc" -> "def"), and
+ * transliterator <b>B</b> decrements character values, then <b>A</b>
+ * is an inverse of <b>B</b> and vice versa. If we compose <b>A</b>
+ * with <b>B</b> in a compound transliterator, the result is the
+ * indentity transliterator, that is, a transliterator that does not
+ * change its input text.
+ *
+ * The <code>Transliterator</code> method <code>getInverse()</code>
+ * returns a transliterator's inverse, if one exists, or
+ * <code>null</code> otherwise. However, the result of
+ * <code>getInverse()</code> usually will <em>not</em> be a true
+ * mathematical inverse. This is because true inverse transliterators
+ * are difficult to formulate. For example, consider two
+ * transliterators: <b>AB</b>, which transliterates the character 'A'
+ * to 'B', and <b>BA</b>, which transliterates 'B' to 'A'. It might
+ * seem that these are exact inverses, since
+ *
+ * \htmlonly<blockquote>\endhtmlonly"A" x <b>AB</b> -> "B"<br>
+ * "B" x <b>BA</b> -> "A"\htmlonly</blockquote>\endhtmlonly
+ *
+ * where 'x' represents transliteration. However,
+ *
+ * \htmlonly<blockquote>\endhtmlonly"ABCD" x <b>AB</b> -> "BBCD"<br>
+ * "BBCD" x <b>BA</b> -> "AACD"\htmlonly</blockquote>\endhtmlonly
+ *
+ * so <b>AB</b> composed with <b>BA</b> is not the
+ * identity. Nonetheless, <b>BA</b> may be usefully considered to be
+ * <b>AB</b>'s inverse, and it is on this basis that
+ * <b>AB</b><code>.getInverse()</code> could legitimately return
+ * <b>BA</b>.
+ *
+ * <p><b>IDs and display names</b>
+ *
+ * <p>A transliterator is designated by a short identifier string or
+ * <em>ID</em>. IDs follow the format <em>source-destination</em>,
+ * where <em>source</em> describes the entity being replaced, and
+ * <em>destination</em> describes the entity replacing
+ * <em>source</em>. The entities may be the names of scripts,
+ * particular sequences of characters, or whatever else it is that the
+ * transliterator converts to or from. For example, a transliterator
+ * from Russian to Latin might be named "Russian-Latin". A
+ * transliterator from keyboard escape sequences to Latin-1 characters
+ * might be named "KeyboardEscape-Latin1". By convention, system
+ * entity names are in English, with the initial letters of words
+ * capitalized; user entity names may follow any format so long as
+ * they do not contain dashes.
+ *
+ * <p>In addition to programmatic IDs, transliterator objects have
+ * display names for presentation in user interfaces, returned by
+ * {@link #getDisplayName }.
+ *
+ * <p><b>Factory methods and registration</b>
+ *
+ * <p>In general, client code should use the factory method
+ * {@link #createInstance } to obtain an instance of a
+ * transliterator given its ID. Valid IDs may be enumerated using
+ * <code>getAvailableIDs()</code>. Since transliterators are mutable,
+ * multiple calls to {@link #createInstance } with the same ID will
+ * return distinct objects.
+ *
+ * <p>In addition to the system transliterators registered at startup,
+ * user transliterators may be registered by calling
+ * <code>registerInstance()</code> at run time. A registered instance
+ * acts a template; future calls to {@link #createInstance } with the ID
+ * of the registered object return clones of that object. Thus any
+ * object passed to <tt>registerInstance()</tt> must implement
+ * <tt>clone()</tt> propertly. To register a transliterator subclass
+ * without instantiating it (until it is needed), users may call
+ * {@link #registerFactory }. In this case, the objects are
+ * instantiated by invoking the zero-argument public constructor of
+ * the class.
+ *
+ * <p><b>Subclassing</b>
+ *
+ * Subclasses must implement the abstract method
+ * <code>handleTransliterate()</code>. <p>Subclasses should override
+ * the <code>transliterate()</code> method taking a
+ * <code>Replaceable</code> and the <code>transliterate()</code>
+ * method taking a <code>String</code> and <code>StringBuffer</code>
+ * if the performance of these methods can be improved over the
+ * performance obtained by the default implementations in this class.
+ *
+ * @author Alan Liu
+ * @stable ICU 2.0
+ */
+class U_I18N_API Transliterator : public UObject {
+
+private:
+
+ /**
+ * Programmatic name, e.g., "Latin-Arabic".
+ */
+ UnicodeString ID;
+
+ /**
+ * This transliterator's filter. Any character for which
+ * <tt>filter.contains()</tt> returns <tt>false</tt> will not be
+ * altered by this transliterator. If <tt>filter</tt> is
+ * <tt>null</tt> then no filtering is applied.
+ */
+ UnicodeFilter* filter;
+
+ int32_t maximumContextLength;
+
+ public:
+
+ /**
+ * A context integer or pointer for a factory function, passed by
+ * value.
+ * @stable ICU 2.4
+ */
+ union Token {
+ /**
+ * This token, interpreted as a 32-bit integer.
+ * @stable ICU 2.4
+ */
+ int32_t integer;
+ /**
+ * This token, interpreted as a native pointer.
+ * @stable ICU 2.4
+ */
+ void* pointer;
+ };
+
+ /**
+ * Return a token containing an integer.
+ * @return a token containing an integer.
+ * @internal
+ */
+ inline static Token integerToken(int32_t);
+
+ /**
+ * Return a token containing a pointer.
+ * @return a token containing a pointer.
+ * @internal
+ */
+ inline static Token pointerToken(void*);
+
+ /**
+ * A function that creates and returns a Transliterator. When
+ * invoked, it will be passed the ID string that is being
+ * instantiated, together with the context pointer that was passed
+ * in when the factory function was first registered. Many
+ * factory functions will ignore both parameters, however,
+ * functions that are registered to more than one ID may use the
+ * ID or the context parameter to parameterize the transliterator
+ * they create.
+ * @param ID the string identifier for this transliterator
+ * @param context a context pointer that will be stored and
+ * later passed to the factory function when an ID matching
+ * the registration ID is being instantiated with this factory.
+ * @stable ICU 2.4
+ */
+ typedef Transliterator* (U_EXPORT2 *Factory)(const UnicodeString& ID, Token context);
+
+protected:
+
+ /**
+ * Default constructor.
+ * @param ID the string identifier for this transliterator
+ * @param adoptedFilter the filter. Any character for which
+ * <tt>filter.contains()</tt> returns <tt>false</tt> will not be
+ * altered by this transliterator. If <tt>filter</tt> is
+ * <tt>null</tt> then no filtering is applied.
+ * @stable ICU 2.4
+ */
+ Transliterator(const UnicodeString& ID, UnicodeFilter* adoptedFilter);
+
+ /**
+ * Copy constructor.
+ * @stable ICU 2.4
+ */
+ Transliterator(const Transliterator&);
+
+ /**
+ * Assignment operator.
+ * @stable ICU 2.4
+ */
+ Transliterator& operator=(const Transliterator&);
+
+ /**
+ * Create a transliterator from a basic ID. This is an ID
+ * containing only the forward direction source, target, and
+ * variant.
+ * @param id a basic ID of the form S-T or S-T/V.
+ * @param canon canonical ID to assign to the object, or
+ * NULL to leave the ID unchanged
+ * @return a newly created Transliterator or null if the ID is
+ * invalid.
+ * @stable ICU 2.4
+ */
+ static Transliterator* createBasicInstance(const UnicodeString& id,
+ const UnicodeString* canon);
+
+ friend class TransliteratorParser; // for parseID()
+ friend class TransliteratorIDParser; // for createBasicInstance()
+ friend class TransliteratorAlias; // for setID()
+
+public:
+
+ /**
+ * Destructor.
+ * @stable ICU 2.0
+ */
+ virtual ~Transliterator();
+
+ /**
+ * Implements Cloneable.
+ * All subclasses are encouraged to implement this method if it is
+ * possible and reasonable to do so. Subclasses that are to be
+ * registered with the system using <tt>registerInstance()</tt>
+ * are required to implement this method. If a subclass does not
+ * implement clone() properly and is registered with the system
+ * using registerInstance(), then the default clone() implementation
+ * will return null, and calls to createInstance() will fail.
+ *
+ * @return a copy of the object.
+ * @see #registerInstance
+ * @stable ICU 2.0
+ */
+ virtual Transliterator* clone() const;
+
+ /**
+ * Transliterates a segment of a string, with optional filtering.
+ *
+ * @param text the string to be transliterated
+ * @param start the beginning index, inclusive; <code>0 <= start
+ * <= limit</code>.
+ * @param limit the ending index, exclusive; <code>start <= limit
+ * <= text.length()</code>.
+ * @return The new limit index. The text previously occupying <code>[start,
+ * limit)</code> has been transliterated, possibly to a string of a different
+ * length, at <code>[start, </code><em>new-limit</em><code>)</code>, where
+ * <em>new-limit</em> is the return value. If the input offsets are out of bounds,
+ * the returned value is -1 and the input string remains unchanged.
+ * @stable ICU 2.0
+ */
+ virtual int32_t transliterate(Replaceable& text,
+ int32_t start, int32_t limit) const;
+
+ /**
+ * Transliterates an entire string in place. Convenience method.
+ * @param text the string to be transliterated
+ * @stable ICU 2.0
+ */
+ virtual void transliterate(Replaceable& text) const;
+
+ /**
+ * Transliterates the portion of the text buffer that can be
+ * transliterated unambiguosly after new text has been inserted,
+ * typically as a result of a keyboard event. The new text in
+ * <code>insertion</code> will be inserted into <code>text</code>
+ * at <code>index.limit</code>, advancing
+ * <code>index.limit</code> by <code>insertion.length()</code>.
+ * Then the transliterator will try to transliterate characters of
+ * <code>text</code> between <code>index.cursor</code> and
+ * <code>index.limit</code>. Characters before
+ * <code>index.cursor</code> will not be changed.
+ *
+ * <p>Upon return, values in <code>index</code> will be updated.
+ * <code>index.start</code> will be advanced to the first
+ * character that future calls to this method will read.
+ * <code>index.cursor</code> and <code>index.limit</code> will
+ * be adjusted to delimit the range of text that future calls to
+ * this method may change.
+ *
+ * <p>Typical usage of this method begins with an initial call
+ * with <code>index.start</code> and <code>index.limit</code>
+ * set to indicate the portion of <code>text</code> to be
+ * transliterated, and <code>index.cursor == index.start</code>.
+ * Thereafter, <code>index</code> can be used without
+ * modification in future calls, provided that all changes to
+ * <code>text</code> are made via this method.
+ *
+ * <p>This method assumes that future calls may be made that will
+ * insert new text into the buffer. As a result, it only performs
+ * unambiguous transliterations. After the last call to this
+ * method, there may be untransliterated text that is waiting for
+ * more input to resolve an ambiguity. In order to perform these
+ * pending transliterations, clients should call {@link
+ * #finishTransliteration } after the last call to this
+ * method has been made.
+ *
+ * @param text the buffer holding transliterated and untransliterated text
+ * @param index an array of three integers.
+ *
+ * <ul><li><code>index.start</code>: the beginning index,
+ * inclusive; <code>0 <= index.start <= index.limit</code>.
+ *
+ * <li><code>index.limit</code>: the ending index, exclusive;
+ * <code>index.start <= index.limit <= text.length()</code>.
+ * <code>insertion</code> is inserted at
+ * <code>index.limit</code>.
+ *
+ * <li><code>index.cursor</code>: the next character to be
+ * considered for transliteration; <code>index.start <=
+ * index.cursor <= index.limit</code>. Characters before
+ * <code>index.cursor</code> will not be changed by future calls
+ * to this method.</ul>
+ *
+ * @param insertion text to be inserted and possibly
+ * transliterated into the translation buffer at
+ * <code>index.limit</code>. If <code>null</code> then no text
+ * is inserted.
+ * @param status Output param to filled in with a success or an error.
+ * @see #handleTransliterate
+ * @exception IllegalArgumentException if <code>index</code>
+ * is invalid
+ * @see UTransPosition
+ * @stable ICU 2.0
+ */
+ virtual void transliterate(Replaceable& text, UTransPosition& index,
+ const UnicodeString& insertion,
+ UErrorCode& status) const;
+
+ /**
+ * Transliterates the portion of the text buffer that can be
+ * transliterated unambiguosly after a new character has been
+ * inserted, typically as a result of a keyboard event. This is a
+ * convenience method; see {@link
+ * #transliterate(Replaceable&, UTransPosition&, const UnicodeString&, UErrorCode&) const}
+ * for details.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param index an array of three integers. See {@link
+ * #transliterate(Replaceable&, UTransPosition&, const UnicodeString&, UErrorCode&) const }.
+ * @param insertion text to be inserted and possibly
+ * transliterated into the translation buffer at
+ * <code>index.limit</code>.
+ * @param status Output param to filled in with a success or an error.
+ * @see #transliterate(Replaceable&, UTransPosition&, const UnicodeString&, UErrorCode&) const
+ * @stable ICU 2.0
+ */
+ virtual void transliterate(Replaceable& text, UTransPosition& index,
+ UChar32 insertion,
+ UErrorCode& status) const;
+
+ /**
+ * Transliterates the portion of the text buffer that can be
+ * transliterated unambiguosly. This is a convenience method; see
+ * {@link
+ * #transliterate(Replaceable&, UTransPosition&, const UnicodeString&, UErrorCode&) const }
+ * for details.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param index an array of three integers. See {@link
+ * #transliterate(Replaceable&, UTransPosition&, const UnicodeString&, UErrorCode&) const }.
+ * @param status Output param to filled in with a success or an error.
+ * @see #transliterate(Replaceable, int[], String)
+ * @stable ICU 2.0
+ */
+ virtual void transliterate(Replaceable& text, UTransPosition& index,
+ UErrorCode& status) const;
+
+ /**
+ * Finishes any pending transliterations that were waiting for
+ * more characters. Clients should call this method as the last
+ * call after a sequence of one or more calls to
+ * <code>transliterate()</code>.
+ * @param text the buffer holding transliterated and
+ * untransliterated text.
+ * @param index the array of indices previously passed to {@link
+ * #transliterate }
+ * @stable ICU 2.0
+ */
+ virtual void finishTransliteration(Replaceable& text,
+ UTransPosition& index) const;
+
+private:
+
+ /**
+ * This internal method does incremental transliteration. If the
+ * 'insertion' is non-null then we append it to 'text' before
+ * proceeding. This method calls through to the pure virtual
+ * framework method handleTransliterate() to do the actual
+ * work.
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ * @param index an array of three integers. See {@link
+ * #transliterate(Replaceable, int[], String)}.
+ * @param insertion text to be inserted and possibly
+ * transliterated into the translation buffer at
+ * <code>index.limit</code>.
+ * @param status Output param to filled in with a success or an error.
+ */
+ void _transliterate(Replaceable& text,
+ UTransPosition& index,
+ const UnicodeString* insertion,
+ UErrorCode &status) const;
+
+protected:
+
+ /**
+ * Abstract method that concrete subclasses define to implement
+ * their transliteration algorithm. This method handles both
+ * incremental and non-incremental transliteration. Let
+ * <code>originalStart</code> refer to the value of
+ * <code>pos.start</code> upon entry.
+ *
+ * <ul>
+ * <li>If <code>incremental</code> is false, then this method
+ * should transliterate all characters between
+ * <code>pos.start</code> and <code>pos.limit</code>. Upon return
+ * <code>pos.start</code> must == <code> pos.limit</code>.</li>
+ *
+ * <li>If <code>incremental</code> is true, then this method
+ * should transliterate all characters between
+ * <code>pos.start</code> and <code>pos.limit</code> that can be
+ * unambiguously transliterated, regardless of future insertions
+ * of text at <code>pos.limit</code>. Upon return,
+ * <code>pos.start</code> should be in the range
+ * [<code>originalStart</code>, <code>pos.limit</code>).
+ * <code>pos.start</code> should be positioned such that
+ * characters [<code>originalStart</code>, <code>
+ * pos.start</code>) will not be changed in the future by this
+ * transliterator and characters [<code>pos.start</code>,
+ * <code>pos.limit</code>) are unchanged.</li>
+ * </ul>
+ *
+ * <p>Implementations of this method should also obey the
+ * following invariants:</p>
+ *
+ * <ul>
+ * <li> <code>pos.limit</code> and <code>pos.contextLimit</code>
+ * should be updated to reflect changes in length of the text
+ * between <code>pos.start</code> and <code>pos.limit</code>. The
+ * difference <code> pos.contextLimit - pos.limit</code> should
+ * not change.</li>
+ *
+ * <li><code>pos.contextStart</code> should not change.</li>
+ *
+ * <li>Upon return, neither <code>pos.start</code> nor
+ * <code>pos.limit</code> should be less than
+ * <code>originalStart</code>.</li>
+ *
+ * <li>Text before <code>originalStart</code> and text after
+ * <code>pos.limit</code> should not change.</li>
+ *
+ * <li>Text before <code>pos.contextStart</code> and text after
+ * <code> pos.contextLimit</code> should be ignored.</li>
+ * </ul>
+ *
+ * <p>Subclasses may safely assume that all characters in
+ * [<code>pos.start</code>, <code>pos.limit</code>) are filtered.
+ * In other words, the filter has already been applied by the time
+ * this method is called. See
+ * <code>filteredTransliterate()</code>.
+ *
+ * <p>This method is <b>not</b> for public consumption. Calling
+ * this method directly will transliterate
+ * [<code>pos.start</code>, <code>pos.limit</code>) without
+ * applying the filter. End user code should call <code>
+ * transliterate()</code> instead of this method. Subclass code
+ * and wrapping transliterators should call
+ * <code>filteredTransliterate()</code> instead of this method.<p>
+ *
+ * @param text the buffer holding transliterated and
+ * untransliterated text
+ *
+ * @param pos the indices indicating the start, limit, context
+ * start, and context limit of the text.
+ *
+ * @param incremental if true, assume more text may be inserted at
+ * <code>pos.limit</code> and act accordingly. Otherwise,
+ * transliterate all text between <code>pos.start</code> and
+ * <code>pos.limit</code> and move <code>pos.start</code> up to
+ * <code>pos.limit</code>.
+ *
+ * @see #transliterate
+ * @stable ICU 2.4
+ */
+ virtual void handleTransliterate(Replaceable& text,
+ UTransPosition& pos,
+ UBool incremental) const = 0;
+
+public:
+ /**
+ * Transliterate a substring of text, as specified by index, taking filters
+ * into account. This method is for subclasses that need to delegate to
+ * another transliterator, such as CompoundTransliterator.
+ * @param text the text to be transliterated
+ * @param index the position indices
+ * @param incremental if TRUE, then assume more characters may be inserted
+ * at index.limit, and postpone processing to accomodate future incoming
+ * characters
+ * @stable ICU 2.4
+ */
+ virtual void filteredTransliterate(Replaceable& text,
+ UTransPosition& index,
+ UBool incremental) const;
+
+private:
+
+ /**
+ * Top-level transliteration method, handling filtering, incremental and
+ * non-incremental transliteration, and rollback. All transliteration
+ * public API methods eventually call this method with a rollback argument
+ * of TRUE. Other entities may call this method but rollback should be
+ * FALSE.
+ *
+ * <p>If this transliterator has a filter, break up the input text into runs
+ * of unfiltered characters. Pass each run to
+ * <subclass>.handleTransliterate().
+ *
+ * <p>In incremental mode, if rollback is TRUE, perform a special
+ * incremental procedure in which several passes are made over the input
+ * text, adding one character at a time, and committing successful
+ * transliterations as they occur. Unsuccessful transliterations are rolled
+ * back and retried with additional characters to give correct results.
+ *
+ * @param text the text to be transliterated
+ * @param index the position indices
+ * @param incremental if TRUE, then assume more characters may be inserted
+ * at index.limit, and postpone processing to accomodate future incoming
+ * characters
+ * @param rollback if TRUE and if incremental is TRUE, then perform special
+ * incremental processing, as described above, and undo partial
+ * transliterations where necessary. If incremental is FALSE then this
+ * parameter is ignored.
+ */
+ virtual void filteredTransliterate(Replaceable& text,
+ UTransPosition& index,
+ UBool incremental,
+ UBool rollback) const;
+
+public:
+
+ /**
+ * Returns the length of the longest context required by this transliterator.
+ * This is <em>preceding</em> context. The default implementation supplied
+ * by <code>Transliterator</code> returns zero; subclasses
+ * that use preceding context should override this method to return the
+ * correct value. For example, if a transliterator translates "ddd" (where
+ * d is any digit) to "555" when preceded by "(ddd)", then the preceding
+ * context length is 5, the length of "(ddd)".
+ *
+ * @return The maximum number of preceding context characters this
+ * transliterator needs to examine
+ * @stable ICU 2.0
+ */
+ int32_t getMaximumContextLength(void) const;
+
+protected:
+
+ /**
+ * Method for subclasses to use to set the maximum context length.
+ * @param maxContextLength the new value to be set.
+ * @see #getMaximumContextLength
+ * @stable ICU 2.4
+ */
+ void setMaximumContextLength(int32_t maxContextLength);
+
+public:
+
+ /**
+ * Returns a programmatic identifier for this transliterator.
+ * If this identifier is passed to <code>createInstance()</code>, it
+ * will return this object, if it has been registered.
+ * @return a programmatic identifier for this transliterator.
+ * @see #registerInstance
+ * @see #registerFactory
+ * @see #getAvailableIDs
+ * @stable ICU 2.0
+ */
+ virtual const UnicodeString& getID(void) const;
+
+ /**
+ * Returns a name for this transliterator that is appropriate for
+ * display to the user in the default locale. See {@link
+ * #getDisplayName } for details.
+ * @param ID the string identifier for this transliterator
+ * @param result Output param to receive the display name
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ static UnicodeString& U_EXPORT2 getDisplayName(const UnicodeString& ID,
+ UnicodeString& result);
+
+ /**
+ * Returns a name for this transliterator that is appropriate for
+ * display to the user in the given locale. This name is taken
+ * from the locale resource data in the standard manner of the
+ * <code>java.text</code> package.
+ *
+ * <p>If no localized names exist in the system resource bundles,
+ * a name is synthesized using a localized
+ * <code>MessageFormat</code> pattern from the resource data. The
+ * arguments to this pattern are an integer followed by one or two
+ * strings. The integer is the number of strings, either 1 or 2.
+ * The strings are formed by splitting the ID for this
+ * transliterator at the first '-'. If there is no '-', then the
+ * entire ID forms the only string.
+ * @param ID the string identifier for this transliterator
+ * @param inLocale the Locale in which the display name should be
+ * localized.
+ * @param result Output param to receive the display name
+ * @return A reference to 'result'.
+ * @stable ICU 2.0
+ */
+ static UnicodeString& U_EXPORT2 getDisplayName(const UnicodeString& ID,
+ const Locale& inLocale,
+ UnicodeString& result);
+
+ /**
+ * Returns the filter used by this transliterator, or <tt>NULL</tt>
+ * if this transliterator uses no filter.
+ * @return the filter used by this transliterator, or <tt>NULL</tt>
+ * if this transliterator uses no filter.
+ * @stable ICU 2.0
+ */
+ const UnicodeFilter* getFilter(void) const;
+
+ /**
+ * Returns the filter used by this transliterator, or <tt>NULL</tt> if this
+ * transliterator uses no filter. The caller must eventually delete the
+ * result. After this call, this transliterator's filter is set to
+ * <tt>NULL</tt>.
+ * @return the filter used by this transliterator, or <tt>NULL</tt> if this
+ * transliterator uses no filter.
+ * @stable ICU 2.4
+ */
+ UnicodeFilter* orphanFilter(void);
+
+ /**
+ * Changes the filter used by this transliterator. If the filter
+ * is set to <tt>null</tt> then no filtering will occur.
+ *
+ * <p>Callers must take care if a transliterator is in use by
+ * multiple threads. The filter should not be changed by one
+ * thread while another thread may be transliterating.
+ * @param adoptedFilter the new filter to be adopted.
+ * @stable ICU 2.0
+ */
+ void adoptFilter(UnicodeFilter* adoptedFilter);
+
+ /**
+ * Returns this transliterator's inverse. See the class
+ * documentation for details. This implementation simply inverts
+ * the two entities in the ID and attempts to retrieve the
+ * resulting transliterator. That is, if <code>getID()</code>
+ * returns "A-B", then this method will return the result of
+ * <code>createInstance("B-A")</code>, or <code>null</code> if that
+ * call fails.
+ *
+ * <p>Subclasses with knowledge of their inverse may wish to
+ * override this method.
+ *
+ * @param status Output param to filled in with a success or an error.
+ * @return a transliterator that is an inverse, not necessarily
+ * exact, of this transliterator, or <code>null</code> if no such
+ * transliterator is registered.
+ * @see #registerInstance
+ * @stable ICU 2.0
+ */
+ Transliterator* createInverse(UErrorCode& status) const;
+
+ /**
+ * Returns a <code>Transliterator</code> object given its ID.
+ * The ID must be either a system transliterator ID or a ID registered
+ * using <code>registerInstance()</code>.
+ *
+ * @param ID a valid ID, as enumerated by <code>getAvailableIDs()</code>
+ * @param dir either FORWARD or REVERSE.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered
+ * @param status Output param to filled in with a success or an error.
+ * @return A <code>Transliterator</code> object with the given ID
+ * @see #registerInstance
+ * @see #getAvailableIDs
+ * @see #getID
+ * @stable ICU 2.0
+ */
+ static Transliterator* U_EXPORT2 createInstance(const UnicodeString& ID,
+ UTransDirection dir,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ /**
+ * Returns a <code>Transliterator</code> object given its ID.
+ * The ID must be either a system transliterator ID or a ID registered
+ * using <code>registerInstance()</code>.
+ * @param ID a valid ID, as enumerated by <code>getAvailableIDs()</code>
+ * @param dir either FORWARD or REVERSE.
+ * @param status Output param to filled in with a success or an error.
+ * @return A <code>Transliterator</code> object with the given ID
+ * @stable ICU 2.0
+ */
+ static Transliterator* U_EXPORT2 createInstance(const UnicodeString& ID,
+ UTransDirection dir,
+ UErrorCode& status);
+
+ /**
+ * Returns a <code>Transliterator</code> object constructed from
+ * the given rule string. This will be a RuleBasedTransliterator,
+ * if the rule string contains only rules, or a
+ * CompoundTransliterator, if it contains ID blocks, or a
+ * NullTransliterator, if it contains ID blocks which parse as
+ * empty for the given direction.
+ * @param ID the id for the transliterator.
+ * @param rules rules, separated by ';'
+ * @param dir either FORWARD or REVERSE.
+ * @param parseError Struct to recieve information on position
+ * of error if an error is encountered
+ * @param status Output param set to success/failure code.
+ * @stable ICU 2.0
+ */
+ static Transliterator* U_EXPORT2 createFromRules(const UnicodeString& ID,
+ const UnicodeString& rules,
+ UTransDirection dir,
+ UParseError& parseError,
+ UErrorCode& status);
+
+ /**
+ * Create a rule string that can be passed to createFromRules()
+ * to recreate this transliterator.
+ * @param result the string to receive the rules. Previous
+ * contents will be deleted.
+ * @param escapeUnprintable if TRUE then convert unprintable
+ * character to their hex escape representations, \\uxxxx or
+ * \\Uxxxxxxxx. Unprintable characters are those other than
+ * U+000A, U+0020..U+007E.
+ * @stable ICU 2.0
+ */
+ virtual UnicodeString& toRules(UnicodeString& result,
+ UBool escapeUnprintable) const;
+
+ /**
+ * Return the number of elements that make up this transliterator.
+ * For example, if the transliterator "NFD;Jamo-Latin;Latin-Greek"
+ * were created, the return value of this method would be 3.
+ *
+ * <p>If this transliterator is not composed of other
+ * transliterators, then this method returns 1.
+ * @return the number of transliterators that compose this
+ * transliterator, or 1 if this transliterator is not composed of
+ * multiple transliterators
+ * @stable ICU 3.0
+ */
+ int32_t countElements() const;
+
+ /**
+ * Return an element that makes up this transliterator. For
+ * example, if the transliterator "NFD;Jamo-Latin;Latin-Greek"
+ * were created, the return value of this method would be one
+ * of the three transliterator objects that make up that
+ * transliterator: [NFD, Jamo-Latin, Latin-Greek].
+ *
+ * <p>If this transliterator is not composed of other
+ * transliterators, then this method will return a reference to
+ * this transliterator when given the index 0.
+ * @param index a value from 0..countElements()-1 indicating the
+ * transliterator to return
+ * @param ec input-output error code
+ * @return one of the transliterators that makes up this
+ * transliterator, if this transliterator is made up of multiple
+ * transliterators, otherwise a reference to this object if given
+ * an index of 0
+ * @stable ICU 3.0
+ */
+ const Transliterator& getElement(int32_t index, UErrorCode& ec) const;
+
+ /**
+ * Returns the set of all characters that may be modified in the
+ * input text by this Transliterator. This incorporates this
+ * object's current filter; if the filter is changed, the return
+ * value of this function will change. The default implementation
+ * returns an empty set. Some subclasses may override {@link
+ * #handleGetSourceSet } to return a more precise result. The
+ * return result is approximate in any case and is intended for
+ * use by tests, tools, or utilities.
+ * @param result receives result set; previous contents lost
+ * @return a reference to result
+ * @see #getTargetSet
+ * @see #handleGetSourceSet
+ * @stable ICU 2.4
+ */
+ UnicodeSet& getSourceSet(UnicodeSet& result) const;
+
+ /**
+ * Framework method that returns the set of all characters that
+ * may be modified in the input text by this Transliterator,
+ * ignoring the effect of this object's filter. The base class
+ * implementation returns the empty set. Subclasses that wish to
+ * implement this should override this method.
+ * @return the set of characters that this transliterator may
+ * modify. The set may be modified, so subclasses should return a
+ * newly-created object.
+ * @param result receives result set; previous contents lost
+ * @see #getSourceSet
+ * @see #getTargetSet
+ * @stable ICU 2.4
+ */
+ virtual void handleGetSourceSet(UnicodeSet& result) const;
+
+ /**
+ * Returns the set of all characters that may be generated as
+ * replacement text by this transliterator. The default
+ * implementation returns the empty set. Some subclasses may
+ * override this method to return a more precise result. The
+ * return result is approximate in any case and is intended for
+ * use by tests, tools, or utilities requiring such
+ * meta-information.
+ * @param result receives result set; previous contents lost
+ * @return a reference to result
+ * @see #getTargetSet
+ * @stable ICU 2.4
+ */
+ virtual UnicodeSet& getTargetSet(UnicodeSet& result) const;
+
+public:
+
+ /**
+ * Registers a factory function that creates transliterators of
+ * a given ID.
+ * @param id the ID being registered
+ * @param factory a function pointer that will be copied and
+ * called later when the given ID is passed to createInstance()
+ * @param context a context pointer that will be stored and
+ * later passed to the factory function when an ID matching
+ * the registration ID is being instantiated with this factory.
+ * @stable ICU 2.0
+ */
+ static void U_EXPORT2 registerFactory(const UnicodeString& id,
+ Factory factory,
+ Token context);
+
+ /**
+ * Registers an instance <tt>obj</tt> of a subclass of
+ * <code>Transliterator</code> with the system. When
+ * <tt>createInstance()</tt> is called with an ID string that is
+ * equal to <tt>obj->getID()</tt>, then <tt>obj->clone()</tt> is
+ * returned.
+ *
+ * After this call the Transliterator class owns the adoptedObj
+ * and will delete it.
+ *
+ * @param adoptedObj an instance of subclass of
+ * <code>Transliterator</code> that defines <tt>clone()</tt>
+ * @see #createInstance
+ * @see #registerFactory
+ * @see #unregister
+ * @stable ICU 2.0
+ */
+ static void U_EXPORT2 registerInstance(Transliterator* adoptedObj);
+
+ /**
+ * Registers an ID string as an alias of another ID string.
+ * That is, after calling this function, <tt>createInstance(aliasID)</tt>
+ * will return the same thing as <tt>createInstance(realID)</tt>.
+ * This is generally used to create shorter, more mnemonic aliases
+ * for long compound IDs.
+ *
+ * @param aliasID The new ID being registered.
+ * @param realID The ID that the new ID is to be an alias for.
+ * This can be a compound ID and can include filters and should
+ * refer to transliterators that have already been registered with
+ * the framework, although this isn't checked.
+ * @stable ICU 3.6
+ */
+ static void U_EXPORT2 registerAlias(const UnicodeString& aliasID,
+ const UnicodeString& realID);
+
+protected:
+
+ /**
+ * @internal
+ * @param id the ID being registered
+ * @param factory a function pointer that will be copied and
+ * called later when the given ID is passed to createInstance()
+ * @param context a context pointer that will be stored and
+ * later passed to the factory function when an ID matching
+ * the registration ID is being instantiated with this factory.
+ */
+ static void _registerFactory(const UnicodeString& id,
+ Factory factory,
+ Token context);
+
+ /**
+ * @internal
+ */
+ static void _registerInstance(Transliterator* adoptedObj);
+
+ /**
+ * @internal
+ */
+ static void _registerAlias(const UnicodeString& aliasID, const UnicodeString& realID);
+
+ /**
+ * Register two targets as being inverses of one another. For
+ * example, calling registerSpecialInverse("NFC", "NFD", true) causes
+ * Transliterator to form the following inverse relationships:
+ *
+ * <pre>NFC => NFD
+ * Any-NFC => Any-NFD
+ * NFD => NFC
+ * Any-NFD => Any-NFC</pre>
+ *
+ * (Without the special inverse registration, the inverse of NFC
+ * would be NFC-Any.) Note that NFD is shorthand for Any-NFD, but
+ * that the presence or absence of "Any-" is preserved.
+ *
+ * <p>The relationship is symmetrical; registering (a, b) is
+ * equivalent to registering (b, a).
+ *
+ * <p>The relevant IDs must still be registered separately as
+ * factories or classes.
+ *
+ * <p>Only the targets are specified. Special inverses always
+ * have the form Any-Target1 <=> Any-Target2. The target should
+ * have canonical casing (the casing desired to be produced when
+ * an inverse is formed) and should contain no whitespace or other
+ * extraneous characters.
+ *
+ * @param target the target against which to register the inverse
+ * @param inverseTarget the inverse of target, that is
+ * Any-target.getInverse() => Any-inverseTarget
+ * @param bidirectional if true, register the reverse relation
+ * as well, that is, Any-inverseTarget.getInverse() => Any-target
+ * @internal
+ */
+ static void _registerSpecialInverse(const UnicodeString& target,
+ const UnicodeString& inverseTarget,
+ UBool bidirectional);
+
+public:
+
+ /**
+ * Unregisters a transliterator or class. This may be either
+ * a system transliterator or a user transliterator or class.
+ * Any attempt to construct an unregistered transliterator based
+ * on its ID will fail.
+ *
+ * @param ID the ID of the transliterator or class
+ * @return the <code>Object</code> that was registered with
+ * <code>ID</code>, or <code>null</code> if none was
+ * @see #registerInstance
+ * @see #registerFactory
+ * @stable ICU 2.0
+ */
+ static void U_EXPORT2 unregister(const UnicodeString& ID);
+
+public:
+
+ /**
+ * Return a StringEnumeration over the IDs available at the time of the
+ * call, including user-registered IDs.
+ * @param ec input-output error code
+ * @return a newly-created StringEnumeration over the transliterators
+ * available at the time of the call. The caller should delete this object
+ * when done using it.
+ * @stable ICU 3.0
+ */
+ static StringEnumeration* U_EXPORT2 getAvailableIDs(UErrorCode& ec);
+
+ /**
+ * Return the number of registered source specifiers.
+ * @return the number of registered source specifiers.
+ * @stable ICU 2.0
+ */
+ static int32_t U_EXPORT2 countAvailableSources(void);
+
+ /**
+ * Return a registered source specifier.
+ * @param index which specifier to return, from 0 to n-1, where
+ * n = countAvailableSources()
+ * @param result fill-in paramter to receive the source specifier.
+ * If index is out of range, result will be empty.
+ * @return reference to result
+ * @stable ICU 2.0
+ */
+ static UnicodeString& U_EXPORT2 getAvailableSource(int32_t index,
+ UnicodeString& result);
+
+ /**
+ * Return the number of registered target specifiers for a given
+ * source specifier.
+ * @param source the given source specifier.
+ * @return the number of registered target specifiers for a given
+ * source specifier.
+ * @stable ICU 2.0
+ */
+ static int32_t U_EXPORT2 countAvailableTargets(const UnicodeString& source);
+
+ /**
+ * Return a registered target specifier for a given source.
+ * @param index which specifier to return, from 0 to n-1, where
+ * n = countAvailableTargets(source)
+ * @param source the source specifier
+ * @param result fill-in paramter to receive the target specifier.
+ * If source is invalid or if index is out of range, result will
+ * be empty.
+ * @return reference to result
+ * @stable ICU 2.0
+ */
+ static UnicodeString& U_EXPORT2 getAvailableTarget(int32_t index,
+ const UnicodeString& source,
+ UnicodeString& result);
+
+ /**
+ * Return the number of registered variant specifiers for a given
+ * source-target pair.
+ * @param source the source specifiers.
+ * @param target the target specifiers.
+ * @stable ICU 2.0
+ */
+ static int32_t U_EXPORT2 countAvailableVariants(const UnicodeString& source,
+ const UnicodeString& target);
+
+ /**
+ * Return a registered variant specifier for a given source-target
+ * pair.
+ * @param index which specifier to return, from 0 to n-1, where
+ * n = countAvailableVariants(source, target)
+ * @param source the source specifier
+ * @param target the target specifier
+ * @param result fill-in paramter to receive the variant
+ * specifier. If source is invalid or if target is invalid or if
+ * index is out of range, result will be empty.
+ * @return reference to result
+ * @stable ICU 2.0
+ */
+ static UnicodeString& U_EXPORT2 getAvailableVariant(int32_t index,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ UnicodeString& result);
+
+protected:
+
+ /**
+ * Non-mutexed internal method
+ * @internal
+ */
+ static int32_t _countAvailableSources(void);
+
+ /**
+ * Non-mutexed internal method
+ * @internal
+ */
+ static UnicodeString& _getAvailableSource(int32_t index,
+ UnicodeString& result);
+
+ /**
+ * Non-mutexed internal method
+ * @internal
+ */
+ static int32_t _countAvailableTargets(const UnicodeString& source);
+
+ /**
+ * Non-mutexed internal method
+ * @internal
+ */
+ static UnicodeString& _getAvailableTarget(int32_t index,
+ const UnicodeString& source,
+ UnicodeString& result);
+
+ /**
+ * Non-mutexed internal method
+ * @internal
+ */
+ static int32_t _countAvailableVariants(const UnicodeString& source,
+ const UnicodeString& target);
+
+ /**
+ * Non-mutexed internal method
+ * @internal
+ */
+ static UnicodeString& _getAvailableVariant(int32_t index,
+ const UnicodeString& source,
+ const UnicodeString& target,
+ UnicodeString& result);
+
+protected:
+
+ /**
+ * Set the ID of this transliterators. Subclasses shouldn't do
+ * this, unless the underlying script behavior has changed.
+ * @param id the new id t to be set.
+ * @stable ICU 2.4
+ */
+ void setID(const UnicodeString& id);
+
+public:
+
+ /**
+ * Return the class ID for this class. This is useful only for
+ * comparing to a return value from getDynamicClassID().
+ * Note that Transliterator is an abstract base class, and therefor
+ * no fully constructed object will have a dynamic
+ * UCLassID that equals the UClassID returned from
+ * TRansliterator::getStaticClassID().
+ * @return The class ID for class Transliterator.
+ * @stable ICU 2.0
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID <b>polymorphically</b>. This method
+ * is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and
+ * clone() methods call this method.
+ *
+ * <p>Concrete subclasses of Transliterator must use the
+ * UOBJECT_DEFINE_RTTI_IMPLEMENTATION macro from
+ * uobject.h to provide the RTTI functions.
+ *
+ * @return The class ID for this object. All objects of a given
+ * class have the same class ID. Objects of other classes have
+ * different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const = 0;
+
+private:
+ static UBool initializeRegistry(void);
+
+public:
+ /**
+ * Return the number of IDs currently registered with the system.
+ * To retrieve the actual IDs, call getAvailableID(i) with
+ * i from 0 to countAvailableIDs() - 1.
+ * @return the number of IDs currently registered with the system.
+ * @obsolete ICU 3.4 use getAvailableIDs() instead
+ */
+ static int32_t U_EXPORT2 countAvailableIDs(void);
+
+ /**
+ * Return the index-th available ID. index must be between 0
+ * and countAvailableIDs() - 1, inclusive. If index is out of
+ * range, the result of getAvailableID(0) is returned.
+ * @param index the given ID index.
+ * @return the index-th available ID. index must be between 0
+ * and countAvailableIDs() - 1, inclusive. If index is out of
+ * range, the result of getAvailableID(0) is returned.
+ * @obsolete ICU 3.4 use getAvailableIDs() instead; this function
+ * is not thread safe, since it returns a reference to storage that
+ * may become invalid if another thread calls unregister
+ */
+ static const UnicodeString& U_EXPORT2 getAvailableID(int32_t index);
+};
+
+inline int32_t Transliterator::getMaximumContextLength(void) const {
+ return maximumContextLength;
+}
+
+inline void Transliterator::setID(const UnicodeString& id) {
+ ID = id;
+ // NUL-terminate the ID string, which is a non-aliased copy.
+ ID.append((UChar)0);
+ ID.truncate(ID.length()-1);
+}
+
+inline Transliterator::Token Transliterator::integerToken(int32_t i) {
+ Token t;
+ t.integer = i;
+ return t;
+}
+
+inline Transliterator::Token Transliterator::pointerToken(void* p) {
+ Token t;
+ t.pointer = p;
+ return t;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/tzrule.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/tzrule.h
new file mode 100644
index 00000000000..a0576ca87a3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/tzrule.h
@@ -0,0 +1,828 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef TZRULE_H
+#define TZRULE_H
+
+/**
+ * \file
+ * \brief C++ API: Time zone rule classes
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+#include "unicode/unistr.h"
+#include "unicode/dtrule.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * <code>TimeZoneRule</code> is a class representing a rule for time zone.
+ * <code>TimeZoneRule</code> has a set of time zone attributes, such as zone name,
+ * raw offset (UTC offset for standard time) and daylight saving time offset.
+ *
+ * @draft ICU 3.8
+ */
+class U_I18N_API TimeZoneRule : public UObject {
+public:
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~TimeZoneRule();
+
+ /**
+ * Clone this TimeZoneRule object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @draft ICU 3.8
+ */
+ virtual TimeZoneRule* clone(void) const = 0;
+
+ /**
+ * Return true if the given <code>TimeZoneRule</code> objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZoneRule</code> objects are semantically equal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator==(const TimeZoneRule& that) const;
+
+ /**
+ * Return true if the given <code>TimeZoneRule</code> objects are semantically unequal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZoneRule</code> objects are semantically unequal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator!=(const TimeZoneRule& that) const;
+
+ /**
+ * Fills in "name" with the name of this time zone.
+ * @param name Receives the name of this time zone.
+ * @return A reference to "name"
+ * @draft ICU 3.8
+ */
+ UnicodeString& getName(UnicodeString& name) const;
+
+ /**
+ * Gets the standard time offset.
+ * @return The standard time offset from UTC in milliseconds.
+ * @draft ICU 3.8
+ */
+ int32_t getRawOffset(void) const;
+
+ /**
+ * Gets the amount of daylight saving delta time from the standard time.
+ * @return The amount of daylight saving offset used by this rule
+ * in milliseconds.
+ * @draft ICU 3.8
+ */
+ int32_t getDSTSavings(void) const;
+
+ /**
+ * Returns if this rule represents the same rule and offsets as another.
+ * When two <code>TimeZoneRule</code> objects differ only its names, this method
+ * returns true.
+ * @param other The <code>TimeZoneRule</code> object to be compared with.
+ * @return true if the other <code>TimeZoneRule</code> is the same as this one.
+ * @draft ICU 3.8
+ */
+ virtual UBool isEquivalentTo(const TimeZoneRule& other) const;
+
+ /**
+ * Gets the very first time when this rule takes effect.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the very first time when this rule takes effect.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getFirstStart(int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const = 0;
+
+ /**
+ * Gets the final time when this rule takes effect.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the final time when this rule takes effect.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getFinalStart(int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const = 0;
+
+ /**
+ * Gets the first time when this rule takes effect after the specified time.
+ * @param base The first start time after this base time will be returned.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives The first time when this rule takes effect after
+ * the specified base time.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getNextStart(UDate base, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UBool inclusive, UDate& result) const = 0;
+
+ /**
+ * Gets the most recent time when this rule takes effect before the specified time.
+ * @param base The most recent time before this base time will be returned.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives The most recent time when this rule takes effect before
+ * the specified base time.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getPreviousStart(UDate base, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UBool inclusive, UDate& result) const = 0;
+
+protected:
+
+ /**
+ * Constructs a <code>TimeZoneRule</code> with the name, the GMT offset of its
+ * standard time and the amount of daylight saving offset adjustment.
+ * @param name The time zone name.
+ * @param rawOffset The UTC offset of its standard time in milliseconds.
+ * @param dstSavings The amount of daylight saving offset adjustment in milliseconds.
+ * If this ia a rule for standard time, the value of this argument is 0.
+ * @draft ICU 3.8
+ */
+ TimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings);
+
+ /**
+ * Copy constructor.
+ * @param source The TimeZoneRule object to be copied.
+ * @draft ICU 3.8
+ */
+ TimeZoneRule(const TimeZoneRule& source);
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @draft ICU 3.8
+ */
+ TimeZoneRule& operator=(const TimeZoneRule& right);
+
+private:
+ UnicodeString fName; // time name
+ int32_t fRawOffset; // UTC offset of the standard time in milliseconds
+ int32_t fDSTSavings; // DST saving amount in milliseconds
+};
+
+/**
+ * <code>InitialTimeZoneRule</code> represents a time zone rule
+ * representing a time zone effective from the beginning and
+ * has no actual start times.
+ * @draft ICU 3.8
+ */
+class U_I18N_API InitialTimeZoneRule : public TimeZoneRule {
+public:
+ /**
+ * Constructs an <code>InitialTimeZoneRule</code> with the name, the GMT offset of its
+ * standard time and the amount of daylight saving offset adjustment.
+ * @param name The time zone name.
+ * @param rawOffset The UTC offset of its standard time in milliseconds.
+ * @param dstSavings The amount of daylight saving offset adjustment in milliseconds.
+ * If this ia a rule for standard time, the value of this argument is 0.
+ * @draft ICU 3.8
+ */
+ InitialTimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings);
+
+ /**
+ * Copy constructor.
+ * @param source The InitialTimeZoneRule object to be copied.
+ * @draft ICU 3.8
+ */
+ InitialTimeZoneRule(const InitialTimeZoneRule& source);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~InitialTimeZoneRule();
+
+ /**
+ * Clone this InitialTimeZoneRule object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @draft ICU 3.8
+ */
+ virtual InitialTimeZoneRule* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @draft ICU 3.8
+ */
+ InitialTimeZoneRule& operator=(const InitialTimeZoneRule& right);
+
+ /**
+ * Return true if the given <code>TimeZoneRule</code> objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZoneRule</code> objects are semantically equal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator==(const TimeZoneRule& that) const;
+
+ /**
+ * Return true if the given <code>TimeZoneRule</code> objects are semantically unequal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZoneRule</code> objects are semantically unequal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator!=(const TimeZoneRule& that) const;
+
+ /**
+ * Gets the time when this rule takes effect in the given year.
+ * @param year The Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the start time in the year.
+ * @return true if this rule takes effect in the year and the result is set to
+ * "result".
+ * @draft ICU 3.8
+ */
+ UBool getStartInYear(int32_t year, int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const;
+
+ /**
+ * Returns if this rule represents the same rule and offsets as another.
+ * When two <code>TimeZoneRule</code> objects differ only its names, this method
+ * returns true.
+ * @param that The <code>TimeZoneRule</code> object to be compared with.
+ * @return true if the other <code>TimeZoneRule</code> is equivalent to this one.
+ * @draft ICU 3.8
+ */
+ virtual UBool isEquivalentTo(const TimeZoneRule& that) const;
+
+ /**
+ * Gets the very first time when this rule takes effect.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the very first time when this rule takes effect.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getFirstStart(int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const;
+
+ /**
+ * Gets the final time when this rule takes effect.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the final time when this rule takes effect.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getFinalStart(int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const;
+
+ /**
+ * Gets the first time when this rule takes effect after the specified time.
+ * @param base The first start time after this base time will be returned.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives The first time when this rule takes effect after
+ * the specified base time.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getNextStart(UDate base, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UBool inclusive, UDate& result) const;
+
+ /**
+ * Gets the most recent time when this rule takes effect before the specified time.
+ * @param base The most recent time before this base time will be returned.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives The most recent time when this rule takes effect before
+ * the specified base time.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getPreviousStart(UDate base, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UBool inclusive, UDate& result) const;
+
+public:
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+/**
+ * <code>AnnualTimeZoneRule</code> is a class used for representing a time zone
+ * rule which takes effect annually. The calenday system used for the rule is
+ * is based on Gregorian calendar
+ *
+ * @draft ICU 3.8
+ */
+class U_I18N_API AnnualTimeZoneRule : public TimeZoneRule {
+public:
+ /**
+ * The constant representing the maximum year used for designating
+ * a rule is permanent.
+ */
+ static const int32_t MAX_YEAR;
+
+ /**
+ * Constructs a <code>AnnualTimeZoneRule</code> with the name, the GMT offset of its
+ * standard time, the amount of daylight saving offset adjustment, the annual start
+ * time rule and the start/until years. The input DateTimeRule is copied by this
+ * constructor, so the caller remains responsible for deleting the object.
+ * @param name The time zone name.
+ * @param rawOffset The GMT offset of its standard time in milliseconds.
+ * @param dstSavings The amount of daylight saving offset adjustment in
+ * milliseconds. If this ia a rule for standard time,
+ * the value of this argument is 0.
+ * @param dateTimeRule The start date/time rule repeated annually.
+ * @param startYear The first year when this rule takes effect.
+ * @param endYear The last year when this rule takes effect. If this
+ * rule is effective forever in future, specify MAX_YEAR.
+ * @draft ICU 3.8
+ */
+ AnnualTimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings,
+ const DateTimeRule& dateTimeRule, int32_t startYear, int32_t endYear);
+
+ /**
+ * Constructs a <code>AnnualTimeZoneRule</code> with the name, the GMT offset of its
+ * standard time, the amount of daylight saving offset adjustment, the annual start
+ * time rule and the start/until years. The input DateTimeRule object is adopted
+ * by this object, therefore, the caller must not delete the object.
+ * @param name The time zone name.
+ * @param rawOffset The GMT offset of its standard time in milliseconds.
+ * @param dstSavings The amount of daylight saving offset adjustment in
+ * milliseconds. If this ia a rule for standard time,
+ * the value of this argument is 0.
+ * @param dateTimeRule The start date/time rule repeated annually.
+ * @param startYear The first year when this rule takes effect.
+ * @param endYear The last year when this rule takes effect. If this
+ * rule is effective forever in future, specify MAX_YEAR.
+ * @draft ICU 3.8
+ */
+ AnnualTimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings,
+ DateTimeRule* dateTimeRule, int32_t startYear, int32_t endYear);
+
+ /**
+ * Copy constructor.
+ * @param source The AnnualTimeZoneRule object to be copied.
+ * @draft ICU 3.8
+ */
+ AnnualTimeZoneRule(const AnnualTimeZoneRule& source);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~AnnualTimeZoneRule();
+
+ /**
+ * Clone this AnnualTimeZoneRule object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @draft ICU 3.8
+ */
+ virtual AnnualTimeZoneRule* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @draft ICU 3.8
+ */
+ AnnualTimeZoneRule& operator=(const AnnualTimeZoneRule& right);
+
+ /**
+ * Return true if the given <code>TimeZoneRule</code> objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZoneRule</code> objects are semantically equal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator==(const TimeZoneRule& that) const;
+
+ /**
+ * Return true if the given <code>TimeZoneRule</code> objects are semantically unequal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZoneRule</code> objects are semantically unequal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator!=(const TimeZoneRule& that) const;
+
+ /**
+ * Gets the start date/time rule used by this rule.
+ * @return The <code>AnnualDateTimeRule</code> which represents the start date/time
+ * rule used by this time zone rule.
+ * @draft ICU 3.8
+ */
+ const DateTimeRule* getRule(void) const;
+
+ /**
+ * Gets the first year when this rule takes effect.
+ * @return The start year of this rule. The year is in Gregorian calendar
+ * with 0 == 1 BCE, -1 == 2 BCE, etc.
+ * @draft ICU 3.8
+ */
+ int32_t getStartYear(void) const;
+
+ /**
+ * Gets the end year when this rule takes effect.
+ * @return The end year of this rule (inclusive). The year is in Gregorian calendar
+ * with 0 == 1 BCE, -1 == 2 BCE, etc.
+ * @draft ICU 3.8
+ */
+ int32_t getEndYear(void) const;
+
+ /**
+ * Gets the time when this rule takes effect in the given year.
+ * @param year The Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the start time in the year.
+ * @return true if this rule takes effect in the year and the result is set to
+ * "result".
+ * @draft ICU 3.8
+ */
+ UBool getStartInYear(int32_t year, int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const;
+
+ /**
+ * Returns if this rule represents the same rule and offsets as another.
+ * When two <code>TimeZoneRule</code> objects differ only its names, this method
+ * returns true.
+ * @param that The <code>TimeZoneRule</code> object to be compared with.
+ * @return true if the other <code>TimeZoneRule</code> is equivalent to this one.
+ * @draft ICU 3.8
+ */
+ virtual UBool isEquivalentTo(const TimeZoneRule& that) const;
+
+ /**
+ * Gets the very first time when this rule takes effect.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the very first time when this rule takes effect.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getFirstStart(int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const;
+
+ /**
+ * Gets the final time when this rule takes effect.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the final time when this rule takes effect.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getFinalStart(int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const;
+
+ /**
+ * Gets the first time when this rule takes effect after the specified time.
+ * @param base The first start time after this base time will be returned.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives The first time when this rule takes effect after
+ * the specified base time.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getNextStart(UDate base, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UBool inclusive, UDate& result) const;
+
+ /**
+ * Gets the most recent time when this rule takes effect before the specified time.
+ * @param base The most recent time before this base time will be returned.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives The most recent time when this rule takes effect before
+ * the specified base time.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getPreviousStart(UDate base, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UBool inclusive, UDate& result) const;
+
+
+private:
+ DateTimeRule* fDateTimeRule;
+ int32_t fStartYear;
+ int32_t fEndYear;
+
+public:
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+/**
+ * <code>TimeArrayTimeZoneRule</code> represents a time zone rule whose start times are
+ * defined by an array of milliseconds since the standard base time.
+ *
+ * @draft ICU 3.8
+ */
+class U_I18N_API TimeArrayTimeZoneRule : public TimeZoneRule {
+public:
+ /**
+ * Constructs a <code>TimeArrayTimeZoneRule</code> with the name, the GMT offset of its
+ * standard time, the amount of daylight saving offset adjustment and
+ * the array of times when this rule takes effect.
+ * @param name The time zone name.
+ * @param rawOffset The UTC offset of its standard time in milliseconds.
+ * @param dstSavings The amount of daylight saving offset adjustment in
+ * milliseconds. If this ia a rule for standard time,
+ * the value of this argument is 0.
+ * @param startTimes The array start times in milliseconds since the base time
+ * (January 1, 1970, 00:00:00).
+ * @param numStartTimes The number of elements in the parameter "startTimes"
+ * @param timeRuleType The time type of the start times, which is one of
+ * <code>DataTimeRule::WALL_TIME</code>, <code>STANDARD_TIME</code>
+ * and <code>UNIVERSAL_TIME</code>.
+ * @draft ICU 3.8
+ */
+ TimeArrayTimeZoneRule(const UnicodeString& name, int32_t rawOffset, int32_t dstSavings,
+ const UDate* startTimes, int32_t numStartTimes, DateTimeRule::TimeRuleType timeRuleType);
+
+ /**
+ * Copy constructor.
+ * @param source The TimeArrayTimeZoneRule object to be copied.
+ * @draft ICU 3.8
+ */
+ TimeArrayTimeZoneRule(const TimeArrayTimeZoneRule& source);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~TimeArrayTimeZoneRule();
+
+ /**
+ * Clone this TimeArrayTimeZoneRule object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @draft ICU 3.8
+ */
+ virtual TimeArrayTimeZoneRule* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @draft ICU 3.8
+ */
+ TimeArrayTimeZoneRule& operator=(const TimeArrayTimeZoneRule& right);
+
+ /**
+ * Return true if the given <code>TimeZoneRule</code> objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZoneRule</code> objects are semantically equal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator==(const TimeZoneRule& that) const;
+
+ /**
+ * Return true if the given <code>TimeZoneRule</code> objects are semantically unequal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZoneRule</code> objects are semantically unequal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator!=(const TimeZoneRule& that) const;
+
+ /**
+ * Gets the time type of the start times used by this rule. The return value
+ * is either <code>DateTimeRule::WALL_TIME</code> or <code>STANDARD_TIME</code>
+ * or <code>UNIVERSAL_TIME</code>.
+ *
+ * @return The time type used of the start times used by this rule.
+ * @draft ICU 3.8
+ */
+ DateTimeRule::TimeRuleType getTimeType(void) const;
+
+ /**
+ * Gets a start time at the index stored in this rule.
+ * @param index The index of start times
+ * @param result Receives the start time at the index
+ * @return true if the index is within the valid range and
+ * and the result is set. When false, the output
+ * parameger "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ UBool getStartTimeAt(int32_t index, UDate& result) const;
+
+ /**
+ * Returns the number of start times stored in this rule
+ * @return The number of start times.
+ * @draft ICU 3.8
+ */
+ int32_t countStartTimes(void) const;
+
+ /**
+ * Returns if this rule represents the same rule and offsets as another.
+ * When two <code>TimeZoneRule</code> objects differ only its names, this method
+ * returns true.
+ * @param that The <code>TimeZoneRule</code> object to be compared with.
+ * @return true if the other <code>TimeZoneRule</code> is equivalent to this one.
+ * @draft ICU 3.8
+ */
+ virtual UBool isEquivalentTo(const TimeZoneRule& that) const;
+
+ /**
+ * Gets the very first time when this rule takes effect.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the very first time when this rule takes effect.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getFirstStart(int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const;
+
+ /**
+ * Gets the final time when this rule takes effect.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param result Receives the final time when this rule takes effect.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getFinalStart(int32_t prevRawOffset, int32_t prevDSTSavings, UDate& result) const;
+
+ /**
+ * Gets the first time when this rule takes effect after the specified time.
+ * @param base The first start time after this base time will be returned.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives The first time when this rule takes effect after
+ * the specified base time.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getNextStart(UDate base, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UBool inclusive, UDate& result) const;
+
+ /**
+ * Gets the most recent time when this rule takes effect before the specified time.
+ * @param base The most recent time before this base time will be returned.
+ * @param prevRawOffset The standard time offset from UTC before this rule
+ * takes effect in milliseconds.
+ * @param prevDSTSavings The amount of daylight saving offset from the
+ * standard time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives The most recent time when this rule takes effect before
+ * the specified base time.
+ * @return true if the start time is available. When false is returned, output parameter
+ * "result" is unchanged.
+ * @draft ICU 3.8
+ */
+ virtual UBool getPreviousStart(UDate base, int32_t prevRawOffset, int32_t prevDSTSavings,
+ UBool inclusive, UDate& result) const;
+
+
+private:
+ enum { TIMEARRAY_STACK_BUFFER_SIZE = 32 };
+ UBool initStartTimes(const UDate source[], int32_t size, UErrorCode& ec);
+ UDate getUTC(UDate time, int32_t raw, int32_t dst) const;
+
+ DateTimeRule::TimeRuleType fTimeRuleType;
+ int32_t fNumStartTimes;
+ UDate* fStartTimes;
+ UDate fLocalStartTimes[TIMEARRAY_STACK_BUFFER_SIZE];
+
+public:
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // TZRULE_H
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/tztrans.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/tztrans.h
new file mode 100644
index 00000000000..6c7b0215f03
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/tztrans.h
@@ -0,0 +1,195 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef TZTRANS_H
+#define TZTRANS_H
+
+/**
+ * \file
+ * \brief C++ API: Time zone transition
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uobject.h"
+
+U_NAMESPACE_BEGIN
+
+// Forward declaration
+class TimeZoneRule;
+
+/**
+ * <code>TimeZoneTransition</code> is a class representing a time zone transition.
+ * An instance has a time of transition and rules for both before and after the transition.
+ * @draft ICU 3.8
+ */
+class U_I18N_API TimeZoneTransition : public UObject {
+public:
+ /**
+ * Constructs a <code>TimeZoneTransition</code> with the time and the rules before/after
+ * the transition.
+ *
+ * @param time The time of transition in milliseconds since the base time.
+ * @param from The time zone rule used before the transition.
+ * @param to The time zone rule used after the transition.
+ * @draft ICU 3.8
+ */
+ TimeZoneTransition(UDate time, const TimeZoneRule& from, const TimeZoneRule& to);
+
+ /**
+ * Constructs an empty <code>TimeZoneTransition</code>
+ * @draft ICU 3.8
+ */
+ TimeZoneTransition();
+
+ /**
+ * Copy constructor.
+ * @param source The TimeZoneTransition object to be copied.
+ * @draft ICU 3.8
+ */
+ TimeZoneTransition(const TimeZoneTransition& source);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ ~TimeZoneTransition();
+
+ /**
+ * Clone this TimeZoneTransition object polymorphically. The caller owns the result and
+ * should delete it when done.
+ * @return A copy of the object.
+ * @draft ICU 3.8
+ */
+ TimeZoneTransition* clone(void) const;
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @draft ICU 3.8
+ */
+ TimeZoneTransition& operator=(const TimeZoneTransition& right);
+
+ /**
+ * Return true if the given TimeZoneTransition objects are semantically equal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given TimeZoneTransition objects are semantically equal.
+ * @draft ICU 3.8
+ */
+ UBool operator==(const TimeZoneTransition& that) const;
+
+ /**
+ * Return true if the given TimeZoneTransition objects are semantically unequal. Objects
+ * of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given TimeZoneTransition objects are semantically unequal.
+ * @draft ICU 3.8
+ */
+ UBool operator!=(const TimeZoneTransition& that) const;
+
+ /**
+ * Returns the time of transition in milliseconds.
+ * @return The time of the transition in milliseconds since the 1970 Jan 1 epoch time.
+ * @draft ICU 3.8
+ */
+ UDate getTime(void) const;
+
+ /**
+ * Sets the time of transition in milliseconds.
+ * @param time The time of the transition in milliseconds since the 1970 Jan 1 epoch time.
+ * @draft ICU 3.8
+ */
+ void setTime(UDate time);
+
+ /**
+ * Returns the rule used before the transition.
+ * @return The time zone rule used after the transition.
+ * @draft ICU 3.8
+ */
+ const TimeZoneRule* getFrom(void) const;
+
+ /**
+ * Sets the rule used before the transition. The caller remains
+ * responsible for deleting the <code>TimeZoneRule</code> object.
+ * @param from The time zone rule used before the transition.
+ * @draft ICU 3.8
+ */
+ void setFrom(const TimeZoneRule& from);
+
+ /**
+ * Adopts the rule used before the transition. The caller must
+ * not delete the <code>TimeZoneRule</code> object passed in.
+ * @param from The time zone rule used before the transition.
+ * @draft ICU 3.8
+ */
+ void adoptFrom(TimeZoneRule* from);
+
+ /**
+ * Sets the rule used after the transition. The caller remains
+ * responsible for deleting the <code>TimeZoneRule</code> object.
+ * @param to The time zone rule used after the transition.
+ * @draft ICU 3.8
+ */
+ void setTo(const TimeZoneRule& to);
+
+ /**
+ * Adopts the rule used after the transition. The caller must
+ * not delete the <code>TimeZoneRule</code> object passed in.
+ * @param to The time zone rule used after the transition.
+ * @draft ICU 3.8
+ */
+ void adoptTo(TimeZoneRule* to);
+
+ /**
+ * Returns the rule used after the transition.
+ * @return The time zone rule used after the transition.
+ * @draft ICU 3.8
+ */
+ const TimeZoneRule* getTo(void) const;
+
+private:
+ UDate fTime;
+ TimeZoneRule* fFrom;
+ TimeZoneRule* fTo;
+
+public:
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // TZTRANS_H
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/ucal.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucal.h
new file mode 100644
index 00000000000..43648f4c502
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucal.h
@@ -0,0 +1,1089 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ *******************************************************************************
+ */
+
+#ifndef UCAL_H
+#define UCAL_H
+
+#include "unicode/utypes.h"
+#include "unicode/uenum.h"
+#include "unicode/uloc.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * \file
+ * \brief C API: Calendar
+ *
+ * <h2>Calendar C API</h2>
+ *
+ * UCalendar C API is used for converting between a <code>UDate</code> object
+ * and a set of integer fields such as <code>UCAL_YEAR</code>, <code>UCAL_MONTH</code>,
+ * <code>UCAL_DAY</code>, <code>UCAL_HOUR</code>, and so on.
+ * (A <code>UDate</code> object represents a specific instant in
+ * time with millisecond precision. See UDate
+ * for information about the <code>UDate</code> .)
+ *
+ * <p>
+ * Types of <code>UCalendar</code> interpret a <code>UDate</code>
+ * according to the rules of a specific calendar system. The U_STABLE
+ * provides the enum UCalendarType with UCAL_TRADITIONAL and
+ * UCAL_GREGORIAN.
+ * <p>
+ * Like other locale-sensitive C API, calendar API provides a
+ * function, <code>ucal_open()</code>, which returns a pointer to
+ * <code>UCalendar</code> whose time fields have been initialized
+ * with the current date and time. We need to specify the type of
+ * calendar to be opened and the timezoneId.
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * \code
+ * UCalendar *caldef;
+ * UChar *tzId;
+ * UErrorCode status;
+ * tzId=(UChar*)malloc(sizeof(UChar) * (strlen("PST") +1) );
+ * u_uastrcpy(tzId, "PST");
+ * caldef=ucal_open(tzID, u_strlen(tzID), NULL, UCAL_TRADITIONAL, &status);
+ * \endcode
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * <p>
+ * A <code>UCalendar</code> object can produce all the time field values
+ * needed to implement the date-time formatting for a particular language
+ * and calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
+ *
+ * <p>
+ * When computing a <code>UDate</code> from time fields, two special circumstances
+ * may arise: there may be insufficient information to compute the
+ * <code>UDate</code> (such as only year and month but no day in the month),
+ * or there may be inconsistent information (such as "Tuesday, July 15, 1996"
+ * -- July 15, 1996 is actually a Monday).
+ *
+ * <p>
+ * <strong>Insufficient information.</strong> The calendar will use default
+ * information to specify the missing fields. This may vary by calendar; for
+ * the Gregorian calendar, the default for a field is the same as that of the
+ * start of the epoch: i.e., UCAL_YEAR = 1970, UCAL_MONTH = JANUARY, UCAL_DATE = 1, etc.
+ *
+ * <p>
+ * <strong>Inconsistent information.</strong> If fields conflict, the calendar
+ * will give preference to fields set more recently. For example, when
+ * determining the day, the calendar will look for one of the following
+ * combinations of fields. The most recent combination, as determined by the
+ * most recently set single field, will be used.
+ *
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * \code
+ * UCAL_MONTH + UCAL_DAY_OF_MONTH
+ * UCAL_MONTH + UCAL_WEEK_OF_MONTH + UCAL_DAY_OF_WEEK
+ * UCAL_MONTH + UCAL_DAY_OF_WEEK_IN_MONTH + UCAL_DAY_OF_WEEK
+ * UCAL_DAY_OF_YEAR
+ * UCAL_DAY_OF_WEEK + UCAL_WEEK_OF_YEAR
+ * \endcode
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * For the time of day:
+ *
+ * \htmlonly<blockquote>\endhtmlonly
+ * <pre>
+ * \code
+ * UCAL_HOUR_OF_DAY
+ * UCAL_AM_PM + UCAL_HOUR
+ * \endcode
+ * </pre>
+ * \htmlonly</blockquote>\endhtmlonly
+ *
+ * <p>
+ * <strong>Note:</strong> for some non-Gregorian calendars, different
+ * fields may be necessary for complete disambiguation. For example, a full
+ * specification of the historial Arabic astronomical calendar requires year,
+ * month, day-of-month <em>and</em> day-of-week in some cases.
+ *
+ * <p>
+ * <strong>Note:</strong> There are certain possible ambiguities in
+ * interpretation of certain singular times, which are resolved in the
+ * following ways:
+ * <ol>
+ * <li> 24:00:00 "belongs" to the following day. That is,
+ * 23:59 on Dec 31, 1969 &lt; 24:00 on Jan 1, 1970 &lt; 24:01:00 on Jan 1, 1970
+ *
+ * <li> Although historically not precise, midnight also belongs to "am",
+ * and noon belongs to "pm", so on the same day,
+ * 12:00 am (midnight) &lt; 12:01 am, and 12:00 pm (noon) &lt; 12:01 pm
+ * </ol>
+ *
+ * <p>
+ * The date or time format strings are not part of the definition of a
+ * calendar, as those must be modifiable or overridable by the user at
+ * runtime. Use {@link DateFormat}
+ * to format dates.
+ *
+ * <p>
+ * <code>Calendar</code> provides an API for field "rolling", where fields
+ * can be incremented or decremented, but wrap around. For example, rolling the
+ * month up in the date <code>December 12, <b>1996</b></code> results in
+ * <code>January 12, <b>1996</b></code>.
+ *
+ * <p>
+ * <code>Calendar</code> also provides a date arithmetic function for
+ * adding the specified (signed) amount of time to a particular time field.
+ * For example, subtracting 5 days from the date <code>September 12, 1996</code>
+ * results in <code>September 7, 1996</code>.
+ *
+ * @stable ICU 2.0
+ */
+
+/** A calendar.
+ * For usage in C programs.
+ * @stable ICU 2.0
+ */
+typedef void* UCalendar;
+
+/** Possible types of UCalendars
+ * @stable ICU 2.0
+ */
+enum UCalendarType {
+ /** A traditional calendar for the locale */
+ UCAL_TRADITIONAL,
+ /** The Gregorian calendar */
+ UCAL_GREGORIAN
+};
+
+/** @stable ICU 2.0 */
+typedef enum UCalendarType UCalendarType;
+
+/** Possible fields in a UCalendar
+ * @stable ICU 2.0
+ */
+enum UCalendarDateFields {
+ /**
+ * Field number indicating the era, e.g., AD or BC in the Gregorian (Julian) calendar.
+ * This is a calendar-specific value.
+ * @stable ICU 2.6
+ */
+ UCAL_ERA,
+
+ /**
+ * Field number indicating the year. This is a calendar-specific value.
+ * @stable ICU 2.6
+ */
+ UCAL_YEAR,
+
+ /**
+ * Field number indicating the month. This is a calendar-specific value.
+ * The first month of the year is
+ * <code>JANUARY</code>; the last depends on the number of months in a year.
+ * @see #UCAL_JANUARY
+ * @see #UCAL_FEBRUARY
+ * @see #UCAL_MARCH
+ * @see #UCAL_APRIL
+ * @see #UCAL_MAY
+ * @see #UCAL_JUNE
+ * @see #UCAL_JULY
+ * @see #UCAL_AUGUST
+ * @see #UCAL_SEPTEMBER
+ * @see #UCAL_OCTOBER
+ * @see #UCAL_NOVEMBER
+ * @see #UCAL_DECEMBER
+ * @see #UCAL_UNDECIMBER
+ * @stable ICU 2.6
+ */
+ UCAL_MONTH,
+
+ /**
+ * Field number indicating the
+ * week number within the current year. The first week of the year, as
+ * defined by <code>UCAL_FIRST_DAY_OF_WEEK</code> and <code>UCAL_MINIMAL_DAYS_IN_FIRST_WEEK</code>
+ * attributes, has value 1. Subclasses define
+ * the value of <code>UCAL_WEEK_OF_YEAR</code> for days before the first week of
+ * the year.
+ * @see ucal_getAttribute
+ * @see ucal_setAttribute
+ * @stable ICU 2.6
+ */
+ UCAL_WEEK_OF_YEAR,
+
+ /**
+ * Field number indicating the
+ * week number within the current month. The first week of the month, as
+ * defined by <code>UCAL_FIRST_DAY_OF_WEEK</code> and <code>UCAL_MINIMAL_DAYS_IN_FIRST_WEEK</code>
+ * attributes, has value 1. Subclasses define
+ * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
+ * the month.
+ * @see ucal_getAttribute
+ * @see ucal_setAttribute
+ * @see #UCAL_FIRST_DAY_OF_WEEK
+ * @see #UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
+ * @stable ICU 2.6
+ */
+ UCAL_WEEK_OF_MONTH,
+
+ /**
+ * Field number indicating the
+ * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
+ * The first day of the month has value 1.
+ * @see #UCAL_DAY_OF_MONTH
+ * @stable ICU 2.6
+ */
+ UCAL_DATE,
+
+ /**
+ * Field number indicating the day
+ * number within the current year. The first day of the year has value 1.
+ * @stable ICU 2.6
+ */
+ UCAL_DAY_OF_YEAR,
+
+ /**
+ * Field number indicating the day
+ * of the week. This field takes values <code>SUNDAY</code>,
+ * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
+ * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
+ * @see #UCAL_SUNDAY
+ * @see #UCAL_MONDAY
+ * @see #UCAL_TUESDAY
+ * @see #UCAL_WEDNESDAY
+ * @see #UCAL_THURSDAY
+ * @see #UCAL_FRIDAY
+ * @see #UCAL_SATURDAY
+ * @stable ICU 2.6
+ */
+ UCAL_DAY_OF_WEEK,
+
+ /**
+ * Field number indicating the
+ * ordinal number of the day of the week within the current month. Together
+ * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
+ * within a month. Unlike <code>WEEK_OF_MONTH</code> and
+ * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
+ * <code>getFirstDayOfWeek()</code> or
+ * <code>getMinimalDaysInFirstWeek()</code>. <code>DAY_OF_MONTH 1</code>
+ * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
+ * 1</code>; <code>8</code> through <code>15</code> correspond to
+ * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
+ * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
+ * <code>DAY_OF_WEEK_IN_MONTH 1</code>. Negative values count back from the
+ * end of the month, so the last Sunday of a month is specified as
+ * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>. Because
+ * negative values count backward they will usually be aligned differently
+ * within the month than positive values. For example, if a month has 31
+ * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
+ * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
+ * @see #UCAL_DAY_OF_WEEK
+ * @see #UCAL_WEEK_OF_MONTH
+ * @stable ICU 2.6
+ */
+ UCAL_DAY_OF_WEEK_IN_MONTH,
+
+ /**
+ * Field number indicating
+ * whether the <code>HOUR</code> is before or after noon.
+ * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
+ * @see #UCAL_AM
+ * @see #UCAL_PM
+ * @see #UCAL_HOUR
+ * @stable ICU 2.6
+ */
+ UCAL_AM_PM,
+
+ /**
+ * Field number indicating the
+ * hour of the morning or afternoon. <code>HOUR</code> is used for the 12-hour
+ * clock.
+ * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
+ * @see #UCAL_AM_PM
+ * @see #UCAL_HOUR_OF_DAY
+ * @stable ICU 2.6
+ */
+ UCAL_HOUR,
+
+ /**
+ * Field number indicating the
+ * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
+ * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
+ * @see #UCAL_HOUR
+ * @stable ICU 2.6
+ */
+ UCAL_HOUR_OF_DAY,
+
+ /**
+ * Field number indicating the
+ * minute within the hour.
+ * E.g., at 10:04:15.250 PM the <code>UCAL_MINUTE</code> is 4.
+ * @stable ICU 2.6
+ */
+ UCAL_MINUTE,
+
+ /**
+ * Field number indicating the
+ * second within the minute.
+ * E.g., at 10:04:15.250 PM the <code>UCAL_SECOND</code> is 15.
+ * @stable ICU 2.6
+ */
+ UCAL_SECOND,
+
+ /**
+ * Field number indicating the
+ * millisecond within the second.
+ * E.g., at 10:04:15.250 PM the <code>UCAL_MILLISECOND</code> is 250.
+ * @stable ICU 2.6
+ */
+ UCAL_MILLISECOND,
+
+ /**
+ * Field number indicating the
+ * raw offset from GMT in milliseconds.
+ * @stable ICU 2.6
+ */
+ UCAL_ZONE_OFFSET,
+
+ /**
+ * Field number indicating the
+ * daylight savings offset in milliseconds.
+ * @stable ICU 2.6
+ */
+ UCAL_DST_OFFSET,
+
+ /**
+ * Field number
+ * indicating the extended year corresponding to the
+ * <code>UCAL_WEEK_OF_YEAR</code> field. This may be one greater or less
+ * than the value of <code>UCAL_EXTENDED_YEAR</code>.
+ * @stable ICU 2.6
+ */
+ UCAL_YEAR_WOY,
+
+ /**
+ * Field number
+ * indicating the localized day of week. This will be a value from 1
+ * to 7 inclusive, with 1 being the localized first day of the week.
+ * @stable ICU 2.6
+ */
+ UCAL_DOW_LOCAL,
+
+ /**
+ * Year of this calendar system, encompassing all supra-year fields. For example,
+ * in Gregorian/Julian calendars, positive Extended Year values indicate years AD,
+ * 1 BC = 0 extended, 2 BC = -1 extended, and so on.
+ * @stable ICU 2.8
+ */
+ UCAL_EXTENDED_YEAR,
+
+ /**
+ * Field number
+ * indicating the modified Julian day number. This is different from
+ * the conventional Julian day number in two regards. First, it
+ * demarcates days at local zone midnight, rather than noon GMT.
+ * Second, it is a local number; that is, it depends on the local time
+ * zone. It can be thought of as a single number that encompasses all
+ * the date-related fields.
+ * @stable ICU 2.8
+ */
+ UCAL_JULIAN_DAY,
+
+ /**
+ * Ranges from 0 to 23:59:59.999 (regardless of DST). This field behaves <em>exactly</em>
+ * like a composite of all time-related fields, not including the zone fields. As such,
+ * it also reflects discontinuities of those fields on DST transition days. On a day
+ * of DST onset, it will jump forward. On a day of DST cessation, it will jump
+ * backward. This reflects the fact that it must be combined with the DST_OFFSET field
+ * to obtain a unique local time value.
+ * @stable ICU 2.8
+ */
+ UCAL_MILLISECONDS_IN_DAY,
+
+ /**
+ * Field count
+ * @stable ICU 2.6
+ */
+ UCAL_FIELD_COUNT,
+
+ /**
+ * Field number indicating the
+ * day of the month. This is a synonym for <code>UCAL_DATE</code>.
+ * The first day of the month has value 1.
+ * @see #UCAL_DATE
+ * Synonym for UCAL_DATE
+ * @stable ICU 2.8
+ **/
+ UCAL_DAY_OF_MONTH=UCAL_DATE
+};
+
+/** @stable ICU 2.0 */
+typedef enum UCalendarDateFields UCalendarDateFields;
+ /**
+ * Useful constant for days of week. Note: Calendar day-of-week is 1-based. Clients
+ * who create locale resources for the field of first-day-of-week should be aware of
+ * this. For instance, in US locale, first-day-of-week is set to 1, i.e., UCAL_SUNDAY.
+ */
+/** Possible days of the week in a UCalendar
+ * @stable ICU 2.0
+ */
+enum UCalendarDaysOfWeek {
+ /** Sunday */
+ UCAL_SUNDAY = 1,
+ /** Monday */
+ UCAL_MONDAY,
+ /** Tuesday */
+ UCAL_TUESDAY,
+ /** Wednesday */
+ UCAL_WEDNESDAY,
+ /** Thursday */
+ UCAL_THURSDAY,
+ /** Friday */
+ UCAL_FRIDAY,
+ /** Saturday */
+ UCAL_SATURDAY
+};
+
+/** @stable ICU 2.0 */
+typedef enum UCalendarDaysOfWeek UCalendarDaysOfWeek;
+
+/** Possible months in a UCalendar. Note: Calendar month is 0-based.
+ * @stable ICU 2.0
+ */
+enum UCalendarMonths {
+ /** January */
+ UCAL_JANUARY,
+ /** February */
+ UCAL_FEBRUARY,
+ /** March */
+ UCAL_MARCH,
+ /** April */
+ UCAL_APRIL,
+ /** May */
+ UCAL_MAY,
+ /** June */
+ UCAL_JUNE,
+ /** July */
+ UCAL_JULY,
+ /** August */
+ UCAL_AUGUST,
+ /** September */
+ UCAL_SEPTEMBER,
+ /** October */
+ UCAL_OCTOBER,
+ /** November */
+ UCAL_NOVEMBER,
+ /** December */
+ UCAL_DECEMBER,
+ /** Value of the <code>UCAL_MONTH</code> field indicating the
+ * thirteenth month of the year. Although the Gregorian calendar
+ * does not use this value, lunar calendars do.
+ */
+ UCAL_UNDECIMBER
+};
+
+/** @stable ICU 2.0 */
+typedef enum UCalendarMonths UCalendarMonths;
+
+/** Possible AM/PM values in a UCalendar
+ * @stable ICU 2.0
+ */
+enum UCalendarAMPMs {
+ /** AM */
+ UCAL_AM,
+ /** PM */
+ UCAL_PM
+};
+
+/** @stable ICU 2.0 */
+typedef enum UCalendarAMPMs UCalendarAMPMs;
+
+/**
+ * Create an enumeration over all time zones.
+ *
+ * @param ec input/output error code
+ *
+ * @return an enumeration object that the caller must dispose of using
+ * uenum_close(), or NULL upon failure. In case of failure *ec will
+ * indicate the error.
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE UEnumeration* U_EXPORT2
+ucal_openTimeZones(UErrorCode* ec);
+
+/**
+ * Create an enumeration over all time zones associated with the given
+ * country. Some zones are affiliated with no country (e.g., "UTC");
+ * these may also be retrieved, as a group.
+ *
+ * @param country the ISO 3166 two-letter country code, or NULL to
+ * retrieve zones not affiliated with any country
+ *
+ * @param ec input/output error code
+ *
+ * @return an enumeration object that the caller must dispose of using
+ * uenum_close(), or NULL upon failure. In case of failure *ec will
+ * indicate the error.
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE UEnumeration* U_EXPORT2
+ucal_openCountryTimeZones(const char* country, UErrorCode* ec);
+
+/**
+ * Return the default time zone. The default is determined initially
+ * by querying the host operating system. It may be changed with
+ * ucal_setDefaultTimeZone() or with the C++ TimeZone API.
+ *
+ * @param result A buffer to receive the result, or NULL
+ *
+ * @param resultCapacity The capacity of the result buffer
+ *
+ * @param ec input/output error code
+ *
+ * @return The result string length, not including the terminating
+ * null
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* ec);
+
+/**
+ * Set the default time zone.
+ *
+ * @param zoneID null-terminated time zone ID
+ *
+ * @param ec input/output error code
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE void U_EXPORT2
+ucal_setDefaultTimeZone(const UChar* zoneID, UErrorCode* ec);
+
+/**
+ * Return the amount of time in milliseconds that the clock is
+ * advanced during daylight savings time for the given time zone, or
+ * zero if the time zone does not observe daylight savings time.
+ *
+ * @param zoneID null-terminated time zone ID
+ *
+ * @param ec input/output error code
+ *
+ * @return the number of milliseconds the time is advanced with
+ * respect to standard time when the daylight savings rules are in
+ * effect. This is always a non-negative number, most commonly either
+ * 3,600,000 (one hour) or zero.
+ *
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+ucal_getDSTSavings(const UChar* zoneID, UErrorCode* ec);
+
+/**
+ * Get the current date and time.
+ * The value returned is represented as milliseconds from the epoch.
+ * @return The current date and time.
+ * @stable ICU 2.0
+ */
+U_STABLE UDate U_EXPORT2
+ucal_getNow(void);
+
+/**
+ * Open a UCalendar.
+ * A UCalendar may be used to convert a millisecond value to a year,
+ * month, and day.
+ * @param zoneID The desired TimeZone ID. If 0, use the default time zone.
+ * @param len The length of zoneID, or -1 if null-terminated.
+ * @param locale The desired locale
+ * @param type The type of UCalendar to open.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @return A pointer to a UCalendar, or 0 if an error occurred.
+ * @stable ICU 2.0
+ */
+U_STABLE UCalendar* U_EXPORT2
+ucal_open(const UChar* zoneID,
+ int32_t len,
+ const char* locale,
+ UCalendarType type,
+ UErrorCode* status);
+
+/**
+ * Close a UCalendar.
+ * Once closed, a UCalendar may no longer be used.
+ * @param cal The UCalendar to close.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_close(UCalendar *cal);
+
+/**
+ * Set the TimeZone used by a UCalendar.
+ * A UCalendar uses a timezone for converting from Greenwich time to local time.
+ * @param cal The UCalendar to set.
+ * @param zoneID The desired TimeZone ID. If 0, use the default time zone.
+ * @param len The length of zoneID, or -1 if null-terminated.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_setTimeZone(UCalendar* cal,
+ const UChar* zoneID,
+ int32_t len,
+ UErrorCode* status);
+
+/**
+ * Possible formats for a UCalendar's display name
+ * @stable ICU 2.0
+ */
+enum UCalendarDisplayNameType {
+ /** Standard display name */
+ UCAL_STANDARD,
+ /** Short standard display name */
+ UCAL_SHORT_STANDARD,
+ /** Daylight savings display name */
+ UCAL_DST,
+ /** Short daylight savings display name */
+ UCAL_SHORT_DST
+};
+
+/** @stable ICU 2.0 */
+typedef enum UCalendarDisplayNameType UCalendarDisplayNameType;
+
+/**
+ * Get the display name for a UCalendar's TimeZone.
+ * A display name is suitable for presentation to a user.
+ * @param cal The UCalendar to query.
+ * @param type The desired display name format; one of UCAL_STANDARD, UCAL_SHORT_STANDARD,
+ * UCAL_DST, UCAL_SHORT_DST
+ * @param locale The desired locale for the display name.
+ * @param result A pointer to a buffer to receive the formatted number.
+ * @param resultLength The maximum size of result.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @return The total buffer size needed; if greater than resultLength, the output was truncated.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucal_getTimeZoneDisplayName(const UCalendar* cal,
+ UCalendarDisplayNameType type,
+ const char* locale,
+ UChar* result,
+ int32_t resultLength,
+ UErrorCode* status);
+
+/**
+ * Determine if a UCalendar is currently in daylight savings time.
+ * Daylight savings time is not used in all parts of the world.
+ * @param cal The UCalendar to query.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @return TRUE if cal is currently in daylight savings time, FALSE otherwise
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+ucal_inDaylightTime(const UCalendar* cal,
+ UErrorCode* status );
+
+/**
+ * Sets the GregorianCalendar change date. This is the point when the switch from
+ * Julian dates to Gregorian dates occurred. Default is 00:00:00 local time, October
+ * 15, 1582. Previous to this time and date will be Julian dates.
+ *
+ * This function works only for Gregorian calendars. If the UCalendar is not
+ * an instance of a Gregorian calendar, then a U_UNSUPPORTED_ERROR
+ * error code is set.
+ *
+ * @param cal The calendar object.
+ * @param date The given Gregorian cutover date.
+ * @param pErrorCode Pointer to a standard ICU error code. Its input value must
+ * pass the U_SUCCESS() test, or else the function returns
+ * immediately. Check for U_FAILURE() on output or use with
+ * function chaining. (See User Guide for details.)
+ *
+ * @see GregorianCalendar::setGregorianChange
+ * @see ucal_getGregorianChange
+ * @stable ICU 3.6
+ */
+U_STABLE void U_EXPORT2
+ucal_setGregorianChange(UCalendar *cal, UDate date, UErrorCode *pErrorCode);
+
+/**
+ * Gets the Gregorian Calendar change date. This is the point when the switch from
+ * Julian dates to Gregorian dates occurred. Default is 00:00:00 local time, October
+ * 15, 1582. Previous to this time and date will be Julian dates.
+ *
+ * This function works only for Gregorian calendars. If the UCalendar is not
+ * an instance of a Gregorian calendar, then a U_UNSUPPORTED_ERROR
+ * error code is set.
+ *
+ * @param cal The calendar object.
+ * @param pErrorCode Pointer to a standard ICU error code. Its input value must
+ * pass the U_SUCCESS() test, or else the function returns
+ * immediately. Check for U_FAILURE() on output or use with
+ * function chaining. (See User Guide for details.)
+ * @return The Gregorian cutover time for this calendar.
+ *
+ * @see GregorianCalendar::getGregorianChange
+ * @see ucal_setGregorianChange
+ * @stable ICU 3.6
+ */
+U_STABLE UDate U_EXPORT2
+ucal_getGregorianChange(const UCalendar *cal, UErrorCode *pErrorCode);
+
+/**
+ * Types of UCalendar attributes
+ * @stable ICU 2.0
+ */
+enum UCalendarAttribute {
+ /** Lenient parsing */
+ UCAL_LENIENT,
+ /** First day of week */
+ UCAL_FIRST_DAY_OF_WEEK,
+ /** Minimum number of days in first week */
+ UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
+};
+
+/** @stable ICU 2.0 */
+typedef enum UCalendarAttribute UCalendarAttribute;
+
+/**
+ * Get a numeric attribute associated with a UCalendar.
+ * Numeric attributes include the first day of the week, or the minimal numbers
+ * of days in the first week of the month.
+ * @param cal The UCalendar to query.
+ * @param attr The desired attribute; one of UCAL_LENIENT, UCAL_FIRST_DAY_OF_WEEK,
+ * or UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
+ * @return The value of attr.
+ * @see ucal_setAttribute
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucal_getAttribute(const UCalendar* cal,
+ UCalendarAttribute attr);
+
+/**
+ * Set a numeric attribute associated with a UCalendar.
+ * Numeric attributes include the first day of the week, or the minimal numbers
+ * of days in the first week of the month.
+ * @param cal The UCalendar to set.
+ * @param attr The desired attribute; one of UCAL_LENIENT, UCAL_FIRST_DAY_OF_WEEK,
+ * or UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
+ * @param newValue The new value of attr.
+ * @see ucal_getAttribute
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_setAttribute(UCalendar* cal,
+ UCalendarAttribute attr,
+ int32_t newValue);
+
+/**
+ * Get a locale for which calendars are available.
+ * A UCalendar in a locale returned by this function will contain the correct
+ * day and month names for the locale.
+ * @param index The index of the desired locale.
+ * @return A locale for which calendars are available, or 0 if none.
+ * @see ucal_countAvailable
+ * @stable ICU 2.0
+ */
+U_STABLE const char* U_EXPORT2
+ucal_getAvailable(int32_t index);
+
+/**
+ * Determine how many locales have calendars available.
+ * This function is most useful as determining the loop ending condition for
+ * calls to \ref ucal_getAvailable.
+ * @return The number of locales for which calendars are available.
+ * @see ucal_getAvailable
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucal_countAvailable(void);
+
+/**
+ * Get a UCalendar's current time in millis.
+ * The time is represented as milliseconds from the epoch.
+ * @param cal The UCalendar to query.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @return The calendar's current time in millis.
+ * @see ucal_setMillis
+ * @see ucal_setDate
+ * @see ucal_setDateTime
+ * @stable ICU 2.0
+ */
+U_STABLE UDate U_EXPORT2
+ucal_getMillis(const UCalendar* cal,
+ UErrorCode* status);
+
+/**
+ * Set a UCalendar's current time in millis.
+ * The time is represented as milliseconds from the epoch.
+ * @param cal The UCalendar to set.
+ * @param dateTime The desired date and time.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @see ucal_getMillis
+ * @see ucal_setDate
+ * @see ucal_setDateTime
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_setMillis(UCalendar* cal,
+ UDate dateTime,
+ UErrorCode* status );
+
+/**
+ * Set a UCalendar's current date.
+ * The date is represented as a series of 32-bit integers.
+ * @param cal The UCalendar to set.
+ * @param year The desired year.
+ * @param month The desired month; one of UCAL_JANUARY, UCAL_FEBRUARY, UCAL_MARCH, UCAL_APRIL, UCAL_MAY,
+ * UCAL_JUNE, UCAL_JULY, UCAL_AUGUST, UCAL_SEPTEMBER, UCAL_OCTOBER, UCAL_NOVEMBER, UCAL_DECEMBER, UCAL_UNDECIMBER
+ * @param date The desired day of the month.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @see ucal_getMillis
+ * @see ucal_setMillis
+ * @see ucal_setDateTime
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_setDate(UCalendar* cal,
+ int32_t year,
+ int32_t month,
+ int32_t date,
+ UErrorCode* status);
+
+/**
+ * Set a UCalendar's current date.
+ * The date is represented as a series of 32-bit integers.
+ * @param cal The UCalendar to set.
+ * @param year The desired year.
+ * @param month The desired month; one of UCAL_JANUARY, UCAL_FEBRUARY, UCAL_MARCH, UCAL_APRIL, UCAL_MAY,
+ * UCAL_JUNE, UCAL_JULY, UCAL_AUGUST, UCAL_SEPTEMBER, UCAL_OCTOBER, UCAL_NOVEMBER, UCAL_DECEMBER, UCAL_UNDECIMBER
+ * @param date The desired day of the month.
+ * @param hour The desired hour of day.
+ * @param minute The desired minute.
+ * @param second The desirec second.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @see ucal_getMillis
+ * @see ucal_setMillis
+ * @see ucal_setDate
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_setDateTime(UCalendar* cal,
+ int32_t year,
+ int32_t month,
+ int32_t date,
+ int32_t hour,
+ int32_t minute,
+ int32_t second,
+ UErrorCode* status);
+
+/**
+ * Returns TRUE if two UCalendars are equivalent. Equivalent
+ * UCalendars will behave identically, but they may be set to
+ * different times.
+ * @param cal1 The first of the UCalendars to compare.
+ * @param cal2 The second of the UCalendars to compare.
+ * @return TRUE if cal1 and cal2 are equivalent, FALSE otherwise.
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+ucal_equivalentTo(const UCalendar* cal1,
+ const UCalendar* cal2);
+
+/**
+ * Add a specified signed amount to a particular field in a UCalendar.
+ * This can modify more significant fields in the calendar.
+ * @param cal The UCalendar to which to add.
+ * @param field The field to which to add the signed value; one of UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
+ * UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_DATE, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK,
+ * UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_AM_PM, UCAL_HOUR, UCAL_HOUR_OF_DAY, UCAL_MINUTE, UCAL_SECOND,
+ * UCAL_MILLISECOND, UCAL_ZONE_OFFSET, UCAL_DST_OFFSET.
+ * @param amount The signed amount to add to field. If the amount causes the value
+ * to exceed to maximum or minimum values for that field, other fields are modified
+ * to preserve the magnitude of the change.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @see ucal_roll
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_add(UCalendar* cal,
+ UCalendarDateFields field,
+ int32_t amount,
+ UErrorCode* status);
+
+/**
+ * Add a specified signed amount to a particular field in a UCalendar.
+ * This will not modify more significant fields in the calendar.
+ * @param cal The UCalendar to which to add.
+ * @param field The field to which to add the signed value; one of UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
+ * UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_DATE, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK,
+ * UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_AM_PM, UCAL_HOUR, UCAL_HOUR_OF_DAY, UCAL_MINUTE, UCAL_SECOND,
+ * UCAL_MILLISECOND, UCAL_ZONE_OFFSET, UCAL_DST_OFFSET.
+ * @param amount The signed amount to add to field. If the amount causes the value
+ * to exceed to maximum or minimum values for that field, the field is pinned to a permissible
+ * value.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @see ucal_add
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_roll(UCalendar* cal,
+ UCalendarDateFields field,
+ int32_t amount,
+ UErrorCode* status);
+
+/**
+ * Get the current value of a field from a UCalendar.
+ * All fields are represented as 32-bit integers.
+ * @param cal The UCalendar to query.
+ * @param field The desired field; one of UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
+ * UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_DATE, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK,
+ * UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_AM_PM, UCAL_HOUR, UCAL_HOUR_OF_DAY, UCAL_MINUTE, UCAL_SECOND,
+ * UCAL_MILLISECOND, UCAL_ZONE_OFFSET, UCAL_DST_OFFSET.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @return The value of the desired field.
+ * @see ucal_set
+ * @see ucal_isSet
+ * @see ucal_clearField
+ * @see ucal_clear
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucal_get(const UCalendar* cal,
+ UCalendarDateFields field,
+ UErrorCode* status );
+
+/**
+ * Set the value of a field in a UCalendar.
+ * All fields are represented as 32-bit integers.
+ * @param cal The UCalendar to set.
+ * @param field The field to set; one of UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
+ * UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_DATE, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK,
+ * UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_AM_PM, UCAL_HOUR, UCAL_HOUR_OF_DAY, UCAL_MINUTE, UCAL_SECOND,
+ * UCAL_MILLISECOND, UCAL_ZONE_OFFSET, UCAL_DST_OFFSET.
+ * @param value The desired value of field.
+ * @see ucal_get
+ * @see ucal_isSet
+ * @see ucal_clearField
+ * @see ucal_clear
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_set(UCalendar* cal,
+ UCalendarDateFields field,
+ int32_t value);
+
+/**
+ * Determine if a field in a UCalendar is set.
+ * All fields are represented as 32-bit integers.
+ * @param cal The UCalendar to query.
+ * @param field The desired field; one of UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
+ * UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_DATE, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK,
+ * UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_AM_PM, UCAL_HOUR, UCAL_HOUR_OF_DAY, UCAL_MINUTE, UCAL_SECOND,
+ * UCAL_MILLISECOND, UCAL_ZONE_OFFSET, UCAL_DST_OFFSET.
+ * @return TRUE if field is set, FALSE otherwise.
+ * @see ucal_get
+ * @see ucal_set
+ * @see ucal_clearField
+ * @see ucal_clear
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+ucal_isSet(const UCalendar* cal,
+ UCalendarDateFields field);
+
+/**
+ * Clear a field in a UCalendar.
+ * All fields are represented as 32-bit integers.
+ * @param cal The UCalendar containing the field to clear.
+ * @param field The field to clear; one of UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
+ * UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_DATE, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK,
+ * UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_AM_PM, UCAL_HOUR, UCAL_HOUR_OF_DAY, UCAL_MINUTE, UCAL_SECOND,
+ * UCAL_MILLISECOND, UCAL_ZONE_OFFSET, UCAL_DST_OFFSET.
+ * @see ucal_get
+ * @see ucal_set
+ * @see ucal_isSet
+ * @see ucal_clear
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_clearField(UCalendar* cal,
+ UCalendarDateFields field);
+
+/**
+ * Clear all fields in a UCalendar.
+ * All fields are represented as 32-bit integers.
+ * @param calendar The UCalendar to clear.
+ * @see ucal_get
+ * @see ucal_set
+ * @see ucal_isSet
+ * @see ucal_clearField
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucal_clear(UCalendar* calendar);
+
+/**
+ * Possible limit values for a UCalendar
+ * @stable ICU 2.0
+ */
+enum UCalendarLimitType {
+ /** Minimum value */
+ UCAL_MINIMUM,
+ /** Maximum value */
+ UCAL_MAXIMUM,
+ /** Greatest minimum value */
+ UCAL_GREATEST_MINIMUM,
+ /** Leaest maximum value */
+ UCAL_LEAST_MAXIMUM,
+ /** Actual minimum value */
+ UCAL_ACTUAL_MINIMUM,
+ /** Actual maximum value */
+ UCAL_ACTUAL_MAXIMUM
+};
+
+/** @stable ICU 2.0 */
+typedef enum UCalendarLimitType UCalendarLimitType;
+
+/**
+ * Determine a limit for a field in a UCalendar.
+ * A limit is a maximum or minimum value for a field.
+ * @param cal The UCalendar to query.
+ * @param field The desired field; one of UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
+ * UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_DATE, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK,
+ * UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_AM_PM, UCAL_HOUR, UCAL_HOUR_OF_DAY, UCAL_MINUTE, UCAL_SECOND,
+ * UCAL_MILLISECOND, UCAL_ZONE_OFFSET, UCAL_DST_OFFSET.
+ * @param type The desired critical point; one of UCAL_MINIMUM, UCAL_MAXIMUM, UCAL_GREATEST_MINIMUM,
+ * UCAL_LEAST_MAXIMUM, UCAL_ACTUAL_MINIMUM, UCAL_ACTUAL_MAXIMUM
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The requested value.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucal_getLimit(const UCalendar* cal,
+ UCalendarDateFields field,
+ UCalendarLimitType type,
+ UErrorCode* status);
+
+/** Get the locale for this calendar object. You can choose between valid and actual locale.
+ * @param cal The calendar object
+ * @param type type of the locale we're looking for (valid or actual)
+ * @param status error code for the operation
+ * @return the locale name
+ * @stable ICU 2.8
+ */
+U_STABLE const char * U_EXPORT2
+ucal_getLocaleByType(const UCalendar *cal, ULocDataLocaleType type, UErrorCode* status);
+
+/**
+ * Returns the timezone data version currently used by ICU.
+ * @param status error code for the operation
+ * @return the version string, such as "2007f"
+ * @draft ICU 3.8
+ */
+U_DRAFT const char * U_EXPORT2
+ucal_getTZDataVersion(UErrorCode* status);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/ucol.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucol.h
new file mode 100644
index 00000000000..37abe2cc22e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucol.h
@@ -0,0 +1,1223 @@
+/*
+*******************************************************************************
+* Copyright (c) 1996-2007, International Business Machines Corporation and others.
+* All Rights Reserved.
+*******************************************************************************
+*/
+
+#ifndef UCOL_H
+#define UCOL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/unorm.h"
+#include "unicode/parseerr.h"
+#include "unicode/uloc.h"
+#include "unicode/uset.h"
+
+/**
+ * \file
+ * \brief C API: Collator
+ *
+ * <h2> Collator C API </h2>
+ *
+ * The C API for Collator performs locale-sensitive
+ * string comparison. You use this service to build
+ * searching and sorting routines for natural language text.
+ * <em>Important: </em>The ICU collation service has been reimplemented
+ * in order to achieve better performance and UCA compliance.
+ * For details, see the
+ * <a href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm">
+ * collation design document</a>.
+ * <p>
+ * For more information about the collation service see
+ * <a href="http://icu-project.org/userguide/Collate_Intro.html">the users guide</a>.
+ * <p>
+ * Collation service provides correct sorting orders for most locales supported in ICU.
+ * If specific data for a locale is not available, the orders eventually falls back
+ * to the <a href="http://www.unicode.org/unicode/reports/tr10/">UCA sort order</a>.
+ * <p>
+ * Sort ordering may be customized by providing your own set of rules. For more on
+ * this subject see the
+ * <a href="http://icu-project.org/userguide/Collate_Customization.html">
+ * Collation customization</a> section of the users guide.
+ * <p>
+ * @see UCollationResult
+ * @see UNormalizationMode
+ * @see UCollationStrength
+ * @see UCollationElements
+ */
+
+/** A collator.
+* For usage in C programs.
+*/
+struct UCollator;
+/** structure representing a collator object instance
+ * @stable ICU 2.0
+ */
+typedef struct UCollator UCollator;
+
+
+/**
+ * UCOL_LESS is returned if source string is compared to be less than target
+ * string in the u_strcoll() method.
+ * UCOL_EQUAL is returned if source string is compared to be equal to target
+ * string in the u_strcoll() method.
+ * UCOL_GREATER is returned if source string is compared to be greater than
+ * target string in the u_strcoll() method.
+ * @see u_strcoll()
+ * <p>
+ * Possible values for a comparison result
+ * @stable ICU 2.0
+ */
+typedef enum {
+ /** string a == string b */
+ UCOL_EQUAL = 0,
+ /** string a > string b */
+ UCOL_GREATER = 1,
+ /** string a < string b */
+ UCOL_LESS = -1
+} UCollationResult ;
+
+
+/** Enum containing attribute values for controling collation behavior.
+ * Here are all the allowable values. Not every attribute can take every value. The only
+ * universal value is UCOL_DEFAULT, which resets the attribute value to the predefined
+ * value for that locale
+ * @stable ICU 2.0
+ */
+typedef enum {
+ /** accepted by most attributes */
+ UCOL_DEFAULT = -1,
+
+ /** Primary collation strength */
+ UCOL_PRIMARY = 0,
+ /** Secondary collation strength */
+ UCOL_SECONDARY = 1,
+ /** Tertiary collation strength */
+ UCOL_TERTIARY = 2,
+ /** Default collation strength */
+ UCOL_DEFAULT_STRENGTH = UCOL_TERTIARY,
+ UCOL_CE_STRENGTH_LIMIT,
+ /** Quaternary collation strength */
+ UCOL_QUATERNARY=3,
+ /** Identical collation strength */
+ UCOL_IDENTICAL=15,
+ UCOL_STRENGTH_LIMIT,
+
+ /** Turn the feature off - works for UCOL_FRENCH_COLLATION,
+ UCOL_CASE_LEVEL, UCOL_HIRAGANA_QUATERNARY_MODE
+ & UCOL_DECOMPOSITION_MODE*/
+ UCOL_OFF = 16,
+ /** Turn the feature on - works for UCOL_FRENCH_COLLATION,
+ UCOL_CASE_LEVEL, UCOL_HIRAGANA_QUATERNARY_MODE
+ & UCOL_DECOMPOSITION_MODE*/
+ UCOL_ON = 17,
+
+ /** Valid for UCOL_ALTERNATE_HANDLING. Alternate handling will be shifted */
+ UCOL_SHIFTED = 20,
+ /** Valid for UCOL_ALTERNATE_HANDLING. Alternate handling will be non ignorable */
+ UCOL_NON_IGNORABLE = 21,
+
+ /** Valid for UCOL_CASE_FIRST -
+ lower case sorts before upper case */
+ UCOL_LOWER_FIRST = 24,
+ /** upper case sorts before lower case */
+ UCOL_UPPER_FIRST = 25,
+
+ UCOL_ATTRIBUTE_VALUE_COUNT
+
+} UColAttributeValue;
+
+/**
+ * Base letter represents a primary difference. Set comparison
+ * level to UCOL_PRIMARY to ignore secondary and tertiary differences.
+ * Use this to set the strength of a Collator object.
+ * Example of primary difference, "abc" &lt; "abd"
+ *
+ * Diacritical differences on the same base letter represent a secondary
+ * difference. Set comparison level to UCOL_SECONDARY to ignore tertiary
+ * differences. Use this to set the strength of a Collator object.
+ * Example of secondary difference, "&auml;" >> "a".
+ *
+ * Uppercase and lowercase versions of the same character represents a
+ * tertiary difference. Set comparison level to UCOL_TERTIARY to include
+ * all comparison differences. Use this to set the strength of a Collator
+ * object.
+ * Example of tertiary difference, "abc" &lt;&lt;&lt; "ABC".
+ *
+ * Two characters are considered "identical" when they have the same
+ * unicode spellings. UCOL_IDENTICAL.
+ * For example, "&auml;" == "&auml;".
+ *
+ * UCollationStrength is also used to determine the strength of sort keys
+ * generated from UCollator objects
+ * These values can be now found in the UColAttributeValue enum.
+ * @stable ICU 2.0
+ **/
+typedef UColAttributeValue UCollationStrength;
+
+/** Attributes that collation service understands. All the attributes can take UCOL_DEFAULT
+ * value, as well as the values specific to each one.
+ * @stable ICU 2.0
+ */
+typedef enum {
+ /** Attribute for direction of secondary weights - used in French.
+ * Acceptable values are UCOL_ON, which results in secondary weights
+ * being considered backwards and UCOL_OFF which treats secondary
+ * weights in the order they appear.*/
+ UCOL_FRENCH_COLLATION,
+ /** Attribute for handling variable elements.
+ * Acceptable values are UCOL_NON_IGNORABLE (default)
+ * which treats all the codepoints with non-ignorable
+ * primary weights in the same way,
+ * and UCOL_SHIFTED which causes codepoints with primary
+ * weights that are equal or below the variable top value
+ * to be ignored on primary level and moved to the quaternary
+ * level.*/
+ UCOL_ALTERNATE_HANDLING,
+ /** Controls the ordering of upper and lower case letters.
+ * Acceptable values are UCOL_OFF (default), which orders
+ * upper and lower case letters in accordance to their tertiary
+ * weights, UCOL_UPPER_FIRST which forces upper case letters to
+ * sort before lower case letters, and UCOL_LOWER_FIRST which does
+ * the opposite. */
+ UCOL_CASE_FIRST,
+ /** Controls whether an extra case level (positioned before the third
+ * level) is generated or not. Acceptable values are UCOL_OFF (default),
+ * when case level is not generated, and UCOL_ON which causes the case
+ * level to be generated. Contents of the case level are affected by
+ * the value of UCOL_CASE_FIRST attribute. A simple way to ignore
+ * accent differences in a string is to set the strength to UCOL_PRIMARY
+ * and enable case level. */
+ UCOL_CASE_LEVEL,
+ /** Controls whether the normalization check and necessary normalizations
+ * are performed. When set to UCOL_OFF (default) no normalization check
+ * is performed. The correctness of the result is guaranteed only if the
+ * input data is in so-called FCD form (see users manual for more info).
+ * When set to UCOL_ON, an incremental check is performed to see whether
+ * the input data is in the FCD form. If the data is not in the FCD form,
+ * incremental NFD normalization is performed. */
+ UCOL_NORMALIZATION_MODE,
+ /** An alias for UCOL_NORMALIZATION_MODE attribute */
+ UCOL_DECOMPOSITION_MODE = UCOL_NORMALIZATION_MODE,
+ /** The strength attribute. Can be either UCOL_PRIMARY, UCOL_SECONDARY,
+ * UCOL_TERTIARY, UCOL_QUATERNARY or UCOL_IDENTICAL. The usual strength
+ * for most locales (except Japanese) is tertiary. Quaternary strength
+ * is useful when combined with shifted setting for alternate handling
+ * attribute and for JIS x 4061 collation, when it is used to distinguish
+ * between Katakana and Hiragana (this is achieved by setting the
+ * UCOL_HIRAGANA_QUATERNARY mode to on. Otherwise, quaternary level
+ * is affected only by the number of non ignorable code points in
+ * the string. Identical strength is rarely useful, as it amounts
+ * to codepoints of the NFD form of the string. */
+ UCOL_STRENGTH,
+ /** When turned on, this attribute positions Hiragana before all
+ * non-ignorables on quaternary level This is a sneaky way to produce JIS
+ * sort order */
+ UCOL_HIRAGANA_QUATERNARY_MODE,
+ /** When turned on, this attribute generates a collation key
+ * for the numeric value of substrings of digits.
+ * This is a way to get '100' to sort AFTER '2'. */
+ UCOL_NUMERIC_COLLATION,
+ UCOL_ATTRIBUTE_COUNT
+} UColAttribute;
+
+/** Options for retrieving the rule string
+ * @stable ICU 2.0
+ */
+typedef enum {
+ /** Retrieve tailoring only */
+ UCOL_TAILORING_ONLY,
+ /** Retrieve UCA rules and tailoring */
+ UCOL_FULL_RULES
+} UColRuleOption ;
+
+/**
+ * Open a UCollator for comparing strings.
+ * The UCollator pointer is used in all the calls to the Collation
+ * service. After finished, collator must be disposed of by calling
+ * {@link #ucol_close }.
+ * @param loc The locale containing the required collation rules.
+ * Special values for locales can be passed in -
+ * if NULL is passed for the locale, the default locale
+ * collation rules will be used. If empty string ("") or
+ * "root" are passed, UCA rules will be used.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @return A pointer to a UCollator, or 0 if an error occurred.
+ * @see ucol_openRules
+ * @see ucol_safeClone
+ * @see ucol_close
+ * @stable ICU 2.0
+ */
+U_STABLE UCollator* U_EXPORT2
+ucol_open(const char *loc, UErrorCode *status);
+
+/**
+ * Produce an UCollator instance according to the rules supplied.
+ * The rules are used to change the default ordering, defined in the
+ * UCA in a process called tailoring. The resulting UCollator pointer
+ * can be used in the same way as the one obtained by {@link #ucol_strcoll }.
+ * @param rules A string describing the collation rules. For the syntax
+ * of the rules please see users guide.
+ * @param rulesLength The length of rules, or -1 if null-terminated.
+ * @param normalizationMode The normalization mode: One of
+ * UCOL_OFF (expect the text to not need normalization),
+ * UCOL_ON (normalize), or
+ * UCOL_DEFAULT (set the mode according to the rules)
+ * @param strength The default collation strength; one of UCOL_PRIMARY, UCOL_SECONDARY,
+ * UCOL_TERTIARY, UCOL_IDENTICAL,UCOL_DEFAULT_STRENGTH - can be also set in the rules.
+ * @param parseError A pointer to UParseError to recieve information about errors
+ * occurred during parsing. This argument can currently be set
+ * to NULL, but at users own risk. Please provide a real structure.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @return A pointer to a UCollator. It is not guaranteed that NULL be returned in case
+ * of error - please use status argument to check for errors.
+ * @see ucol_open
+ * @see ucol_safeClone
+ * @see ucol_close
+ * @stable ICU 2.0
+ */
+U_STABLE UCollator* U_EXPORT2
+ucol_openRules( const UChar *rules,
+ int32_t rulesLength,
+ UColAttributeValue normalizationMode,
+ UCollationStrength strength,
+ UParseError *parseError,
+ UErrorCode *status);
+
+/**
+ * Open a collator defined by a short form string.
+ * The structure and the syntax of the string is defined in the "Naming collators"
+ * section of the users guide:
+ * http://icu-project.org/userguide/Collate_Concepts.html#Naming_Collators
+ * Attributes are overriden by the subsequent attributes. So, for "S2_S3", final
+ * strength will be 3. 3066bis locale overrides individual locale parts.
+ * The call to this function is equivalent to a call to ucol_open, followed by a
+ * series of calls to ucol_setAttribute and ucol_setVariableTop.
+ * @param definition A short string containing a locale and a set of attributes.
+ * Attributes not explicitly mentioned are left at the default
+ * state for a locale.
+ * @param parseError if not NULL, structure that will get filled with error's pre
+ * and post context in case of error.
+ * @param forceDefaults if FALSE, the settings that are the same as the collator
+ * default settings will not be applied (for example, setting
+ * French secondary on a French collator would not be executed).
+ * If TRUE, all the settings will be applied regardless of the
+ * collator default value. If the definition
+ * strings are to be cached, should be set to FALSE.
+ * @param status Error code. Apart from regular error conditions connected to
+ * instantiating collators (like out of memory or similar), this
+ * API will return an error if an invalid attribute or attribute/value
+ * combination is specified.
+ * @return A pointer to a UCollator or 0 if an error occured (including an
+ * invalid attribute).
+ * @see ucol_open
+ * @see ucol_setAttribute
+ * @see ucol_setVariableTop
+ * @see ucol_getShortDefinitionString
+ * @see ucol_normalizeShortDefinitionString
+ * @stable ICU 3.0
+ *
+ */
+U_STABLE UCollator* U_EXPORT2
+ucol_openFromShortString( const char *definition,
+ UBool forceDefaults,
+ UParseError *parseError,
+ UErrorCode *status);
+
+/**
+ * Get a set containing the contractions defined by the collator. The set includes
+ * both the UCA contractions and the contractions defined by the collator. This set
+ * will contain only strings. If a tailoring explicitly suppresses contractions from
+ * the UCA (like Russian), removed contractions will not be in the resulting set.
+ * @param coll collator
+ * @param conts the set to hold the result. It gets emptied before
+ * contractions are added.
+ * @param status to hold the error code
+ * @return the size of the contraction set
+ *
+ * @deprecated ICU 3.4, use ucol_getContractionsAndExpansions instead
+ */
+U_DEPRECATED int32_t U_EXPORT2
+ucol_getContractions( const UCollator *coll,
+ USet *conts,
+ UErrorCode *status);
+
+/**
+ * Get a set containing the expansions defined by the collator. The set includes
+ * both the UCA expansions and the expansions defined by the tailoring
+ * @param coll collator
+ * @param contractions if not NULL, the set to hold the contractions
+ * @param expansions if not NULL, the set to hold the expansions
+ * @param addPrefixes add the prefix contextual elements to contractions
+ * @param status to hold the error code
+ *
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+ucol_getContractionsAndExpansions( const UCollator *coll,
+ USet *contractions, USet *expansions,
+ UBool addPrefixes, UErrorCode *status);
+
+/**
+ * Close a UCollator.
+ * Once closed, a UCollator should not be used. Every open collator should
+ * be closed. Otherwise, a memory leak will result.
+ * @param coll The UCollator to close.
+ * @see ucol_open
+ * @see ucol_openRules
+ * @see ucol_safeClone
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucol_close(UCollator *coll);
+
+/**
+ * Compare two strings.
+ * The strings will be compared using the options already specified.
+ * @param coll The UCollator containing the comparison rules.
+ * @param source The source string.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param target The target string.
+ * @param targetLength The length of target, or -1 if null-terminated.
+ * @return The result of comparing the strings; one of UCOL_EQUAL,
+ * UCOL_GREATER, UCOL_LESS
+ * @see ucol_greater
+ * @see ucol_greaterOrEqual
+ * @see ucol_equal
+ * @stable ICU 2.0
+ */
+U_STABLE UCollationResult U_EXPORT2
+ucol_strcoll( const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ const UChar *target,
+ int32_t targetLength);
+
+/**
+ * Determine if one string is greater than another.
+ * This function is equivalent to {@link #ucol_strcoll } == UCOL_GREATER
+ * @param coll The UCollator containing the comparison rules.
+ * @param source The source string.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param target The target string.
+ * @param targetLength The length of target, or -1 if null-terminated.
+ * @return TRUE if source is greater than target, FALSE otherwise.
+ * @see ucol_strcoll
+ * @see ucol_greaterOrEqual
+ * @see ucol_equal
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+ucol_greater(const UCollator *coll,
+ const UChar *source, int32_t sourceLength,
+ const UChar *target, int32_t targetLength);
+
+/**
+ * Determine if one string is greater than or equal to another.
+ * This function is equivalent to {@link #ucol_strcoll } != UCOL_LESS
+ * @param coll The UCollator containing the comparison rules.
+ * @param source The source string.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param target The target string.
+ * @param targetLength The length of target, or -1 if null-terminated.
+ * @return TRUE if source is greater than or equal to target, FALSE otherwise.
+ * @see ucol_strcoll
+ * @see ucol_greater
+ * @see ucol_equal
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+ucol_greaterOrEqual(const UCollator *coll,
+ const UChar *source, int32_t sourceLength,
+ const UChar *target, int32_t targetLength);
+
+/**
+ * Compare two strings for equality.
+ * This function is equivalent to {@link #ucol_strcoll } == UCOL_EQUAL
+ * @param coll The UCollator containing the comparison rules.
+ * @param source The source string.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param target The target string.
+ * @param targetLength The length of target, or -1 if null-terminated.
+ * @return TRUE if source is equal to target, FALSE otherwise
+ * @see ucol_strcoll
+ * @see ucol_greater
+ * @see ucol_greaterOrEqual
+ * @stable ICU 2.0
+ */
+U_STABLE UBool U_EXPORT2
+ucol_equal(const UCollator *coll,
+ const UChar *source, int32_t sourceLength,
+ const UChar *target, int32_t targetLength);
+
+/**
+ * Compare two UTF-8 encoded trings.
+ * The strings will be compared using the options already specified.
+ * @param coll The UCollator containing the comparison rules.
+ * @param sIter The source string iterator.
+ * @param tIter The target string iterator.
+ * @return The result of comparing the strings; one of UCOL_EQUAL,
+ * UCOL_GREATER, UCOL_LESS
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @see ucol_strcoll
+ * @stable ICU 2.6
+ */
+U_STABLE UCollationResult U_EXPORT2
+ucol_strcollIter( const UCollator *coll,
+ UCharIterator *sIter,
+ UCharIterator *tIter,
+ UErrorCode *status);
+
+/**
+ * Get the collation strength used in a UCollator.
+ * The strength influences how strings are compared.
+ * @param coll The UCollator to query.
+ * @return The collation strength; one of UCOL_PRIMARY, UCOL_SECONDARY,
+ * UCOL_TERTIARY, UCOL_QUATERNARY, UCOL_IDENTICAL
+ * @see ucol_setStrength
+ * @stable ICU 2.0
+ */
+U_STABLE UCollationStrength U_EXPORT2
+ucol_getStrength(const UCollator *coll);
+
+/**
+ * Set the collation strength used in a UCollator.
+ * The strength influences how strings are compared.
+ * @param coll The UCollator to set.
+ * @param strength The desired collation strength; one of UCOL_PRIMARY,
+ * UCOL_SECONDARY, UCOL_TERTIARY, UCOL_QUATERNARY, UCOL_IDENTICAL, UCOL_DEFAULT
+ * @see ucol_getStrength
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucol_setStrength(UCollator *coll,
+ UCollationStrength strength);
+
+/**
+ * Get the display name for a UCollator.
+ * The display name is suitable for presentation to a user.
+ * @param objLoc The locale of the collator in question.
+ * @param dispLoc The locale for display.
+ * @param result A pointer to a buffer to receive the attribute.
+ * @param resultLength The maximum size of result.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @return The total buffer size needed; if greater than resultLength,
+ * the output was truncated.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_getDisplayName( const char *objLoc,
+ const char *dispLoc,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status);
+
+/**
+ * Get a locale for which collation rules are available.
+ * A UCollator in a locale returned by this function will perform the correct
+ * collation for the locale.
+ * @param index The index of the desired locale.
+ * @return A locale for which collation rules are available, or 0 if none.
+ * @see ucol_countAvailable
+ * @stable ICU 2.0
+ */
+U_STABLE const char* U_EXPORT2
+ucol_getAvailable(int32_t index);
+
+/**
+ * Determine how many locales have collation rules available.
+ * This function is most useful as determining the loop ending condition for
+ * calls to {@link #ucol_getAvailable }.
+ * @return The number of locales for which collation rules are available.
+ * @see ucol_getAvailable
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_countAvailable(void);
+
+#if !UCONFIG_NO_SERVICE
+/**
+ * Create a string enumerator of all locales for which a valid
+ * collator may be opened.
+ * @param status input-output error code
+ * @return a string enumeration over locale strings. The caller is
+ * responsible for closing the result.
+ * @stable ICU 3.0
+ */
+U_STABLE UEnumeration* U_EXPORT2
+ucol_openAvailableLocales(UErrorCode *status);
+#endif
+
+/**
+ * Create a string enumerator of all possible keywords that are relevant to
+ * collation. At this point, the only recognized keyword for this
+ * service is "collation".
+ * @param status input-output error code
+ * @return a string enumeration over locale strings. The caller is
+ * responsible for closing the result.
+ * @stable ICU 3.0
+ */
+U_STABLE UEnumeration* U_EXPORT2
+ucol_getKeywords(UErrorCode *status);
+
+/**
+ * Given a keyword, create a string enumeration of all values
+ * for that keyword that are currently in use.
+ * @param keyword a particular keyword as enumerated by
+ * ucol_getKeywords. If any other keyword is passed in, *status is set
+ * to U_ILLEGAL_ARGUMENT_ERROR.
+ * @param status input-output error code
+ * @return a string enumeration over collation keyword values, or NULL
+ * upon error. The caller is responsible for closing the result.
+ * @stable ICU 3.0
+ */
+U_STABLE UEnumeration* U_EXPORT2
+ucol_getKeywordValues(const char *keyword, UErrorCode *status);
+
+/**
+ * Return the functionally equivalent locale for the given
+ * requested locale, with respect to given keyword, for the
+ * collation service. If two locales return the same result, then
+ * collators instantiated for these locales will behave
+ * equivalently. The converse is not always true; two collators
+ * may in fact be equivalent, but return different results, due to
+ * internal details. The return result has no other meaning than
+ * that stated above, and implies nothing as to the relationship
+ * between the two locales. This is intended for use by
+ * applications who wish to cache collators, or otherwise reuse
+ * collators when possible. The functional equivalent may change
+ * over time. For more information, please see the <a
+ * href="http://icu-project.org/userguide/locale.html#services">
+ * Locales and Services</a> section of the ICU User Guide.
+ * @param result fillin for the functionally equivalent locale
+ * @param resultCapacity capacity of the fillin buffer
+ * @param keyword a particular keyword as enumerated by
+ * ucol_getKeywords.
+ * @param locale the requested locale
+ * @param isAvailable if non-NULL, pointer to a fillin parameter that
+ * indicates whether the requested locale was 'available' to the
+ * collation service. A locale is defined as 'available' if it
+ * physically exists within the collation locale data.
+ * @param status pointer to input-output error code
+ * @return the actual buffer size needed for the locale. If greater
+ * than resultCapacity, the returned full name will be truncated and
+ * an error code will be returned.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_getFunctionalEquivalent(char* result, int32_t resultCapacity,
+ const char* keyword, const char* locale,
+ UBool* isAvailable, UErrorCode* status);
+
+/**
+ * Get the collation rules from a UCollator.
+ * The rules will follow the rule syntax.
+ * @param coll The UCollator to query.
+ * @param length
+ * @return The collation rules.
+ * @stable ICU 2.0
+ */
+U_STABLE const UChar* U_EXPORT2
+ucol_getRules( const UCollator *coll,
+ int32_t *length);
+
+/** Get the short definition string for a collator. This API harvests the collator's
+ * locale and the attribute set and produces a string that can be used for opening
+ * a collator with the same properties using the ucol_openFromShortString API.
+ * This string will be normalized.
+ * The structure and the syntax of the string is defined in the "Naming collators"
+ * section of the users guide:
+ * http://icu-project.org/userguide/Collate_Concepts.html#Naming_Collators
+ * This API supports preflighting.
+ * @param coll a collator
+ * @param locale a locale that will appear as a collators locale in the resulting
+ * short string definition. If NULL, the locale will be harvested
+ * from the collator.
+ * @param buffer space to hold the resulting string
+ * @param capacity capacity of the buffer
+ * @param status for returning errors. All the preflighting errors are featured
+ * @return length of the resulting string
+ * @see ucol_openFromShortString
+ * @see ucol_normalizeShortDefinitionString
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_getShortDefinitionString(const UCollator *coll,
+ const char *locale,
+ char *buffer,
+ int32_t capacity,
+ UErrorCode *status);
+
+/** Verifies and normalizes short definition string.
+ * Normalized short definition string has all the option sorted by the argument name,
+ * so that equivalent definition strings are the same.
+ * This API supports preflighting.
+ * @param source definition string
+ * @param destination space to hold the resulting string
+ * @param capacity capacity of the buffer
+ * @param parseError if not NULL, structure that will get filled with error's pre
+ * and post context in case of error.
+ * @param status Error code. This API will return an error if an invalid attribute
+ * or attribute/value combination is specified. All the preflighting
+ * errors are also featured
+ * @return length of the resulting normalized string.
+ *
+ * @see ucol_openFromShortString
+ * @see ucol_getShortDefinitionString
+ *
+ * @stable ICU 3.0
+ */
+
+U_STABLE int32_t U_EXPORT2
+ucol_normalizeShortDefinitionString(const char *source,
+ char *destination,
+ int32_t capacity,
+ UParseError *parseError,
+ UErrorCode *status);
+
+
+/**
+ * Get a sort key for a string from a UCollator.
+ * Sort keys may be compared using <TT>strcmp</TT>.
+ * @param coll The UCollator containing the collation rules.
+ * @param source The string to transform.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param result A pointer to a buffer to receive the attribute.
+ * @param resultLength The maximum size of result.
+ * @return The size needed to fully store the sort key..
+ * @see ucol_keyHashCode
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_getSortKey(const UCollator *coll,
+ const UChar *source,
+ int32_t sourceLength,
+ uint8_t *result,
+ int32_t resultLength);
+
+
+/** Gets the next count bytes of a sort key. Caller needs
+ * to preserve state array between calls and to provide
+ * the same type of UCharIterator set with the same string.
+ * The destination buffer provided must be big enough to store
+ * the number of requested bytes. Generated sortkey is not
+ * compatible with sortkeys generated using ucol_getSortKey
+ * API, since we don't do any compression. If uncompressed
+ * sortkeys are required, this API can be used.
+ * @param coll The UCollator containing the collation rules.
+ * @param iter UCharIterator containing the string we need
+ * the sort key to be calculated for.
+ * @param state Opaque state of sortkey iteration.
+ * @param dest Buffer to hold the resulting sortkey part
+ * @param count number of sort key bytes required.
+ * @param status error code indicator.
+ * @return the actual number of bytes of a sortkey. It can be
+ * smaller than count if we have reached the end of
+ * the sort key.
+ * @stable ICU 2.6
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_nextSortKeyPart(const UCollator *coll,
+ UCharIterator *iter,
+ uint32_t state[2],
+ uint8_t *dest, int32_t count,
+ UErrorCode *status);
+
+/** enum that is taken by ucol_getBound API
+ * See below for explanation
+ * do not change the values assigned to the
+ * members of this enum. Underlying code
+ * depends on them having these numbers
+ * @stable ICU 2.0
+ */
+typedef enum {
+ /** lower bound */
+ UCOL_BOUND_LOWER = 0,
+ /** upper bound that will match strings of exact size */
+ UCOL_BOUND_UPPER = 1,
+ /** upper bound that will match all the strings that have the same initial substring as the given string */
+ UCOL_BOUND_UPPER_LONG = 2,
+ UCOL_BOUND_VALUE_COUNT
+} UColBoundMode;
+
+/**
+ * Produce a bound for a given sortkey and a number of levels.
+ * Return value is always the number of bytes needed, regardless of
+ * whether the result buffer was big enough or even valid.<br>
+ * Resulting bounds can be used to produce a range of strings that are
+ * between upper and lower bounds. For example, if bounds are produced
+ * for a sortkey of string "smith", strings between upper and lower
+ * bounds with one level would include "Smith", "SMITH", "sMiTh".<br>
+ * There are two upper bounds that can be produced. If UCOL_BOUND_UPPER
+ * is produced, strings matched would be as above. However, if bound
+ * produced using UCOL_BOUND_UPPER_LONG is used, the above example will
+ * also match "Smithsonian" and similar.<br>
+ * For more on usage, see example in cintltst/capitst.c in procedure
+ * TestBounds.
+ * Sort keys may be compared using <TT>strcmp</TT>.
+ * @param source The source sortkey.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * (If an unmodified sortkey is passed, it is always null
+ * terminated).
+ * @param boundType Type of bound required. It can be UCOL_BOUND_LOWER, which
+ * produces a lower inclusive bound, UCOL_BOUND_UPPER, that
+ * produces upper bound that matches strings of the same length
+ * or UCOL_BOUND_UPPER_LONG that matches strings that have the
+ * same starting substring as the source string.
+ * @param noOfLevels Number of levels required in the resulting bound (for most
+ * uses, the recommended value is 1). See users guide for
+ * explanation on number of levels a sortkey can have.
+ * @param result A pointer to a buffer to receive the resulting sortkey.
+ * @param resultLength The maximum size of result.
+ * @param status Used for returning error code if something went wrong. If the
+ * number of levels requested is higher than the number of levels
+ * in the source key, a warning (U_SORT_KEY_TOO_SHORT_WARNING) is
+ * issued.
+ * @return The size needed to fully store the bound.
+ * @see ucol_keyHashCode
+ * @stable ICU 2.1
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_getBound(const uint8_t *source,
+ int32_t sourceLength,
+ UColBoundMode boundType,
+ uint32_t noOfLevels,
+ uint8_t *result,
+ int32_t resultLength,
+ UErrorCode *status);
+
+/**
+ * Gets the version information for a Collator. Version is currently
+ * an opaque 32-bit number which depends, among other things, on major
+ * versions of the collator tailoring and UCA.
+ * @param coll The UCollator to query.
+ * @param info the version # information, the result will be filled in
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucol_getVersion(const UCollator* coll, UVersionInfo info);
+
+/**
+ * Gets the UCA version information for a Collator. Version is the
+ * UCA version number (3.1.1, 4.0).
+ * @param coll The UCollator to query.
+ * @param info the version # information, the result will be filled in
+ * @stable ICU 2.8
+ */
+U_STABLE void U_EXPORT2
+ucol_getUCAVersion(const UCollator* coll, UVersionInfo info);
+
+/**
+ * Merge two sort keys. The levels are merged with their corresponding counterparts
+ * (primaries with primaries, secondaries with secondaries etc.). Between the values
+ * from the same level a separator is inserted.
+ * example (uncompressed):
+ * 191B1D 01 050505 01 910505 00 and 1F2123 01 050505 01 910505 00
+ * will be merged as
+ * 191B1D 02 1F212301 050505 02 050505 01 910505 02 910505 00
+ * This allows for concatenating of first and last names for sorting, among other things.
+ * If the destination buffer is not big enough, the results are undefined.
+ * If any of source lengths are zero or any of source pointers are NULL/undefined,
+ * result is of size zero.
+ * @param src1 pointer to the first sortkey
+ * @param src1Length length of the first sortkey
+ * @param src2 pointer to the second sortkey
+ * @param src2Length length of the second sortkey
+ * @param dest buffer to hold the result
+ * @param destCapacity size of the buffer for the result
+ * @return size of the result. If the buffer is big enough size is always
+ * src1Length+src2Length-1
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_mergeSortkeys(const uint8_t *src1, int32_t src1Length,
+ const uint8_t *src2, int32_t src2Length,
+ uint8_t *dest, int32_t destCapacity);
+
+/**
+ * Universal attribute setter
+ * @param coll collator which attributes are to be changed
+ * @param attr attribute type
+ * @param value attribute value
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @see UColAttribute
+ * @see UColAttributeValue
+ * @see ucol_getAttribute
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucol_setAttribute(UCollator *coll, UColAttribute attr, UColAttributeValue value, UErrorCode *status);
+
+/**
+ * Universal attribute getter
+ * @param coll collator which attributes are to be changed
+ * @param attr attribute type
+ * @return attribute value
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @see UColAttribute
+ * @see UColAttributeValue
+ * @see ucol_setAttribute
+ * @stable ICU 2.0
+ */
+U_STABLE UColAttributeValue U_EXPORT2
+ucol_getAttribute(const UCollator *coll, UColAttribute attr, UErrorCode *status);
+
+/** Variable top
+ * is a two byte primary value which causes all the codepoints with primary values that
+ * are less or equal than the variable top to be shifted when alternate handling is set
+ * to UCOL_SHIFTED.
+ * Sets the variable top to a collation element value of a string supplied.
+ * @param coll collator which variable top needs to be changed
+ * @param varTop one or more (if contraction) UChars to which the variable top should be set
+ * @param len length of variable top string. If -1 it is considered to be zero terminated.
+ * @param status error code. If error code is set, the return value is undefined.
+ * Errors set by this function are: <br>
+ * U_CE_NOT_FOUND_ERROR if more than one character was passed and there is no such
+ * a contraction<br>
+ * U_PRIMARY_TOO_LONG_ERROR if the primary for the variable top has more than two bytes
+ * @return a 32 bit value containing the value of the variable top in upper 16 bits.
+ * Lower 16 bits are undefined
+ * @see ucol_getVariableTop
+ * @see ucol_restoreVariableTop
+ * @stable ICU 2.0
+ */
+U_STABLE uint32_t U_EXPORT2
+ucol_setVariableTop(UCollator *coll,
+ const UChar *varTop, int32_t len,
+ UErrorCode *status);
+
+/**
+ * Gets the variable top value of a Collator.
+ * Lower 16 bits are undefined and should be ignored.
+ * @param coll collator which variable top needs to be retrieved
+ * @param status error code (not changed by function). If error code is set,
+ * the return value is undefined.
+ * @return the variable top value of a Collator.
+ * @see ucol_setVariableTop
+ * @see ucol_restoreVariableTop
+ * @stable ICU 2.0
+ */
+U_STABLE uint32_t U_EXPORT2 ucol_getVariableTop(const UCollator *coll, UErrorCode *status);
+
+/**
+ * Sets the variable top to a collation element value supplied. Variable top is
+ * set to the upper 16 bits.
+ * Lower 16 bits are ignored.
+ * @param coll collator which variable top needs to be changed
+ * @param varTop CE value, as returned by ucol_setVariableTop or ucol)getVariableTop
+ * @param status error code (not changed by function)
+ * @see ucol_getVariableTop
+ * @see ucol_setVariableTop
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucol_restoreVariableTop(UCollator *coll, const uint32_t varTop, UErrorCode *status);
+
+/**
+ * Thread safe cloning operation. The result is a clone of a given collator.
+ * @param coll collator to be cloned
+ * @param stackBuffer user allocated space for the new clone.
+ * If NULL new memory will be allocated.
+ * If buffer is not large enough, new memory will be allocated.
+ * Clients can use the U_COL_SAFECLONE_BUFFERSIZE.
+ * This will probably be enough to avoid memory allocations.
+ * @param pBufferSize pointer to size of allocated space.
+ * If *pBufferSize == 0, a sufficient size for use in cloning will
+ * be returned ('pre-flighting')
+ * If *pBufferSize is not enough for a stack-based safe clone,
+ * new memory will be allocated.
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used if any
+ * allocations were necessary.
+ * @return pointer to the new clone
+ * @see ucol_open
+ * @see ucol_openRules
+ * @see ucol_close
+ * @stable ICU 2.0
+ */
+U_STABLE UCollator* U_EXPORT2
+ucol_safeClone(const UCollator *coll,
+ void *stackBuffer,
+ int32_t *pBufferSize,
+ UErrorCode *status);
+
+/** default memory size for the new clone. It needs to be this large for os/400 large pointers
+ * @stable ICU 2.0
+ */
+#define U_COL_SAFECLONE_BUFFERSIZE 512
+
+/**
+ * Returns current rules. Delta defines whether full rules are returned or just the tailoring.
+ * Returns number of UChars needed to store rules. If buffer is NULL or bufferLen is not enough
+ * to store rules, will store up to available space.
+ * @param coll collator to get the rules from
+ * @param delta one of UCOL_TAILORING_ONLY, UCOL_FULL_RULES.
+ * @param buffer buffer to store the result in. If NULL, you'll get no rules.
+ * @param bufferLen lenght of buffer to store rules in. If less then needed you'll get only the part that fits in.
+ * @return current rules
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_getRulesEx(const UCollator *coll, UColRuleOption delta, UChar *buffer, int32_t bufferLen);
+
+/**
+ * gets the locale name of the collator. If the collator
+ * is instantiated from the rules, then this function returns
+ * NULL.
+ * @param coll The UCollator for which the locale is needed
+ * @param type You can choose between requested, valid and actual
+ * locale. For description see the definition of
+ * ULocDataLocaleType in uloc.h
+ * @param status error code of the operation
+ * @return real locale name from which the collation data comes.
+ * If the collator was instantiated from rules, returns
+ * NULL.
+ * @deprecated ICU 2.8 Use ucol_getLocaleByType instead
+ */
+U_DEPRECATED const char * U_EXPORT2
+ucol_getLocale(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status);
+
+
+/**
+ * gets the locale name of the collator. If the collator
+ * is instantiated from the rules, then this function returns
+ * NULL.
+ * @param coll The UCollator for which the locale is needed
+ * @param type You can choose between requested, valid and actual
+ * locale. For description see the definition of
+ * ULocDataLocaleType in uloc.h
+ * @param status error code of the operation
+ * @return real locale name from which the collation data comes.
+ * If the collator was instantiated from rules, returns
+ * NULL.
+ * @stable ICU 2.8
+ */
+U_STABLE const char * U_EXPORT2
+ucol_getLocaleByType(const UCollator *coll, ULocDataLocaleType type, UErrorCode *status);
+
+/**
+ * Get an Unicode set that contains all the characters and sequences tailored in
+ * this collator. The result must be disposed of by using uset_close.
+ * @param coll The UCollator for which we want to get tailored chars
+ * @param status error code of the operation
+ * @return a pointer to newly created USet. Must be be disposed by using uset_close
+ * @see ucol_openRules
+ * @see uset_close
+ * @stable ICU 2.4
+ */
+U_STABLE USet * U_EXPORT2
+ucol_getTailoredSet(const UCollator *coll, UErrorCode *status);
+
+#ifndef U_HIDE_INTERNAL_API
+/**
+ * Returned by ucol_collatorToIdentifier to signify that collator is
+ * not encodable as an identifier.
+ * @internal ICU 3.0
+ */
+#define UCOL_SIT_COLLATOR_NOT_ENCODABLE 0x80000000
+#endif /* U_HIDE_INTERNAL_API */
+
+/**
+ * Get a 31-bit identifier given a collator.
+ * @param coll UCollator
+ * @param locale a locale that will appear as a collators locale in the resulting
+ * short string definition. If NULL, the locale will be harvested
+ * from the collator.
+ * @param status holds error messages
+ * @return 31-bit identifier. MSB is used if the collator cannot be encoded. In that
+ * case UCOL_SIT_COLLATOR_NOT_ENCODABLE is returned
+ * @see ucol_openFromIdentifier
+ * @see ucol_identifierToShortString
+ * @internal ICU 3.0
+ */
+U_INTERNAL uint32_t U_EXPORT2
+ucol_collatorToIdentifier(const UCollator *coll,
+ const char *locale,
+ UErrorCode *status);
+
+/**
+ * Open a collator given a 31-bit identifier
+ * @param identifier 31-bit identifier, encoded by calling ucol_collatorToIdentifier
+ * @param forceDefaults if FALSE, the settings that are the same as the collator
+ * default settings will not be applied (for example, setting
+ * French secondary on a French collator would not be executed).
+ * If TRUE, all the settings will be applied regardless of the
+ * collator default value. If the definition
+ * strings that can be produced from a collator instantiated by
+ * calling this API are to be cached, should be set to FALSE.
+ * @param status for returning errors
+ * @return UCollator object
+ * @see ucol_collatorToIdentifier
+ * @see ucol_identifierToShortString
+ * @internal ICU 3.0
+ */
+U_INTERNAL UCollator* U_EXPORT2
+ucol_openFromIdentifier(uint32_t identifier,
+ UBool forceDefaults,
+ UErrorCode *status);
+
+
+/**
+ * Calculate the short definition string given an identifier. Supports preflighting.
+ * @param identifier 31-bit identifier, encoded by calling ucol_collatorToIdentifier
+ * @param buffer buffer to store the result
+ * @param capacity buffer capacity
+ * @param forceDefaults whether the settings that are the same as the default setting
+ * should be forced anyway. Setting this argument to FALSE reduces
+ * the number of different configurations, but decreases performace
+ * as a collator has to be instantiated.
+ * @param status for returning errors
+ * @return length of the short definition string
+ * @see ucol_collatorToIdentifier
+ * @see ucol_openFromIdentifier
+ * @see ucol_shortStringToIdentifier
+ * @internal ICU 3.0
+ */
+U_INTERNAL int32_t U_EXPORT2
+ucol_identifierToShortString(uint32_t identifier,
+ char *buffer,
+ int32_t capacity,
+ UBool forceDefaults,
+ UErrorCode *status);
+
+/**
+ * Calculate the identifier given a short definition string. Supports preflighting.
+ * @param definition short string definition
+ * @param forceDefaults whether the settings that are the same as the default setting
+ * should be forced anyway. Setting this argument to FALSE reduces
+ * the number of different configurations, but decreases performace
+ * as a collator has to be instantiated.
+ * @param status for returning errors
+ * @return identifier
+ * @see ucol_collatorToIdentifier
+ * @see ucol_openFromIdentifier
+ * @see ucol_identifierToShortString
+ * @internal ICU 3.0
+ */
+U_INTERNAL uint32_t U_EXPORT2
+ucol_shortStringToIdentifier(const char *definition,
+ UBool forceDefaults,
+ UErrorCode *status);
+
+
+
+/**
+ * Universal attribute getter that returns UCOL_DEFAULT if the value is default
+ * @param coll collator which attributes are to be changed
+ * @param attr attribute type
+ * @return attribute value or UCOL_DEFAULT if the value is default
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @see UColAttribute
+ * @see UColAttributeValue
+ * @see ucol_setAttribute
+ * @internal ICU 3.0
+ */
+U_INTERNAL UColAttributeValue U_EXPORT2
+ucol_getAttributeOrDefault(const UCollator *coll, UColAttribute attr, UErrorCode *status);
+
+/** Check whether two collators are equal. Collators are considered equal if they
+ * will sort strings the same. This means that both the current attributes and the
+ * rules must be equivalent. Currently used for RuleBasedCollator::operator==.
+ * @param source first collator
+ * @param target second collator
+ * @return TRUE or FALSE
+ * @internal ICU 3.0
+ */
+U_INTERNAL UBool U_EXPORT2
+ucol_equals(const UCollator *source, const UCollator *target);
+
+/** Calculates the set of unsafe code points, given a collator.
+ * A character is unsafe if you could append any character and cause the ordering to alter significantly.
+ * Collation sorts in normalized order, so anything that rearranges in normalization can cause this.
+ * Thus if you have a character like a_umlaut, and you add a lower_dot to it,
+ * then it normalizes to a_lower_dot + umlaut, and sorts differently.
+ * @param coll Collator
+ * @param unsafe a fill-in set to receive the unsafe points
+ * @param status for catching errors
+ * @return number of elements in the set
+ * @internal ICU 3.0
+ */
+U_INTERNAL int32_t U_EXPORT2
+ucol_getUnsafeSet( const UCollator *coll,
+ USet *unsafe,
+ UErrorCode *status);
+
+/** Reset UCA's static pointers. You don't want to use this, unless your static memory can go away.
+ * @internal ICU 3.2.1
+ */
+U_INTERNAL void U_EXPORT2
+ucol_forgetUCA(void);
+
+/** Touches all resources needed for instantiating a collator from a short string definition,
+ * thus filling up the cache.
+ * @param definition A short string containing a locale and a set of attributes.
+ * Attributes not explicitly mentioned are left at the default
+ * state for a locale.
+ * @param parseError if not NULL, structure that will get filled with error's pre
+ * and post context in case of error.
+ * @param forceDefaults if FALSE, the settings that are the same as the collator
+ * default settings will not be applied (for example, setting
+ * French secondary on a French collator would not be executed).
+ * If TRUE, all the settings will be applied regardless of the
+ * collator default value. If the definition
+ * strings are to be cached, should be set to FALSE.
+ * @param status Error code. Apart from regular error conditions connected to
+ * instantiating collators (like out of memory or similar), this
+ * API will return an error if an invalid attribute or attribute/value
+ * combination is specified.
+ * @see ucol_openFromShortString
+ * @internal ICU 3.2.1
+ */
+U_INTERNAL void U_EXPORT2
+ucol_prepareShortStringOpen( const char *definition,
+ UBool forceDefaults,
+ UParseError *parseError,
+ UErrorCode *status);
+
+/** Creates a binary image of a collator. This binary image can be stored and
+ * later used to instantiate a collator using ucol_openBinary.
+ * This API supports preflighting.
+ * @param coll Collator
+ * @param buffer a fill-in buffer to receive the binary image
+ * @param capacity capacity of the destination buffer
+ * @param status for catching errors
+ * @return size of the image
+ * @see ucol_openBinary
+ * @stable ICU 3.2
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_cloneBinary(const UCollator *coll,
+ uint8_t *buffer, int32_t capacity,
+ UErrorCode *status);
+
+/** Opens a collator from a collator binary image created using
+ * ucol_cloneBinary. Binary image used in instantiation of the
+ * collator remains owned by the user and should stay around for
+ * the lifetime of the collator. The API also takes a base collator
+ * which usualy should be UCA.
+ * @param bin binary image owned by the user and required through the
+ * lifetime of the collator
+ * @param length size of the image. If negative, the API will try to
+ * figure out the length of the image
+ * @param base fallback collator, usually UCA. Base is required to be
+ * present through the lifetime of the collator. Currently
+ * it cannot be NULL.
+ * @param status for catching errors
+ * @return newly created collator
+ * @see ucol_cloneBinary
+ * @stable ICU 3.2
+ */
+U_STABLE UCollator* U_EXPORT2
+ucol_openBinary(const uint8_t *bin, int32_t length,
+ const UCollator *base,
+ UErrorCode *status);
+
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/ucoleitr.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucoleitr.h
new file mode 100644
index 00000000000..7184e96a767
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucoleitr.h
@@ -0,0 +1,268 @@
+/*
+*******************************************************************************
+* Copyright (C) 2001-2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+*
+* File ucoleitr.cpp
+*
+* Modification History:
+*
+* Date Name Description
+* 02/15/2001 synwee Modified all methods to process its own function
+* instead of calling the equivalent c++ api (coleitr.h)
+*******************************************************************************/
+
+#ifndef UCOLEITR_H
+#define UCOLEITR_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+/**
+ * This indicates an error has occured during processing or if no more CEs is
+ * to be returned.
+ * @stable ICU 2.0
+ */
+#define UCOL_NULLORDER ((int32_t)0xFFFFFFFF)
+
+#include "unicode/ucol.h"
+
+/**
+ * The UCollationElements struct.
+ * For usage in C programs.
+ * @stable ICU 2.0
+ */
+typedef struct UCollationElements UCollationElements;
+
+/**
+ * \file
+ * \brief C API: UCollationElements
+ *
+ * The UCollationElements API is used as an iterator to walk through each
+ * character of an international string. Use the iterator to return the
+ * ordering priority of the positioned character. The ordering priority of a
+ * character, which we refer to as a key, defines how a character is collated
+ * in the given collation object.
+ * For example, consider the following in Spanish:
+ * <pre>
+ * . "ca" -> the first key is key('c') and second key is key('a').
+ * . "cha" -> the first key is key('ch') and second key is key('a').
+ * </pre>
+ * And in German,
+ * <pre>
+ * . "<ae ligature>b"-> the first key is key('a'), the second key is key('e'), and
+ * . the third key is key('b').
+ * </pre>
+ * <p>Example of the iterator usage: (without error checking)
+ * <pre>
+ * . void CollationElementIterator_Example()
+ * . {
+ * . UChar *s;
+ * . t_int32 order, primaryOrder;
+ * . UCollationElements *c;
+ * . UCollatorOld *coll;
+ * . UErrorCode success = U_ZERO_ERROR;
+ * . s=(UChar*)malloc(sizeof(UChar) * (strlen("This is a test")+1) );
+ * . u_uastrcpy(s, "This is a test");
+ * . coll = ucol_open(NULL, &success);
+ * . c = ucol_openElements(coll, str, u_strlen(str), &status);
+ * . order = ucol_next(c, &success);
+ * . ucol_reset(c);
+ * . order = ucol_prev(c, &success);
+ * . free(s);
+ * . ucol_close(coll);
+ * . ucol_closeElements(c);
+ * . }
+ * </pre>
+ * <p>
+ * ucol_next() returns the collation order of the next.
+ * ucol_prev() returns the collation order of the previous character.
+ * The Collation Element Iterator moves only in one direction between calls to
+ * ucol_reset. That is, ucol_next() and ucol_prev can not be inter-used.
+ * Whenever ucol_prev is to be called after ucol_next() or vice versa,
+ * ucol_reset has to be called first to reset the status, shifting pointers to
+ * either the end or the start of the string. Hence at the next call of
+ * ucol_prev or ucol_next, the first or last collation order will be returned.
+ * If a change of direction is done without a ucol_reset, the result is
+ * undefined.
+ * The result of a forward iterate (ucol_next) and reversed result of the
+ * backward iterate (ucol_prev) on the same string are equivalent, if
+ * collation orders with the value UCOL_IGNORABLE are ignored.
+ * Character based on the comparison level of the collator. A collation order
+ * consists of primary order, secondary order and tertiary order. The data
+ * type of the collation order is <strong>t_int32</strong>.
+ *
+ * @see UCollator
+ */
+
+/**
+ * Open the collation elements for a string.
+ *
+ * @param coll The collator containing the desired collation rules.
+ * @param text The text to iterate over.
+ * @param textLength The number of characters in text, or -1 if null-terminated
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return a struct containing collation element information
+ * @stable ICU 2.0
+ */
+U_STABLE UCollationElements* U_EXPORT2
+ucol_openElements(const UCollator *coll,
+ const UChar *text,
+ int32_t textLength,
+ UErrorCode *status);
+
+/**
+ * get a hash code for a key... Not very useful!
+ * @param key the given key.
+ * @param length the size of the key array.
+ * @return the hash code.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_keyHashCode(const uint8_t* key, int32_t length);
+
+/**
+ * Close a UCollationElements.
+ * Once closed, a UCollationElements may no longer be used.
+ * @param elems The UCollationElements to close.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucol_closeElements(UCollationElements *elems);
+
+/**
+ * Reset the collation elements to their initial state.
+ * This will move the 'cursor' to the beginning of the text.
+ * Property settings for collation will be reset to the current status.
+ * @param elems The UCollationElements to reset.
+ * @see ucol_next
+ * @see ucol_previous
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucol_reset(UCollationElements *elems);
+
+/**
+ * Get the ordering priority of the next collation element in the text.
+ * A single character may contain more than one collation element.
+ * @param elems The UCollationElements containing the text.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The next collation elements ordering, otherwise returns NULLORDER
+ * if an error has occured or if the end of string has been reached
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_next(UCollationElements *elems, UErrorCode *status);
+
+/**
+ * Get the ordering priority of the previous collation element in the text.
+ * A single character may contain more than one collation element.
+ * Note that internally a stack is used to store buffered collation elements.
+ * It is very rare that the stack will overflow, however if such a case is
+ * encountered, the problem can be solved by increasing the size
+ * UCOL_EXPAND_CE_BUFFER_SIZE in ucol_imp.h.
+ * @param elems The UCollationElements containing the text.
+ * @param status A pointer to an UErrorCode to receive any errors. Noteably
+ * a U_BUFFER_OVERFLOW_ERROR is returned if the internal stack
+ * buffer has been exhausted.
+ * @return The previous collation elements ordering, otherwise returns
+ * NULLORDER if an error has occured or if the start of string has
+ * been reached.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_previous(UCollationElements *elems, UErrorCode *status);
+
+/**
+ * Get the maximum length of any expansion sequences that end with the
+ * specified comparison order.
+ * This is useful for .... ?
+ * @param elems The UCollationElements containing the text.
+ * @param order A collation order returned by previous or next.
+ * @return maximum size of the expansion sequences ending with the collation
+ * element or 1 if collation element does not occur at the end of any
+ * expansion sequence
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_getMaxExpansion(const UCollationElements *elems, int32_t order);
+
+/**
+ * Set the text containing the collation elements.
+ * Property settings for collation will remain the same.
+ * In order to reset the iterator to the current collation property settings,
+ * the API reset() has to be called.
+ * @param elems The UCollationElements to set.
+ * @param text The source text containing the collation elements.
+ * @param textLength The length of text, or -1 if null-terminated.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @see ucol_getText
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucol_setText( UCollationElements *elems,
+ const UChar *text,
+ int32_t textLength,
+ UErrorCode *status);
+
+/**
+ * Get the offset of the current source character.
+ * This is an offset into the text of the character containing the current
+ * collation elements.
+ * @param elems The UCollationElements to query.
+ * @return The offset of the current source character.
+ * @see ucol_setOffset
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucol_getOffset(const UCollationElements *elems);
+
+/**
+ * Set the offset of the current source character.
+ * This is an offset into the text of the character to be processed.
+ * Property settings for collation will remain the same.
+ * In order to reset the iterator to the current collation property settings,
+ * the API reset() has to be called.
+ * @param elems The UCollationElements to set.
+ * @param offset The desired character offset.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @see ucol_getOffset
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+ucol_setOffset(UCollationElements *elems,
+ int32_t offset,
+ UErrorCode *status);
+
+/**
+* Get the primary order of a collation order.
+* @param order the collation order
+* @return the primary order of a collation order.
+* @stable ICU 2.6
+*/
+U_STABLE int32_t U_EXPORT2
+ucol_primaryOrder (int32_t order);
+
+/**
+* Get the secondary order of a collation order.
+* @param order the collation order
+* @return the secondary order of a collation order.
+* @stable ICU 2.6
+*/
+U_STABLE int32_t U_EXPORT2
+ucol_secondaryOrder (int32_t order);
+
+/**
+* Get the tertiary order of a collation order.
+* @param order the collation order
+* @return the tertiary order of a collation order.
+* @stable ICU 2.6
+*/
+U_STABLE int32_t U_EXPORT2
+ucol_tertiaryOrder (int32_t order);
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/ucsdet.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucsdet.h
new file mode 100644
index 00000000000..31f622c01a4
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucsdet.h
@@ -0,0 +1,349 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ * file name: ucsdet.h
+ * encoding: US-ASCII
+ * indentation:4
+ *
+ * created on: 2005Aug04
+ * created by: Andy Heninger
+ *
+ * ICU Character Set Detection, API for C
+ *
+ * Draft version 18 Oct 2005
+ *
+ */
+
+#ifndef __UCSDET_H
+#define __UCSDET_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_CONVERSION
+#include "unicode/uenum.h"
+
+/**
+ * \file
+ * \brief C API: Charset Detection API
+ *
+ * This API provides a facility for detecting the
+ * charset or encoding of character data in an unknown text format.
+ * The input data can be from an array of bytes.
+ * <p>
+ * Character set detection is at best an imprecise operation. The detection
+ * process will attempt to identify the charset that best matches the characteristics
+ * of the byte data, but the process is partly statistical in nature, and
+ * the results can not be guaranteed to always be correct.
+ * <p>
+ * For best accuracy in charset detection, the input data should be primarily
+ * in a single language, and a minimum of a few hundred bytes worth of plain text
+ * in the language are needed. The detection process will attempt to
+ * ignore html or xml style markup that could otherwise obscure the content.
+ */
+
+
+struct UCharsetDetector;
+/**
+ * Structure representing a charset detector
+ * @stable ICU 3.6
+ */
+typedef struct UCharsetDetector UCharsetDetector;
+
+struct UCharsetMatch;
+/**
+ * Opaque structure representing a match that was identified
+ * from a charset detection operation.
+ * @stable ICU 3.6
+ */
+typedef struct UCharsetMatch UCharsetMatch;
+
+/**
+ * Open a charset detector.
+ *
+ * @param status Any error conditions occurring during the open
+ * operation are reported back in this variable.
+ * @return the newly opened charset detector.
+ * @stable ICU 3.6
+ */
+U_STABLE UCharsetDetector * U_EXPORT2
+ucsdet_open(UErrorCode *status);
+
+/**
+ * Close a charset detector. All storage and any other resources
+ * owned by this charset detector will be released. Failure to
+ * close a charset detector when finished with it can result in
+ * memory leaks in the application.
+ *
+ * @param ucsd The charset detector to be closed.
+ * @stable ICU 3.6
+ */
+U_STABLE void U_EXPORT2
+ucsdet_close(UCharsetDetector *ucsd);
+
+/**
+ * Set the input byte data whose charset is to detected.
+ *
+ * Ownership of the input text byte array remains with the caller.
+ * The input string must not be altered or deleted until the charset
+ * detector is either closed or reset to refer to different input text.
+ *
+ * @param ucsd the charset detector to be used.
+ * @param textIn the input text of unknown encoding. .
+ * @param len the length of the input text, or -1 if the text
+ * is NUL terminated.
+ * @param status any error conditions are reported back in this variable.
+ *
+ * @stable ICU 3.6
+ */
+U_STABLE void U_EXPORT2
+ucsdet_setText(UCharsetDetector *ucsd, const char *textIn, int32_t len, UErrorCode *status);
+
+
+/** Set the declared encoding for charset detection.
+ * The declared encoding of an input text is an encoding obtained
+ * by the user from an http header or xml declaration or similar source that
+ * can be provided as an additional hint to the charset detector.
+ *
+ * How and whether the declared encoding will be used during the
+ * detection process is TBD.
+ *
+ * @param ucsd the charset detector to be used.
+ * @param encoding an encoding for the current data obtained from
+ * a header or declaration or other source outside
+ * of the byte data itself.
+ * @param length the length of the encoding name, or -1 if the name string
+ * is NUL terminated.
+ * @param status any error conditions are reported back in this variable.
+ *
+ * @stable ICU 3.6
+ */
+U_STABLE void U_EXPORT2
+ucsdet_setDeclaredEncoding(UCharsetDetector *ucsd, const char *encoding, int32_t length, UErrorCode *status);
+
+
+/**
+ * Return the charset that best matches the supplied input data.
+ *
+ * Note though, that because the detection
+ * only looks at the start of the input data,
+ * there is a possibility that the returned charset will fail to handle
+ * the full set of input data.
+ * <p>
+ * The returned UCharsetMatch object is owned by the UCharsetDetector.
+ * It will remain valid until the detector input is reset, or until
+ * the detector is closed.
+ * <p>
+ * The function will fail if
+ * <ul>
+ * <li>no charset appears to match the data.</li>
+ * <li>no input text has been provided</li>
+ * </ul>
+ *
+ * @param ucsd the charset detector to be used.
+ * @param status any error conditions are reported back in this variable.
+ * @return a UCharsetMatch representing the best matching charset,
+ * or NULL if no charset matches the byte data.
+ *
+ * @stable ICU 3.6
+ */
+U_STABLE const UCharsetMatch * U_EXPORT2
+ucsdet_detect(UCharsetDetector *ucsd, UErrorCode *status);
+
+
+/**
+ * Find all charset matches that appear to be consistent with the input,
+ * returning an array of results. The results are ordered with the
+ * best quality match first.
+ *
+ * Because the detection only looks at a limited amount of the
+ * input byte data, some of the returned charsets may fail to handle
+ * the all of input data.
+ * <p>
+ * The returned UCharsetMatch objects are owned by the UCharsetDetector.
+ * They will remain valid until the detector is closed or modified
+ *
+ * <p>
+ * Return an error if
+ * <ul>
+ * <li>no charsets appear to match the input data.</li>
+ * <li>no input text has been provided</li>
+ * </ul>
+ *
+ * @param ucsd the charset detector to be used.
+ * @param matchesFound pointer to a variable that will be set to the
+ * number of charsets identified that are consistent with
+ * the input data. Output only.
+ * @param status any error conditions are reported back in this variable.
+ * @return A pointer to an array of pointers to UCharSetMatch objects.
+ * This array, and the UCharSetMatch instances to which it refers,
+ * are owned by the UCharsetDetector, and will remain valid until
+ * the detector is closed or modified.
+ * @stable ICU 3.6
+ */
+U_STABLE const UCharsetMatch ** U_EXPORT2
+ucsdet_detectAll(UCharsetDetector *ucsd, int32_t *matchesFound, UErrorCode *status);
+
+
+
+/**
+ * Get the name of the charset represented by a UCharsetMatch.
+ *
+ * The storage for the returned name string is owned by the
+ * UCharsetMatch, and will remain valid while the UCharsetMatch
+ * is valid.
+ *
+ * The name returned is suitable for use with the ICU conversion APIs.
+ *
+ * @param ucsm The charset match object.
+ * @param status Any error conditions are reported back in this variable.
+ * @return The name of the matching charset.
+ *
+ * @stable ICU 3.6
+ */
+U_STABLE const char * U_EXPORT2
+ucsdet_getName(const UCharsetMatch *ucsm, UErrorCode *status);
+
+/**
+ * Get a confidence number for the quality of the match of the byte
+ * data with the charset. Confidence numbers range from zero to 100,
+ * with 100 representing complete confidence and zero representing
+ * no confidence.
+ *
+ * The confidence values are somewhat arbitrary. They define an
+ * an ordering within the results for any single detection operation
+ * but are not generally comparable between the results for different input.
+ *
+ * A confidence value of ten does have a general meaning - it is used
+ * for charsets that can represent the input data, but for which there
+ * is no other indication that suggests that the charset is the correct one.
+ * Pure 7 bit ASCII data, for example, is compatible with a
+ * great many charsets, most of which will appear as possible matches
+ * with a confidence of 10.
+ *
+ * @param ucsm The charset match object.
+ * @param status Any error conditions are reported back in this variable.
+ * @return A confidence number for the charset match.
+ *
+ * @stable ICU 3.6
+ */
+U_STABLE int32_t U_EXPORT2
+ucsdet_getConfidence(const UCharsetMatch *ucsm, UErrorCode *status);
+
+/**
+ * Get the RFC 3066 code for the language of the input data.
+ *
+ * The Charset Detection service is intended primarily for detecting
+ * charsets, not language. For some, but not all, charsets, a language is
+ * identified as a byproduct of the detection process, and that is what
+ * is returned by this function.
+ *
+ * CAUTION:
+ * 1. Language information is not available for input data encoded in
+ * all charsets. In particular, no language is identified
+ * for UTF-8 input data.
+ *
+ * 2. Closely related languages may sometimes be confused.
+ *
+ * If more accurate language detection is required, a linguistic
+ * analysis package should be used.
+ *
+ * The storage for the returned name string is owned by the
+ * UCharsetMatch, and will remain valid while the UCharsetMatch
+ * is valid.
+ *
+ * @param ucsm The charset match object.
+ * @param status Any error conditions are reported back in this variable.
+ * @return The RFC 3066 code for the language of the input data, or
+ * an empty string if the language could not be determined.
+ *
+ * @stable ICU 3.6
+ */
+U_STABLE const char * U_EXPORT2
+ucsdet_getLanguage(const UCharsetMatch *ucsm, UErrorCode *status);
+
+
+/**
+ * Get the entire input text as a UChar string, placing it into
+ * a caller-supplied buffer. A terminating
+ * NUL character will be appended to the buffer if space is available.
+ *
+ * The number of UChars in the output string, not including the terminating
+ * NUL, is returned.
+ *
+ * If the supplied buffer is smaller than required to hold the output,
+ * the contents of the buffer are undefined. The full output string length
+ * (in UChars) is returned as always, and can be used to allocate a buffer
+ * of the correct size.
+ *
+ *
+ * @param ucsm The charset match object.
+ * @param buf A UChar buffer to be filled with the converted text data.
+ * @param cap The capacity of the buffer in UChars.
+ * @param status Any error conditions are reported back in this variable.
+ * @return The number of UChars in the output string.
+ *
+ * @stable ICU 3.6
+ */
+U_STABLE int32_t U_EXPORT2
+ucsdet_getUChars(const UCharsetMatch *ucsm,
+ UChar *buf, int32_t cap, UErrorCode *status);
+
+
+
+/**
+ * Get an iterator over the set of all detectable charsets -
+ * over the charsets that are known to the charset detection
+ * service.
+ *
+ * The returned UEnumeration provides access to the names of
+ * the charsets.
+ *
+ * The state of the Charset detector that is passed in does not
+ * affect the result of this function, but requiring a valid, open
+ * charset detector as a parameter insures that the charset detection
+ * service has been safely initialized and that the required detection
+ * data is available.
+ *
+ * @param ucsd a Charset detector.
+ * @param status Any error conditions are reported back in this variable.
+ * @return an iterator providing access to the detectable charset names.
+ * @stable ICU 3.6
+ */
+U_STABLE UEnumeration * U_EXPORT2
+ucsdet_getAllDetectableCharsets(const UCharsetDetector *ucsd, UErrorCode *status);
+
+
+/**
+ * Test whether input filtering is enabled for this charset detector.
+ * Input filtering removes text that appears to be HTML or xml
+ * markup from the input before applying the code page detection
+ * heuristics.
+ *
+ * @param ucsd The charset detector to check.
+ * @return TRUE if filtering is enabled.
+ * @stable ICU 3.6
+ */
+U_STABLE UBool U_EXPORT2
+ucsdet_isInputFilterEnabled(const UCharsetDetector *ucsd);
+
+
+/**
+ * Enable filtering of input text. If filtering is enabled,
+ * text within angle brackets ("<" and ">") will be removed
+ * before detection, which will remove most HTML or xml markup.
+ *
+ * @param ucsd the charset detector to be modified.
+ * @param filter <code>true</code> to enable input text filtering.
+ * @return The previous setting.
+ *
+ * @stable ICU 3.6
+ */
+U_STABLE UBool U_EXPORT2
+ucsdet_enableInputFilter(UCharsetDetector *ucsd, UBool filter);
+
+#endif
+#endif /* __UCSDET_H */
+
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/ucurr.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucurr.h
new file mode 100644
index 00000000000..842b8864472
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/ucurr.h
@@ -0,0 +1,225 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*/
+#ifndef _UCURR_H_
+#define _UCURR_H_
+
+#include "unicode/utypes.h"
+#include "unicode/uenum.h"
+
+/**
+ * \file
+ * \brief C API: Encapsulates information about a currency.
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * The ucurr API encapsulates information about a currency, as defined by
+ * ISO 4217. A currency is represented by a 3-character string
+ * containing its ISO 4217 code. This API can return various data
+ * necessary the proper display of a currency:
+ *
+ * <ul><li>A display symbol, for a specific locale
+ * <li>The number of fraction digits to display
+ * <li>A rounding increment
+ * </ul>
+ *
+ * The <tt>DecimalFormat</tt> class uses these data to display
+ * currencies.
+ * @author Alan Liu
+ * @since ICU 2.2
+ */
+
+/**
+ * Finds a currency code for the given locale.
+ * @param locale the locale for which to retrieve a currency code.
+ * Currency can be specified by the "currency" keyword
+ * in which case it overrides the default currency code
+ * @param buff fill in buffer. Can be NULL for preflighting.
+ * @param buffCapacity capacity of the fill in buffer. Can be 0 for
+ * preflighting. If it is non-zero, the buff parameter
+ * must not be NULL.
+ * @param ec error code
+ * @return length of the currency string. It should always be 3. If 0,
+ * currency couldn't be found or the input values are
+ * invalid.
+ * @stable ICU 2.8
+ */
+U_STABLE int32_t U_EXPORT2
+ucurr_forLocale(const char* locale,
+ UChar* buff,
+ int32_t buffCapacity,
+ UErrorCode* ec);
+
+/**
+ * Selector constants for ucurr_getName().
+ *
+ * @see ucurr_getName
+ * @stable ICU 2.6
+ */
+typedef enum UCurrNameStyle {
+ /**
+ * Selector for ucurr_getName indicating a symbolic name for a
+ * currency, such as "$" for USD.
+ * @stable ICU 2.6
+ */
+ UCURR_SYMBOL_NAME,
+
+ /**
+ * Selector for ucurr_getName indicating the long name for a
+ * currency, such as "US Dollar" for USD.
+ * @stable ICU 2.6
+ */
+ UCURR_LONG_NAME
+} UCurrNameStyle;
+
+#if !UCONFIG_NO_SERVICE
+/**
+ * @stable ICU 2.6
+ */
+typedef const void* UCurrRegistryKey;
+
+/**
+ * Register an (existing) ISO 4217 currency code for the given locale.
+ * Only the country code and the two variants EURO and PRE_EURO are
+ * recognized.
+ * @param isoCode the three-letter ISO 4217 currency code
+ * @param locale the locale for which to register this currency code
+ * @param status the in/out status code
+ * @return a registry key that can be used to unregister this currency code, or NULL
+ * if there was an error.
+ * @stable ICU 2.6
+ */
+U_STABLE UCurrRegistryKey U_EXPORT2
+ucurr_register(const UChar* isoCode,
+ const char* locale,
+ UErrorCode* status);
+/**
+ * Unregister the previously-registered currency definitions using the
+ * URegistryKey returned from ucurr_register. Key becomes invalid after
+ * a successful call and should not be used again. Any currency
+ * that might have been hidden by the original ucurr_register call is
+ * restored.
+ * @param key the registry key returned by a previous call to ucurr_register
+ * @param status the in/out status code, no special meanings are assigned
+ * @return TRUE if the currency for this key was successfully unregistered
+ * @stable ICU 2.6
+ */
+U_STABLE UBool U_EXPORT2
+ucurr_unregister(UCurrRegistryKey key, UErrorCode* status);
+#endif /* UCONFIG_NO_SERVICE */
+
+/**
+ * Returns the display name for the given currency in the
+ * given locale. For example, the display name for the USD
+ * currency object in the en_US locale is "$".
+ * @param currency null-terminated 3-letter ISO 4217 code
+ * @param locale locale in which to display currency
+ * @param nameStyle selector for which kind of name to return
+ * @param isChoiceFormat fill-in set to TRUE if the returned value
+ * is a ChoiceFormat pattern; otherwise it is a static string
+ * @param len fill-in parameter to receive length of result
+ * @param ec error code
+ * @return pointer to display string of 'len' UChars. If the resource
+ * data contains no entry for 'currency', then 'currency' itself is
+ * returned. If *isChoiceFormat is TRUE, then the result is a
+ * ChoiceFormat pattern. Otherwise it is a static string.
+ * @stable ICU 2.6
+ */
+U_STABLE const UChar* U_EXPORT2
+ucurr_getName(const UChar* currency,
+ const char* locale,
+ UCurrNameStyle nameStyle,
+ UBool* isChoiceFormat,
+ int32_t* len,
+ UErrorCode* ec);
+
+/**
+ * Returns the number of the number of fraction digits that should
+ * be displayed for the given currency.
+ * @param currency null-terminated 3-letter ISO 4217 code
+ * @param ec input-output error code
+ * @return a non-negative number of fraction digits to be
+ * displayed, or 0 if there is an error
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+ucurr_getDefaultFractionDigits(const UChar* currency,
+ UErrorCode* ec);
+
+/**
+ * Returns the rounding increment for the given currency, or 0.0 if no
+ * rounding is done by the currency.
+ * @param currency null-terminated 3-letter ISO 4217 code
+ * @param ec input-output error code
+ * @return the non-negative rounding increment, or 0.0 if none,
+ * or 0.0 if there is an error
+ * @stable ICU 3.0
+ */
+U_STABLE double U_EXPORT2
+ucurr_getRoundingIncrement(const UChar* currency,
+ UErrorCode* ec);
+
+/**
+ * Selector constants for ucurr_openCurrencies().
+ *
+ * @see ucurr_openCurrencies
+ * @stable ICU 3.2
+ */
+typedef enum UCurrCurrencyType {
+ /**
+ * Select all ISO-4217 currency codes.
+ * @stable ICU 3.2
+ */
+ UCURR_ALL = INT32_MAX,
+ /**
+ * Select only ISO-4217 commonly used currency codes.
+ * These currencies can be found in common use, and they usually have
+ * bank notes or coins associated with the currency code.
+ * This does not include fund codes, precious metals and other
+ * various ISO-4217 codes limited to special financial products.
+ * @stable ICU 3.2
+ */
+ UCURR_COMMON = 1,
+ /**
+ * Select ISO-4217 uncommon currency codes.
+ * These codes respresent fund codes, precious metals and other
+ * various ISO-4217 codes limited to special financial products.
+ * A fund code is a monetary resource associated with a currency.
+ * @stable ICU 3.2
+ */
+ UCURR_UNCOMMON = 2,
+ /**
+ * Select only deprecated ISO-4217 codes.
+ * These codes are no longer in general public use.
+ * @stable ICU 3.2
+ */
+ UCURR_DEPRECATED = 4,
+ /**
+ * Select only non-deprecated ISO-4217 codes.
+ * These codes are in general public use.
+ * @stable ICU 3.2
+ */
+ UCURR_NON_DEPRECATED = 8
+} UCurrCurrencyType;
+
+/**
+ * Provides a UEnumeration object for listing ISO-4217 codes.
+ * @param currType You can use one of several UCurrCurrencyType values for this
+ * variable. You can also | (or) them together to get a specific list of
+ * currencies. Most people will want to use the (UCURR_CURRENCY|UCURR_NON_DEPRECATED) value to
+ * get a list of current currencies.
+ * @param pErrorCode Error code
+ * @stable ICU 3.2
+ */
+U_STABLE UEnumeration * U_EXPORT2
+ucurr_openISOCurrencies(uint32_t currType, UErrorCode *pErrorCode);
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/udat.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/udat.h
new file mode 100644
index 00000000000..34573d2a1cf
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/udat.h
@@ -0,0 +1,826 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *******************************************************************************
+*/
+
+#ifndef UDAT_H
+#define UDAT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ucal.h"
+#include "unicode/unum.h"
+/**
+ * \file
+ * \brief C API: DateFormat
+ *
+ * <h2> Date Format C API</h2>
+ *
+ * Date Format C API consists of functions that convert dates and
+ * times from their internal representations to textual form and back again in a
+ * language-independent manner. Converting from the internal representation (milliseconds
+ * since midnight, January 1, 1970) to text is known as "formatting," and converting
+ * from text to millis is known as "parsing." We currently define only one concrete
+ * structure UDateFormat, which can handle pretty much all normal
+ * date formatting and parsing actions.
+ * <P>
+ * Date Format helps you to format and parse dates for any locale. Your code can
+ * be completely independent of the locale conventions for months, days of the
+ * week, or even the calendar format: lunar vs. solar.
+ * <P>
+ * To format a date for the current Locale with default time and date style,
+ * use one of the static factory methods:
+ * <pre>
+ * \code
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar *myString;
+ * int32_t myStrlen = 0;
+ * UDateFormat* dfmt = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, NULL, NULL, -1, NULL, -1, &status);
+ * myStrlen = udat_format(dfmt, myDate, NULL, myStrlen, NULL, &status);
+ * if (status==U_BUFFER_OVERFLOW_ERROR){
+ * status=U_ZERO_ERROR;
+ * myString=(UChar*)malloc(sizeof(UChar) * (myStrlen+1) );
+ * udat_format(dfmt, myDate, myString, myStrlen+1, NULL, &status);
+ * }
+ * \endcode
+ * </pre>
+ * If you are formatting multiple numbers, it is more efficient to get the
+ * format and use it multiple times so that the system doesn't have to fetch the
+ * information about the local language and country conventions multiple times.
+ * <pre>
+ * \code
+ * UErrorCode status = U_ZERO_ERROR;
+ * int32_t i, myStrlen = 0;
+ * UChar* myString;
+ * char buffer[1024];
+ * UDate myDateArr[] = { 0.0, 100000000.0, 2000000000.0 }; // test values
+ * UDateFormat* df = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, NULL, NULL, -1, NULL, 0, &status);
+ * for (i = 0; i < 3; i++) {
+ * myStrlen = udat_format(df, myDateArr[i], NULL, myStrlen, NULL, &status);
+ * if(status == U_BUFFER_OVERFLOW_ERROR){
+ * status = U_ZERO_ERROR;
+ * myString = (UChar*)malloc(sizeof(UChar) * (myStrlen+1) );
+ * udat_format(df, myDateArr[i], myString, myStrlen+1, NULL, &status);
+ * printf("%s\n", u_austrcpy(buffer, myString) );
+ * free(myString);
+ * }
+ * }
+ * \endcode
+ * </pre>
+ * To get specific fields of a date, you can use UFieldPosition to
+ * get specific fields.
+ * <pre>
+ * \code
+ * UErrorCode status = U_ZERO_ERROR;
+ * UFieldPosition pos;
+ * UChar *myString;
+ * int32_t myStrlen = 0;
+ * char buffer[1024];
+ *
+ * pos.field = 1; // Same as the DateFormat::EField enum
+ * UDateFormat* dfmt = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, NULL, -1, NULL, 0, &status);
+ * myStrlen = udat_format(dfmt, myDate, NULL, myStrlen, &pos, &status);
+ * if (status==U_BUFFER_OVERFLOW_ERROR){
+ * status=U_ZERO_ERROR;
+ * myString=(UChar*)malloc(sizeof(UChar) * (myStrlen+1) );
+ * udat_format(dfmt, myDate, myString, myStrlen+1, &pos, &status);
+ * }
+ * printf("date format: %s\n", u_austrcpy(buffer, myString));
+ * buffer[pos.endIndex] = 0; // NULL terminate the string.
+ * printf("UFieldPosition position equals %s\n", &buffer[pos.beginIndex]);
+ * \endcode
+ * </pre>
+ * To format a date for a different Locale, specify it in the call to
+ * udat_open()
+ * <pre>
+ * \code
+ * UDateFormat* df = udat_open(UDAT_SHORT, UDAT_SHORT, "fr_FR", NULL, -1, NULL, 0, &status);
+ * \endcode
+ * </pre>
+ * You can use a DateFormat API udat_parse() to parse.
+ * <pre>
+ * \code
+ * UErrorCode status = U_ZERO_ERROR;
+ * int32_t parsepos=0;
+ * UDate myDate = udat_parse(df, myString, u_strlen(myString), &parsepos, &status);
+ * \endcode
+ * </pre>
+ * You can pass in different options for the arguments for date and time style
+ * to control the length of the result; from SHORT to MEDIUM to LONG to FULL.
+ * The exact result depends on the locale, but generally:
+ * see UDateFormatStyle for more details
+ * <ul type=round>
+ * <li> UDAT_SHORT is completely numeric, such as 12/13/52 or 3:30pm
+ * <li> UDAT_MEDIUM is longer, such as Jan 12, 1952
+ * <li> UDAT_LONG is longer, such as January 12, 1952 or 3:30:32pm
+ * <li> UDAT_FULL is pretty completely specified, such as
+ * Tuesday, April 12, 1952 AD or 3:30:42pm PST.
+ * </ul>
+ * You can also set the time zone on the format if you wish.
+ * <P>
+ * You can also use forms of the parse and format methods with Parse Position and
+ * UFieldPosition to allow you to
+ * <ul type=round>
+ * <li> Progressively parse through pieces of a string.
+ * <li> Align any particular field, or find out where it is for selection
+ * on the screen.
+ * </ul>
+ */
+
+/** A date formatter.
+ * For usage in C programs.
+ * @stable ICU 2.6
+ */
+typedef void* UDateFormat;
+
+/** The possible date/time format styles
+ * @stable ICU 2.6
+ */
+typedef enum UDateFormatStyle {
+ /** Full style */
+ UDAT_FULL,
+ /** Long style */
+ UDAT_LONG,
+ /** Medium style */
+ UDAT_MEDIUM,
+ /** Short style */
+ UDAT_SHORT,
+ /** Default style */
+ UDAT_DEFAULT = UDAT_MEDIUM,
+
+ /** Bitfield for relative date */
+ UDAT_RELATIVE = (1 << 7),
+
+ UDAT_FULL_RELATIVE = UDAT_FULL | UDAT_RELATIVE,
+
+ UDAT_LONG_RELATIVE = UDAT_LONG | UDAT_RELATIVE,
+
+ UDAT_MEDIUM_RELATIVE = UDAT_MEDIUM | UDAT_RELATIVE,
+
+ UDAT_SHORT_RELATIVE = UDAT_SHORT | UDAT_RELATIVE,
+
+
+ /** No style */
+ UDAT_NONE = -1,
+ /** for internal API use only */
+ UDAT_IGNORE = -2
+
+} UDateFormatStyle;
+
+/**
+ * FieldPosition and UFieldPosition selectors for format fields
+ * defined by DateFormat and UDateFormat.
+ * @stable ICU 3.0
+ */
+typedef enum UDateFormatField {
+ /**
+ * FieldPosition and UFieldPosition selector for 'G' field alignment,
+ * corresponding to the UCAL_ERA field.
+ * @stable ICU 3.0
+ */
+ UDAT_ERA_FIELD = 0,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'y' field alignment,
+ * corresponding to the UCAL_YEAR field.
+ * @stable ICU 3.0
+ */
+ UDAT_YEAR_FIELD = 1,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'M' field alignment,
+ * corresponding to the UCAL_MONTH field.
+ * @stable ICU 3.0
+ */
+ UDAT_MONTH_FIELD = 2,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'd' field alignment,
+ * corresponding to the UCAL_DATE field.
+ * @stable ICU 3.0
+ */
+ UDAT_DATE_FIELD = 3,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'k' field alignment,
+ * corresponding to the UCAL_HOUR_OF_DAY field.
+ * UDAT_HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
+ * For example, 23:59 + 01:00 results in 24:59.
+ * @stable ICU 3.0
+ */
+ UDAT_HOUR_OF_DAY1_FIELD = 4,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'H' field alignment,
+ * corresponding to the UCAL_HOUR_OF_DAY field.
+ * UDAT_HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
+ * For example, 23:59 + 01:00 results in 00:59.
+ * @stable ICU 3.0
+ */
+ UDAT_HOUR_OF_DAY0_FIELD = 5,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'm' field alignment,
+ * corresponding to the UCAL_MINUTE field.
+ * @stable ICU 3.0
+ */
+ UDAT_MINUTE_FIELD = 6,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 's' field alignment,
+ * corresponding to the UCAL_SECOND field.
+ * @stable ICU 3.0
+ */
+ UDAT_SECOND_FIELD = 7,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'S' field alignment,
+ * corresponding to the UCAL_MILLISECOND field.
+ * @stable ICU 3.0
+ */
+ UDAT_FRACTIONAL_SECOND_FIELD = 8,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'E' field alignment,
+ * corresponding to the UCAL_DAY_OF_WEEK field.
+ * @stable ICU 3.0
+ */
+ UDAT_DAY_OF_WEEK_FIELD = 9,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'D' field alignment,
+ * corresponding to the UCAL_DAY_OF_YEAR field.
+ * @stable ICU 3.0
+ */
+ UDAT_DAY_OF_YEAR_FIELD = 10,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'F' field alignment,
+ * corresponding to the UCAL_DAY_OF_WEEK_IN_MONTH field.
+ * @stable ICU 3.0
+ */
+ UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'w' field alignment,
+ * corresponding to the UCAL_WEEK_OF_YEAR field.
+ * @stable ICU 3.0
+ */
+ UDAT_WEEK_OF_YEAR_FIELD = 12,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'W' field alignment,
+ * corresponding to the UCAL_WEEK_OF_MONTH field.
+ * @stable ICU 3.0
+ */
+ UDAT_WEEK_OF_MONTH_FIELD = 13,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'a' field alignment,
+ * corresponding to the UCAL_AM_PM field.
+ * @stable ICU 3.0
+ */
+ UDAT_AM_PM_FIELD = 14,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'h' field alignment,
+ * corresponding to the UCAL_HOUR field.
+ * UDAT_HOUR1_FIELD is used for the one-based 12-hour clock.
+ * For example, 11:30 PM + 1 hour results in 12:30 AM.
+ * @stable ICU 3.0
+ */
+ UDAT_HOUR1_FIELD = 15,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'K' field alignment,
+ * corresponding to the UCAL_HOUR field.
+ * UDAT_HOUR0_FIELD is used for the zero-based 12-hour clock.
+ * For example, 11:30 PM + 1 hour results in 00:30 AM.
+ * @stable ICU 3.0
+ */
+ UDAT_HOUR0_FIELD = 16,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'z' field alignment,
+ * corresponding to the UCAL_ZONE_OFFSET and
+ * UCAL_DST_OFFSET fields.
+ * @stable ICU 3.0
+ */
+ UDAT_TIMEZONE_FIELD = 17,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'Y' field alignment,
+ * corresponding to the UCAL_YEAR_WOY field.
+ * @stable ICU 3.0
+ */
+ UDAT_YEAR_WOY_FIELD = 18,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'e' field alignment,
+ * corresponding to the UCAL_DOW_LOCAL field.
+ * @stable ICU 3.0
+ */
+ UDAT_DOW_LOCAL_FIELD = 19,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'u' field alignment,
+ * corresponding to the UCAL_EXTENDED_YEAR field.
+ * @stable ICU 3.0
+ */
+ UDAT_EXTENDED_YEAR_FIELD = 20,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'g' field alignment,
+ * corresponding to the UCAL_JULIAN_DAY field.
+ * @stable ICU 3.0
+ */
+ UDAT_JULIAN_DAY_FIELD = 21,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'A' field alignment,
+ * corresponding to the UCAL_MILLISECONDS_IN_DAY field.
+ * @stable ICU 3.0
+ */
+ UDAT_MILLISECONDS_IN_DAY_FIELD = 22,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'Z' field alignment,
+ * corresponding to the UCAL_ZONE_OFFSET and
+ * UCAL_DST_OFFSET fields.
+ * @stable ICU 3.0
+ */
+ UDAT_TIMEZONE_RFC_FIELD = 23,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'v' field alignment,
+ * corresponding to the UCAL_ZONE_OFFSET field.
+ * @stable ICU 3.4
+ */
+ UDAT_TIMEZONE_GENERIC_FIELD = 24,
+ /**
+ * FieldPosition selector for 'c' field alignment,
+ * corresponding to the {@link #UCAL_DAY} field.
+ * This displays the stand alone day name, if available.
+ * @stable ICU 3.4
+ */
+ UDAT_STANDALONE_DAY_FIELD = 25,
+
+ /**
+ * FieldPosition selector for 'L' field alignment,
+ * corresponding to the {@link #UCAL_MONTH} field.
+ * This displays the stand alone month name, if available.
+ * @stable ICU 3.4
+ */
+ UDAT_STANDALONE_MONTH_FIELD = 26,
+
+ /**
+ * FieldPosition selector for "Q" field alignment,
+ * corresponding to quarters. This is implemented
+ * using the {@link #UCAL_MONTH} field. This
+ * displays the quarter.
+ * @stable ICU 3.6
+ */
+ UDAT_QUARTER_FIELD = 27,
+
+ /**
+ * FieldPosition selector for the "q" field alignment,
+ * corresponding to stand-alone quarters. This is
+ * implemented using the {@link #UCAL_MONTH} field.
+ * This displays the stand-alone quarter.
+ * @stable ICU 3.6
+ */
+ UDAT_STANDALONE_QUARTER_FIELD = 28,
+
+ /**
+ * FieldPosition and UFieldPosition selector for 'V' field alignment,
+ * corresponding to the UCAL_ZONE_OFFSET field.
+ * @stable ICU 3.8
+ */
+ UDAT_TIMEZONE_SPECIAL_FIELD = 29,
+
+ /**
+ * Number of FieldPosition and UFieldPosition selectors for
+ * DateFormat and UDateFormat.
+ * Valid selectors range from 0 to UDAT_FIELD_COUNT-1.
+ * This value is subject to change if new fields are defined
+ * in the future.
+ * @stable ICU 3.0
+ */
+ UDAT_FIELD_COUNT = 30
+
+} UDateFormatField;
+
+/**
+ * Open a new UDateFormat for formatting and parsing dates and times.
+ * A UDateFormat may be used to format dates in calls to {@link #udat_format },
+ * and to parse dates in calls to {@link #udat_parse }.
+ * @param timeStyle The style used to format times; one of UDAT_FULL, UDAT_LONG,
+ * UDAT_MEDIUM, UDAT_SHORT, or UDAT_DEFAULT
+ * @param dateStyle The style used to format dates; one of UDAT_FULL, UDAT_LONG,
+ * UDAT_MEDIUM, UDAT_SHORT, or UDAT_DEFAULT
+ * @param locale The locale specifying the formatting conventions
+ * @param tzID A timezone ID specifying the timezone to use. If 0, use
+ * the default timezone.
+ * @param tzIDLength The length of tzID, or -1 if null-terminated.
+ * @param pattern A pattern specifying the format to use.
+ * @param patternLength The number of characters in the pattern, or -1 if null-terminated.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @return A pointer to a UDateFormat to use for formatting dates and times, or 0 if
+ * an error occurred.
+ * @stable ICU 2.0
+ */
+U_STABLE UDateFormat* U_EXPORT2
+udat_open(UDateFormatStyle timeStyle,
+ UDateFormatStyle dateStyle,
+ const char *locale,
+ const UChar *tzID,
+ int32_t tzIDLength,
+ const UChar *pattern,
+ int32_t patternLength,
+ UErrorCode *status);
+
+
+/**
+* Close a UDateFormat.
+* Once closed, a UDateFormat may no longer be used.
+* @param format The formatter to close.
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+udat_close(UDateFormat* format);
+
+/**
+ * Open a copy of a UDateFormat.
+ * This function performs a deep copy.
+ * @param fmt The format to copy
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return A pointer to a UDateFormat identical to fmt.
+ * @stable ICU 2.0
+ */
+U_STABLE UDateFormat* U_EXPORT2
+udat_clone(const UDateFormat *fmt,
+ UErrorCode *status);
+
+/**
+* Format a date using an UDateFormat.
+* The date will be formatted using the conventions specified in {@link #udat_open }
+* @param format The formatter to use
+* @param dateToFormat The date to format
+* @param result A pointer to a buffer to receive the formatted number.
+* @param resultLength The maximum size of result.
+* @param position A pointer to a UFieldPosition. On input, position->field
+* is read. On output, position->beginIndex and position->endIndex indicate
+* the beginning and ending indices of field number position->field, if such
+* a field exists. This parameter may be NULL, in which case no field
+* position data is returned.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The total buffer size needed; if greater than resultLength, the output was truncated.
+* @see udat_parse
+* @see UFieldPosition
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+udat_format( const UDateFormat* format,
+ UDate dateToFormat,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition* position,
+ UErrorCode* status);
+
+/**
+* Parse a string into an date/time using a UDateFormat.
+* The date will be parsed using the conventions specified in {@link #udat_open }
+* @param format The formatter to use.
+* @param text The text to parse.
+* @param textLength The length of text, or -1 if null-terminated.
+* @param parsePos If not 0, on input a pointer to an integer specifying the offset at which
+* to begin parsing. If not 0, on output the offset at which parsing ended.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The value of the parsed date/time
+* @see udat_format
+* @stable ICU 2.0
+*/
+U_STABLE UDate U_EXPORT2
+udat_parse( const UDateFormat* format,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos,
+ UErrorCode *status);
+
+/**
+* Parse a string into an date/time using a UDateFormat.
+* The date will be parsed using the conventions specified in {@link #udat_open }
+* @param format The formatter to use.
+* @param calendar The calendar in which to store the parsed data.
+* @param text The text to parse.
+* @param textLength The length of text, or -1 if null-terminated.
+* @param parsePos If not 0, on input a pointer to an integer specifying the offset at which
+* to begin parsing. If not 0, on output the offset at which parsing ended.
+* @param status A pointer to an UErrorCode to receive any errors
+* @see udat_format
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+udat_parseCalendar(const UDateFormat* format,
+ UCalendar* calendar,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos,
+ UErrorCode *status);
+
+/**
+* Determine if an UDateFormat will perform lenient parsing.
+* With lenient parsing, the parser may use heuristics to interpret inputs that do not
+* precisely match the pattern. With strict parsing, inputs must match the pattern.
+* @param fmt The formatter to query
+* @return TRUE if fmt is set to perform lenient parsing, FALSE otherwise.
+* @see udat_setLenient
+* @stable ICU 2.0
+*/
+U_STABLE UBool U_EXPORT2
+udat_isLenient(const UDateFormat* fmt);
+
+/**
+* Specify whether an UDateFormat will perform lenient parsing.
+* With lenient parsing, the parser may use heuristics to interpret inputs that do not
+* precisely match the pattern. With strict parsing, inputs must match the pattern.
+* @param fmt The formatter to set
+* @param isLenient TRUE if fmt should perform lenient parsing, FALSE otherwise.
+* @see dat_isLenient
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+udat_setLenient( UDateFormat* fmt,
+ UBool isLenient);
+
+/**
+* Get the UCalendar associated with an UDateFormat.
+* A UDateFormat uses a UCalendar to convert a raw value to, for example,
+* the day of the week.
+* @param fmt The formatter to query.
+* @return A pointer to the UCalendar used by fmt.
+* @see udat_setCalendar
+* @stable ICU 2.0
+*/
+U_STABLE const UCalendar* U_EXPORT2
+udat_getCalendar(const UDateFormat* fmt);
+
+/**
+* Set the UCalendar associated with an UDateFormat.
+* A UDateFormat uses a UCalendar to convert a raw value to, for example,
+* the day of the week.
+* @param fmt The formatter to set.
+* @param calendarToSet A pointer to an UCalendar to be used by fmt.
+* @see udat_setCalendar
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+udat_setCalendar( UDateFormat* fmt,
+ const UCalendar* calendarToSet);
+
+/**
+* Get the UNumberFormat associated with an UDateFormat.
+* A UDateFormat uses a UNumberFormat to format numbers within a date,
+* for example the day number.
+* @param fmt The formatter to query.
+* @return A pointer to the UNumberFormat used by fmt to format numbers.
+* @see udat_setNumberFormat
+* @stable ICU 2.0
+*/
+U_STABLE const UNumberFormat* U_EXPORT2
+udat_getNumberFormat(const UDateFormat* fmt);
+
+/**
+* Set the UNumberFormat associated with an UDateFormat.
+* A UDateFormat uses a UNumberFormat to format numbers within a date,
+* for example the day number.
+* @param fmt The formatter to set.
+* @param numberFormatToSet A pointer to the UNumberFormat to be used by fmt to format numbers.
+* @see udat_getNumberFormat
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+udat_setNumberFormat( UDateFormat* fmt,
+ const UNumberFormat* numberFormatToSet);
+
+/**
+* Get a locale for which date/time formatting patterns are available.
+* A UDateFormat in a locale returned by this function will perform the correct
+* formatting and parsing for the locale.
+* @param index The index of the desired locale.
+* @return A locale for which date/time formatting patterns are available, or 0 if none.
+* @see udat_countAvailable
+* @stable ICU 2.0
+*/
+U_STABLE const char* U_EXPORT2
+udat_getAvailable(int32_t index);
+
+/**
+* Determine how many locales have date/time formatting patterns available.
+* This function is most useful as determining the loop ending condition for
+* calls to {@link #udat_getAvailable }.
+* @return The number of locales for which date/time formatting patterns are available.
+* @see udat_getAvailable
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+udat_countAvailable(void);
+
+/**
+* Get the year relative to which all 2-digit years are interpreted.
+* For example, if the 2-digit start year is 2100, the year 99 will be
+* interpreted as 2199.
+* @param fmt The formatter to query.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The year relative to which all 2-digit years are interpreted.
+* @see udat_Set2DigitYearStart
+* @stable ICU 2.0
+*/
+U_STABLE UDate U_EXPORT2
+udat_get2DigitYearStart( const UDateFormat *fmt,
+ UErrorCode *status);
+
+/**
+* Set the year relative to which all 2-digit years will be interpreted.
+* For example, if the 2-digit start year is 2100, the year 99 will be
+* interpreted as 2199.
+* @param fmt The formatter to set.
+* @param d The year relative to which all 2-digit years will be interpreted.
+* @param status A pointer to an UErrorCode to receive any errors
+* @see udat_Set2DigitYearStart
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+udat_set2DigitYearStart( UDateFormat *fmt,
+ UDate d,
+ UErrorCode *status);
+
+/**
+* Extract the pattern from a UDateFormat.
+* The pattern will follow the pattern syntax rules.
+* @param fmt The formatter to query.
+* @param localized TRUE if the pattern should be localized, FALSE otherwise.
+* @param result A pointer to a buffer to receive the pattern.
+* @param resultLength The maximum size of result.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The total buffer size needed; if greater than resultLength, the output was truncated.
+* @see udat_applyPattern
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+udat_toPattern( const UDateFormat *fmt,
+ UBool localized,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status);
+
+/**
+* Set the pattern used by an UDateFormat.
+* The pattern should follow the pattern syntax rules.
+* @param format The formatter to set.
+* @param localized TRUE if the pattern is localized, FALSE otherwise.
+* @param pattern The new pattern
+* @param patternLength The length of pattern, or -1 if null-terminated.
+* @see udat_toPattern
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+udat_applyPattern( UDateFormat *format,
+ UBool localized,
+ const UChar *pattern,
+ int32_t patternLength);
+
+/**
+ * The possible types of date format symbols
+ * @stable ICU 2.6
+ */
+typedef enum UDateFormatSymbolType {
+ /** The era names, for example AD */
+ UDAT_ERAS,
+ /** The month names, for example February */
+ UDAT_MONTHS,
+ /** The short month names, for example Feb. */
+ UDAT_SHORT_MONTHS,
+ /** The weekday names, for example Monday */
+ UDAT_WEEKDAYS,
+ /** The short weekday names, for example Mon. */
+ UDAT_SHORT_WEEKDAYS,
+ /** The AM/PM names, for example AM */
+ UDAT_AM_PMS,
+ /** The localized characters */
+ UDAT_LOCALIZED_CHARS,
+ /** The long era names, for example Anno Domini */
+ UDAT_ERA_NAMES,
+ /** The narrow month names, for example F */
+ UDAT_NARROW_MONTHS,
+ /** The narrow weekday names, for example N */
+ UDAT_NARROW_WEEKDAYS,
+ /** Standalone context versions of months */
+ UDAT_STANDALONE_MONTHS,
+ UDAT_STANDALONE_SHORT_MONTHS,
+ UDAT_STANDALONE_NARROW_MONTHS,
+ /** Standalone context versions of weekdays */
+ UDAT_STANDALONE_WEEKDAYS,
+ UDAT_STANDALONE_SHORT_WEEKDAYS,
+ UDAT_STANDALONE_NARROW_WEEKDAYS,
+ /** The quarters, for example 1st Quarter */
+ UDAT_QUARTERS,
+ /** The short quarter names, for example Q1 */
+ UDAT_SHORT_QUARTERS,
+ /** Standalone context versions of quarters */
+ UDAT_STANDALONE_QUARTERS,
+ UDAT_STANDALONE_SHORT_QUARTERS
+
+} UDateFormatSymbolType;
+
+struct UDateFormatSymbols;
+/** Date format symbols.
+ * For usage in C programs.
+ * @stable ICU 2.6
+ */
+typedef struct UDateFormatSymbols UDateFormatSymbols;
+
+/**
+* Get the symbols associated with an UDateFormat.
+* The symbols are what a UDateFormat uses to represent locale-specific data,
+* for example month or day names.
+* @param fmt The formatter to query.
+* @param type The type of symbols to get. One of UDAT_ERAS, UDAT_MONTHS, UDAT_SHORT_MONTHS,
+* UDAT_WEEKDAYS, UDAT_SHORT_WEEKDAYS, UDAT_AM_PMS, or UDAT_LOCALIZED_CHARS
+* @param index The desired symbol of type type.
+* @param result A pointer to a buffer to receive the pattern.
+* @param resultLength The maximum size of result.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The total buffer size needed; if greater than resultLength, the output was truncated.
+* @see udat_countSymbols
+* @see udat_setSymbols
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+udat_getSymbols(const UDateFormat *fmt,
+ UDateFormatSymbolType type,
+ int32_t index,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status);
+
+/**
+* Count the number of particular symbols for an UDateFormat.
+* This function is most useful as for detemining the loop termination condition
+* for calls to {@link #udat_getSymbols }.
+* @param fmt The formatter to query.
+* @param type The type of symbols to count. One of UDAT_ERAS, UDAT_MONTHS, UDAT_SHORT_MONTHS,
+* UDAT_WEEKDAYS, UDAT_SHORT_WEEKDAYS, UDAT_AM_PMS, or UDAT_LOCALIZED_CHARS
+* @return The number of symbols of type type.
+* @see udat_getSymbols
+* @see udat_setSymbols
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+udat_countSymbols( const UDateFormat *fmt,
+ UDateFormatSymbolType type);
+
+/**
+* Set the symbols associated with an UDateFormat.
+* The symbols are what a UDateFormat uses to represent locale-specific data,
+* for example month or day names.
+* @param format The formatter to set
+* @param type The type of symbols to set. One of UDAT_ERAS, UDAT_MONTHS, UDAT_SHORT_MONTHS,
+* UDAT_WEEKDAYS, UDAT_SHORT_WEEKDAYS, UDAT_AM_PMS, or UDAT_LOCALIZED_CHARS
+* @param index The index of the symbol to set of type type.
+* @param value The new value
+* @param valueLength The length of value, or -1 if null-terminated
+* @param status A pointer to an UErrorCode to receive any errors
+* @see udat_getSymbols
+* @see udat_countSymbols
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+udat_setSymbols( UDateFormat *format,
+ UDateFormatSymbolType type,
+ int32_t index,
+ UChar *value,
+ int32_t valueLength,
+ UErrorCode *status);
+
+/**
+ * Get the locale for this date format object.
+ * You can choose between valid and actual locale.
+ * @param fmt The formatter to get the locale from
+ * @param type type of the locale we're looking for (valid or actual)
+ * @param status error code for the operation
+ * @return the locale name
+ * @stable ICU 2.8
+ */
+U_STABLE const char* U_EXPORT2
+udat_getLocaleByType(const UDateFormat *fmt,
+ ULocDataLocaleType type,
+ UErrorCode* status);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/udatpg.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/udatpg.h
new file mode 100644
index 00000000000..4a7f29594dd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/udatpg.h
@@ -0,0 +1,475 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: udatpg.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2007jul30
+* created by: Markus W. Scherer
+*/
+
+#ifndef __UDATPG_H__
+#define __UDATPG_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uenum.h"
+
+/**
+ * \file
+ * \brief C API: Wrapper for DateTimePatternGenerator (unicode/dtptngen.h).
+ *
+ * UDateTimePatternGenerator provides flexible generation of date format patterns,
+ * like "yy-MM-dd". The user can build up the generator by adding successive
+ * patterns. Once that is done, a query can be made using a "skeleton", which is
+ * a pattern which just includes the desired fields and lengths. The generator
+ * will return the "best fit" pattern corresponding to that skeleton.
+ * <p>The main method people will use is udatpg_getBestPattern, since normally
+ * UDateTimePatternGenerator is pre-built with data from a particular locale.
+ * However, generators can be built directly from other data as well.
+ * <p><i>Issue: may be useful to also have a function that returns the list of
+ * fields in a pattern, in order, since we have that internally.
+ * That would be useful for getting the UI order of field elements.</i>
+ */
+
+/**
+ * Opaque type for a date/time pattern generator object.
+ * @draft ICU 3.8
+ */
+typedef void *UDateTimePatternGenerator;
+
+#ifndef U_HIDE_DRAFT_API
+
+/**
+ * Field number constants for udatpg_getAppendItemFormats() and similar functions.
+ * These constants are separate from UDateFormatField despite semantic overlap
+ * because some fields are merged for the date/time pattern generator.
+ * @draft ICU 3.8
+ */
+typedef enum UDateTimePatternField {
+ /** @draft ICU 3.8 */
+ UDATPG_ERA_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_YEAR_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_QUARTER_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_MONTH_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_WEEK_OF_YEAR_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_WEEK_OF_MONTH_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_WEEKDAY_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_DAY_OF_YEAR_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_DAY_OF_WEEK_IN_MONTH_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_DAY_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_DAYPERIOD_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_HOUR_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_MINUTE_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_SECOND_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_FRACTIONAL_SECOND_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_ZONE_FIELD,
+ /** @draft ICU 3.8 */
+ UDATPG_FIELD_COUNT
+} UDateTimePatternField;
+
+/**
+ * Status return values from udatpg_addPattern().
+ * @draft ICU 3.8
+ */
+typedef enum UDateTimePatternConflict {
+ /** @draft ICU 3.8 */
+ UDATPG_NO_CONFLICT,
+ /** @draft ICU 3.8 */
+ UDATPG_BASE_CONFLICT,
+ /** @draft ICU 3.8 */
+ UDATPG_CONFLICT,
+ /** @draft ICU 3.8 */
+ UDATPG_CONFLICT_COUNT
+} UDateTimePatternConflict;
+
+#endif
+
+/**
+ * Open a generator according to a given locale.
+ * @param locale
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call.
+ * @return a pointer to UDateTimePatternGenerator.
+ * @draft ICU 3.8
+ */
+U_DRAFT UDateTimePatternGenerator * U_EXPORT2
+udatpg_open(const char *locale, UErrorCode *pErrorCode);
+
+/**
+ * Open an empty generator, to be constructed with udatpg_addPattern(...) etc.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call.
+ * @return a pointer to UDateTimePatternGenerator.
+ * @draft ICU 3.8
+ */
+U_DRAFT UDateTimePatternGenerator * U_EXPORT2
+udatpg_openEmpty(UErrorCode *pErrorCode);
+
+/**
+ * Close a generator.
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @draft ICU 3.8
+ */
+U_DRAFT void U_EXPORT2
+udatpg_close(UDateTimePatternGenerator *dtpg);
+
+/**
+ * Create a copy pf a generator.
+ * @param dtpg a pointer to UDateTimePatternGenerator to be copied.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call.
+ * @return a pointer to a new UDateTimePatternGenerator.
+ * @draft ICU 3.8
+ */
+U_DRAFT UDateTimePatternGenerator * U_EXPORT2
+udatpg_clone(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode);
+
+/**
+ * Get the best pattern matching the input skeleton. It is guaranteed to
+ * have all of the fields in the skeleton.
+ *
+ * Note that this function uses a non-const UDateTimePatternGenerator:
+ * It uses a stateful pattern parser which is set up for each generator object,
+ * rather than creating one for each function call.
+ * Consecutive calls to this function do not affect each other,
+ * but this function cannot be used concurrently on a single generator object.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param skeleton
+ * The skeleton is a pattern containing only the variable fields.
+ * For example, "MMMdd" and "mmhh" are skeletons.
+ * @param length the length of skeleton
+ * @param bestPattern
+ * The best pattern found from the given skeleton.
+ * @param capacity the capacity of bestPattern.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call.
+ * @return the length of bestPattern.
+ * @draft ICU 3.8
+ */
+U_DRAFT int32_t U_EXPORT2
+udatpg_getBestPattern(UDateTimePatternGenerator *dtpg,
+ const UChar *skeleton, int32_t length,
+ UChar *bestPattern, int32_t capacity,
+ UErrorCode *pErrorCode);
+
+/**
+ * Get a unique skeleton from a given pattern. For example,
+ * both "MMM-dd" and "dd/MMM" produce the skeleton "MMMdd".
+ *
+ * Note that this function uses a non-const UDateTimePatternGenerator:
+ * It uses a stateful pattern parser which is set up for each generator object,
+ * rather than creating one for each function call.
+ * Consecutive calls to this function do not affect each other,
+ * but this function cannot be used concurrently on a single generator object.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param pattern input pattern, such as "dd/MMM".
+ * @param length the length of pattern.
+ * @param skeleton such as "MMMdd"
+ * @param capacity the capacity of skeleton.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call.
+ * @return the length of skeleton.
+ * @draft ICU 3.8
+ */
+U_DRAFT int32_t U_EXPORT2
+udatpg_getSkeleton(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t length,
+ UChar *skeleton, int32_t capacity,
+ UErrorCode *pErrorCode);
+
+/**
+ * Get a unique base skeleton from a given pattern. This is the same
+ * as the skeleton, except that differences in length are minimized so
+ * as to only preserve the difference between string and numeric form. So
+ * for example, both "MMM-dd" and "d/MMM" produce the skeleton "MMMd"
+ * (notice the single d).
+ *
+ * Note that this function uses a non-const UDateTimePatternGenerator:
+ * It uses a stateful pattern parser which is set up for each generator object,
+ * rather than creating one for each function call.
+ * Consecutive calls to this function do not affect each other,
+ * but this function cannot be used concurrently on a single generator object.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param pattern input pattern, such as "dd/MMM".
+ * @param length the length of pattern.
+ * @param baseSkeleton such as "Md"
+ * @param capacity the capacity of base skeleton.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call.
+ * @return the length of baseSkeleton.
+ * @draft ICU 3.8
+ */
+U_DRAFT int32_t U_EXPORT2
+udatpg_getBaseSkeleton(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t length,
+ UChar *baseSkeleton, int32_t capacity,
+ UErrorCode *pErrorCode);
+
+/**
+ * Adds a pattern to the generator. If the pattern has the same skeleton as
+ * an existing pattern, and the override parameter is set, then the previous
+ * value is overriden. Otherwise, the previous value is retained. In either
+ * case, the conflicting status is set and previous vale is stored in
+ * conflicting pattern.
+ * <p>
+ * Note that single-field patterns (like "MMM") are automatically added, and
+ * don't need to be added explicitly!
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param pattern input pattern, such as "dd/MMM"
+ * @param patternLength the length of pattern.
+ * @param override When existing values are to be overridden use true,
+ * otherwise use false.
+ * @param conflictingPattern Previous pattern with the same skeleton.
+ * @param capacity the capacity of conflictingPattern.
+ * @param pLength a pointer to the length of conflictingPattern.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call.
+ * @return conflicting status. The value could be UDATPG_NO_CONFLICT,
+ * UDATPG_BASE_CONFLICT or UDATPG_CONFLICT.
+ * @draft ICU 3.8
+ */
+U_DRAFT UDateTimePatternConflict U_EXPORT2
+udatpg_addPattern(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t patternLength,
+ UBool override,
+ UChar *conflictingPattern, int32_t capacity, int32_t *pLength,
+ UErrorCode *pErrorCode);
+
+/**
+ * An AppendItem format is a pattern used to append a field if there is no
+ * good match. For example, suppose that the input skeleton is "GyyyyMMMd",
+ * and there is no matching pattern internally, but there is a pattern
+ * matching "yyyyMMMd", say "d-MM-yyyy". Then that pattern is used, plus the
+ * G. The way these two are conjoined is by using the AppendItemFormat for G
+ * (era). So if that value is, say "{0}, {1}" then the final resulting
+ * pattern is "d-MM-yyyy, G".
+ * <p>
+ * There are actually three available variables: {0} is the pattern so far,
+ * {1} is the element we are adding, and {2} is the name of the element.
+ * <p>
+ * This reflects the way that the CLDR data is organized.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param field UDateTimePatternField, such as UDATPG_ERA_FIELD
+ * @param value pattern, such as "{0}, {1}"
+ * @param length the length of value.
+ * @draft ICU 3.8
+ */
+U_DRAFT void U_EXPORT2
+udatpg_setAppendItemFormat(UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ const UChar *value, int32_t length);
+
+/**
+ * Getter corresponding to setAppendItemFormat. Values below 0 or at or
+ * above UDATPG_FIELD_COUNT are illegal arguments.
+ *
+ * @param dtpg A pointer to UDateTimePatternGenerator.
+ * @param field UDateTimePatternField, such as UDATPG_ERA_FIELD
+ * @param pLength A pointer that will receive the length of appendItemFormat.
+ * @return appendItemFormat for field.
+ * @draft ICU 3.8
+ */
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getAppendItemFormat(const UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ int32_t *pLength);
+
+/**
+ * Set the name of field, eg "era" in English for ERA. These are only
+ * used if the corresponding AppendItemFormat is used, and if it contains a
+ * {2} variable.
+ * <p>
+ * This reflects the way that the CLDR data is organized.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param field UDateTimePatternField
+ * @param value name for the field.
+ * @param length the length of value.
+ * @draft ICU 3.8
+ */
+U_DRAFT void U_EXPORT2
+udatpg_setAppendItemName(UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ const UChar *value, int32_t length);
+
+/**
+ * Getter corresponding to setAppendItemNames. Values below 0 or at or above
+ * UDATPG_FIELD_COUNT are illegal arguments.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param field UDateTimePatternField, such as UDATPG_ERA_FIELD
+ * @param pLength A pointer that will receive the length of the name for field.
+ * @return name for field
+ * @draft ICU 3.8
+ */
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getAppendItemName(const UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ int32_t *pLength);
+
+/**
+ * The date time format is a message format pattern used to compose date and
+ * time patterns. The default value is "{0} {1}", where {0} will be replaced
+ * by the date pattern and {1} will be replaced by the time pattern.
+ * <p>
+ * This is used when the input skeleton contains both date and time fields,
+ * but there is not a close match among the added patterns. For example,
+ * suppose that this object was created by adding "dd-MMM" and "hh:mm", and
+ * its datetimeFormat is the default "{0} {1}". Then if the input skeleton
+ * is "MMMdhmm", there is not an exact match, so the input skeleton is
+ * broken up into two components "MMMd" and "hmm". There are close matches
+ * for those two skeletons, so the result is put together with this pattern,
+ * resulting in "d-MMM h:mm".
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param dtFormat
+ * message format pattern, here {0} will be replaced by the date
+ * pattern and {1} will be replaced by the time pattern.
+ * @param length the length of dtFormat.
+ * @draft ICU 3.8
+ */
+U_DRAFT void U_EXPORT2
+udatpg_setDateTimeFormat(const UDateTimePatternGenerator *dtpg,
+ const UChar *dtFormat, int32_t length);
+
+/**
+ * Getter corresponding to setDateTimeFormat.
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param pLength A pointer that will receive the length of the format
+ * @return dateTimeFormat.
+ * @draft ICU 3.8
+ */
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getDateTimeFormat(const UDateTimePatternGenerator *dtpg,
+ int32_t *pLength);
+
+/**
+ * The decimal value is used in formatting fractions of seconds. If the
+ * skeleton contains fractional seconds, then this is used with the
+ * fractional seconds. For example, suppose that the input pattern is
+ * "hhmmssSSSS", and the best matching pattern internally is "H:mm:ss", and
+ * the decimal string is ",". Then the resulting pattern is modified to be
+ * "H:mm:ss,SSSS"
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param decimal
+ * @param length the length of decimal.
+ * @draft ICU 3.8
+ */
+U_DRAFT void U_EXPORT2
+udatpg_setDecimal(UDateTimePatternGenerator *dtpg,
+ const UChar *decimal, int32_t length);
+
+/**
+ * Getter corresponding to setDecimal.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param pLength A pointer that will receive the length of the decimal string.
+ * @return corresponding to the decimal point.
+ * @draft ICU 3.8
+ */
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getDecimal(const UDateTimePatternGenerator *dtpg,
+ int32_t *pLength);
+
+/**
+ * Adjusts the field types (width and subtype) of a pattern to match what is
+ * in a skeleton. That is, if you supply a pattern like "d-M H:m", and a
+ * skeleton of "MMMMddhhmm", then the input pattern is adjusted to be
+ * "dd-MMMM hh:mm". This is used internally to get the best match for the
+ * input skeleton, but can also be used externally.
+ *
+ * Note that this function uses a non-const UDateTimePatternGenerator:
+ * It uses a stateful pattern parser which is set up for each generator object,
+ * rather than creating one for each function call.
+ * Consecutive calls to this function do not affect each other,
+ * but this function cannot be used concurrently on a single generator object.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param pattern Input pattern
+ * @param patternLength the length of input pattern.
+ * @param skeleton
+ * @param skeletonLength the length of input skeleton.
+ * @param dest pattern adjusted to match the skeleton fields widths and subtypes.
+ * @param destCapacity the capacity of dest.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call.
+ * @return the length of dest.
+ * @draft ICU 3.8
+ */
+U_DRAFT int32_t U_EXPORT2
+udatpg_replaceFieldTypes(UDateTimePatternGenerator *dtpg,
+ const UChar *pattern, int32_t patternLength,
+ const UChar *skeleton, int32_t skeletonLength,
+ UChar *dest, int32_t destCapacity,
+ UErrorCode *pErrorCode);
+
+/**
+ * Return a UEnumeration list of all the skeletons in canonical form.
+ * Call udatpg_getPatternForSkeleton() to get the corresponding pattern.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call
+ * @return a UEnumeration list of all the skeletons
+ * The caller must close the object.
+ * @draft ICU 3.8
+ */
+U_DRAFT UEnumeration * U_EXPORT2
+udatpg_openSkeletons(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode);
+
+/**
+ * Return a UEnumeration list of all the base skeletons in canonical form.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param pErrorCode a pointer to the UErrorCode which must not indicate a
+ * failure before the function call.
+ * @return a UEnumeration list of all the base skeletons
+ * The caller must close the object.
+ * @draft ICU 3.8
+ */
+U_DRAFT UEnumeration * U_EXPORT2
+udatpg_openBaseSkeletons(const UDateTimePatternGenerator *dtpg, UErrorCode *pErrorCode);
+
+/**
+ * Get the pattern corresponding to a given skeleton.
+ *
+ * @param dtpg a pointer to UDateTimePatternGenerator.
+ * @param skeleton
+ * @param skeletonLength pointer to the length of skeleton.
+ * @param pLength pointer to the length of return pattern.
+ * @return pattern corresponding to a given skeleton.
+ * @draft ICU 3.8
+ */
+U_DRAFT const UChar * U_EXPORT2
+udatpg_getPatternForSkeleton(const UDateTimePatternGenerator *dtpg,
+ const UChar *skeleton, int32_t skeletonLength,
+ int32_t *pLength);
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/ulocdata.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/ulocdata.h
new file mode 100644
index 00000000000..6bcc47220a7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/ulocdata.h
@@ -0,0 +1,194 @@
+/*
+******************************************************************************
+* *
+* Copyright (C) 2003-2007, International Business Machines *
+* Corporation and others. All Rights Reserved. *
+* *
+******************************************************************************
+* file name: ulocdata.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2003Oct21
+* created by: Ram Viswanadha
+*/
+
+#ifndef __ULOCDATA_H__
+#define __ULOCDATA_H__
+
+#include "unicode/ures.h"
+#include "unicode/uloc.h"
+#include "unicode/uset.h"
+
+/**
+ * \file
+ * \brief C API: Provides access to locale data.
+ */
+
+/** Forward declaration of the ULocaleData structure. @stable ICU 3.6 */
+struct ULocaleData;
+
+/** A locale data object. @stable ICU 3.6 */
+typedef struct ULocaleData ULocaleData;
+
+
+
+/** The possible types of exemplar character sets.
+ * @stable ICU 3.4
+ */
+typedef enum ULocaleDataExemplarSetType {
+ ULOCDATA_ES_STANDARD=0, /* Basic set */
+ ULOCDATA_ES_AUXILIARY=1, /* Auxiliary set */
+ ULOCDATA_ES_COUNT=2
+} ULocaleDataExemplarSetType;
+
+/** The possible types of delimiters.
+ * @stable ICU 3.4
+ */
+typedef enum ULocaleDataDelimiterType {
+#ifndef U_HIDE_DRAFT_API
+ ULOCDATA_QUOTATION_START = 0, /* Quotation start */
+ ULOCDATA_QUOTATION_END = 1, /* Quotation end */
+ ULOCDATA_ALT_QUOTATION_START = 2, /* Alternate quotation start */
+ ULOCDATA_ALT_QUOTATION_END = 3, /* Alternate quotation end */
+#endif
+ ULOCDATA_DELIMITER_COUNT = 4
+} ULocaleDataDelimiterType;
+
+/**
+ * Opens a locale data object for the given locale
+ *
+ * @param localeID Specifies the locale associated with this locale
+ * data object.
+ * @param status Pointer to error status code.
+ * @stable ICU 3.4
+ */
+U_STABLE ULocaleData* U_EXPORT2
+ulocdata_open(const char *localeID, UErrorCode *status);
+
+/**
+ * Closes a locale data object.
+ *
+ * @param uld The locale data object to close
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+ulocdata_close(ULocaleData *uld);
+
+/**
+ * Sets the "no Substitute" attribute of the locale data
+ * object. If true, then any methods associated with the
+ * locale data object will return null when there is no
+ * data available for that method, given the locale ID
+ * supplied to ulocdata_open().
+ *
+ * @param uld The locale data object to set.
+ * @param setting Value of the "no substitute" attribute.
+ * @stable ICU 3.4
+ */
+U_STABLE void U_EXPORT2
+ulocdata_setNoSubstitute(ULocaleData *uld, UBool setting);
+
+/**
+ * Retrieves the current "no Substitute" value of the locale data
+ * object. If true, then any methods associated with the
+ * locale data object will return null when there is no
+ * data available for that method, given the locale ID
+ * supplied to ulocdata_open().
+ *
+ * @param uld Pointer to the The locale data object to set.
+ * @return UBool Value of the "no substitute" attribute.
+ * @stable ICU 3.4
+ */
+U_STABLE UBool U_EXPORT2
+ulocdata_getNoSubstitute(ULocaleData *uld);
+
+/**
+ * Returns the set of exemplar characters for a locale.
+ *
+ * @param uld Pointer to the locale data object from which the
+ * exemplar character set is to be retrieved.
+ * @param fillIn Pointer to a USet object to receive the
+ * exemplar character set for the given locale. Previous
+ * contents of fillIn are lost. <em>If fillIn is NULL,
+ * then a new USet is created and returned. The caller
+ * owns the result and must dispose of it by calling
+ * uset_close.</em>
+ * @param options Bitmask for options to apply to the exemplar pattern.
+ * Specify zero to retrieve the exemplar set as it is
+ * defined in the locale data. Specify
+ * USET_CASE_INSENSITIVE to retrieve a case-folded
+ * exemplar set. See uset_applyPattern for a complete
+ * list of valid options. The USET_IGNORE_SPACE bit is
+ * always set, regardless of the value of 'options'.
+ * @param extype Specifies the type of exemplar set to be retrieved.
+ * @param status Pointer to an input-output error code value;
+ * must not be NULL.
+ * @return USet* Either fillIn, or if fillIn is NULL, a pointer to
+ * a newly-allocated USet that the user must close.
+ * @stable ICU 3.4
+ */
+U_STABLE USet* U_EXPORT2
+ulocdata_getExemplarSet(ULocaleData *uld, USet *fillIn,
+ uint32_t options, ULocaleDataExemplarSetType extype, UErrorCode *status);
+
+/**
+ * Returns one of the delimiter strings associated with a locale.
+ *
+ * @param uld Pointer to the locale data object from which the
+ * delimiter string is to be retrieved.
+ * @param type the type of delimiter to be retrieved.
+ * @param result A pointer to a buffer to receive the result.
+ * @param resultLength The maximum size of result.
+ * @param status Pointer to an error code value
+ * @return int32_t The total buffer size needed; if greater than resultLength,
+ * the output was truncated.
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+ulocdata_getDelimiter(ULocaleData *uld, ULocaleDataDelimiterType type, UChar *result, int32_t resultLength, UErrorCode *status);
+
+/**
+ * Enumeration for representing the measurement systems.
+ * @stable ICU 2.8
+ */
+typedef enum UMeasurementSystem {
+ UMS_SI, /** Measurement system specified by SI otherwise known as Metric system. */
+ UMS_US, /** Measurement system followed in the United States of America. */
+ UMS_LIMIT
+} UMeasurementSystem;
+
+/**
+ * Returns the measurement system used in the locale specified by the localeID.
+ * Please note that this API will change in ICU 3.6 and will use an ulocdata object.
+ *
+ * @param localeID The id of the locale for which the measurement system to be retrieved.
+ * @param status Must be a valid pointer to an error code value,
+ * which must not indicate a failure before the function call.
+ * @return UMeasurementSystem the measurement system used in the locale.
+ * @stable ICU 2.8
+ */
+U_STABLE UMeasurementSystem U_EXPORT2
+ulocdata_getMeasurementSystem(const char *localeID, UErrorCode *status);
+
+/**
+ * Returns the element gives the normal business letter size, and customary units.
+ * The units for the numbers are always in <em>milli-meters</em>.
+ * For US since 8.5 and 11 do not yeild an integral value when converted to milli-meters,
+ * the values are rounded off.
+ * So for A4 size paper the height and width are 297 mm and 210 mm repectively,
+ * and for US letter size the height and width are 279 mm and 216 mm respectively.
+ * Please note that this API will change in ICU 3.6 and will use an ulocdata object.
+ *
+ * @param localeID The id of the locale for which the paper size information to be retrieved.
+ * @param height A pointer to int to recieve the height information.
+ * @param width A pointer to int to recieve the width information.
+ * @param status Must be a valid pointer to an error code value,
+ * which must not indicate a failure before the function call.
+ * @stable ICU 2.8
+ */
+U_STABLE void U_EXPORT2
+ulocdata_getPaperSize(const char *localeID, int32_t *height, int32_t *width, UErrorCode *status);
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/umsg.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/umsg.h
new file mode 100644
index 00000000000..32ed063c274
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/umsg.h
@@ -0,0 +1,647 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation
+* and others. All Rights Reserved.
+*******************************************************************************
+*
+* file name: umsg.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* Change history:
+*
+* 08/5/2001 Ram Added C wrappers for C++ API.
+*
+*
+*/
+
+#ifndef UMSG_H
+#define UMSG_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uloc.h"
+#include "unicode/parseerr.h"
+#include <stdarg.h>
+/**
+ * \file
+ * \brief C API: MessageFormat
+ *
+ * <h2>Message Format C API </h2>
+ *
+ * Provides means to produce concatenated messages in language-neutral way.
+ * Use this for all concatenations that show up to end users.
+ * <P>
+ * Takes a set of objects, formats them, then inserts the formatted
+ * strings into the pattern at the appropriate places.
+ * <P>
+ * Here are some examples of usage:
+ * Example 1:
+ * <pre>
+ * \code
+ * UChar *result, *tzID, *str;
+ * UChar pattern[100];
+ * int32_t resultLengthOut, resultlength;
+ * UCalendar *cal;
+ * UDate d1;
+ * UDateFormat *def1;
+ * UErrorCode status = U_ZERO_ERROR;
+ *
+ * str=(UChar*)malloc(sizeof(UChar) * (strlen("disturbance in force") +1));
+ * u_uastrcpy(str, "disturbance in force");
+ * tzID=(UChar*)malloc(sizeof(UChar) * 4);
+ * u_uastrcpy(tzID, "PST");
+ * cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_TRADITIONAL, &status);
+ * ucal_setDateTime(cal, 1999, UCAL_MARCH, 18, 0, 0, 0, &status);
+ * d1=ucal_getMillis(cal, &status);
+ * u_uastrcpy(pattern, "On {0, date, long}, there was a {1} on planet {2,number,integer}");
+ * resultlength=0;
+ * resultLengthOut=u_formatMessage( "en_US", pattern, u_strlen(pattern), NULL, resultlength, &status, d1, str, 7);
+ * if(status==U_BUFFER_OVERFLOW_ERROR){
+ * status=U_ZERO_ERROR;
+ * resultlength=resultLengthOut+1;
+ * result=(UChar*)realloc(result, sizeof(UChar) * resultlength);
+ * u_formatMessage( "en_US", pattern, u_strlen(pattern), result, resultlength, &status, d1, str, 7);
+ * }
+ * printf("%s\n", austrdup(result) );//austrdup( a function used to convert UChar* to char*)
+ * //output>: "On March 18, 1999, there was a disturbance in force on planet 7
+ * \endcode
+ * </pre>
+ * Typically, the message format will come from resources, and the
+ * arguments will be dynamically set at runtime.
+ * <P>
+ * Example 2:
+ * <pre>
+ * \code
+ * UChar* str;
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar *result;
+ * UChar pattern[100];
+ * int32_t resultlength, resultLengthOut, i;
+ * double testArgs= { 100.0, 1.0, 0.0};
+ *
+ * str=(UChar*)malloc(sizeof(UChar) * 10);
+ * u_uastrcpy(str, "MyDisk");
+ * u_uastrcpy(pattern, "The disk {1} contains {0,choice,0#no files|1#one file|1<{0,number,integer} files}");
+ * for(i=0; i<3; i++){
+ * resultlength=0;
+ * resultLengthOut=u_formatMessage( "en_US", pattern, u_strlen(pattern), NULL, resultlength, &status, testArgs[i], str);
+ * if(status==U_BUFFER_OVERFLOW_ERROR){
+ * status=U_ZERO_ERROR;
+ * resultlength=resultLengthOut+1;
+ * result=(UChar*)malloc(sizeof(UChar) * resultlength);
+ * u_formatMessage( "en_US", pattern, u_strlen(pattern), result, resultlength, &status, testArgs[i], str);
+ * }
+ * printf("%s\n", austrdup(result) ); //austrdup( a function used to convert UChar* to char*)
+ * free(result);
+ * }
+ * // output, with different testArgs:
+ * // output: The disk "MyDisk" contains 100 files.
+ * // output: The disk "MyDisk" contains one file.
+ * // output: The disk "MyDisk" contains no files.
+ * \endcode
+ * </pre>
+ *
+ * The pattern is of the following form. Legend:
+ * <pre>
+ * \code
+ * {optional item}
+ * (group that may be repeated)*
+ * \endcode
+ * </pre>
+ * Do not confuse optional items with items inside quotes braces, such
+ * as this: "{". Quoted braces are literals.
+ * <pre>
+ * \code
+ * messageFormatPattern := string ( "{" messageFormatElement "}" string )*
+ *
+ * messageFormatElement := argument { "," elementFormat }
+ *
+ * elementFormat := "time" { "," datetimeStyle }
+ * | "date" { "," datetimeStyle }
+ * | "number" { "," numberStyle }
+ * | "choice" "," choiceStyle
+ *
+ * datetimeStyle := "short"
+ * | "medium"
+ * | "long"
+ * | "full"
+ * | dateFormatPattern
+ *
+ * numberStyle := "currency"
+ * | "percent"
+ * | "integer"
+ * | numberFormatPattern
+ *
+ * choiceStyle := choiceFormatPattern
+ * \endcode
+ * </pre>
+ * If there is no elementFormat, then the argument must be a string,
+ * which is substituted. If there is no dateTimeStyle or numberStyle,
+ * then the default format is used (e.g. NumberFormat.getInstance(),
+ * DateFormat.getDefaultTime() or DateFormat.getDefaultDate(). For
+ * a ChoiceFormat, the pattern must always be specified, since there
+ * is no default.
+ * <P>
+ * In strings, single quotes can be used to quote the "{" sign if
+ * necessary. A real single quote is represented by ''. Inside a
+ * messageFormatElement, quotes are [not] removed. For example,
+ * {1,number,$'#',##} will produce a number format with the pound-sign
+ * quoted, with a result such as: "$#31,45".
+ * <P>
+ * If a pattern is used, then unquoted braces in the pattern, if any,
+ * must match: that is, "ab {0} de" and "ab '}' de" are ok, but "ab
+ * {0'}' de" and "ab } de" are not.
+ * <p>
+ * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
+ * format patterns unfortunately have shown to be somewhat confusing.
+ * In particular, it isn't always obvious to localizers whether single
+ * quotes need to be doubled or not. Make sure to inform localizers about
+ * the rules, and tell them (for example, by using comments in resource
+ * bundle source files) which strings will be processed by MessageFormat.
+ * Note that localizers may need to use single quotes in translated
+ * strings where the original version doesn't have them.
+ * <br>Note also that the simplest way to avoid the problem is to
+ * use the real apostrophe (single quote) character U+2019 (') for
+ * human-readable text, and to use the ASCII apostrophe (U+0027 ' )
+ * only in program syntax, like quoting in MessageFormat.
+ * See the annotations for U+0027 Apostrophe in The Unicode Standard.</p>
+ * </dl>
+ * <P>
+ * The argument is a number from 0 to 9, which corresponds to the
+ * arguments presented in an array to be formatted.
+ * <P>
+ * It is ok to have unused arguments in the array. With missing
+ * arguments or arguments that are not of the right class for the
+ * specified format, a failing UErrorCode result is set.
+ * <P>
+
+ * <P>
+ * [Note:] As we see above, the string produced by a choice Format in
+ * MessageFormat is treated specially; occurances of '{' are used to
+ * indicated subformats.
+ * <P>
+ * [Note:] Formats are numbered by order of variable in the string.
+ * This is [not] the same as the argument numbering!
+ * <pre>
+ * \code
+ * For example: with "abc{2}def{3}ghi{0}...",
+ *
+ * format0 affects the first variable {2}
+ * format1 affects the second variable {3}
+ * format2 affects the second variable {0}
+ * \endcode
+ * </pre>
+ * and so on.
+ */
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param locale The locale for which the message will be formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments specified
+ * in pattern.
+ * @return The total buffer size needed; if greater than resultLength, the
+ * output was truncated.
+ * @see u_parseMessage
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_formatMessage(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param locale The locale for which the message will be formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param ap A variable-length argument list containing the arguments specified
+ * @param status A pointer to an UErrorCode to receive any errors
+ * in pattern.
+ * @return The total buffer size needed; if greater than resultLength, the
+ * output was truncated.
+ * @see u_parseMessage
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vformatMessage( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ va_list ap,
+ UErrorCode *status);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #u_formatMessage }.
+ * @param locale The locale for which the message is formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments
+ * specified in pattern.
+ * @see u_formatMessage
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_parseMessage( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #u_formatMessage }.
+ * @param locale The locale for which the message is formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param ap A variable-length argument list containing the arguments
+ * @param status A pointer to an UErrorCode to receive any errors
+ * specified in pattern.
+ * @see u_formatMessage
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_vparseMessage(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ va_list ap,
+ UErrorCode *status);
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param locale The locale for which the message will be formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments specified
+ * in pattern.
+ * @param parseError A pointer to UParseError to receive information about errors
+ * occurred during parsing.
+ * @return The total buffer size needed; if greater than resultLength, the
+ * output was truncated.
+ * @see u_parseMessage
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_formatMessageWithError( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UParseError *parseError,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param locale The locale for which the message will be formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param parseError A pointer to UParseError to receive information about errors
+ * occurred during parsing.
+ * @param ap A variable-length argument list containing the arguments specified
+ * @param status A pointer to an UErrorCode to receive any errors
+ * in pattern.
+ * @return The total buffer size needed; if greater than resultLength, the
+ * output was truncated.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+u_vformatMessageWithError( const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ UChar *result,
+ int32_t resultLength,
+ UParseError* parseError,
+ va_list ap,
+ UErrorCode *status);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #u_formatMessage }.
+ * @param locale The locale for which the message is formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param parseError A pointer to UParseError to receive information about errors
+ * occurred during parsing.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments
+ * specified in pattern.
+ * @see u_formatMessage
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_parseMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ UParseError *parseError,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #u_formatMessage }.
+ * @param locale The locale for which the message is formatted
+ * @param pattern The pattern specifying the message's format
+ * @param patternLength The length of pattern
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param ap A variable-length argument list containing the arguments
+ * @param parseError A pointer to UParseError to receive information about errors
+ * occurred during parsing.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * specified in pattern.
+ * @see u_formatMessage
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+u_vparseMessageWithError(const char *locale,
+ const UChar *pattern,
+ int32_t patternLength,
+ const UChar *source,
+ int32_t sourceLength,
+ va_list ap,
+ UParseError *parseError,
+ UErrorCode* status);
+
+/*----------------------- New experimental API --------------------------- */
+/**
+ * The message format object
+ * @stable ICU 2.0
+ */
+typedef void* UMessageFormat;
+
+
+/**
+ * Open a message formatter with given pattern and for the given locale.
+ * @param pattern A pattern specifying the format to use.
+ * @param patternLength Length of the pattern to use
+ * @param locale The locale for which the messages are formatted.
+ * @param parseError A pointer to UParseError struct to receive any errors
+ * occured during parsing. Can be NULL.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return A pointer to a UMessageFormat to use for formatting
+ * messages, or 0 if an error occurred.
+ * @stable ICU 2.0
+ */
+U_STABLE UMessageFormat* U_EXPORT2
+umsg_open( const UChar *pattern,
+ int32_t patternLength,
+ const char *locale,
+ UParseError *parseError,
+ UErrorCode *status);
+
+/**
+ * Close a UMessageFormat.
+ * Once closed, a UMessageFormat may no longer be used.
+ * @param format The formatter to close.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+umsg_close(UMessageFormat* format);
+
+/**
+ * Open a copy of a UMessageFormat.
+ * This function performs a deep copy.
+ * @param fmt The formatter to copy
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return A pointer to a UDateFormat identical to fmt.
+ * @stable ICU 2.0
+ */
+U_STABLE UMessageFormat U_EXPORT2
+umsg_clone(const UMessageFormat *fmt,
+ UErrorCode *status);
+
+/**
+ * Sets the locale. This locale is used for fetching default number or date
+ * format information.
+ * @param fmt The formatter to set
+ * @param locale The locale the formatter should use.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+umsg_setLocale(UMessageFormat *fmt,
+ const char* locale);
+
+/**
+ * Gets the locale. This locale is used for fetching default number or date
+ * format information.
+ * @param fmt The formatter to querry
+ * @return the locale.
+ * @stable ICU 2.0
+ */
+U_STABLE const char* U_EXPORT2
+umsg_getLocale(const UMessageFormat *fmt);
+
+/**
+ * Sets the pattern.
+ * @param fmt The formatter to use
+ * @param pattern The pattern to be applied.
+ * @param patternLength Length of the pattern to use
+ * @param parseError Struct to receive information on position
+ * of error if an error is encountered.Can be NULL.
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+umsg_applyPattern( UMessageFormat *fmt,
+ const UChar* pattern,
+ int32_t patternLength,
+ UParseError* parseError,
+ UErrorCode* status);
+
+/**
+ * Gets the pattern.
+ * @param fmt The formatter to use
+ * @param result A pointer to a buffer to receive the pattern.
+ * @param resultLength The maximum size of result.
+ * @param status Output param set to success/failure code on
+ * exit. If the pattern is invalid, this will be
+ * set to a failure result.
+ * @return the pattern of the format
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+umsg_toPattern(const UMessageFormat *fmt,
+ UChar* result,
+ int32_t resultLength,
+ UErrorCode* status);
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param fmt The formatter to use
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments
+ * specified in pattern.
+ * @return The total buffer size needed; if greater than resultLength,
+ * the output was truncated.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+umsg_format( const UMessageFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Format a message for a locale.
+ * This function may perform re-ordering of the arguments depending on the
+ * locale. For all numeric arguments, double is assumed unless the type is
+ * explicitly integer. All choice format arguments must be of type double.
+ * @param fmt The formatter to use
+ * @param result A pointer to a buffer to receive the formatted message.
+ * @param resultLength The maximum size of result.
+ * @param ap A variable-length argument list containing the arguments
+ * @param status A pointer to an UErrorCode to receive any errors
+ * specified in pattern.
+ * @return The total buffer size needed; if greater than resultLength,
+ * the output was truncated.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+umsg_vformat( const UMessageFormat *fmt,
+ UChar *result,
+ int32_t resultLength,
+ va_list ap,
+ UErrorCode *status);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #umsg_format }.
+ * @param fmt The formatter to use
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param count Output param to receive number of elements returned.
+ * @param status A pointer to an UErrorCode to receive any errors
+ * @param ... A variable-length argument list containing the arguments
+ * specified in pattern.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+umsg_parse( const UMessageFormat *fmt,
+ const UChar *source,
+ int32_t sourceLength,
+ int32_t *count,
+ UErrorCode *status,
+ ...);
+
+/**
+ * Parse a message.
+ * For numeric arguments, this function will always use doubles. Integer types
+ * should not be passed.
+ * This function is not able to parse all output from {@link #umsg_format }.
+ * @param fmt The formatter to use
+ * @param source The text to parse.
+ * @param sourceLength The length of source, or -1 if null-terminated.
+ * @param count Output param to receive number of elements returned.
+ * @param ap A variable-length argument list containing the arguments
+ * @param status A pointer to an UErrorCode to receive any errors
+ * specified in pattern.
+ * @see u_formatMessage
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+umsg_vparse(const UMessageFormat *fmt,
+ const UChar *source,
+ int32_t sourceLength,
+ int32_t *count,
+ va_list ap,
+ UErrorCode *status);
+
+
+/**
+ * Convert an 'apostrophe-friendly' pattern into a standard
+ * pattern. Standard patterns treat all apostrophes as
+ * quotes, which is problematic in some languages, e.g.
+ * French, where apostrophe is commonly used. This utility
+ * assumes that only an unpaired apostrophe immediately before
+ * a brace is a true quote. Other unpaired apostrophes are paired,
+ * and the resulting standard pattern string is returned.
+ *
+ * <p><b>Note</b> it is not guaranteed that the returned pattern
+ * is indeed a valid pattern. The only effect is to convert
+ * between patterns having different quoting semantics.
+ *
+ * @param pattern the 'apostrophe-friendly' patttern to convert
+ * @param patternLength the length of pattern, or -1 if unknown and pattern is null-terminated
+ * @param dest the buffer for the result, or NULL if preflight only
+ * @param destCapacity the length of the buffer, or 0 if preflighting
+ * @param ec the error code
+ * @return the length of the resulting text, not including trailing null
+ * if buffer has room for the trailing null, it is provided, otherwise
+ * not
+ * @stable ICU 3.4
+ */
+U_STABLE int32_t U_EXPORT2
+umsg_autoQuoteApostrophe(const UChar* pattern,
+ int32_t patternLength,
+ UChar* dest,
+ int32_t destCapacity,
+ UErrorCode* ec);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/unirepl.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/unirepl.h
new file mode 100644
index 00000000000..6b7746b2213
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/unirepl.h
@@ -0,0 +1,97 @@
+/*
+**********************************************************************
+* Copyright (c) 2002-2005, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 01/14/2002 aliu Creation.
+**********************************************************************
+*/
+#ifndef UNIREPL_H
+#define UNIREPL_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: UnicodeReplacer
+ */
+
+U_NAMESPACE_BEGIN
+
+class Replaceable;
+class UnicodeString;
+class UnicodeSet;
+
+/**
+ * <code>UnicodeReplacer</code> defines a protocol for objects that
+ * replace a range of characters in a Replaceable string with output
+ * text. The replacement is done via the Replaceable API so as to
+ * preserve out-of-band data.
+ *
+ * <p>This is a mixin class.
+ * @author Alan Liu
+ * @stable ICU 2.4
+ */
+class U_I18N_API UnicodeReplacer /* not : public UObject because this is an interface/mixin class */ {
+
+ public:
+
+ /**
+ * Destructor.
+ * @stable ICU 2.4
+ */
+ virtual ~UnicodeReplacer();
+
+ /**
+ * Replace characters in 'text' from 'start' to 'limit' with the
+ * output text of this object. Update the 'cursor' parameter to
+ * give the cursor position and return the length of the
+ * replacement text.
+ *
+ * @param text the text to be matched
+ * @param start inclusive start index of text to be replaced
+ * @param limit exclusive end index of text to be replaced;
+ * must be greater than or equal to start
+ * @param cursor output parameter for the cursor position.
+ * Not all replacer objects will update this, but in a complete
+ * tree of replacer objects, representing the entire output side
+ * of a transliteration rule, at least one must update it.
+ * @return the number of 16-bit code units in the text replacing
+ * the characters at offsets start..(limit-1) in text
+ * @stable ICU 2.4
+ */
+ virtual int32_t replace(Replaceable& text,
+ int32_t start,
+ int32_t limit,
+ int32_t& cursor) = 0;
+
+ /**
+ * Returns a string representation of this replacer. If the
+ * result of calling this function is passed to the appropriate
+ * parser, typically TransliteratorParser, it will produce another
+ * replacer that is equal to this one.
+ * @param result the string to receive the pattern. Previous
+ * contents will be deleted.
+ * @param escapeUnprintable if TRUE then convert unprintable
+ * character to their hex escape representations, \\uxxxx or
+ * \\Uxxxxxxxx. Unprintable characters are defined by
+ * Utility.isUnprintable().
+ * @return a reference to 'result'.
+ * @stable ICU 2.4
+ */
+ virtual UnicodeString& toReplacerPattern(UnicodeString& result,
+ UBool escapeUnprintable) const = 0;
+
+ /**
+ * Union the set of all characters that may output by this object
+ * into the given set.
+ * @param toUnionTo the set into which to union the output characters
+ * @stable ICU 2.4
+ */
+ virtual void addReplacementSetTo(UnicodeSet& toUnionTo) const = 0;
+};
+
+U_NAMESPACE_END
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/unum.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/unum.h
new file mode 100644
index 00000000000..c69d2f4b8b5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/unum.h
@@ -0,0 +1,869 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2007, International Business Machines Corporation and others.
+* All Rights Reserved.
+* Modification History:
+*
+* Date Name Description
+* 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
+*******************************************************************************
+*/
+
+#ifndef _UNUM
+#define _UNUM
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/uloc.h"
+#include "unicode/umisc.h"
+#include "unicode/parseerr.h"
+/**
+ * \file
+ * \brief C API: NumberFormat
+ *
+ * <h2> Number Format C API </h2>
+ *
+ * Number Format C API Provides functions for
+ * formatting and parsing a number. Also provides methods for
+ * determining which locales have number formats, and what their names
+ * are.
+ * <P>
+ * UNumberFormat helps you to format and parse numbers for any locale.
+ * Your code can be completely independent of the locale conventions
+ * for decimal points, thousands-separators, or even the particular
+ * decimal digits used, or whether the number format is even decimal.
+ * There are different number format styles like decimal, currency,
+ * percent and spellout.
+ * <P>
+ * To format a number for the current Locale, use one of the static
+ * factory methods:
+ * <pre>
+ * \code
+ * UChar myString[20];
+ * double myNumber = 7.0;
+ * UErrorCode status = U_ZERO_ERROR;
+ * UNumberFormat* nf = unum_open(UNUM_DEFAULT, NULL, -1, NULL, NULL, &status);
+ * unum_formatDouble(nf, myNumber, myString, 20, NULL, &status);
+ * printf(" Example 1: %s\n", austrdup(myString) ); //austrdup( a function used to convert UChar* to char*)
+ * \endcode
+ * </pre>
+ * If you are formatting multiple numbers, it is more efficient to get
+ * the format and use it multiple times so that the system doesn't
+ * have to fetch the information about the local language and country
+ * conventions multiple times.
+ * <pre>
+ * \code
+ * uint32_t i, resultlength, reslenneeded;
+ * UErrorCode status = U_ZERO_ERROR;
+ * UFieldPosition pos;
+ * uint32_t a[] = { 123, 3333, -1234567 };
+ * const uint32_t a_len = sizeof(a) / sizeof(a[0]);
+ * UNumberFormat* nf;
+ * UChar* result = NULL;
+ *
+ * nf = unum_open(UNUM_DEFAULT, NULL, -1, NULL, NULL, &status);
+ * for (i = 0; i < a_len; i++) {
+ * resultlength=0;
+ * reslenneeded=unum_format(nf, a[i], NULL, resultlength, &pos, &status);
+ * result = NULL;
+ * if(status==U_BUFFER_OVERFLOW_ERROR){
+ * status=U_ZERO_ERROR;
+ * resultlength=reslenneeded+1;
+ * result=(UChar*)malloc(sizeof(UChar) * resultlength);
+ * unum_format(nf, a[i], result, resultlength, &pos, &status);
+ * }
+ * printf( " Example 2: %s\n", austrdup(result));
+ * free(result);
+ * }
+ * \endcode
+ * </pre>
+ * To format a number for a different Locale, specify it in the
+ * call to unum_open().
+ * <pre>
+ * \code
+ * UNumberFormat* nf = unum_open(UNUM_DEFAULT, NULL, -1, "fr_FR", NULL, &success)
+ * \endcode
+ * </pre>
+ * You can use a NumberFormat API unum_parse() to parse.
+ * <pre>
+ * \code
+ * UErrorCode status = U_ZERO_ERROR;
+ * int32_t pos=0;
+ * int32_t num;
+ * num = unum_parse(nf, str, u_strlen(str), &pos, &status);
+ * \endcode
+ * </pre>
+ * Use UCAL_DECIMAL to get the normal number format for that country.
+ * There are other static options available. Use UCAL_CURRENCY
+ * to get the currency number format for that country. Use UCAL_PERCENT
+ * to get a format for displaying percentages. With this format, a
+ * fraction from 0.53 is displayed as 53%.
+ * <P>
+ * Use a pattern to create either a DecimalFormat or a RuleBasedNumberFormat
+ * formatter. The pattern must conform to the syntax defined for those
+ * formatters.
+ * <P>
+ * You can also control the display of numbers with such function as
+ * unum_getAttribues() and unum_setAtributes(), which let you set the
+ * miminum fraction digits, grouping, etc.
+ * @see UNumberFormatAttributes for more details
+ * <P>
+ * You can also use forms of the parse and format methods with
+ * ParsePosition and UFieldPosition to allow you to:
+ * <ul type=round>
+ * <li>(a) progressively parse through pieces of a string.
+ * <li>(b) align the decimal point and other areas.
+ * </ul>
+ * <p>
+ * It is also possible to change or set the symbols used for a particular
+ * locale like the currency symbol, the grouping seperator , monetary seperator
+ * etc by making use of functions unum_setSymbols() and unum_getSymbols().
+ */
+
+/** A number formatter.
+ * For usage in C programs.
+ * @stable ICU 2.0
+ */
+typedef void* UNumberFormat;
+
+/** The possible number format styles.
+ * @stable ICU 2.0
+ */
+typedef enum UNumberFormatStyle {
+ /**
+ * Decimal format defined by pattern
+ * @stable ICU 3.0
+ */
+ UNUM_PATTERN_DECIMAL=0,
+ /** Decimal format */
+ UNUM_DECIMAL=1,
+ /** Currency format */
+ UNUM_CURRENCY,
+ /** Percent format */
+ UNUM_PERCENT,
+ /** Scientific format */
+ UNUM_SCIENTIFIC,
+ /** Spellout rule-based format */
+ UNUM_SPELLOUT,
+ /**
+ * Ordinal rule-based format
+ * @stable ICU 3.0
+ */
+ UNUM_ORDINAL,
+ /**
+ * Duration rule-based format
+ * @stable ICU 3.0
+ */
+ UNUM_DURATION,
+ /**
+ * Rule-based format defined by pattern
+ * @stable ICU 3.0
+ */
+ UNUM_PATTERN_RULEBASED,
+ /** Default format */
+ UNUM_DEFAULT = UNUM_DECIMAL,
+ /** (Alias for UNUM_PATTERN_DECIMAL) */
+ UNUM_IGNORE = UNUM_PATTERN_DECIMAL
+} UNumberFormatStyle;
+
+/** The possible number format rounding modes.
+ * @stable ICU 2.0
+ */
+typedef enum UNumberFormatRoundingMode {
+ UNUM_ROUND_CEILING,
+ UNUM_ROUND_FLOOR,
+ UNUM_ROUND_DOWN,
+ UNUM_ROUND_UP,
+ /**
+ * Half-even rounding, misspelled name
+ * @deprecated, ICU 3.8
+ */
+ UNUM_FOUND_HALFEVEN,
+ UNUM_ROUND_HALFDOWN,
+ UNUM_ROUND_HALFUP,
+ /**
+ * Half-even rounding
+ * @stable, ICU 3.8
+ */
+ UNUM_ROUND_HALFEVEN = UNUM_FOUND_HALFEVEN
+} UNumberFormatRoundingMode;
+
+/** The possible number format pad positions.
+ * @stable ICU 2.0
+ */
+typedef enum UNumberFormatPadPosition {
+ UNUM_PAD_BEFORE_PREFIX,
+ UNUM_PAD_AFTER_PREFIX,
+ UNUM_PAD_BEFORE_SUFFIX,
+ UNUM_PAD_AFTER_SUFFIX
+} UNumberFormatPadPosition;
+
+/**
+ * Create and return a new UNumberFormat for formatting and parsing
+ * numbers. A UNumberFormat may be used to format numbers by calling
+ * {@link #unum_format }, and to parse numbers by calling {@link #unum_parse }.
+ * The caller must call {@link #unum_close } when done to release resources
+ * used by this object.
+ * @param style The type of number format to open: one of
+ * UNUM_DECIMAL, UNUM_CURRENCY, UNUM_PERCENT, UNUM_SCIENTIFIC, UNUM_SPELLOUT,
+ * UNUM_PATTERN_DECIMAL, UNUM_PATTERN_RULEBASED, or UNUM_DEFAULT.
+ * If UNUM_PATTERN_DECIMAL or UNUM_PATTERN_RULEBASED is passed then the
+ * number format is opened using the given pattern, which must conform
+ * to the syntax described in DecimalFormat or RuleBasedNumberFormat,
+ * respectively.
+ * @param pattern A pattern specifying the format to use.
+ * This parameter is ignored unless the style is
+ * UNUM_PATTERN_DECIMAL or UNUM_PATTERN_RULEBASED.
+ * @param patternLength The number of characters in the pattern, or -1
+ * if null-terminated. This parameter is ignored unless the style is
+ * UNUM_PATTERN.
+ * @param locale A locale identifier to use to determine formatting
+ * and parsing conventions, or NULL to use the default locale.
+ * @param parseErr A pointer to a UParseError struct to receive the
+ * details of any parsing errors, or NULL if no parsing error details
+ * are desired.
+ * @param status A pointer to an input-output UErrorCode.
+ * @return A pointer to a newly created UNumberFormat, or NULL if an
+ * error occurred.
+ * @see unum_close
+ * @see DecimalFormat
+ * @stable ICU 2.0
+ */
+U_STABLE UNumberFormat* U_EXPORT2
+unum_open( UNumberFormatStyle style,
+ const UChar* pattern,
+ int32_t patternLength,
+ const char* locale,
+ UParseError* parseErr,
+ UErrorCode* status);
+
+
+/**
+* Close a UNumberFormat.
+* Once closed, a UNumberFormat may no longer be used.
+* @param fmt The formatter to close.
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+unum_close(UNumberFormat* fmt);
+
+/**
+ * Open a copy of a UNumberFormat.
+ * This function performs a deep copy.
+ * @param fmt The format to copy
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return A pointer to a UNumberFormat identical to fmt.
+ * @stable ICU 2.0
+ */
+U_STABLE UNumberFormat* U_EXPORT2
+unum_clone(const UNumberFormat *fmt,
+ UErrorCode *status);
+
+/**
+* Format an integer using a UNumberFormat.
+* The integer will be formatted according to the UNumberFormat's locale.
+* @param fmt The formatter to use.
+* @param number The number to format.
+* @param result A pointer to a buffer to receive the formatted number.
+* @param resultLength The maximum size of result.
+* @param pos A pointer to a UFieldPosition. On input, position->field
+* is read. On output, position->beginIndex and position->endIndex indicate
+* the beginning and ending indices of field number position->field, if such
+* a field exists. This parameter may be NULL, in which case no field
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The total buffer size needed; if greater than resultLength, the output was truncated.
+* @see unum_formatInt64
+* @see unum_formatDouble
+* @see unum_parse
+* @see unum_parseInt64
+* @see unum_parseDouble
+* @see UFieldPosition
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+unum_format( const UNumberFormat* fmt,
+ int32_t number,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition *pos,
+ UErrorCode* status);
+
+/**
+* Format an int64 using a UNumberFormat.
+* The int64 will be formatted according to the UNumberFormat's locale.
+* @param fmt The formatter to use.
+* @param number The number to format.
+* @param result A pointer to a buffer to receive the formatted number.
+* @param resultLength The maximum size of result.
+* @param pos A pointer to a UFieldPosition. On input, position->field
+* is read. On output, position->beginIndex and position->endIndex indicate
+* the beginning and ending indices of field number position->field, if such
+* a field exists. This parameter may be NULL, in which case no field
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The total buffer size needed; if greater than resultLength, the output was truncated.
+* @see unum_format
+* @see unum_formatDouble
+* @see unum_parse
+* @see unum_parseInt64
+* @see unum_parseDouble
+* @see UFieldPosition
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+unum_formatInt64(const UNumberFormat *fmt,
+ int64_t number,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition *pos,
+ UErrorCode* status);
+
+/**
+* Format a double using a UNumberFormat.
+* The double will be formatted according to the UNumberFormat's locale.
+* @param fmt The formatter to use.
+* @param number The number to format.
+* @param result A pointer to a buffer to receive the formatted number.
+* @param resultLength The maximum size of result.
+* @param pos A pointer to a UFieldPosition. On input, position->field
+* is read. On output, position->beginIndex and position->endIndex indicate
+* the beginning and ending indices of field number position->field, if such
+* a field exists. This parameter may be NULL, in which case no field
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The total buffer size needed; if greater than resultLength, the output was truncated.
+* @see unum_format
+* @see unum_formatInt64
+* @see unum_parse
+* @see unum_parseInt64
+* @see unum_parseDouble
+* @see UFieldPosition
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+unum_formatDouble( const UNumberFormat* fmt,
+ double number,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition *pos, /* 0 if ignore */
+ UErrorCode* status);
+
+/**
+ * Format a double currency amount using a UNumberFormat.
+ * The double will be formatted according to the UNumberFormat's locale.
+ * @param fmt the formatter to use
+ * @param number the number to format
+ * @param currency the 3-letter null-terminated ISO 4217 currency code
+ * @param result a pointer to the buffer to receive the formatted number
+ * @param resultLength the maximum number of UChars to write to result
+ * @param pos a pointer to a UFieldPosition. On input,
+ * position->field is read. On output, position->beginIndex and
+ * position->endIndex indicate the beginning and ending indices of
+ * field number position->field, if such a field exists. This
+ * parameter may be NULL, in which case it is ignored.
+ * @param status a pointer to an input-output UErrorCode
+ * @return the total buffer size needed; if greater than resultLength,
+ * the output was truncated.
+ * @see unum_formatDouble
+ * @see unum_parseDoubleCurrency
+ * @see UFieldPosition
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+unum_formatDoubleCurrency(const UNumberFormat* fmt,
+ double number,
+ UChar* currency,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition* pos, /* ignored if 0 */
+ UErrorCode* status);
+
+/**
+* Parse a string into an integer using a UNumberFormat.
+* The string will be parsed according to the UNumberFormat's locale.
+* @param fmt The formatter to use.
+* @param text The text to parse.
+* @param textLength The length of text, or -1 if null-terminated.
+* @param parsePos If not 0, on input a pointer to an integer specifying the offset at which
+* to begin parsing. If not 0, on output the offset at which parsing ended.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The value of the parsed integer
+* @see unum_parseInt64
+* @see unum_parseDouble
+* @see unum_format
+* @see unum_formatInt64
+* @see unum_formatDouble
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+unum_parse( const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos /* 0 = start */,
+ UErrorCode *status);
+
+/**
+* Parse a string into an int64 using a UNumberFormat.
+* The string will be parsed according to the UNumberFormat's locale.
+* @param fmt The formatter to use.
+* @param text The text to parse.
+* @param textLength The length of text, or -1 if null-terminated.
+* @param parsePos If not 0, on input a pointer to an integer specifying the offset at which
+* to begin parsing. If not 0, on output the offset at which parsing ended.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The value of the parsed integer
+* @see unum_parse
+* @see unum_parseDouble
+* @see unum_format
+* @see unum_formatInt64
+* @see unum_formatDouble
+* @stable ICU 2.8
+*/
+U_STABLE int64_t U_EXPORT2
+unum_parseInt64(const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos /* 0 = start */,
+ UErrorCode *status);
+
+/**
+* Parse a string into a double using a UNumberFormat.
+* The string will be parsed according to the UNumberFormat's locale.
+* @param fmt The formatter to use.
+* @param text The text to parse.
+* @param textLength The length of text, or -1 if null-terminated.
+* @param parsePos If not 0, on input a pointer to an integer specifying the offset at which
+* to begin parsing. If not 0, on output the offset at which parsing ended.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The value of the parsed double
+* @see unum_parse
+* @see unum_parseInt64
+* @see unum_format
+* @see unum_formatInt64
+* @see unum_formatDouble
+* @stable ICU 2.0
+*/
+U_STABLE double U_EXPORT2
+unum_parseDouble( const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos /* 0 = start */,
+ UErrorCode *status);
+
+/**
+ * Parse a string into a double and a currency using a UNumberFormat.
+ * The string will be parsed according to the UNumberFormat's locale.
+ * @param fmt the formatter to use
+ * @param text the text to parse
+ * @param textLength the length of text, or -1 if null-terminated
+ * @param parsePos a pointer to an offset index into text at which to
+ * begin parsing. On output, *parsePos will point after the last
+ * parsed character. This parameter may be 0, in which case parsing
+ * begins at offset 0.
+ * @param currency a pointer to the buffer to receive the parsed null-
+ * terminated currency. This buffer must have a capacity of at least
+ * 4 UChars.
+ * @param status a pointer to an input-output UErrorCode
+ * @return the parsed double
+ * @see unum_parseDouble
+ * @see unum_formatDoubleCurrency
+ * @stable ICU 3.0
+ */
+U_STABLE double U_EXPORT2
+unum_parseDoubleCurrency(const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t* parsePos, /* 0 = start */
+ UChar* currency,
+ UErrorCode* status);
+
+/**
+ * Set the pattern used by a UNumberFormat. This can only be used
+ * on a DecimalFormat, other formats return U_ILLEGAL_ARGUMENT_ERROR
+ * in the status.
+ * @param format The formatter to set.
+ * @param localized TRUE if the pattern is localized, FALSE otherwise.
+ * @param pattern The new pattern
+ * @param patternLength The length of pattern, or -1 if null-terminated.
+ * @param parseError A pointer to UParseError to recieve information
+ * about errors occurred during parsing, or NULL if no parse error
+ * information is desired.
+ * @param status A pointer to an input-output UErrorCode.
+ * @see unum_toPattern
+ * @see DecimalFormat
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+unum_applyPattern( UNumberFormat *format,
+ UBool localized,
+ const UChar *pattern,
+ int32_t patternLength,
+ UParseError *parseError,
+ UErrorCode *status
+ );
+
+/**
+* Get a locale for which decimal formatting patterns are available.
+* A UNumberFormat in a locale returned by this function will perform the correct
+* formatting and parsing for the locale. The results of this call are not
+* valid for rule-based number formats.
+* @param index The index of the desired locale.
+* @return A locale for which number formatting patterns are available, or 0 if none.
+* @see unum_countAvailable
+* @stable ICU 2.0
+*/
+U_STABLE const char* U_EXPORT2
+unum_getAvailable(int32_t index);
+
+/**
+* Determine how many locales have decimal formatting patterns available. The
+* results of this call are not valid for rule-based number formats.
+* This function is useful for determining the loop ending condition for
+* calls to {@link #unum_getAvailable }.
+* @return The number of locales for which decimal formatting patterns are available.
+* @see unum_getAvailable
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+unum_countAvailable(void);
+
+/** The possible UNumberFormat numeric attributes @stable ICU 2.0 */
+typedef enum UNumberFormatAttribute {
+ /** Parse integers only */
+ UNUM_PARSE_INT_ONLY,
+ /** Use grouping separator */
+ UNUM_GROUPING_USED,
+ /** Always show decimal point */
+ UNUM_DECIMAL_ALWAYS_SHOWN,
+ /** Maximum integer digits */
+ UNUM_MAX_INTEGER_DIGITS,
+ /** Minimum integer digits */
+ UNUM_MIN_INTEGER_DIGITS,
+ /** Integer digits */
+ UNUM_INTEGER_DIGITS,
+ /** Maximum fraction digits */
+ UNUM_MAX_FRACTION_DIGITS,
+ /** Minimum fraction digits */
+ UNUM_MIN_FRACTION_DIGITS,
+ /** Fraction digits */
+ UNUM_FRACTION_DIGITS,
+ /** Multiplier */
+ UNUM_MULTIPLIER,
+ /** Grouping size */
+ UNUM_GROUPING_SIZE,
+ /** Rounding Mode */
+ UNUM_ROUNDING_MODE,
+ /** Rounding increment */
+ UNUM_ROUNDING_INCREMENT,
+ /** The width to which the output of <code>format()</code> is padded. */
+ UNUM_FORMAT_WIDTH,
+ /** The position at which padding will take place. */
+ UNUM_PADDING_POSITION,
+ /** Secondary grouping size */
+ UNUM_SECONDARY_GROUPING_SIZE,
+ /** Use significant digits
+ * @stable ICU 3.0 */
+ UNUM_SIGNIFICANT_DIGITS_USED,
+ /** Minimum significant digits
+ * @stable ICU 3.0 */
+ UNUM_MIN_SIGNIFICANT_DIGITS,
+ /** Maximum significant digits
+ * @stable ICU 3.0 */
+ UNUM_MAX_SIGNIFICANT_DIGITS,
+ /** Lenient parse mode used by rule-based formats.
+ * @stable ICU 3.0
+ */
+ UNUM_LENIENT_PARSE
+} UNumberFormatAttribute;
+
+/**
+* Get a numeric attribute associated with a UNumberFormat.
+* An example of a numeric attribute is the number of integer digits a formatter will produce.
+* @param fmt The formatter to query.
+* @param attr The attribute to query; one of UNUM_PARSE_INT_ONLY, UNUM_GROUPING_USED,
+* UNUM_DECIMAL_ALWAYS_SHOWN, UNUM_MAX_INTEGER_DIGITS, UNUM_MIN_INTEGER_DIGITS, UNUM_INTEGER_DIGITS,
+* UNUM_MAX_FRACTION_DIGITS, UNUM_MIN_FRACTION_DIGITS, UNUM_FRACTION_DIGITS, UNUM_MULTIPLIER,
+* UNUM_GROUPING_SIZE, UNUM_ROUNDING_MODE, UNUM_FORMAT_WIDTH, UNUM_PADDING_POSITION, UNUM_SECONDARY_GROUPING_SIZE.
+* @return The value of attr.
+* @see unum_setAttribute
+* @see unum_getDoubleAttribute
+* @see unum_setDoubleAttribute
+* @see unum_getTextAttribute
+* @see unum_setTextAttribute
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+unum_getAttribute(const UNumberFormat* fmt,
+ UNumberFormatAttribute attr);
+
+/**
+* Set a numeric attribute associated with a UNumberFormat.
+* An example of a numeric attribute is the number of integer digits a formatter will produce. If the
+* formatter does not understand the attribute, the call is ignored. Rule-based formatters only understand
+* the lenient-parse attribute.
+* @param fmt The formatter to set.
+* @param attr The attribute to set; one of UNUM_PARSE_INT_ONLY, UNUM_GROUPING_USED,
+* UNUM_DECIMAL_ALWAYS_SHOWN, UNUM_MAX_INTEGER_DIGITS, UNUM_MIN_INTEGER_DIGITS, UNUM_INTEGER_DIGITS,
+* UNUM_MAX_FRACTION_DIGITS, UNUM_MIN_FRACTION_DIGITS, UNUM_FRACTION_DIGITS, UNUM_MULTIPLIER,
+* UNUM_GROUPING_SIZE, UNUM_ROUNDING_MODE, UNUM_FORMAT_WIDTH, UNUM_PADDING_POSITION, UNUM_SECONDARY_GROUPING_SIZE,
+* or UNUM_LENIENT_PARSE.
+* @param newValue The new value of attr.
+* @see unum_getAttribute
+* @see unum_getDoubleAttribute
+* @see unum_setDoubleAttribute
+* @see unum_getTextAttribute
+* @see unum_setTextAttribute
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+unum_setAttribute( UNumberFormat* fmt,
+ UNumberFormatAttribute attr,
+ int32_t newValue);
+
+
+/**
+* Get a numeric attribute associated with a UNumberFormat.
+* An example of a numeric attribute is the number of integer digits a formatter will produce.
+* If the formatter does not understand the attribute, -1 is returned.
+* @param fmt The formatter to query.
+* @param attr The attribute to query; e.g. UNUM_ROUNDING_INCREMENT.
+* @return The value of attr.
+* @see unum_getAttribute
+* @see unum_setAttribute
+* @see unum_setDoubleAttribute
+* @see unum_getTextAttribute
+* @see unum_setTextAttribute
+* @stable ICU 2.0
+*/
+U_STABLE double U_EXPORT2
+unum_getDoubleAttribute(const UNumberFormat* fmt,
+ UNumberFormatAttribute attr);
+
+/**
+* Set a numeric attribute associated with a UNumberFormat.
+* An example of a numeric attribute is the number of integer digits a formatter will produce.
+* If the formatter does not understand the attribute, this call is ignored.
+* @param fmt The formatter to set.
+* @param attr The attribute to set; e.g. UNUM_ROUNDING_INCREMENT.
+* @param newValue The new value of attr.
+* @see unum_getAttribute
+* @see unum_setAttribute
+* @see unum_getDoubleAttribute
+* @see unum_getTextAttribute
+* @see unum_setTextAttribute
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+unum_setDoubleAttribute( UNumberFormat* fmt,
+ UNumberFormatAttribute attr,
+ double newValue);
+
+/** The possible UNumberFormat text attributes @stable ICU 2.0*/
+typedef enum UNumberFormatTextAttribute {
+ /** Positive prefix */
+ UNUM_POSITIVE_PREFIX,
+ /** Positive suffix */
+ UNUM_POSITIVE_SUFFIX,
+ /** Negative prefix */
+ UNUM_NEGATIVE_PREFIX,
+ /** Negative suffix */
+ UNUM_NEGATIVE_SUFFIX,
+ /** The character used to pad to the format width. */
+ UNUM_PADDING_CHARACTER,
+ /** The ISO currency code */
+ UNUM_CURRENCY_CODE,
+ /**
+ * The default rule set. This is only available with rule-based formatters.
+ * @stable ICU 3.0
+ */
+ UNUM_DEFAULT_RULESET,
+ /**
+ * The public rule sets. This is only available with rule-based formatters.
+ * This is a read-only attribute. The public rulesets are returned as a
+ * single string, with each ruleset name delimited by ';' (semicolon).
+ * @stable ICU 3.0
+ */
+ UNUM_PUBLIC_RULESETS
+} UNumberFormatTextAttribute;
+
+/**
+* Get a text attribute associated with a UNumberFormat.
+* An example of a text attribute is the suffix for positive numbers. If the formatter
+* does not understand the attributre, U_UNSUPPORTED_ERROR is returned as the status.
+* Rule-based formatters only understand UNUM_DEFAULT_RULESET and UNUM_PUBLIC_RULESETS.
+* @param fmt The formatter to query.
+* @param tag The attribute to query; one of UNUM_POSITIVE_PREFIX, UNUM_POSITIVE_SUFFIX,
+* UNUM_NEGATIVE_PREFIX, UNUM_NEGATIVE_SUFFIX, UNUM_PADDING_CHARACTER, UNUM_CURRENCY_CODE,
+* UNUM_DEFAULT_RULESET, or UNUM_PUBLIC_RULESETS.
+* @param result A pointer to a buffer to receive the attribute.
+* @param resultLength The maximum size of result.
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The total buffer size needed; if greater than resultLength, the output was truncated.
+* @see unum_setTextAttribute
+* @see unum_getAttribute
+* @see unum_setAttribute
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+unum_getTextAttribute( const UNumberFormat* fmt,
+ UNumberFormatTextAttribute tag,
+ UChar* result,
+ int32_t resultLength,
+ UErrorCode* status);
+
+/**
+* Set a text attribute associated with a UNumberFormat.
+* An example of a text attribute is the suffix for positive numbers. Rule-based formatters
+* only understand UNUM_DEFAULT_RULESET.
+* @param fmt The formatter to set.
+* @param tag The attribute to set; one of UNUM_POSITIVE_PREFIX, UNUM_POSITIVE_SUFFIX,
+* UNUM_NEGATIVE_PREFIX, UNUM_NEGATIVE_SUFFIX, UNUM_PADDING_CHARACTER, UNUM_CURRENCY_CODE,
+* or UNUM_DEFAULT_RULESET.
+* @param newValue The new value of attr.
+* @param newValueLength The length of newValue, or -1 if null-terminated.
+* @param status A pointer to an UErrorCode to receive any errors
+* @see unum_getTextAttribute
+* @see unum_getAttribute
+* @see unum_setAttribute
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+unum_setTextAttribute( UNumberFormat* fmt,
+ UNumberFormatTextAttribute tag,
+ const UChar* newValue,
+ int32_t newValueLength,
+ UErrorCode *status);
+
+/**
+ * Extract the pattern from a UNumberFormat. The pattern will follow
+ * the DecimalFormat pattern syntax.
+ * @param fmt The formatter to query.
+ * @param isPatternLocalized TRUE if the pattern should be localized,
+ * FALSE otherwise. This is ignored if the formatter is a rule-based
+ * formatter.
+ * @param result A pointer to a buffer to receive the pattern.
+ * @param resultLength The maximum size of result.
+ * @param status A pointer to an input-output UErrorCode.
+ * @return The total buffer size needed; if greater than resultLength,
+ * the output was truncated.
+ * @see unum_applyPattern
+ * @see DecimalFormat
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+unum_toPattern( const UNumberFormat* fmt,
+ UBool isPatternLocalized,
+ UChar* result,
+ int32_t resultLength,
+ UErrorCode* status);
+
+
+/**
+ * Constants for specifying a number format symbol.
+ * @stable ICU 2.0
+ */
+typedef enum UNumberFormatSymbol {
+ /** The decimal separator */
+ UNUM_DECIMAL_SEPARATOR_SYMBOL = 0,
+ /** The grouping separator */
+ UNUM_GROUPING_SEPARATOR_SYMBOL = 1,
+ /** The pattern separator */
+ UNUM_PATTERN_SEPARATOR_SYMBOL = 2,
+ /** The percent sign */
+ UNUM_PERCENT_SYMBOL = 3,
+ /** Zero*/
+ UNUM_ZERO_DIGIT_SYMBOL = 4,
+ /** Character representing a digit in the pattern */
+ UNUM_DIGIT_SYMBOL = 5,
+ /** The minus sign */
+ UNUM_MINUS_SIGN_SYMBOL = 6,
+ /** The plus sign */
+ UNUM_PLUS_SIGN_SYMBOL = 7,
+ /** The currency symbol */
+ UNUM_CURRENCY_SYMBOL = 8,
+ /** The international currency symbol */
+ UNUM_INTL_CURRENCY_SYMBOL = 9,
+ /** The monetary separator */
+ UNUM_MONETARY_SEPARATOR_SYMBOL = 10,
+ /** The exponential symbol */
+ UNUM_EXPONENTIAL_SYMBOL = 11,
+ /** Per mill symbol */
+ UNUM_PERMILL_SYMBOL = 12,
+ /** Escape padding character */
+ UNUM_PAD_ESCAPE_SYMBOL = 13,
+ /** Infinity symbol */
+ UNUM_INFINITY_SYMBOL = 14,
+ /** Nan symbol */
+ UNUM_NAN_SYMBOL = 15,
+ /** Significant digit symbol
+ * @stable ICU 3.0 */
+ UNUM_SIGNIFICANT_DIGIT_SYMBOL = 16,
+ /** The monetary grouping separator
+ * @stable ICU 3.6
+ */
+ UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL = 17,
+ /** count symbol constants */
+ UNUM_FORMAT_SYMBOL_COUNT = 18
+} UNumberFormatSymbol;
+
+/**
+* Get a symbol associated with a UNumberFormat.
+* A UNumberFormat uses symbols to represent the special locale-dependent
+* characters in a number, for example the percent sign. This API is not
+* supported for rule-based formatters.
+* @param fmt The formatter to query.
+* @param symbol The UNumberFormatSymbol constant for the symbol to get
+* @param buffer The string buffer that will receive the symbol string;
+* if it is NULL, then only the length of the symbol is returned
+* @param size The size of the string buffer
+* @param status A pointer to an UErrorCode to receive any errors
+* @return The length of the symbol; the buffer is not modified if
+* <code>length&gt;=size</code>
+* @see unum_setSymbol
+* @stable ICU 2.0
+*/
+U_STABLE int32_t U_EXPORT2
+unum_getSymbol(const UNumberFormat *fmt,
+ UNumberFormatSymbol symbol,
+ UChar *buffer,
+ int32_t size,
+ UErrorCode *status);
+
+/**
+* Set a symbol associated with a UNumberFormat.
+* A UNumberFormat uses symbols to represent the special locale-dependent
+* characters in a number, for example the percent sign. This API is not
+* supported for rule-based formatters.
+* @param fmt The formatter to set.
+* @param symbol The UNumberFormatSymbol constant for the symbol to set
+* @param value The string to set the symbol to
+* @param length The length of the string, or -1 for a zero-terminated string
+* @param status A pointer to an UErrorCode to receive any errors.
+* @see unum_getSymbol
+* @stable ICU 2.0
+*/
+U_STABLE void U_EXPORT2
+unum_setSymbol(UNumberFormat *fmt,
+ UNumberFormatSymbol symbol,
+ const UChar *value,
+ int32_t length,
+ UErrorCode *status);
+
+
+/**
+ * Get the locale for this number format object.
+ * You can choose between valid and actual locale.
+ * @param fmt The formatter to get the locale from
+ * @param type type of the locale we're looking for (valid or actual)
+ * @param status error code for the operation
+ * @return the locale name
+ * @stable ICU 2.8
+ */
+U_STABLE const char* U_EXPORT2
+unum_getLocaleByType(const UNumberFormat *fmt,
+ ULocDataLocaleType type,
+ UErrorCode* status);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/uregex.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/uregex.h
new file mode 100644
index 00000000000..862cf344641
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/uregex.h
@@ -0,0 +1,631 @@
+/*
+**********************************************************************
+* Copyright (C) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* file name: regex.h
+* encoding: US-ASCII
+* indentation:4
+*
+* created on: 2004mar09
+* created by: Andy Heninger
+*
+* ICU Regular Expressions, API for C
+*/
+
+/**
+ * \file
+ * \brief C API: Regular Expressions
+ *
+ * <p>This is a C wrapper around the C++ RegexPattern and RegexMatcher classes.</p>
+ */
+
+#ifndef UREGEX_H
+#define UREGEX_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/parseerr.h"
+
+struct URegularExpression;
+/**
+ * Structure represeting a compiled regular rexpression, plus the results
+ * of a match operation.
+ * @stable ICU 3.0
+ */
+typedef struct URegularExpression URegularExpression;
+
+
+/**
+ * Constants for Regular Expression Match Modes.
+ * @stable ICU 2.4
+ */
+typedef enum URegexpFlag{
+
+#ifndef U_HIDE_DRAFT_API
+ /** Forces normalization of pattern and strings.
+ Not implemented yet, just a placeholder, hence draft.
+ @draft ICU 2.4 */
+ UREGEX_CANON_EQ = 128,
+#endif
+ /** Enable case insensitive matching. @stable ICU 2.4 */
+ UREGEX_CASE_INSENSITIVE = 2,
+
+ /** Allow white space and comments within patterns @stable ICU 2.4 */
+ UREGEX_COMMENTS = 4,
+
+ /** If set, '.' matches line terminators, otherwise '.' matching stops at line end.
+ * @stable ICU 2.4 */
+ UREGEX_DOTALL = 32,
+
+ /** Control behavior of "$" and "^"
+ * If set, recognize line terminators within string,
+ * otherwise, match only at start and end of input string.
+ * @stable ICU 2.4 */
+ UREGEX_MULTILINE = 8,
+
+ /** Unicode word boundaries.
+ * If set, \b uses the Unicode TR 29 definition of word boundaries.
+ * Warning: Unicode word boundaries are quite different from
+ * traditional regular expression word boundaries. See
+ * http://unicode.org/reports/tr29/#Word_Boundaries
+ * @stable ICU 2.8
+ */
+ UREGEX_UWORD = 256
+} URegexpFlag;
+
+/**
+ * Open (compile) an ICU regular expression. Compiles the regular expression in
+ * string form into an internal representation using the specified match mode flags.
+ * The resulting regular expression handle can then be used to perform various
+ * matching operations.
+ *
+ * @param pattern The Regular Expression pattern to be compiled.
+ * @param patternLength The length of the pattern, or -1 if the pattern is
+ * NUL termintated.
+ * @param flags Flags that alter the default matching behavior for
+ * the regular expression, UREGEX_CASE_INSENSITIVE, for
+ * example. For default behavior, set this parameter to zero.
+ * See <code>enum URegexpFlag</code>. All desired flags
+ * are bitwise-ORed together.
+ * @param pe Receives the position (line and column nubers) of any syntax
+ * error within the source regular expression string. If this
+ * information is not wanted, pass NULL for this parameter.
+ * @param status Receives error detected by this function.
+ * @stable ICU 3.0
+ *
+ */
+U_STABLE URegularExpression * U_EXPORT2
+uregex_open( const UChar *pattern,
+ int32_t patternLength,
+ uint32_t flags,
+ UParseError *pe,
+ UErrorCode *status);
+
+/**
+ * Open (compile) an ICU regular expression. The resulting regular expression
+ * handle can then be used to perform various matching operations.
+ * <p>
+ * This function is the same as uregex_open, except that the pattern
+ * is supplied as an 8 bit char * string in the default code page.
+ *
+ * @param pattern The Regular Expression pattern to be compiled,
+ * NUL termintated.
+ * @param flags Flags that alter the default matching behavior for
+ * the regular expression, UREGEX_CASE_INSENSITIVE, for
+ * example. For default behavior, set this parameter to zero.
+ * See <code>enum URegexpFlag</code>. All desired flags
+ * are bitwise-ORed together.
+ * @param pe Receives the position (line and column nubers) of any syntax
+ * error within the source regular expression string. If this
+ * information is not wanted, pass NULL for this parameter.
+ * @param status Receives errors detected by this function.
+ * @return The URegularExpression object representing the compiled
+ * pattern.
+ *
+ * @stable ICU 3.0
+ */
+#if !UCONFIG_NO_CONVERSION
+U_STABLE URegularExpression * U_EXPORT2
+uregex_openC( const char *pattern,
+ uint32_t flags,
+ UParseError *pe,
+ UErrorCode *status);
+#endif
+
+
+
+/**
+ * Close the regular expression, recovering all resources (memory) it
+ * was holding.
+ *
+ * @param regexp The regular expression to be closed.
+ * @stable ICU 3.0
+ */
+U_STABLE void U_EXPORT2
+uregex_close(URegularExpression *regexp);
+
+/**
+ * Make a copy of a compiled regular expression. Cloning a regular
+ * expression is faster than opening a second instance from the source
+ * form of the expression, and requires less memory.
+ * <p>
+ * Note that the current input string and the position of any matched text
+ * within it are not cloned; only the pattern itself and and the
+ * match mode flags are copied.
+ * <p>
+ * Cloning can be particularly useful to threaded applications that perform
+ * multiple match operations in parallel. Each concurrent RE
+ * operation requires its own instance of a URegularExpression.
+ *
+ * @param regexp The compiled regular expression to be cloned.
+ * @param status Receives indication of any errors encountered
+ * @return the cloned copy of the compiled regular expression.
+ * @stable ICU 3.0
+ */
+U_STABLE URegularExpression * U_EXPORT2
+uregex_clone(const URegularExpression *regexp, UErrorCode *status);
+
+/**
+ * Return a pointer to the source form of the pattern for this regular expression.
+ *
+ * @param regexp The compiled regular expression.
+ * @param patLength This output parameter will be set to the length of the
+ * pattern string. A NULL pointer may be used here if the
+ * pattern length is not needed, as would be the case if
+ * the pattern is known in advance to be a NUL terminated
+ * string.
+ * @param status Receives errors detected by this function.
+ * @return a pointer to the pattern string. The storage for the string is
+ * owned by the regular expression object, and must not be
+ * altered or deleted by the application. The returned string
+ * will remain valid until the regular expression is closed.
+ * @stable ICU 3.0
+ */
+U_STABLE const UChar * U_EXPORT2
+uregex_pattern(const URegularExpression *regexp,
+ int32_t *patLength,
+ UErrorCode *status);
+
+
+/**
+ * Get the match mode flags that were specified when compiling this regular expression.
+ * @param status Receives errors detected by this function.
+ * @param regexp The compiled regular expression.
+ * @return The match mode flags
+ * @see URegexpFlag
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_flags(const URegularExpression *regexp,
+ UErrorCode *status);
+
+
+/**
+ * Set the subject text string upon which the regular expression will look for matches.
+ * This function may be called any number of times, allowing the regular
+ * expression pattern to be applied to different strings.
+ * <p>
+ * Regular expression matching operations work directly on the application's
+ * string data. No copy is made. The subject string data must not be
+ * altered after calling this function until after all regular expression
+ * operations involving this string data are completed.
+ * <p>
+ * Zero length strings are permitted. In this case, no subsequent match
+ * operation will dereference the text string pointer.
+ *
+ * @param regexp The compiled regular expression.
+ * @param text The subject text string.
+ * @param textLength The length of the subject text, or -1 if the string
+ * is NUL terminated.
+ * @param status Receives errors detected by this function.
+ * @stable ICU 3.0
+ */
+U_STABLE void U_EXPORT2
+uregex_setText(URegularExpression *regexp,
+ const UChar *text,
+ int32_t textLength,
+ UErrorCode *status);
+
+/**
+ * Get the subject text that is currently associated with this
+ * regular expression object. This simply returns whatever string
+ * pointer was previously supplied via uregex_setText().
+ *
+ * @param regexp The compiled regular expression.
+ * @param textLength The length of the string is returned in this output parameter.
+ * A NULL pointer may be used here if the
+ * text length is not needed, as would be the case if
+ * the text is known in advance to be a NUL terminated
+ * string.
+ * @param status Receives errors detected by this function.
+ * @return Poiner to the subject text string currently associated with
+ * this regular expression.
+ * @stable ICU 3.0
+ */
+U_STABLE const UChar * U_EXPORT2
+uregex_getText(URegularExpression *regexp,
+ int32_t *textLength,
+ UErrorCode *status);
+
+/**
+ * Attempts to match the input string, beginning at startIndex, against the pattern.
+ * To succeed, the match must extend to the end of the input string.
+ *
+ * @param regexp The compiled regular expression.
+ * @param startIndex The input string index at which to begin matching.
+ * @param status Receives errors detected by this function.
+ * @return TRUE if there is a match
+ * @stable ICU 3.0
+ */
+U_STABLE UBool U_EXPORT2
+uregex_matches(URegularExpression *regexp,
+ int32_t startIndex,
+ UErrorCode *status);
+
+/**
+ * Attempts to match the input string, starting from the specified index, against the pattern.
+ * The match may be of any length, and is not required to extend to the end
+ * of the input string. Contrast with uregex_matches().
+ *
+ * <p>If the match succeeds then more information can be obtained via the
+ * <code>uregexp_start()</code>, <code>uregexp_end()</code>,
+ * and <code>uregexp_group()</code> functions.</p>
+ *
+ * @param regexp The compiled regular expression.
+ * @param startIndex The input string index at which to begin matching.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if there is a match.
+ * @stable ICU 3.0
+ */
+U_STABLE UBool U_EXPORT2
+uregex_lookingAt(URegularExpression *regexp,
+ int32_t startIndex,
+ UErrorCode *status);
+
+/**
+ * Find the first matching substring of the input string that matches the pattern.
+ * The search for a match begins at the specified index.
+ * If a match is found, <code>uregex_start(), uregex_end()</code>, and
+ * <code>uregex_group()</code> will provide more information regarding the match.
+ *
+ * @param regexp The compiled regular expression.
+ * @param startIndex The position in the input string to begin the search
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if a match is found.
+ * @stable ICU 3.0
+ */
+U_STABLE UBool U_EXPORT2
+uregex_find(URegularExpression *regexp,
+ int32_t startIndex,
+ UErrorCode *status);
+
+/**
+ * Find the next pattern match in the input string.
+ * Begin searching the input at the location following the end of
+ * the previous match, or at the start of the string if there is no previous match.
+ * If a match is found, <code>uregex_start(), uregex_end()</code>, and
+ * <code>uregex_group()</code> will provide more information regarding the match.
+ *
+ * @param regexp The compiled regular expression.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return TRUE if a match is found.
+ * @see uregex_reset
+ * @stable ICU 3.0
+ */
+U_STABLE UBool U_EXPORT2
+uregex_findNext(URegularExpression *regexp,
+ UErrorCode *status);
+
+/**
+ * Get the number of capturing groups in this regular expression's pattern.
+ * @param regexp The compiled regular expression.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return the number of capture groups
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_groupCount(URegularExpression *regexp,
+ UErrorCode *status);
+
+/** Extract the string for the specified matching expression or subexpression.
+ * Group #0 is the complete string of matched text.
+ * Group #1 is the text matched by the first set of capturing parentheses.
+ *
+ * @param regexp The compiled regular expression.
+ * @param groupNum The capture group to extract. Group 0 is the complete
+ * match. The value of this parameter must be
+ * less than or equal to the number of capture groups in
+ * the pattern.
+ * @param dest Buffer to receive the matching string data
+ * @param destCapacity Capacity of the dest buffer.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return Length of matching data,
+ * or -1 if no applicable match.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_group(URegularExpression *regexp,
+ int32_t groupNum,
+ UChar *dest,
+ int32_t destCapacity,
+ UErrorCode *status);
+
+
+/**
+ * Returns the index in the input string of the start of the text matched by the
+ * specified capture group during the previous match operation. Return -1 if
+ * the capture group was not part of the last match.
+ * Group #0 refers to the complete range of matched text.
+ * Group #1 refers to the text matched by the first set of capturing parentheses.
+ *
+ * @param regexp The compiled regular expression.
+ * @param groupNum The capture group number
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return the starting position in the input of the text matched
+ * by the specified group.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_start(URegularExpression *regexp,
+ int32_t groupNum,
+ UErrorCode *status);
+
+/**
+ * Returns the index in the input string of the position following the end
+ * of the text matched by the specified capture group.
+ * Return -1 if the capture group was not part of the last match.
+ * Group #0 refers to the complete range of matched text.
+ * Group #1 refers to the text matched by the first set of capturing parentheses.
+ *
+ * @param regexp The compiled regular expression.
+ * @param groupNum The capture group number
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return the index of the position following the last matched character.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_end(URegularExpression *regexp,
+ int32_t groupNum,
+ UErrorCode *status);
+
+/**
+ * Reset any saved state from the previous match. Has the effect of
+ * causing uregex_findNext to begin at the specified index, and causing
+ * uregex_start(), uregex_end() and uregex_group() to return an error
+ * indicating that there is no match information available.
+ *
+ * @param regexp The compiled regular expression.
+ * @param index The position in the text at which a
+ * uregex_findNext() should begin searching.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @stable ICU 3.0
+ */
+U_STABLE void U_EXPORT2
+uregex_reset(URegularExpression *regexp,
+ int32_t index,
+ UErrorCode *status);
+
+/**
+ * Replaces every substring of the input that matches the pattern
+ * with the given replacement string. This is a convenience function that
+ * provides a complete find-and-replace-all operation.
+ *
+ * This method scans the input string looking for matches of the pattern.
+ * Input that is not part of any match is copied unchanged to the
+ * destination buffer. Matched regions are replaced in the output
+ * buffer by the replacement string. The replacement string may contain
+ * references to capture groups; these take the form of $1, $2, etc.
+ *
+ * @param regexp The compiled regular expression.
+ * @param replacementText A string containing the replacement text.
+ * @param replacementLength The length of the replacement string, or
+ * -1 if it is NUL terminated.
+ * @param destBuf A (UChar *) buffer that will receive the result.
+ * @param destCapacity The capacity of the desitnation buffer.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The length of the string resulting from the find
+ * and replace operation. In the event that the
+ * destination capacity is inadequate, the return value
+ * is still the full length of the untruncated string.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_replaceAll(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar *destBuf,
+ int32_t destCapacity,
+ UErrorCode *status);
+
+
+/**
+ * Replaces the first substring of the input that matches the pattern
+ * with the given replacement string. This is a convenience function that
+ * provides a complete find-and-replace operation.
+ *
+ * This method scans the input string looking for a match of the pattern.
+ * All input that is not part of the match is copied unchanged to the
+ * destination buffer. The matched region is replaced in the output
+ * buffer by the replacement string. The replacement string may contain
+ * references to capture groups; these take the form of $1, $2, etc.
+ *
+ * @param regexp The compiled regular expression.
+ * @param replacementText A string containing the replacement text.
+ * @param replacementLength The length of the replacement string, or
+ * -1 if it is NUL terminated.
+ * @param destBuf A (UChar *) buffer that will receive the result.
+ * @param destCapacity The capacity of the desitnation buffer.
+ * @param status a reference to a UErrorCode to receive any errors.
+ * @return The length of the string resulting from the find
+ * and replace operation. In the event that the
+ * destination capacity is inadequate, the return value
+ * is still the full length of the untruncated string.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_replaceFirst(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar *destBuf,
+ int32_t destCapacity,
+ UErrorCode *status);
+
+
+/**
+ * Implements a replace operation intended to be used as part of an
+ * incremental find-and-replace.
+ *
+ * <p>The input string, starting from the end of the previous match and ending at
+ * the start of the current match, is appended to the destination string. Then the
+ * replacement string is appended to the output string,
+ * including handling any substitutions of captured text.</p>
+ *
+ * <p>A note on preflight computation of buffersize and error handling:
+ * Calls to uregex_appendReplacement() and uregex_appendTail() are
+ * designed to be chained, one after another, with the destination
+ * buffer pointer and buffer capacity updated after each in preparation
+ * to for the next. If the destination buffer is exhausted partway through such a
+ * sequence, a U_BUFFER_OVERFLOW_ERROR status will be returned. Normal
+ * ICU conventions are for a function to perform no action if it is
+ * called with an error status, but for this one case, uregex_appendRepacement()
+ * will operate normally so that buffer size computations will complete
+ * correctly.
+ *
+ * <p>For simple, prepackaged, non-incremental find-and-replace
+ * operations, see replaceFirst() or replaceAll().</p>
+ *
+ * @param regexp The regular expression object.
+ * @param replacementText The string that will replace the matched portion of the
+ * input string as it is copied to the destination buffer.
+ * The replacement text may contain references ($1, for
+ * example) to capture groups from the match.
+ * @param replacementLength The length of the replacement text string,
+ * or -1 if the string is NUL terminated.
+ * @param destBuf The buffer into which the results of the
+ * find-and-replace are placed. On return, this pointer
+ * will be updated to refer to the beginning of the
+ * unused portion of buffer, leaving it in position for
+ * a subsequent call to this function.
+ * @param destCapacity The size of the output buffer, On return, this
+ * parameter will be updated to reflect the space remaining
+ * unused in the output buffer.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The length of the result string. In the event that
+ * destCapacity is inadequate, the full length of the
+ * untruncated output string is returned.
+ *
+ * @stable ICU 3.0
+ *
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_appendReplacement(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status);
+
+
+/**
+ * As the final step in a find-and-replace operation, append the remainder
+ * of the input string, starting at the position following the last match,
+ * to the destination string. <code>uregex_appendTail()</code> is intended
+ * to be invoked after one or more invocations of the
+ * <code>uregex_appendReplacement()</code> function.
+ *
+ * @param regexp The regular expression object. This is needed to
+ * obtain the input string and with the position
+ * of the last match within it.
+ * @param destBuf The buffer in which the results of the
+ * find-and-replace are placed. On return, the pointer
+ * will be updated to refer to the beginning of the
+ * unused portion of buffer.
+ * @param destCapacity The size of the output buffer, On return, this
+ * value will be updated to reflect the space remaining
+ * unused in the output buffer.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The length of the result string. In the event that
+ * destCapacity is inadequate, the full length of the
+ * untruncated output string is returned.
+ *
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_appendTail(URegularExpression *regexp,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status);
+
+
+
+
+ /**
+ * Split a string into fields. Somewhat like split() from Perl.
+ * The pattern matches identify delimiters that separate the input
+ * into fields. The input data between the matches becomes the
+ * fields themselves.
+ * <p>
+ * Each of the fields is copied from the input string to the destination
+ * buffer, and the NUL terminated. The position of each field within
+ * the destination buffer is returned in the destFields array.
+ *
+ * Note: another choice for the design of this function would be to not
+ * copy the resulting fields at all, but to return indexes and
+ * lengths within the source text.
+ * Advantages would be
+ * o Faster. No Copying.
+ * o Nothing extra needed when field data may contain embedded NUL chars.
+ * o Less memory needed if working on large data.
+ * Disadvantages
+ * o Less consistent with C++ split, which copies into an
+ * array of UnicodeStrings.
+ * o No NUL termination, extracted fields would be less convenient
+ * to use in most cases.
+ * o Possible problems in the future, when support Unicode Normalization
+ * could cause the fields to not correspond exactly to
+ * a range of the source text.
+ *
+ * @param regexp The compiled regular expression.
+ * @param destBuf A (UChar *) buffer to receive the fields that
+ * are extracted from the input string. These
+ * field pointers will refer to positions within the
+ * destination buffer supplied by the caller. Any
+ * extra positions within the destFields array will be
+ * set to NULL.
+ * @param destCapacity The capacity of the destBuf.
+ * @param requiredCapacity The actual capacity required of the destBuf.
+ * If destCapacity is too small, requiredCapacity will return
+ * the total capacity required to hold all of the output, and
+ * a U_BUFFER_OVERFLOW_ERROR will be returned.
+ * @param destFields An array to be filled with the position of each
+ * of the extracted fields within destBuf.
+ * @param destFieldsCapacity The number of elements in the destFields array.
+ * If the number of fields found is less than destFieldsCapacity,
+ * the extra destFields elements are set to zero.
+ * If destFieldsCapacity is too small, the trailing part of the
+ * input, including any field delimiters, is treated as if it
+ * were the last field - it is copied to the destBuf, and
+ * its position is in the destBuf is stored in the last element
+ * of destFields. This behavior mimics that of Perl. It is not
+ * an error condition, and no error status is returned when all destField
+ * positions are used.
+ * @param status A reference to a UErrorCode to receive any errors.
+ * @return The number of fields into which the input string was split.
+ * @stable ICU 3.0
+ */
+U_STABLE int32_t U_EXPORT2
+uregex_split( URegularExpression *regexp,
+ UChar *destBuf,
+ int32_t destCapacity,
+ int32_t *requiredCapacity,
+ UChar *destFields[],
+ int32_t destFieldsCapacity,
+ UErrorCode *status);
+
+
+
+#endif /* !UCONFIG_NO_REGULAR_EXPRESSIONS */
+#endif /* UREGEX_H */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/usearch.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/usearch.h
new file mode 100644
index 00000000000..0de1abb9e1a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/usearch.h
@@ -0,0 +1,646 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 06/28/2001 synwee Creation.
+**********************************************************************
+*/
+#ifndef USEARCH_H
+#define USEARCH_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/ucol.h"
+#include "unicode/ucoleitr.h"
+#include "unicode/ubrk.h"
+
+/**
+ * \file
+ * \brief C API: StringSearch
+ *
+ * C Apis for an engine that provides language-sensitive text searching based
+ * on the comparison rules defined in a <tt>UCollator</tt> data struct,
+ * see <tt>ucol.h</tt>. This ensures that language eccentricity can be
+ * handled, e.g. for the German collator, characters &szlig; and SS will be matched
+ * if case is chosen to be ignored.
+ * See the <a href="http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm">
+ * "ICU Collation Design Document"</a> for more information.
+ * <p>
+ * The algorithm implemented is a modified form of the Boyer Moore's search.
+ * For more information see
+ * <a href="http://icu-project.org/docs/papers/efficient_text_searching_in_java.html">
+ * "Efficient Text Searching in Java"</a>, published in <i>Java Report</i>
+ * in February, 1999, for further information on the algorithm.
+ * <p>
+ * There are 2 match options for selection:<br>
+ * Let S' be the sub-string of a text string S between the offsets start and
+ * end <start, end>.
+ * <br>
+ * A pattern string P matches a text string S at the offsets <start, end>
+ * if
+ * <pre>
+ * option 1. Some canonical equivalent of P matches some canonical equivalent
+ * of S'
+ * option 2. P matches S' and if P starts or ends with a combining mark,
+ * there exists no non-ignorable combining mark before or after S'
+ * in S respectively.
+ * </pre>
+ * Option 2. will be the default.
+ * <p>
+ * This search has APIs similar to that of other text iteration mechanisms
+ * such as the break iterators in <tt>ubrk.h</tt>. Using these
+ * APIs, it is easy to scan through text looking for all occurances of
+ * a given pattern. This search iterator allows changing of direction by
+ * calling a <tt>reset</tt> followed by a <tt>next</tt> or <tt>previous</tt>.
+ * Though a direction change can occur without calling <tt>reset</tt> first,
+ * this operation comes with some speed penalty.
+ * Generally, match results in the forward direction will match the result
+ * matches in the backwards direction in the reverse order
+ * <p>
+ * <tt>usearch.h</tt> provides APIs to specify the starting position
+ * within the text string to be searched, e.g. <tt>usearch_setOffset</tt>,
+ * <tt>usearch_preceding</tt> and <tt>usearch_following</tt>. Since the
+ * starting position will be set as it is specified, please take note that
+ * there are some dangerous positions which the search may render incorrect
+ * results:
+ * <ul>
+ * <li> The midst of a substring that requires normalization.
+ * <li> If the following match is to be found, the position should not be the
+ * second character which requires to be swapped with the preceding
+ * character. Vice versa, if the preceding match is to be found,
+ * position to search from should not be the first character which
+ * requires to be swapped with the next character. E.g certain Thai and
+ * Lao characters require swapping.
+ * <li> If a following pattern match is to be found, any position within a
+ * contracting sequence except the first will fail. Vice versa if a
+ * preceding pattern match is to be found, a invalid starting point
+ * would be any character within a contracting sequence except the last.
+ * </ul>
+ * <p>
+ * A breakiterator can be used if only matches at logical breaks are desired.
+ * Using a breakiterator will only give you results that exactly matches the
+ * boundaries given by the breakiterator. For instance the pattern "e" will
+ * not be found in the string "\u00e9" if a character break iterator is used.
+ * <p>
+ * Options are provided to handle overlapping matches.
+ * E.g. In English, overlapping matches produces the result 0 and 2
+ * for the pattern "abab" in the text "ababab", where else mutually
+ * exclusive matches only produce the result of 0.
+ * <p>
+ * Though collator attributes will be taken into consideration while
+ * performing matches, there are no APIs here for setting and getting the
+ * attributes. These attributes can be set by getting the collator
+ * from <tt>usearch_getCollator</tt> and using the APIs in <tt>ucol.h</tt>.
+ * Lastly to update String Search to the new collator attributes,
+ * usearch_reset() has to be called.
+ * <p>
+ * Restriction: <br>
+ * Currently there are no composite characters that consists of a
+ * character with combining class > 0 before a character with combining
+ * class == 0. However, if such a character exists in the future, the
+ * search mechanism does not guarantee the results for option 1.
+ *
+ * <p>
+ * Example of use:<br>
+ * <pre><code>
+ * char *tgtstr = "The quick brown fox jumped over the lazy fox";
+ * char *patstr = "fox";
+ * UChar target[64];
+ * UChar pattern[16];
+ * UErrorCode status = U_ZERO_ERROR;
+ * u_uastrcpy(target, tgtstr);
+ * u_uastrcpy(pattern, patstr);
+ *
+ * UStringSearch *search = usearch_open(pattern, -1, target, -1, "en_US",
+ * NULL, &status);
+ * if (U_SUCCESS(status)) {
+ * for (int pos = usearch_first(search, &status);
+ * pos != USEARCH_DONE;
+ * pos = usearch_next(search, &status))
+ * {
+ * printf("Found match at %d pos, length is %d\n", pos,
+ * usearch_getMatchLength(search));
+ * }
+ * }
+ *
+ * usearch_close(search);
+ * </code></pre>
+ * @stable ICU 2.4
+ */
+
+/**
+* DONE is returned by previous() and next() after all valid matches have
+* been returned, and by first() and last() if there are no matches at all.
+* @stable ICU 2.4
+*/
+#define USEARCH_DONE -1
+
+/**
+* Data structure for searching
+* @stable ICU 2.4
+*/
+struct UStringSearch;
+/**
+* Data structure for searching
+* @stable ICU 2.4
+*/
+typedef struct UStringSearch UStringSearch;
+
+/**
+* @stable ICU 2.4
+*/
+typedef enum {
+ /** Option for overlapping matches */
+ USEARCH_OVERLAP,
+ /**
+ Option for canonical matches. option 1 in header documentation.
+ The default value will be USEARCH_OFF
+ */
+ USEARCH_CANONICAL_MATCH,
+ USEARCH_ATTRIBUTE_COUNT
+} USearchAttribute;
+
+/**
+* @stable ICU 2.4
+*/
+typedef enum {
+ /** default value for any USearchAttribute */
+ USEARCH_DEFAULT = -1,
+ /** value for USEARCH_OVERLAP and USEARCH_CANONICAL_MATCH */
+ USEARCH_OFF,
+ /** value for USEARCH_OVERLAP and USEARCH_CANONICAL_MATCH */
+ USEARCH_ON,
+ USEARCH_ATTRIBUTE_VALUE_COUNT
+} USearchAttributeValue;
+
+/* open and close ------------------------------------------------------ */
+
+/**
+* Creating a search iterator data struct using the argument locale language
+* rule set. A collator will be created in the process, which will be owned by
+* this search and will be deleted in <tt>usearch_close</tt>.
+* @param pattern for matching
+* @param patternlength length of the pattern, -1 for null-termination
+* @param text text string
+* @param textlength length of the text string, -1 for null-termination
+* @param locale name of locale for the rules to be used
+* @param breakiter A BreakIterator that will be used to restrict the points
+* at which matches are detected. If a match is found, but
+* the match's start or end index is not a boundary as
+* determined by the <tt>BreakIterator</tt>, the match will
+* be rejected and another will be searched for.
+* If this parameter is <tt>NULL</tt>, no break detection is
+* attempted.
+* @param status for errors if it occurs. If pattern or text is NULL, or if
+* patternlength or textlength is 0 then an
+* U_ILLEGAL_ARGUMENT_ERROR is returned.
+* @return search iterator data structure, or NULL if there is an error.
+* @stable ICU 2.4
+*/
+U_STABLE UStringSearch * U_EXPORT2 usearch_open(const UChar *pattern,
+ int32_t patternlength,
+ const UChar *text,
+ int32_t textlength,
+ const char *locale,
+ UBreakIterator *breakiter,
+ UErrorCode *status);
+
+/**
+* Creating a search iterator data struct using the argument collator language
+* rule set. Note, user retains the ownership of this collator, thus the
+* responsibility of deletion lies with the user.
+* NOTE: string search cannot be instantiated from a collator that has
+* collate digits as numbers (CODAN) turned on.
+* @param pattern for matching
+* @param patternlength length of the pattern, -1 for null-termination
+* @param text text string
+* @param textlength length of the text string, -1 for null-termination
+* @param collator used for the language rules
+* @param breakiter A BreakIterator that will be used to restrict the points
+* at which matches are detected. If a match is found, but
+* the match's start or end index is not a boundary as
+* determined by the <tt>BreakIterator</tt>, the match will
+* be rejected and another will be searched for.
+* If this parameter is <tt>NULL</tt>, no break detection is
+* attempted.
+* @param status for errors if it occurs. If collator, pattern or text is NULL,
+* or if patternlength or textlength is 0 then an
+* U_ILLEGAL_ARGUMENT_ERROR is returned.
+* @return search iterator data structure, or NULL if there is an error.
+* @stable ICU 2.4
+*/
+U_STABLE UStringSearch * U_EXPORT2 usearch_openFromCollator(
+ const UChar *pattern,
+ int32_t patternlength,
+ const UChar *text,
+ int32_t textlength,
+ const UCollator *collator,
+ UBreakIterator *breakiter,
+ UErrorCode *status);
+
+/**
+* Destroying and cleaning up the search iterator data struct.
+* If a collator is created in <tt>usearch_open</tt>, it will be destroyed here.
+* @param searchiter data struct to clean up
+* @stable ICU 2.4
+*/
+U_STABLE void U_EXPORT2 usearch_close(UStringSearch *searchiter);
+
+/* get and set methods -------------------------------------------------- */
+
+/**
+* Sets the current position in the text string which the next search will
+* start from. Clears previous states.
+* This method takes the argument index and sets the position in the text
+* string accordingly without checking if the index is pointing to a
+* valid starting point to begin searching.
+* Search positions that may render incorrect results are highlighted in the
+* header comments
+* @param strsrch search iterator data struct
+* @param position position to start next search from. If position is less
+* than or greater than the text range for searching,
+* an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+* @param status error status if any.
+* @stable ICU 2.4
+*/
+U_STABLE void U_EXPORT2 usearch_setOffset(UStringSearch *strsrch,
+ int32_t position,
+ UErrorCode *status);
+
+/**
+* Return the current index in the string text being searched.
+* If the iteration has gone past the end of the text (or past the beginning
+* for a backwards search), <tt>USEARCH_DONE</tt> is returned.
+* @param strsrch search iterator data struct
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_getOffset(const UStringSearch *strsrch);
+
+/**
+* Sets the text searching attributes located in the enum USearchAttribute
+* with values from the enum USearchAttributeValue.
+* <tt>USEARCH_DEFAULT</tt> can be used for all attributes for resetting.
+* @param strsrch search iterator data struct
+* @param attribute text attribute to be set
+* @param value text attribute value
+* @param status for errors if it occurs
+* @see #usearch_getAttribute
+* @stable ICU 2.4
+*/
+U_STABLE void U_EXPORT2 usearch_setAttribute(UStringSearch *strsrch,
+ USearchAttribute attribute,
+ USearchAttributeValue value,
+ UErrorCode *status);
+
+/**
+* Gets the text searching attributes.
+* @param strsrch search iterator data struct
+* @param attribute text attribute to be retrieve
+* @return text attribute value
+* @see #usearch_setAttribute
+* @stable ICU 2.4
+*/
+U_STABLE USearchAttributeValue U_EXPORT2 usearch_getAttribute(
+ const UStringSearch *strsrch,
+ USearchAttribute attribute);
+
+/**
+* Returns the index to the match in the text string that was searched.
+* This call returns a valid result only after a successful call to
+* <tt>usearch_first</tt>, <tt>usearch_next</tt>, <tt>usearch_previous</tt>,
+* or <tt>usearch_last</tt>.
+* Just after construction, or after a searching method returns
+* <tt>USEARCH_DONE</tt>, this method will return <tt>USEARCH_DONE</tt>.
+* <p>
+* Use <tt>usearch_getMatchedLength</tt> to get the matched string length.
+* @param strsrch search iterator data struct
+* @return index to a substring within the text string that is being
+* searched.
+* @see #usearch_first
+* @see #usearch_next
+* @see #usearch_previous
+* @see #usearch_last
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_getMatchedStart(
+ const UStringSearch *strsrch);
+
+/**
+* Returns the length of text in the string which matches the search pattern.
+* This call returns a valid result only after a successful call to
+* <tt>usearch_first</tt>, <tt>usearch_next</tt>, <tt>usearch_previous</tt>,
+* or <tt>usearch_last</tt>.
+* Just after construction, or after a searching method returns
+* <tt>USEARCH_DONE</tt>, this method will return 0.
+* @param strsrch search iterator data struct
+* @return The length of the match in the string text, or 0 if there is no
+* match currently.
+* @see #usearch_first
+* @see #usearch_next
+* @see #usearch_previous
+* @see #usearch_last
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_getMatchedLength(
+ const UStringSearch *strsrch);
+
+/**
+* Returns the text that was matched by the most recent call to
+* <tt>usearch_first</tt>, <tt>usearch_next</tt>, <tt>usearch_previous</tt>,
+* or <tt>usearch_last</tt>.
+* If the iterator is not pointing at a valid match (e.g. just after
+* construction or after <tt>USEARCH_DONE</tt> has been returned, returns
+* an empty string. If result is not large enough to store the matched text,
+* result will be filled with the partial text and an U_BUFFER_OVERFLOW_ERROR
+* will be returned in status. result will be null-terminated whenever
+* possible. If the buffer fits the matched text exactly, a null-termination
+* is not possible, then a U_STRING_NOT_TERMINATED_ERROR set in status.
+* Pre-flighting can be either done with length = 0 or the API
+* <tt>usearch_getMatchLength</tt>.
+* @param strsrch search iterator data struct
+* @param result UChar buffer to store the matched string
+* @param resultCapacity length of the result buffer
+* @param status error returned if result is not large enough
+* @return exact length of the matched text, not counting the null-termination
+* @see #usearch_first
+* @see #usearch_next
+* @see #usearch_previous
+* @see #usearch_last
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_getMatchedText(const UStringSearch *strsrch,
+ UChar *result,
+ int32_t resultCapacity,
+ UErrorCode *status);
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+/**
+* Set the BreakIterator that will be used to restrict the points at which
+* matches are detected.
+* @param strsrch search iterator data struct
+* @param breakiter A BreakIterator that will be used to restrict the points
+* at which matches are detected. If a match is found, but
+* the match's start or end index is not a boundary as
+* determined by the <tt>BreakIterator</tt>, the match will
+* be rejected and another will be searched for.
+* If this parameter is <tt>NULL</tt>, no break detection is
+* attempted.
+* @param status for errors if it occurs
+* @see #usearch_getBreakIterator
+* @stable ICU 2.4
+*/
+U_STABLE void U_EXPORT2 usearch_setBreakIterator(UStringSearch *strsrch,
+ UBreakIterator *breakiter,
+ UErrorCode *status);
+
+/**
+* Returns the BreakIterator that is used to restrict the points at which
+* matches are detected. This will be the same object that was passed to the
+* constructor or to <tt>usearch_setBreakIterator</tt>. Note that
+* <tt>NULL</tt>
+* is a legal value; it means that break detection should not be attempted.
+* @param strsrch search iterator data struct
+* @return break iterator used
+* @see #usearch_setBreakIterator
+* @stable ICU 2.4
+*/
+U_STABLE const UBreakIterator * U_EXPORT2 usearch_getBreakIterator(
+ const UStringSearch *strsrch);
+
+#endif
+
+/**
+* Set the string text to be searched. Text iteration will hence begin at the
+* start of the text string. This method is useful if you want to re-use an
+* iterator to search for the same pattern within a different body of text.
+* @param strsrch search iterator data struct
+* @param text new string to look for match
+* @param textlength length of the new string, -1 for null-termination
+* @param status for errors if it occurs. If text is NULL, or textlength is 0
+* then an U_ILLEGAL_ARGUMENT_ERROR is returned with no change
+* done to strsrch.
+* @see #usearch_getText
+* @stable ICU 2.4
+*/
+U_STABLE void U_EXPORT2 usearch_setText( UStringSearch *strsrch,
+ const UChar *text,
+ int32_t textlength,
+ UErrorCode *status);
+
+/**
+* Return the string text to be searched.
+* @param strsrch search iterator data struct
+* @param length returned string text length
+* @return string text
+* @see #usearch_setText
+* @stable ICU 2.4
+*/
+U_STABLE const UChar * U_EXPORT2 usearch_getText(const UStringSearch *strsrch,
+ int32_t *length);
+
+/**
+* Gets the collator used for the language rules.
+* <p>
+* Deleting the returned <tt>UCollator</tt> before calling
+* <tt>usearch_close</tt> would cause the string search to fail.
+* <tt>usearch_close</tt> will delete the collator if this search owns it.
+* @param strsrch search iterator data struct
+* @return collator
+* @stable ICU 2.4
+*/
+U_STABLE UCollator * U_EXPORT2 usearch_getCollator(
+ const UStringSearch *strsrch);
+
+/**
+* Sets the collator used for the language rules. User retains the ownership
+* of this collator, thus the responsibility of deletion lies with the user.
+* This method causes internal data such as Boyer-Moore shift tables to
+* be recalculated, but the iterator's position is unchanged.
+* @param strsrch search iterator data struct
+* @param collator to be used
+* @param status for errors if it occurs
+* @stable ICU 2.4
+*/
+U_STABLE void U_EXPORT2 usearch_setCollator( UStringSearch *strsrch,
+ const UCollator *collator,
+ UErrorCode *status);
+
+/**
+* Sets the pattern used for matching.
+* Internal data like the Boyer Moore table will be recalculated, but the
+* iterator's position is unchanged.
+* @param strsrch search iterator data struct
+* @param pattern string
+* @param patternlength pattern length, -1 for null-terminated string
+* @param status for errors if it occurs. If text is NULL, or textlength is 0
+* then an U_ILLEGAL_ARGUMENT_ERROR is returned with no change
+* done to strsrch.
+* @stable ICU 2.4
+*/
+U_STABLE void U_EXPORT2 usearch_setPattern( UStringSearch *strsrch,
+ const UChar *pattern,
+ int32_t patternlength,
+ UErrorCode *status);
+
+/**
+* Gets the search pattern
+* @param strsrch search iterator data struct
+* @param length return length of the pattern, -1 indicates that the pattern
+* is null-terminated
+* @return pattern string
+* @stable ICU 2.4
+*/
+U_STABLE const UChar * U_EXPORT2 usearch_getPattern(
+ const UStringSearch *strsrch,
+ int32_t *length);
+
+/* methods ------------------------------------------------------------- */
+
+/**
+* Returns the first index at which the string text matches the search
+* pattern.
+* The iterator is adjusted so that its current index (as returned by
+* <tt>usearch_getOffset</tt>) is the match position if one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>.
+* @param strsrch search iterator data struct
+* @param status for errors if it occurs
+* @return The character index of the first match, or
+* <tt>USEARCH_DONE</tt> if there are no matches.
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_first(UStringSearch *strsrch,
+ UErrorCode *status);
+
+/**
+* Returns the first index greater than <tt>position</tt> at which the string
+* text
+* matches the search pattern. The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>
+* <p>
+* Search positions that may render incorrect results are highlighted in the
+* header comments. If position is less than or greater than the text range
+* for searching, an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+* @param strsrch search iterator data struct
+* @param position to start the search at
+* @param status for errors if it occurs
+* @return The character index of the first match following <tt>pos</tt>,
+* or <tt>USEARCH_DONE</tt> if there are no matches.
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_following(UStringSearch *strsrch,
+ int32_t position,
+ UErrorCode *status);
+
+/**
+* Returns the last index in the target text at which it matches the search
+* pattern. The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>.
+* @param strsrch search iterator data struct
+* @param status for errors if it occurs
+* @return The index of the first match, or <tt>USEARCH_DONE</tt> if there
+* are no matches.
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_last(UStringSearch *strsrch,
+ UErrorCode *status);
+
+/**
+* Returns the first index less than <tt>position</tt> at which the string text
+* matches the search pattern. The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>
+* <p>
+* Search positions that may render incorrect results are highlighted in the
+* header comments. If position is less than or greater than the text range
+* for searching, an U_INDEX_OUTOFBOUNDS_ERROR will be returned
+* @param strsrch search iterator data struct
+* @param position index position the search is to begin at
+* @param status for errors if it occurs
+* @return The character index of the first match preceding <tt>pos</tt>,
+* or <tt>USEARCH_DONE</tt> if there are no matches.
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_preceding(UStringSearch *strsrch,
+ int32_t position,
+ UErrorCode *status);
+
+/**
+* Returns the index of the next point at which the string text matches the
+* search pattern, starting from the current position.
+* The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>
+* @param strsrch search iterator data struct
+* @param status for errors if it occurs
+* @return The index of the next match after the current position, or
+* <tt>USEARCH_DONE</tt> if there are no more matches.
+* @see #usearch_first
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_next(UStringSearch *strsrch,
+ UErrorCode *status);
+
+/**
+* Returns the index of the previous point at which the string text matches
+* the search pattern, starting at the current position.
+* The iterator is adjusted so that its current
+* index (as returned by <tt>usearch_getOffset</tt>) is the match position if
+* one was found.
+* If a match is not found, <tt>USEARCH_DONE</tt> will be returned and
+* the iterator will be adjusted to the index <tt>USEARCH_DONE</tt>
+* @param strsrch search iterator data struct
+* @param status for errors if it occurs
+* @return The index of the previous match before the current position,
+* or <tt>USEARCH_DONE</tt> if there are no more matches.
+* @see #usearch_last
+* @see #usearch_getOffset
+* @see #USEARCH_DONE
+* @stable ICU 2.4
+*/
+U_STABLE int32_t U_EXPORT2 usearch_previous(UStringSearch *strsrch,
+ UErrorCode *status);
+
+/**
+* Reset the iteration.
+* Search will begin at the start of the text string if a forward iteration
+* is initiated before a backwards iteration. Otherwise if a backwards
+* iteration is initiated before a forwards iteration, the search will begin
+* at the end of the text string.
+* @param strsrch search iterator data struct
+* @see #usearch_first
+* @stable ICU 2.4
+*/
+U_STABLE void U_EXPORT2 usearch_reset(UStringSearch *strsrch);
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/utmscale.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/utmscale.h
new file mode 100644
index 00000000000..e903c88b7f8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/utmscale.h
@@ -0,0 +1,481 @@
+/*
+*******************************************************************************
+* Copyright (C) 2004 - 2006, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#ifndef UTMSCALE_H
+#define UTMSCALE_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * \file
+ * \brief C API: Universal Time Scale
+ *
+ * There are quite a few different conventions for binary datetime, depending on different
+ * platforms and protocols. Some of these have severe drawbacks. For example, people using
+ * Unix time (seconds since Jan 1, 1970) think that they are safe until near the year 2038.
+ * But cases can and do arise where arithmetic manipulations causes serious problems. Consider
+ * the computation of the average of two datetimes, for example: if one calculates them with
+ * <code>averageTime = (time1 + time2)/2</code>, there will be overflow even with dates
+ * around the present. Moreover, even if these problems don't occur, there is the issue of
+ * conversion back and forth between different systems.
+ *
+ * <p>
+ * Binary datetimes differ in a number of ways: the datatype, the unit,
+ * and the epoch (origin). We'll refer to these as time scales. For example:
+ *
+ * <table border="1" cellspacing="0" cellpadding="4">
+ * <caption>Table 1: Binary Time Scales</caption>
+ * <tr>
+ * <th align="left">Source</th>
+ * <th align="left">Datatype</th>
+ * <th align="left">Unit</th>
+ * <th align="left">Epoch</th>
+ * </tr>
+ *
+ * <tr>
+ * <td>UDTS_JAVA_TIME</td>
+ * <td>int64_t</td>
+ * <td>milliseconds</td>
+ * <td>Jan 1, 1970</td>
+ * </tr>
+ * <tr>
+ *
+ * <td>UDTS_UNIX_TIME</td>
+ * <td>int32_t or int64_t</td>
+ * <td>seconds</td>
+ * <td>Jan 1, 1970</td>
+ * </tr>
+ * <tr>
+ * <td>UDTS_ICU4C_TIME</td>
+ *
+ * <td>double</td>
+ * <td>milliseconds</td>
+ * <td>Jan 1, 1970</td>
+ * </tr>
+ * <tr>
+ * <td>UDTS_WINDOWS_FILE_TIME</td>
+ * <td>int64_t</td>
+ *
+ * <td>ticks (100 nanoseconds)</td>
+ * <td>Jan 1, 1601</td>
+ * </tr>
+ * <tr>
+ * <td>UDTS_DOTNET_DATE_TIME</td>
+ * <td>int64_t</td>
+ * <td>ticks (100 nanoseconds)</td>
+ *
+ * <td>Jan 1, 0001</td>
+ * </tr>
+ * <tr>
+ * <td>UDTS_MAC_OLD_TIME</td>
+ * <td>int32_t or int64_t</td>
+ * <td>seconds</td>
+ * <td>Jan 1, 1904</td>
+ *
+ * </tr>
+ * <tr>
+ * <td>UDTS_MAC_TIME</td>
+ * <td>double</td>
+ * <td>seconds</td>
+ * <td>Jan 1, 2001</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>UDTS_EXCEL_TIME</td>
+ * <td>?</td>
+ * <td>days</td>
+ * <td>Dec 31, 1899</td>
+ * </tr>
+ * <tr>
+ *
+ * <td>UDTS_DB2_TIME</td>
+ * <td>?</td>
+ * <td>days</td>
+ * <td>Dec 31, 1899</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>UDTS_UNIX_MICROSECONDS_TIME</td>
+ * <td>int64_t</td>
+ * <td>microseconds</td>
+ * <td>Jan 1, 1970</td>
+ * </tr>
+ * </table>
+ *
+ * <p>
+ * All of the epochs start at 00:00 am (the earliest possible time on the day in question),
+ * and are assumed to be UTC.
+ *
+ * <p>
+ * The ranges for different datatypes are given in the following table (all values in years).
+ * The range of years includes the entire range expressible with positive and negative
+ * values of the datatype. The range of years for double is the range that would be allowed
+ * without losing precision to the corresponding unit.
+ *
+ * <table border="1" cellspacing="0" cellpadding="4">
+ * <tr>
+ * <th align="left">Units</th>
+ * <th align="left">int64_t</th>
+ * <th align="left">double</th>
+ * <th align="left">int32_t</th>
+ * </tr>
+ *
+ * <tr>
+ * <td>1 sec</td>
+ * <td align="right">5.84542x10<sup>11</sup></td>
+ * <td align="right">285,420,920.94</td>
+ * <td align="right">136.10</td>
+ * </tr>
+ * <tr>
+ *
+ * <td>1 millisecond</td>
+ * <td align="right">584,542,046.09</td>
+ * <td align="right">285,420.92</td>
+ * <td align="right">0.14</td>
+ * </tr>
+ * <tr>
+ * <td>1 microsecond</td>
+ *
+ * <td align="right">584,542.05</td>
+ * <td align="right">285.42</td>
+ * <td align="right">0.00</td>
+ * </tr>
+ * <tr>
+ * <td>100 nanoseconds (tick)</td>
+ * <td align="right">58,454.20</td>
+ * <td align="right">28.54</td>
+ * <td align="right">0.00</td>
+ * </tr>
+ * <tr>
+ * <td>1 nanosecond</td>
+ * <td align="right">584.5420461</td>
+ * <td align="right">0.2854</td>
+ * <td align="right">0.00</td>
+ * </tr>
+ * </table>
+ *
+ * <p>
+ * These functions implement a universal time scale which can be used as a 'pivot',
+ * and provide conversion functions to and from all other major time scales.
+ * This datetimes to be converted to the pivot time, safely manipulated,
+ * and converted back to any other datetime time scale.
+ *
+ *<p>
+ * So what to use for this pivot? Java time has plenty of range, but cannot represent
+ * .NET <code>System.DateTime</code> values without severe loss of precision. ICU4C time addresses this by using a
+ * <code>double</code> that is otherwise equivalent to the Java time. However, there are disadvantages
+ * with <code>doubles</code>. They provide for much more graceful degradation in arithmetic operations.
+ * But they only have 53 bits of accuracy, which means that they will lose precision when
+ * converting back and forth to ticks. What would really be nice would be a
+ * <code>long double</code> (80 bits -- 64 bit mantissa), but that is not supported on most systems.
+ *
+ *<p>
+ * The Unix extended time uses a structure with two components: time in seconds and a
+ * fractional field (microseconds). However, this is clumsy, slow, and
+ * prone to error (you always have to keep track of overflow and underflow in the
+ * fractional field). <code>BigDecimal</code> would allow for arbitrary precision and arbitrary range,
+ * but we do not want to use this as the normal type, because it is slow and does not
+ * have a fixed size.
+ *
+ *<p>
+ * Because of these issues, we ended up concluding that the .NET framework's
+ * <code>System.DateTime</code> would be the best pivot. However, we use the full range
+ * allowed by the datatype, allowing for datetimes back to 29,000 BC and up to 29,000 AD.
+ * This time scale is very fine grained, does not lose precision, and covers a range that
+ * will meet almost all requirements. It will not handle the range that Java times do,
+ * but frankly, being able to handle dates before 29,000 BC or after 29,000 AD is of very limited interest.
+ *
+ */
+
+/**
+ * <code>UDateTimeScale</code> values are used to specify the time scale used for
+ * conversion into or out if the universal time scale.
+ *
+ * @stable ICU 3.2
+ */
+typedef enum UDateTimeScale {
+ /**
+ * Used in the JDK. Data is a Java <code>long</code> (<code>int64_t</code>). Value
+ * is milliseconds since January 1, 1970.
+ *
+ * @stable ICU 3.2
+ */
+ UDTS_JAVA_TIME = 0,
+
+ /**
+ * Used on Unix systems. Data is <code>int32_t</code> or <code>int64_t</code>. Value
+ * is seconds since January 1, 1970.
+ *
+ * @stable ICU 3.2
+ */
+ UDTS_UNIX_TIME,
+
+ /**
+ * Used in IUC4C. Data is a <code>double</code>. Value
+ * is milliseconds since January 1, 1970.
+ *
+ * @stable ICU 3.2
+ */
+ UDTS_ICU4C_TIME,
+
+ /**
+ * Used in Windows for file times. Data is an <code>int64_t</code>. Value
+ * is ticks (1 tick == 100 nanoseconds) since January 1, 1601.
+ *
+ * @stable ICU 3.2
+ */
+ UDTS_WINDOWS_FILE_TIME,
+
+ /**
+ * Used in the .NET framework's <code>System.DateTime</code> structure. Data is an <code>int64_t</code>. Value
+ * is ticks (1 tick == 100 nanoseconds) since January 1, 0001.
+ *
+ * @stable ICU 3.2
+ */
+ UDTS_DOTNET_DATE_TIME,
+
+ /**
+ * Used in older Macintosh systems. Data is <code>int32_t</code> or <code>int64_t</code>. Value
+ * is seconds since January 1, 1904.
+ *
+ * @stable ICU 3.2
+ */
+ UDTS_MAC_OLD_TIME,
+
+ /**
+ * Used in newer Macintosh systems. Data is a <code>double</code>. Value
+ * is seconds since January 1, 2001.
+ *
+ * @stable ICU 3.2
+ */
+ UDTS_MAC_TIME,
+
+ /**
+ * Used in Excel. Data is an <code>?unknown?</code>. Value
+ * is days since December 31, 1899.
+ *
+ * @stable ICU 3.2
+ */
+ UDTS_EXCEL_TIME,
+
+ /**
+ * Used in DB2. Data is an <code>?unknown?</code>. Value
+ * is days since December 31, 1899.
+ *
+ * @stable ICU 3.2
+ */
+ UDTS_DB2_TIME,
+
+ /**
+ * Data is a <code>long</code>. Value is microseconds since January 1, 1970.
+ * Similar to Unix time (linear value from 1970) and struct timeval
+ * (microseconds resolution).
+ *
+ * @draft ICU 3.8
+ */
+ UDTS_UNIX_MICROSECONDS_TIME,
+
+ /**
+ * The first unused time scale value. The limit of this enum
+ */
+ UDTS_MAX_SCALE
+} UDateTimeScale;
+
+/**
+ * <code>UTimeScaleValue</code> values are used to specify the time scale values
+ * to <code>utmscale_getTimeScaleValue</code>.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @stable ICU 3.2
+ */
+typedef enum UTimeScaleValue {
+ /**
+ * The constant used to select the units vale
+ * for a time scale.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @stable ICU 3.2
+ */
+ UTSV_UNITS_VALUE = 0,
+
+ /**
+ * The constant used to select the epoch offset value
+ * for a time scale.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @stable ICU 3.2
+ */
+ UTSV_EPOCH_OFFSET_VALUE=1,
+
+ /**
+ * The constant used to select the minimum from value
+ * for a time scale.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @stable ICU 3.2
+ */
+ UTSV_FROM_MIN_VALUE=2,
+
+ /**
+ * The constant used to select the maximum from value
+ * for a time scale.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @stable ICU 3.2
+ */
+ UTSV_FROM_MAX_VALUE=3,
+
+ /**
+ * The constant used to select the minimum to value
+ * for a time scale.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @stable ICU 3.2
+ */
+ UTSV_TO_MIN_VALUE=4,
+
+ /**
+ * The constant used to select the maximum to value
+ * for a time scale.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @stable ICU 3.2
+ */
+ UTSV_TO_MAX_VALUE=5,
+
+#ifndef U_HIDE_INTERNAL_API
+ /**
+ * The constant used to select the epoch plus one value
+ * for a time scale.
+ *
+ * NOTE: This is an internal value. DO NOT USE IT. May not
+ * actually be equal to the epoch offset value plus one.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @internal ICU 3.2
+ */
+ UTSV_EPOCH_OFFSET_PLUS_1_VALUE=6,
+
+ /**
+ * The constant used to select the epoch plus one value
+ * for a time scale.
+ *
+ * NOTE: This is an internal value. DO NOT USE IT. May not
+ * actually be equal to the epoch offset value plus one.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @internal ICU 3.2
+ */
+ UTSV_EPOCH_OFFSET_MINUS_1_VALUE=7,
+
+ /**
+ * The constant used to select the units round value
+ * for a time scale.
+ *
+ * NOTE: This is an internal value. DO NOT USE IT.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @internal ICU 3.2
+ */
+ UTSV_UNITS_ROUND_VALUE=8,
+
+ /**
+ * The constant used to select the minimum safe rounding value
+ * for a time scale.
+ *
+ * NOTE: This is an internal value. DO NOT USE IT.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @internal ICU 3.2
+ */
+ UTSV_MIN_ROUND_VALUE=9,
+
+ /**
+ * The constant used to select the maximum safe rounding value
+ * for a time scale.
+ *
+ * NOTE: This is an internal value. DO NOT USE IT.
+ *
+ * @see utmscale_getTimeScaleValue
+ *
+ * @internal ICU 3.2
+ */
+ UTSV_MAX_ROUND_VALUE=10,
+
+#endif /* U_HIDE_INTERNAL_API */
+
+ /**
+ * The number of time scale values, in other words limit of this enum.
+ *
+ * @see utmscale_getTimeScaleValue
+ */
+ UTSV_MAX_SCALE_VALUE=11
+
+} UTimeScaleValue;
+
+/**
+ * Get a value associated with a particular time scale.
+ *
+ * @param timeScale The time scale
+ * @param value A constant representing the value to get
+ * @param status The status code. Set to <code>U_ILLEGAL_ARGUMENT_ERROR</code> if arguments are invalid.
+ * @return - the value.
+ *
+ * @stable ICU 3.2
+ */
+U_STABLE int64_t U_EXPORT2
+ utmscale_getTimeScaleValue(UDateTimeScale timeScale, UTimeScaleValue value, UErrorCode *status);
+
+/* Conversion to 'universal time scale' */
+
+/**
+ * Convert a <code>int64_t</code> datetime from the given time scale to the universal time scale.
+ *
+ * @param otherTime The <code>int64_t</code> datetime
+ * @param timeScale The time scale to convert from
+ * @param status The status code. Set to <code>U_ILLEGAL_ARGUMENT_ERROR</code> if the conversion is out of range.
+ *
+ * @return The datetime converted to the universal time scale
+ *
+ * @stable ICU 3.2
+ */
+U_STABLE int64_t U_EXPORT2
+ utmscale_fromInt64(int64_t otherTime, UDateTimeScale timeScale, UErrorCode *status);
+
+/* Conversion from 'universal time scale' */
+
+/**
+ * Convert a datetime from the universal time scale to a <code>int64_t</code> in the given time scale.
+ *
+ * @param universalTime The datetime in the universal time scale
+ * @param timeScale The time scale to convert to
+ * @param status The status code. Set to <code>U_ILLEGAL_ARGUMENT_ERROR</code> if the conversion is out of range.
+ *
+ * @return The datetime converted to the given time scale
+ *
+ * @stable ICU 3.2
+ */
+U_STABLE int64_t U_EXPORT2
+ utmscale_toInt64(int64_t universalTime, UDateTimeScale timeScale, UErrorCode *status);
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/utrans.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/utrans.h
new file mode 100644
index 00000000000..a460a34c5b7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/utrans.h
@@ -0,0 +1,583 @@
+/*
+*******************************************************************************
+* Copyright (C) 1997-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* Date Name Description
+* 06/21/00 aliu Creation.
+*******************************************************************************
+*/
+
+#ifndef UTRANS_H
+#define UTRANS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/urep.h"
+#include "unicode/parseerr.h"
+#include "unicode/uenum.h"
+
+/********************************************************************
+ * General Notes
+ ********************************************************************
+ */
+/**
+ * \file
+ * \brief C API: Transliterator
+ *
+ * <h2> Transliteration </h2>
+ * The data structures and functions described in this header provide
+ * transliteration services. Transliteration services are implemented
+ * as C++ classes. The comments and documentation in this header
+ * assume the reader is familiar with the C++ headers translit.h and
+ * associated documentation.
+ *
+ * A significant but incomplete subset of the C++ transliteration
+ * services are available to C code through this header. In order to
+ * access more complex transliteration services, refer to the C++
+ * headers and documentation.
+ *
+ * There are two sets of functions for working with transliterator IDs:
+ *
+ * An old, deprecated set uses char * IDs, which works for true and pure
+ * identifiers that these APIs were designed for,
+ * for example "Cyrillic-Latin".
+ * It does not work when the ID contains filters ("[:Script=Cyrl:]")
+ * or even a complete set of rules because then the ID string contains more
+ * than just "invariant" characters (see utypes.h).
+ *
+ * A new set of functions replaces the old ones and uses UChar * IDs,
+ * paralleling the UnicodeString IDs in the C++ API. (New in ICU 2.8.)
+ */
+
+/********************************************************************
+ * Data Structures
+ ********************************************************************/
+
+/**
+ * An opaque transliterator for use in C. Open with utrans_openxxx()
+ * and close with utrans_close() when done. Equivalent to the C++ class
+ * Transliterator and its subclasses.
+ * @see Transliterator
+ * @stable ICU 2.0
+ */
+typedef void* UTransliterator;
+
+/**
+ * Direction constant indicating the direction in a transliterator,
+ * e.g., the forward or reverse rules of a RuleBasedTransliterator.
+ * Specified when a transliterator is opened. An "A-B" transliterator
+ * transliterates A to B when operating in the forward direction, and
+ * B to A when operating in the reverse direction.
+ * @stable ICU 2.0
+ */
+typedef enum UTransDirection {
+
+ /**
+ * UTRANS_FORWARD means from &lt;source&gt; to &lt;target&gt; for a
+ * transliterator with ID &lt;source&gt;-&lt;target&gt;. For a transliterator
+ * opened using a rule, it means forward direction rules, e.g.,
+ * "A > B".
+ */
+ UTRANS_FORWARD,
+
+ /**
+ * UTRANS_REVERSE means from &lt;target&gt; to &lt;source&gt; for a
+ * transliterator with ID &lt;source&gt;-&lt;target&gt;. For a transliterator
+ * opened using a rule, it means reverse direction rules, e.g.,
+ * "A < B".
+ */
+ UTRANS_REVERSE
+
+} UTransDirection;
+
+/**
+ * Position structure for utrans_transIncremental() incremental
+ * transliteration. This structure defines two substrings of the text
+ * being transliterated. The first region, [contextStart,
+ * contextLimit), defines what characters the transliterator will read
+ * as context. The second region, [start, limit), defines what
+ * characters will actually be transliterated. The second region
+ * should be a subset of the first.
+ *
+ * <p>After a transliteration operation, some of the indices in this
+ * structure will be modified. See the field descriptions for
+ * details.
+ *
+ * <p>contextStart <= start <= limit <= contextLimit
+ *
+ * <p>Note: All index values in this structure must be at code point
+ * boundaries. That is, none of them may occur between two code units
+ * of a surrogate pair. If any index does split a surrogate pair,
+ * results are unspecified.
+ *
+ * @stable ICU 2.0
+ */
+typedef struct UTransPosition {
+
+ /**
+ * Beginning index, inclusive, of the context to be considered for
+ * a transliteration operation. The transliterator will ignore
+ * anything before this index. INPUT/OUTPUT parameter: This parameter
+ * is updated by a transliteration operation to reflect the maximum
+ * amount of antecontext needed by a transliterator.
+ * @stable ICU 2.4
+ */
+ int32_t contextStart;
+
+ /**
+ * Ending index, exclusive, of the context to be considered for a
+ * transliteration operation. The transliterator will ignore
+ * anything at or after this index. INPUT/OUTPUT parameter: This
+ * parameter is updated to reflect changes in the length of the
+ * text, but points to the same logical position in the text.
+ * @stable ICU 2.4
+ */
+ int32_t contextLimit;
+
+ /**
+ * Beginning index, inclusive, of the text to be transliteratd.
+ * INPUT/OUTPUT parameter: This parameter is advanced past
+ * characters that have already been transliterated by a
+ * transliteration operation.
+ * @stable ICU 2.4
+ */
+ int32_t start;
+
+ /**
+ * Ending index, exclusive, of the text to be transliteratd.
+ * INPUT/OUTPUT parameter: This parameter is updated to reflect
+ * changes in the length of the text, but points to the same
+ * logical position in the text.
+ * @stable ICU 2.4
+ */
+ int32_t limit;
+
+} UTransPosition;
+
+/********************************************************************
+ * General API
+ ********************************************************************/
+
+/**
+ * Open a custom transliterator, given a custom rules string
+ * OR
+ * a system transliterator, given its ID.
+ * Any non-NULL result from this function should later be closed with
+ * utrans_close().
+ *
+ * @param id a valid transliterator ID
+ * @param idLength the length of the ID string, or -1 if NUL-terminated
+ * @param dir the desired direction
+ * @param rules the transliterator rules. See the C++ header rbt.h for
+ * rules syntax. If NULL then a system transliterator matching
+ * the ID is returned.
+ * @param rulesLength the length of the rules, or -1 if the rules
+ * are NUL-terminated.
+ * @param parseError a pointer to a UParseError struct to receive the details
+ * of any parsing errors. This parameter may be NULL if no
+ * parsing error details are desired.
+ * @param pErrorCode a pointer to the UErrorCode
+ * @return a transliterator pointer that may be passed to other
+ * utrans_xxx() functions, or NULL if the open call fails.
+ * @stable ICU 2.8
+ */
+U_STABLE UTransliterator* U_EXPORT2
+utrans_openU(const UChar *id,
+ int32_t idLength,
+ UTransDirection dir,
+ const UChar *rules,
+ int32_t rulesLength,
+ UParseError *parseError,
+ UErrorCode *pErrorCode);
+
+/**
+ * Open an inverse of an existing transliterator. For this to work,
+ * the inverse must be registered with the system. For example, if
+ * the Transliterator "A-B" is opened, and then its inverse is opened,
+ * the result is the Transliterator "B-A", if such a transliterator is
+ * registered with the system. Otherwise the result is NULL and a
+ * failing UErrorCode is set. Any non-NULL result from this function
+ * should later be closed with utrans_close().
+ *
+ * @param trans the transliterator to open the inverse of.
+ * @param status a pointer to the UErrorCode
+ * @return a pointer to a newly-opened transliterator that is the
+ * inverse of trans, or NULL if the open call fails.
+ * @stable ICU 2.0
+ */
+U_STABLE UTransliterator* U_EXPORT2
+utrans_openInverse(const UTransliterator* trans,
+ UErrorCode* status);
+
+/**
+ * Create a copy of a transliterator. Any non-NULL result from this
+ * function should later be closed with utrans_close().
+ *
+ * @param trans the transliterator to be copied.
+ * @param status a pointer to the UErrorCode
+ * @return a transliterator pointer that may be passed to other
+ * utrans_xxx() functions, or NULL if the clone call fails.
+ * @stable ICU 2.0
+ */
+U_STABLE UTransliterator* U_EXPORT2
+utrans_clone(const UTransliterator* trans,
+ UErrorCode* status);
+
+/**
+ * Close a transliterator. Any non-NULL pointer returned by
+ * utrans_openXxx() or utrans_clone() should eventually be closed.
+ * @param trans the transliterator to be closed.
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+utrans_close(UTransliterator* trans);
+
+/**
+ * Return the programmatic identifier for this transliterator.
+ * If this identifier is passed to utrans_openU(), it will open
+ * a transliterator equivalent to this one, if the ID has been
+ * registered.
+ *
+ * @param trans the transliterator to return the ID of.
+ * @param resultLength pointer to an output variable receiving the length
+ * of the ID string; can be NULL
+ * @return the NUL-terminated ID string. This pointer remains
+ * valid until utrans_close() is called on this transliterator.
+ *
+ * @stable ICU 2.8
+ */
+U_STABLE const UChar * U_EXPORT2
+utrans_getUnicodeID(const UTransliterator *trans,
+ int32_t *resultLength);
+
+/**
+ * Register an open transliterator with the system. When
+ * utrans_open() is called with an ID string that is equal to that
+ * returned by utrans_getID(adoptedTrans,...), then
+ * utrans_clone(adoptedTrans,...) is returned.
+ *
+ * <p>NOTE: After this call the system owns the adoptedTrans and will
+ * close it. The user must not call utrans_close() on adoptedTrans.
+ *
+ * @param adoptedTrans a transliterator, typically the result of
+ * utrans_openRules(), to be registered with the system.
+ * @param status a pointer to the UErrorCode
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+utrans_register(UTransliterator* adoptedTrans,
+ UErrorCode* status);
+
+/**
+ * Unregister a transliterator from the system. After this call the
+ * system will no longer recognize the given ID when passed to
+ * utrans_open(). If the ID is invalid then nothing is done.
+ *
+ * @param id an ID to unregister
+ * @param idLength the length of id, or -1 if id is zero-terminated
+ * @stable ICU 2.8
+ */
+U_STABLE void U_EXPORT2
+utrans_unregisterID(const UChar* id, int32_t idLength);
+
+/**
+ * Set the filter used by a transliterator. A filter can be used to
+ * make the transliterator pass certain characters through untouched.
+ * The filter is expressed using a UnicodeSet pattern. If the
+ * filterPattern is NULL or the empty string, then the transliterator
+ * will be reset to use no filter.
+ *
+ * @param trans the transliterator
+ * @param filterPattern a pattern string, in the form accepted by
+ * UnicodeSet, specifying which characters to apply the
+ * transliteration to. May be NULL or the empty string to indicate no
+ * filter.
+ * @param filterPatternLen the length of filterPattern, or -1 if
+ * filterPattern is zero-terminated
+ * @param status a pointer to the UErrorCode
+ * @see UnicodeSet
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+utrans_setFilter(UTransliterator* trans,
+ const UChar* filterPattern,
+ int32_t filterPatternLen,
+ UErrorCode* status);
+
+/**
+ * Return the number of system transliterators.
+ * It is recommended to use utrans_openIDs() instead.
+ *
+ * @return the number of system transliterators.
+ * @stable ICU 2.0
+ */
+U_STABLE int32_t U_EXPORT2
+utrans_countAvailableIDs(void);
+
+/**
+ * Return a UEnumeration for the available transliterators.
+ *
+ * @param pErrorCode Pointer to the UErrorCode in/out parameter.
+ * @return UEnumeration for the available transliterators.
+ * Close with uenum_close().
+ *
+ * @stable ICU 2.8
+ */
+U_STABLE UEnumeration * U_EXPORT2
+utrans_openIDs(UErrorCode *pErrorCode);
+
+/********************************************************************
+ * Transliteration API
+ ********************************************************************/
+
+/**
+ * Transliterate a segment of a UReplaceable string. The string is
+ * passed in as a UReplaceable pointer rep and a UReplaceableCallbacks
+ * function pointer struct repFunc. Functions in the repFunc struct
+ * will be called in order to modify the rep string.
+ *
+ * @param trans the transliterator
+ * @param rep a pointer to the string. This will be passed to the
+ * repFunc functions.
+ * @param repFunc a set of function pointers that will be used to
+ * modify the string pointed to by rep.
+ * @param start the beginning index, inclusive; <code>0 <= start <=
+ * limit</code>.
+ * @param limit pointer to the ending index, exclusive; <code>start <=
+ * limit <= repFunc->length(rep)</code>. Upon return, *limit will
+ * contain the new limit index. The text previously occupying
+ * <code>[start, limit)</code> has been transliterated, possibly to a
+ * string of a different length, at <code>[start,
+ * </code><em>new-limit</em><code>)</code>, where <em>new-limit</em>
+ * is the return value.
+ * @param status a pointer to the UErrorCode
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+utrans_trans(const UTransliterator* trans,
+ UReplaceable* rep,
+ UReplaceableCallbacks* repFunc,
+ int32_t start,
+ int32_t* limit,
+ UErrorCode* status);
+
+/**
+ * Transliterate the portion of the UReplaceable text buffer that can
+ * be transliterated unambiguosly. This method is typically called
+ * after new text has been inserted, e.g. as a result of a keyboard
+ * event. The transliterator will try to transliterate characters of
+ * <code>rep</code> between <code>index.cursor</code> and
+ * <code>index.limit</code>. Characters before
+ * <code>index.cursor</code> will not be changed.
+ *
+ * <p>Upon return, values in <code>index</code> will be updated.
+ * <code>index.start</code> will be advanced to the first
+ * character that future calls to this method will read.
+ * <code>index.cursor</code> and <code>index.limit</code> will
+ * be adjusted to delimit the range of text that future calls to
+ * this method may change.
+ *
+ * <p>Typical usage of this method begins with an initial call
+ * with <code>index.start</code> and <code>index.limit</code>
+ * set to indicate the portion of <code>text</code> to be
+ * transliterated, and <code>index.cursor == index.start</code>.
+ * Thereafter, <code>index</code> can be used without
+ * modification in future calls, provided that all changes to
+ * <code>text</code> are made via this method.
+ *
+ * <p>This method assumes that future calls may be made that will
+ * insert new text into the buffer. As a result, it only performs
+ * unambiguous transliterations. After the last call to this method,
+ * there may be untransliterated text that is waiting for more input
+ * to resolve an ambiguity. In order to perform these pending
+ * transliterations, clients should call utrans_trans() with a start
+ * of index.start and a limit of index.end after the last call to this
+ * method has been made.
+ *
+ * @param trans the transliterator
+ * @param rep a pointer to the string. This will be passed to the
+ * repFunc functions.
+ * @param repFunc a set of function pointers that will be used to
+ * modify the string pointed to by rep.
+ * @param pos a struct containing the start and limit indices of the
+ * text to be read and the text to be transliterated
+ * @param status a pointer to the UErrorCode
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+utrans_transIncremental(const UTransliterator* trans,
+ UReplaceable* rep,
+ UReplaceableCallbacks* repFunc,
+ UTransPosition* pos,
+ UErrorCode* status);
+
+/**
+ * Transliterate a segment of a UChar* string. The string is passed
+ * in in a UChar* buffer. The string is modified in place. If the
+ * result is longer than textCapacity, it is truncated. The actual
+ * length of the result is returned in *textLength, if textLength is
+ * non-NULL. *textLength may be greater than textCapacity, but only
+ * textCapacity UChars will be written to *text, including the zero
+ * terminator.
+ *
+ * @param trans the transliterator
+ * @param text a pointer to a buffer containing the text to be
+ * transliterated on input and the result text on output.
+ * @param textLength a pointer to the length of the string in text.
+ * If the length is -1 then the string is assumed to be
+ * zero-terminated. Upon return, the new length is stored in
+ * *textLength. If textLength is NULL then the string is assumed to
+ * be zero-terminated.
+ * @param textCapacity a pointer to the length of the text buffer.
+ * Upon return,
+ * @param start the beginning index, inclusive; <code>0 <= start <=
+ * limit</code>.
+ * @param limit pointer to the ending index, exclusive; <code>start <=
+ * limit <= repFunc->length(rep)</code>. Upon return, *limit will
+ * contain the new limit index. The text previously occupying
+ * <code>[start, limit)</code> has been transliterated, possibly to a
+ * string of a different length, at <code>[start,
+ * </code><em>new-limit</em><code>)</code>, where <em>new-limit</em>
+ * is the return value.
+ * @param status a pointer to the UErrorCode
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+utrans_transUChars(const UTransliterator* trans,
+ UChar* text,
+ int32_t* textLength,
+ int32_t textCapacity,
+ int32_t start,
+ int32_t* limit,
+ UErrorCode* status);
+
+/**
+ * Transliterate the portion of the UChar* text buffer that can be
+ * transliterated unambiguosly. See utrans_transIncremental(). The
+ * string is passed in in a UChar* buffer. The string is modified in
+ * place. If the result is longer than textCapacity, it is truncated.
+ * The actual length of the result is returned in *textLength, if
+ * textLength is non-NULL. *textLength may be greater than
+ * textCapacity, but only textCapacity UChars will be written to
+ * *text, including the zero terminator. See utrans_transIncremental()
+ * for usage details.
+ *
+ * @param trans the transliterator
+ * @param text a pointer to a buffer containing the text to be
+ * transliterated on input and the result text on output.
+ * @param textLength a pointer to the length of the string in text.
+ * If the length is -1 then the string is assumed to be
+ * zero-terminated. Upon return, the new length is stored in
+ * *textLength. If textLength is NULL then the string is assumed to
+ * be zero-terminated.
+ * @param textCapacity the length of the text buffer
+ * @param pos a struct containing the start and limit indices of the
+ * text to be read and the text to be transliterated
+ * @param status a pointer to the UErrorCode
+ * @see utrans_transIncremental
+ * @stable ICU 2.0
+ */
+U_STABLE void U_EXPORT2
+utrans_transIncrementalUChars(const UTransliterator* trans,
+ UChar* text,
+ int32_t* textLength,
+ int32_t textCapacity,
+ UTransPosition* pos,
+ UErrorCode* status);
+
+/* deprecated API ----------------------------------------------------------- */
+
+/* see utrans.h documentation for why these functions are deprecated */
+
+/**
+ * Deprecated, use utrans_openU() instead.
+ * Open a custom transliterator, given a custom rules string
+ * OR
+ * a system transliterator, given its ID.
+ * Any non-NULL result from this function should later be closed with
+ * utrans_close().
+ *
+ * @param id a valid ID, as returned by utrans_getAvailableID()
+ * @param dir the desired direction
+ * @param rules the transliterator rules. See the C++ header rbt.h
+ * for rules syntax. If NULL then a system transliterator matching
+ * the ID is returned.
+ * @param rulesLength the length of the rules, or -1 if the rules
+ * are zero-terminated.
+ * @param parseError a pointer to a UParseError struct to receive the
+ * details of any parsing errors. This parameter may be NULL if no
+ * parsing error details are desired.
+ * @param status a pointer to the UErrorCode
+ * @return a transliterator pointer that may be passed to other
+ * utrans_xxx() functions, or NULL if the open call fails.
+ * @deprecated ICU 2.8 Use utrans_openU() instead, see utrans.h
+ */
+U_DEPRECATED UTransliterator* U_EXPORT2
+utrans_open(const char* id,
+ UTransDirection dir,
+ const UChar* rules, /* may be Null */
+ int32_t rulesLength, /* -1 if null-terminated */
+ UParseError* parseError, /* may be Null */
+ UErrorCode* status);
+
+/**
+ * Deprecated, use utrans_getUnicodeID() instead.
+ * Return the programmatic identifier for this transliterator.
+ * If this identifier is passed to utrans_open(), it will open
+ * a transliterator equivalent to this one, if the ID has been
+ * registered.
+ * @param trans the transliterator to return the ID of.
+ * @param buf the buffer in which to receive the ID. This may be
+ * NULL, in which case no characters are copied.
+ * @param bufCapacity the capacity of the buffer. Ignored if buf is
+ * NULL.
+ * @return the actual length of the ID, not including
+ * zero-termination. This may be greater than bufCapacity.
+ * @deprecated ICU 2.8 Use utrans_getUnicodeID() instead, see utrans.h
+ */
+U_DEPRECATED int32_t U_EXPORT2
+utrans_getID(const UTransliterator* trans,
+ char* buf,
+ int32_t bufCapacity);
+
+/**
+ * Deprecated, use utrans_unregisterID() instead.
+ * Unregister a transliterator from the system. After this call the
+ * system will no longer recognize the given ID when passed to
+ * utrans_open(). If the id is invalid then nothing is done.
+ *
+ * @param id a zero-terminated ID
+ * @deprecated ICU 2.8 Use utrans_unregisterID() instead, see utrans.h
+ */
+U_DEPRECATED void U_EXPORT2
+utrans_unregister(const char* id);
+
+/**
+ * Deprecated, use utrans_openIDs() instead.
+ * Return the ID of the index-th system transliterator. The result
+ * is placed in the given buffer. If the given buffer is too small,
+ * the initial substring is copied to buf. The result in buf is
+ * always zero-terminated.
+ *
+ * @param index the number of the transliterator to return. Must
+ * satisfy 0 <= index < utrans_countAvailableIDs(). If index is out
+ * of range then it is treated as if it were 0.
+ * @param buf the buffer in which to receive the ID. This may be
+ * NULL, in which case no characters are copied.
+ * @param bufCapacity the capacity of the buffer. Ignored if buf is
+ * NULL.
+ * @return the actual length of the index-th ID, not including
+ * zero-termination. This may be greater than bufCapacity.
+ * @deprecated ICU 2.8 Use utrans_openIDs() instead, see utrans.h
+ */
+U_DEPRECATED int32_t U_EXPORT2
+utrans_getAvailableID(int32_t index,
+ char* buf,
+ int32_t bufCapacity);
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unicode/vtzone.h b/Build/source/libs/icu/icu-xetex/i18n/unicode/vtzone.h
new file mode 100644
index 00000000000..420f61a2baa
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unicode/vtzone.h
@@ -0,0 +1,443 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef VTZONE_H
+#define VTZONE_H
+
+#include "unicode/utypes.h"
+
+/**
+ * \file
+ * \brief C++ API: RFC2445 VTIMEZONE support
+ */
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/basictz.h"
+
+U_NAMESPACE_BEGIN
+
+class VTZWriter;
+class VTZReader;
+class UVector;
+
+/**
+ * <code>VTimeZone</code> is a class implementing RFC2445 VTIMEZONE. You can create a
+ * <code>VTimeZone</code> instance from a time zone ID supported by <code>TimeZone</code>.
+ * With the <code>VTimeZone</code> instance created from the ID, you can write out the rule
+ * in RFC2445 VTIMEZONE format. Also, you can create a <code>VTimeZone</code> instance
+ * from RFC2445 VTIMEZONE data stream, which allows you to calculate time
+ * zone offset by the rules defined by the data.<br><br>
+ * Note: The consumer of this class reading or writing VTIMEZONE data is responsible to
+ * decode or encode Non-ASCII text. Methods reading/writing VTIMEZONE data in this class
+ * do nothing with MIME encoding.
+ * @draft ICU 3.8
+ */
+class U_I18N_API VTimeZone : public BasicTimeZone {
+public:
+ /**
+ * Copy constructor.
+ * @param source The <code>VTimeZone</code> object to be copied.
+ * @draft ICU 3.8
+ */
+ VTimeZone(const VTimeZone& source);
+
+ /**
+ * Destructor.
+ * @draft ICU 3.8
+ */
+ virtual ~VTimeZone();
+
+ /**
+ * Assignment operator.
+ * @param right The object to be copied.
+ * @draft ICU 3.8
+ */
+ VTimeZone& operator=(const VTimeZone& right);
+
+ /**
+ * Return true if the given <code>TimeZone</code> objects are
+ * semantically equal. Objects of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZone</code> objects are
+ *semantically equal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator==(const TimeZone& that) const;
+
+ /**
+ * Return true if the given <code>TimeZone</code> objects are
+ * semantically unequal. Objects of different subclasses are considered unequal.
+ * @param that The object to be compared with.
+ * @return true if the given <code>TimeZone</code> objects are
+ * semantically unequal.
+ * @draft ICU 3.8
+ */
+ virtual UBool operator!=(const TimeZone& that) const;
+
+ /**
+ * Create a <code>VTimeZone</code> instance by the time zone ID.
+ * @param ID The time zone ID, such as America/New_York
+ * @return A <code>VTimeZone</code> object initialized by the time zone ID,
+ * or NULL when the ID is unknown.
+ * @draft ICU 3.8
+ */
+ static VTimeZone* createVTimeZoneByID(const UnicodeString& ID);
+
+ /**
+ * Create a <code>VTimeZone</code> instance by RFC2445 VTIMEZONE data
+ *
+ * @param vtzdata The string including VTIMEZONE data block
+ * @param status Output param to filled in with a success or an error.
+ * @return A <code>VTimeZone</code> initialized by the VTIMEZONE data or
+ * NULL if failed to load the rule from the VTIMEZONE data.
+ * @draft ICU 3.8
+ */
+ static VTimeZone* createVTimeZone(const UnicodeString& vtzdata, UErrorCode& status);
+
+ /**
+ * Gets the RFC2445 TZURL property value. When a <code>VTimeZone</code> instance was
+ * created from VTIMEZONE data, the initial value is set by the TZURL property value
+ * in the data. Otherwise, the initial value is not set.
+ * @param url Receives the RFC2445 TZURL property value.
+ * @return TRUE if TZURL attribute is available and value is set.
+ * @draft ICU 3.8
+ */
+ UBool getTZURL(UnicodeString& url) const;
+
+ /**
+ * Sets the RFC2445 TZURL property value.
+ * @param url The TZURL property value.
+ * @draft ICU 3.8
+ */
+ void setTZURL(const UnicodeString& url);
+
+ /**
+ * Gets the RFC2445 LAST-MODIFIED property value. When a <code>VTimeZone</code> instance
+ * was created from VTIMEZONE data, the initial value is set by the LAST-MODIFIED property
+ * value in the data. Otherwise, the initial value is not set.
+ * @param lastModified Receives the last modified date.
+ * @return TRUE if lastModified attribute is available and value is set.
+ * @draft ICU 3.8
+ */
+ UBool getLastModified(UDate& lastModified) const;
+
+ /**
+ * Sets the RFC2445 LAST-MODIFIED property value.
+ * @param lastModified The LAST-MODIFIED date.
+ * @draft ICU 3.8
+ */
+ void setLastModified(UDate lastModified);
+
+ /**
+ * Writes RFC2445 VTIMEZONE data for this time zone
+ * @param result Output param to filled in with the VTIMEZONE data.
+ * @param status Output param to filled in with a success or an error.
+ * @draft ICU 3.8
+ */
+ void write(UnicodeString& result, UErrorCode& status) const;
+
+ /**
+ * Writes RFC2445 VTIMEZONE data for this time zone applicalbe
+ * for dates after the specified start time.
+ * @param start The start date.
+ * @param result Output param to filled in with the VTIMEZONE data.
+ * @param status Output param to filled in with a success or an error.
+ * @draft ICU 3.8
+ */
+ void write(UDate start, UnicodeString& result, UErrorCode& status) /*const*/;
+
+ /**
+ * Writes RFC2445 VTIMEZONE data applicalbe for the specified date.
+ * Some common iCalendar implementations can only handle a single time
+ * zone property or a pair of standard and daylight time properties using
+ * BYDAY rule with day of week (such as BYDAY=1SUN). This method produce
+ * the VTIMEZONE data which can be handled these implementations. The rules
+ * produced by this method can be used only for calculating time zone offset
+ * around the specified date.
+ * @param time The date used for rule extraction.
+ * @param result Output param to filled in with the VTIMEZONE data.
+ * @param status Output param to filled in with a success or an error.
+ * @draft ICU 3.8
+ */
+ void writeSimple(UDate time, UnicodeString& result, UErrorCode& status) /*const*/;
+
+ /**
+ * Clones TimeZone objects polymorphically. Clients are responsible for deleting
+ * the TimeZone object cloned.
+ * @return A new copy of this TimeZone object.
+ * @draft ICU 3.8
+ */
+ virtual TimeZone* clone(void) const;
+
+ /**
+ * Returns the TimeZone's adjusted GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time in this time zone, taking daylight savings time into
+ * account) as of a particular reference date. The reference date is used to determine
+ * whether daylight savings time is in effect and needs to be figured into the offset
+ * that is returned (in other words, what is the adjusted GMT offset in this time zone
+ * at this particular date and time?). For the time zones produced by createTimeZone(),
+ * the reference data is specified according to the Gregorian calendar, and the date
+ * and time fields are local standard time.
+ *
+ * <p>Note: Don't call this method. Instead, call the getOffset(UDate...) overload,
+ * which returns both the raw and the DST offset for a given time. This method
+ * is retained only for backward compatibility.
+ *
+ * @param era The reference date's era
+ * @param year The reference date's year
+ * @param month The reference date's month (0-based; 0 is January)
+ * @param day The reference date's day-in-month (1-based)
+ * @param dayOfWeek The reference date's day-of-week (1-based; 1 is Sunday)
+ * @param millis The reference date's milliseconds in day, local standard time
+ * @param status Output param to filled in with a success or an error.
+ * @return The offset in milliseconds to add to GMT to get local time.
+ * @draft ICU 3.8
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const;
+
+ /**
+ * Gets the time zone offset, for current date, modified in case of
+ * daylight savings. This is the offset to add *to* UTC to get local time.
+ *
+ * <p>Note: Don't call this method. Instead, call the getOffset(UDate...) overload,
+ * which returns both the raw and the DST offset for a given time. This method
+ * is retained only for backward compatibility.
+ *
+ * @param era The reference date's era
+ * @param year The reference date's year
+ * @param month The reference date's month (0-based; 0 is January)
+ * @param day The reference date's day-in-month (1-based)
+ * @param dayOfWeek The reference date's day-of-week (1-based; 1 is Sunday)
+ * @param millis The reference date's milliseconds in day, local standard time
+ * @param monthLength The length of the given month in days.
+ * @param status Output param to filled in with a success or an error.
+ * @return The offset in milliseconds to add to GMT to get local time.
+ * @draft ICU 3.8
+ */
+ virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis,
+ int32_t monthLength, UErrorCode& status) const;
+
+ /**
+ * Returns the time zone raw and GMT offset for the given moment
+ * in time. Upon return, local-millis = GMT-millis + rawOffset +
+ * dstOffset. All computations are performed in the proleptic
+ * Gregorian calendar. The default implementation in the TimeZone
+ * class delegates to the 8-argument getOffset().
+ *
+ * @param date moment in time for which to return offsets, in
+ * units of milliseconds from January 1, 1970 0:00 GMT, either GMT
+ * time or local wall time, depending on `local'.
+ * @param local if true, `date' is local wall time; otherwise it
+ * is in GMT time.
+ * @param rawOffset output parameter to receive the raw offset, that
+ * is, the offset not including DST adjustments
+ * @param dstOffset output parameter to receive the DST offset,
+ * that is, the offset to be added to `rawOffset' to obtain the
+ * total offset between local and GMT time. If DST is not in
+ * effect, this value is zero; otherwise it is a positive value,
+ * typically one hour.
+ * @param ec input-output error code
+ * @draft ICU 3.8
+ */
+ virtual void getOffset(UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& ec) const;
+
+ /**
+ * Sets the TimeZone's raw GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time, before taking daylight savings time into account).
+ *
+ * @param offsetMillis The new raw GMT offset for this time zone.
+ * @draft ICU 3.8
+ */
+ virtual void setRawOffset(int32_t offsetMillis);
+
+ /**
+ * Returns the TimeZone's raw GMT offset (i.e., the number of milliseconds to add
+ * to GMT to get local time, before taking daylight savings time into account).
+ *
+ * @return The TimeZone's raw GMT offset.
+ * @draft ICU 3.8
+ */
+ virtual int32_t getRawOffset(void) const;
+
+ /**
+ * Queries if this time zone uses daylight savings time.
+ * @return true if this time zone uses daylight savings time,
+ * false, otherwise.
+ * @draft ICU 3.8
+ */
+ virtual UBool useDaylightTime(void) const;
+
+ /**
+ * Queries if the given date is in daylight savings time in
+ * this time zone.
+ * This method is wasteful since it creates a new GregorianCalendar and
+ * deletes it each time it is called. This is a deprecated method
+ * and provided only for Java compatibility.
+ *
+ * @param date the given UDate.
+ * @param status Output param filled in with success/error code.
+ * @return true if the given date is in daylight savings time,
+ * false, otherwise.
+ * @deprecated ICU 2.4. Use Calendar::inDaylightTime() instead.
+ */
+ virtual UBool inDaylightTime(UDate date, UErrorCode& status) const;
+
+ /**
+ * Returns true if this zone has the same rule and offset as another zone.
+ * That is, if this zone differs only in ID, if at all.
+ * @param other the <code>TimeZone</code> object to be compared with
+ * @return true if the given zone is the same as this one,
+ * with the possible exception of the ID
+ * @draft ICU 3.8
+ */
+ virtual UBool hasSameRules(const TimeZone& other) const;
+
+ /**
+ * Gets the first time zone transition after the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the first transition after the base time.
+ * @return TRUE if the transition is found.
+ * @draft ICU 3.8
+ */
+ virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * Gets the most recent time zone transition before the base time.
+ * @param base The base time.
+ * @param inclusive Whether the base time is inclusive or not.
+ * @param result Receives the most recent transition before the base time.
+ * @return TRUE if the transition is found.
+ * @draft ICU 3.8
+ */
+ virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
+
+ /**
+ * Returns the number of <code>TimeZoneRule</code>s which represents time transitions,
+ * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except
+ * <code>InitialTimeZoneRule</code>. The return value range is 0 or any positive value.
+ * @param status Receives error status code.
+ * @return The number of <code>TimeZoneRule</code>s representing time transitions.
+ * @draft ICU 3.8
+ */
+ virtual int32_t countTransitionRules(UErrorCode& status) /*const*/;
+
+ /**
+ * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code>
+ * which represent time transitions for this time zone. On successful return,
+ * the argument initial points to non-NULL <code>InitialTimeZoneRule</code> and
+ * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code>
+ * instances up to the size specified by trscount. The results are referencing the
+ * rule instance held by this time zone instance. Therefore, after this time zone
+ * is destructed, they are no longer available.
+ * @param initial Receives the initial timezone rule
+ * @param trsrules Receives the timezone transition rules
+ * @param trscount On input, specify the size of the array 'transitions' receiving
+ * the timezone transition rules. On output, actual number of
+ * rules filled in the array will be set.
+ * @param status Receives error status code.
+ * @draft ICU 3.8
+ */
+ virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/;
+
+private:
+ enum { DEFAULT_VTIMEZONE_LINES = 100 };
+
+ /**
+ * Default constructor.
+ */
+ VTimeZone();
+ static VTimeZone* createVTimeZone(VTZReader* reader);
+ void write(VTZWriter& writer, UErrorCode& status) const;
+ void write(UDate start, VTZWriter& writer, UErrorCode& status) /*const*/;
+ void writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) /*const*/;
+ void load(VTZReader& reader, UErrorCode& status);
+ void parse(UErrorCode& status);
+
+ void writeZone(VTZWriter& w, BasicTimeZone& basictz, UVector* customProps,
+ UErrorCode& status) const;
+
+ void writeHeaders(VTZWriter& w, UErrorCode& status) const;
+ void writeFooter(VTZWriter& writer, UErrorCode& status) const;
+
+ void writeZonePropsByTime(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset, UDate time, UBool withRDATE,
+ UErrorCode& status) const;
+ void writeZonePropsByDOM(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset,
+ int32_t month, int32_t dayOfMonth, UDate startTime, UDate untilTime,
+ UErrorCode& status) const;
+ void writeZonePropsByDOW(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset,
+ int32_t month, int32_t weekInMonth, int32_t dayOfWeek,
+ UDate startTime, UDate untilTime, UErrorCode& status) const;
+ void writeZonePropsByDOW_GEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset,
+ int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ UDate startTime, UDate untilTime, UErrorCode& status) const;
+ void writeZonePropsByDOW_GEQ_DOM_sub(VTZWriter& writer, int32_t month, int32_t dayOfMonth,
+ int32_t dayOfWeek, int32_t numDays,
+ UDate untilTime, int32_t fromOffset, UErrorCode& status) const;
+ void writeZonePropsByDOW_LEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset,
+ int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ UDate startTime, UDate untilTime, UErrorCode& status) const;
+ void writeFinalRule(VTZWriter& writer, UBool isDst, const AnnualTimeZoneRule* rule,
+ int32_t fromRawOffset, int32_t fromDSTSavings,
+ UDate startTime, UErrorCode& status) const;
+
+ void beginZoneProps(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset, UDate startTime, UErrorCode& status) const;
+ void endZoneProps(VTZWriter& writer, UBool isDst, UErrorCode& status) const;
+ void beginRRULE(VTZWriter& writer, int32_t month, UErrorCode& status) const;
+ void appendUNTIL(VTZWriter& writer, const UnicodeString& until, UErrorCode& status) const;
+
+ BasicTimeZone *tz;
+ UVector *vtzlines;
+ UnicodeString tzurl;
+ UDate lastmod;
+ UnicodeString olsonzid;
+ UnicodeString icutzver;
+
+public:
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.8
+ */
+ static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.8
+ */
+ virtual UClassID getDynamicClassID(void) const;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // VTZONE_H
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/i18n/unum.cpp b/Build/source/libs/icu/icu-xetex/i18n/unum.cpp
new file mode 100644
index 00000000000..1ba90922843
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/unum.cpp
@@ -0,0 +1,841 @@
+/*
+*******************************************************************************
+* Copyright (C) 1996-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* Modification History:
+*
+* Date Name Description
+* 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unum.h"
+
+#include "unicode/uloc.h"
+#include "unicode/numfmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/rbnf.h"
+#include "unicode/ustring.h"
+#include "unicode/fmtable.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/curramt.h"
+#include "uassert.h"
+#include "cpputils.h"
+
+
+U_NAMESPACE_USE
+
+
+U_CAPI UNumberFormat* U_EXPORT2
+unum_open( UNumberFormatStyle style,
+ const UChar* pattern,
+ int32_t patternLength,
+ const char* locale,
+ UParseError* parseErr,
+ UErrorCode* status)
+{
+
+ if(U_FAILURE(*status))
+ {
+ return 0;
+ }
+
+ UNumberFormat *retVal = 0;
+
+ switch(style) {
+ case UNUM_DECIMAL:
+ if(locale == 0)
+ retVal = (UNumberFormat*)NumberFormat::createInstance(*status);
+ else
+ retVal = (UNumberFormat*)NumberFormat::createInstance(Locale(locale),
+ *status);
+ break;
+
+ case UNUM_CURRENCY:
+ if(locale == 0)
+ retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(*status);
+ else
+ retVal = (UNumberFormat*)NumberFormat::createCurrencyInstance(Locale(locale),
+ *status);
+ break;
+
+ case UNUM_PERCENT:
+ if(locale == 0)
+ retVal = (UNumberFormat*)NumberFormat::createPercentInstance(*status);
+ else
+ retVal = (UNumberFormat*)NumberFormat::createPercentInstance(Locale(locale),
+ *status);
+ break;
+
+ case UNUM_SCIENTIFIC:
+ if(locale == 0)
+ retVal = (UNumberFormat*)NumberFormat::createScientificInstance(*status);
+ else
+ retVal = (UNumberFormat*)NumberFormat::createScientificInstance(Locale(locale),
+ *status);
+ break;
+
+ case UNUM_PATTERN_DECIMAL: {
+ UParseError tErr;
+ /* UnicodeString can handle the case when patternLength = -1. */
+ const UnicodeString pat(pattern, patternLength);
+ DecimalFormatSymbols *syms = 0;
+
+ if(parseErr==NULL){
+ parseErr = &tErr;
+ }
+
+ if(locale == 0)
+ syms = new DecimalFormatSymbols(*status);
+ else
+ syms = new DecimalFormatSymbols(Locale(locale), *status);
+
+ if(syms == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ retVal = (UNumberFormat*)new DecimalFormat(pat, syms, *parseErr, *status);
+ if(retVal == 0) {
+ delete syms;
+ }
+ } break;
+
+#if U_HAVE_RBNF
+ case UNUM_PATTERN_RULEBASED: {
+ UParseError tErr;
+ /* UnicodeString can handle the case when patternLength = -1. */
+ const UnicodeString pat(pattern, patternLength);
+
+ if(parseErr==NULL){
+ parseErr = &tErr;
+ }
+
+ retVal = (UNumberFormat*)new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
+ } break;
+
+ case UNUM_SPELLOUT:
+ retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
+ break;
+
+ case UNUM_ORDINAL:
+ retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
+ break;
+
+ case UNUM_DURATION:
+ retVal = (UNumberFormat*)new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
+ break;
+#endif
+
+ default:
+ *status = U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ if(retVal == 0 && U_SUCCESS(*status)) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+
+ return retVal;
+}
+
+U_CAPI void U_EXPORT2
+unum_close(UNumberFormat* fmt)
+{
+ delete (NumberFormat*) fmt;
+}
+
+U_CAPI UNumberFormat* U_EXPORT2
+unum_clone(const UNumberFormat *fmt,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status))
+ return 0;
+
+ Format *res = 0;
+ if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ res = ((const DecimalFormat*)fmt)->clone();
+ } else {
+ U_ASSERT(((const NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
+ res = ((const RuleBasedNumberFormat*)fmt)->clone();
+ }
+
+ if(res == 0) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+
+ return (UNumberFormat*) res;
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_format( const UNumberFormat* fmt,
+ int32_t number,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition *pos,
+ UErrorCode* status)
+{
+ return unum_formatInt64(fmt, number, result, resultLength, pos, status);
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_formatInt64(const UNumberFormat* fmt,
+ int64_t number,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition *pos,
+ UErrorCode* status)
+{
+ if(U_FAILURE(*status))
+ return -1;
+
+ UnicodeString res;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res.setTo(result, 0, resultLength);
+ }
+
+ FieldPosition fp;
+
+ if(pos != 0)
+ fp.setField(pos->field);
+
+ ((const NumberFormat*)fmt)->format(number, res, fp);
+
+ if(pos != 0) {
+ pos->beginIndex = fp.getBeginIndex();
+ pos->endIndex = fp.getEndIndex();
+ }
+
+ return res.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_formatDouble( const UNumberFormat* fmt,
+ double number,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition *pos, /* 0 if ignore */
+ UErrorCode* status)
+{
+
+ if(U_FAILURE(*status)) return -1;
+
+ UnicodeString res;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res.setTo(result, 0, resultLength);
+ }
+
+ FieldPosition fp;
+
+ if(pos != 0)
+ fp.setField(pos->field);
+
+ ((const NumberFormat*)fmt)->format(number, res, fp);
+
+ if(pos != 0) {
+ pos->beginIndex = fp.getBeginIndex();
+ pos->endIndex = fp.getEndIndex();
+ }
+
+ return res.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_formatDoubleCurrency(const UNumberFormat* fmt,
+ double number,
+ UChar* currency,
+ UChar* result,
+ int32_t resultLength,
+ UFieldPosition* pos, /* ignored if 0 */
+ UErrorCode* status) {
+ if (U_FAILURE(*status)) return -1;
+
+ UnicodeString res;
+ if (!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res.setTo(result, 0, resultLength);
+ }
+
+ FieldPosition fp;
+ if (pos != 0) {
+ fp.setField(pos->field);
+ }
+
+ Formattable n(new CurrencyAmount(number, currency, *status));
+ ((const NumberFormat*)fmt)->format(n, res, fp, *status);
+
+ if (pos != 0) {
+ pos->beginIndex = fp.getBeginIndex();
+ pos->endIndex = fp.getEndIndex();
+ }
+
+ return res.extract(result, resultLength, *status);
+}
+
+static void
+parseRes(Formattable& res,
+ const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos /* 0 = start */,
+ UBool parseCurrency,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status))
+ return;
+
+ int32_t len = (textLength == -1 ? u_strlen(text) : textLength);
+ const UnicodeString src((UChar*)text, len, len);
+ ParsePosition pp;
+
+ if(parsePos != 0)
+ pp.setIndex(*parsePos);
+
+ if (parseCurrency) {
+ ((const NumberFormat*)fmt)->parseCurrency(src, res, pp);
+ } else {
+ ((const NumberFormat*)fmt)->parse(src, res, pp);
+ }
+
+ if(parsePos != 0) {
+ if(pp.getErrorIndex() == -1)
+ *parsePos = pp.getIndex();
+ else {
+ *parsePos = pp.getErrorIndex();
+ *status = U_PARSE_ERROR;
+ }
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_parse( const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos /* 0 = start */,
+ UErrorCode *status)
+{
+ Formattable res;
+ parseRes(res, fmt, text, textLength, parsePos, FALSE, status);
+ return res.getLong(*status);
+}
+
+U_CAPI int64_t U_EXPORT2
+unum_parseInt64( const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos /* 0 = start */,
+ UErrorCode *status)
+{
+ Formattable res;
+ parseRes(res, fmt, text, textLength, parsePos, FALSE, status);
+ return res.getInt64(*status);
+}
+
+U_CAPI double U_EXPORT2
+unum_parseDouble( const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t *parsePos /* 0 = start */,
+ UErrorCode *status)
+{
+ Formattable res;
+ parseRes(res, fmt, text, textLength, parsePos, FALSE, status);
+ return res.getDouble(*status);
+}
+
+U_CAPI double U_EXPORT2
+unum_parseDoubleCurrency(const UNumberFormat* fmt,
+ const UChar* text,
+ int32_t textLength,
+ int32_t* parsePos, /* 0 = start */
+ UChar* currency,
+ UErrorCode* status) {
+ Formattable res;
+ parseRes(res, fmt, text, textLength, parsePos, TRUE, status);
+ currency[0] = 0;
+ if (res.getType() == Formattable::kObject &&
+ res.getObject()->getDynamicClassID() == CurrencyAmount::getStaticClassID()) {
+ const CurrencyAmount* c = (const CurrencyAmount*) res.getObject();
+ u_strcpy(currency, c->getISOCurrency());
+ }
+ return res.getDouble(*status);
+}
+
+U_CAPI const char* U_EXPORT2
+unum_getAvailable(int32_t index)
+{
+ return uloc_getAvailable(index);
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_countAvailable()
+{
+ return uloc_countAvailable();
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_getAttribute(const UNumberFormat* fmt,
+ UNumberFormatAttribute attr)
+{
+ if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ const DecimalFormat* df = (const DecimalFormat*) fmt;
+ switch(attr) {
+ case UNUM_PARSE_INT_ONLY:
+ return df->isParseIntegerOnly();
+
+ case UNUM_GROUPING_USED:
+ return df->isGroupingUsed();
+
+ case UNUM_DECIMAL_ALWAYS_SHOWN:
+ return df->isDecimalSeparatorAlwaysShown();
+
+ case UNUM_MAX_INTEGER_DIGITS:
+ return df->getMaximumIntegerDigits();
+
+ case UNUM_MIN_INTEGER_DIGITS:
+ return df->getMinimumIntegerDigits();
+
+ case UNUM_INTEGER_DIGITS:
+ // TBD: what should this return?
+ return df->getMinimumIntegerDigits();
+
+ case UNUM_MAX_FRACTION_DIGITS:
+ return df->getMaximumFractionDigits();
+
+ case UNUM_MIN_FRACTION_DIGITS:
+ return df->getMinimumFractionDigits();
+
+ case UNUM_FRACTION_DIGITS:
+ // TBD: what should this return?
+ return df->getMinimumFractionDigits();
+
+ case UNUM_SIGNIFICANT_DIGITS_USED:
+ return df->areSignificantDigitsUsed();
+
+ case UNUM_MAX_SIGNIFICANT_DIGITS:
+ return df->getMaximumSignificantDigits();
+
+ case UNUM_MIN_SIGNIFICANT_DIGITS:
+ return df->getMinimumSignificantDigits();
+
+ case UNUM_MULTIPLIER:
+ return df->getMultiplier();
+
+ case UNUM_GROUPING_SIZE:
+ return df->getGroupingSize();
+
+ case UNUM_ROUNDING_MODE:
+ return df->getRoundingMode();
+
+ case UNUM_FORMAT_WIDTH:
+ return df->getFormatWidth();
+
+ case UNUM_PADDING_POSITION:
+ return df->getPadPosition();
+
+ case UNUM_SECONDARY_GROUPING_SIZE:
+ return df->getSecondaryGroupingSize();
+
+ default:
+ /* enums out of sync? unsupported enum? */
+ break;
+ }
+ } else {
+ U_ASSERT(((const NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
+ if (attr == UNUM_LENIENT_PARSE) {
+#if !UCONFIG_NO_COLLATION
+ return ((const RuleBasedNumberFormat*)fmt)->isLenient();
+#endif
+ }
+ }
+
+ return -1;
+}
+
+U_CAPI void U_EXPORT2
+unum_setAttribute( UNumberFormat* fmt,
+ UNumberFormatAttribute attr,
+ int32_t newValue)
+{
+ if (((NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ DecimalFormat* df = (DecimalFormat*) fmt;
+ switch(attr) {
+ case UNUM_PARSE_INT_ONLY:
+ df->setParseIntegerOnly(newValue!=0);
+ break;
+
+ case UNUM_GROUPING_USED:
+ df->setGroupingUsed(newValue!=0);
+ break;
+
+ case UNUM_DECIMAL_ALWAYS_SHOWN:
+ df->setDecimalSeparatorAlwaysShown(newValue!=0);
+ break;
+
+ case UNUM_MAX_INTEGER_DIGITS:
+ df->setMaximumIntegerDigits(newValue);
+ break;
+
+ case UNUM_MIN_INTEGER_DIGITS:
+ df->setMinimumIntegerDigits(newValue);
+ break;
+
+ case UNUM_INTEGER_DIGITS:
+ df->setMinimumIntegerDigits(newValue);
+ df->setMaximumIntegerDigits(newValue);
+ break;
+
+ case UNUM_MAX_FRACTION_DIGITS:
+ df->setMaximumFractionDigits(newValue);
+ break;
+
+ case UNUM_MIN_FRACTION_DIGITS:
+ df->setMinimumFractionDigits(newValue);
+ break;
+
+ case UNUM_FRACTION_DIGITS:
+ df->setMinimumFractionDigits(newValue);
+ df->setMaximumFractionDigits(newValue);
+ break;
+
+ case UNUM_SIGNIFICANT_DIGITS_USED:
+ df->setSignificantDigitsUsed(newValue!=0);
+ break;
+
+ case UNUM_MAX_SIGNIFICANT_DIGITS:
+ df->setMaximumSignificantDigits(newValue);
+ break;
+
+ case UNUM_MIN_SIGNIFICANT_DIGITS:
+ df->setMinimumSignificantDigits(newValue);
+ break;
+
+ case UNUM_MULTIPLIER:
+ df->setMultiplier(newValue);
+ break;
+
+ case UNUM_GROUPING_SIZE:
+ df->setGroupingSize(newValue);
+ break;
+
+ case UNUM_ROUNDING_MODE:
+ df->setRoundingMode((DecimalFormat::ERoundingMode)newValue);
+ break;
+
+ case UNUM_FORMAT_WIDTH:
+ df->setFormatWidth(newValue);
+ break;
+
+ case UNUM_PADDING_POSITION:
+ /** The position at which padding will take place. */
+ df->setPadPosition((DecimalFormat::EPadPosition)newValue);
+ break;
+
+ case UNUM_SECONDARY_GROUPING_SIZE:
+ df->setSecondaryGroupingSize(newValue);
+ break;
+
+ default:
+ /* Shouldn't get here anyway */
+ break;
+ }
+ } else {
+ U_ASSERT(((NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
+ if (attr == UNUM_LENIENT_PARSE) {
+#if !UCONFIG_NO_COLLATION
+ ((RuleBasedNumberFormat*)fmt)->setLenient((UBool)newValue);
+#endif
+ }
+ }
+}
+
+U_CAPI double U_EXPORT2
+unum_getDoubleAttribute(const UNumberFormat* fmt,
+ UNumberFormatAttribute attr)
+{
+ if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID() &&
+ attr == UNUM_ROUNDING_INCREMENT) {
+ return ((const DecimalFormat*)fmt)->getRoundingIncrement();
+ } else {
+ return -1.0;
+ }
+}
+
+U_CAPI void U_EXPORT2
+unum_setDoubleAttribute( UNumberFormat* fmt,
+ UNumberFormatAttribute attr,
+ double newValue)
+{
+ if (((NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID() &&
+ attr == UNUM_ROUNDING_INCREMENT) {
+ ((DecimalFormat*)fmt)->setRoundingIncrement(newValue);
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_getTextAttribute(const UNumberFormat* fmt,
+ UNumberFormatTextAttribute tag,
+ UChar* result,
+ int32_t resultLength,
+ UErrorCode* status)
+{
+ if(U_FAILURE(*status))
+ return -1;
+
+ UnicodeString res;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ res.setTo(result, 0, resultLength);
+ }
+
+ if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ const DecimalFormat* df = (const DecimalFormat*) fmt;
+ switch(tag) {
+ case UNUM_POSITIVE_PREFIX:
+ df->getPositivePrefix(res);
+ break;
+
+ case UNUM_POSITIVE_SUFFIX:
+ df->getPositiveSuffix(res);
+ break;
+
+ case UNUM_NEGATIVE_PREFIX:
+ df->getNegativePrefix(res);
+ break;
+
+ case UNUM_NEGATIVE_SUFFIX:
+ df->getNegativeSuffix(res);
+ break;
+
+ case UNUM_PADDING_CHARACTER:
+ res = df->getPadCharacterString();
+ break;
+
+ case UNUM_CURRENCY_CODE:
+ res = UnicodeString(df->getCurrency());
+ break;
+
+ default:
+ *status = U_UNSUPPORTED_ERROR;
+ return -1;
+ }
+ } else {
+ U_ASSERT(((const NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
+ const RuleBasedNumberFormat* rbnf = (const RuleBasedNumberFormat*)fmt;
+ if (tag == UNUM_DEFAULT_RULESET) {
+ res = rbnf->getDefaultRuleSetName();
+ } else if (tag == UNUM_PUBLIC_RULESETS) {
+ int32_t count = rbnf->getNumberOfRuleSetNames();
+ for (int i = 0; i < count; ++i) {
+ res += rbnf->getRuleSetName(i);
+ res += (UChar)0x003b; // semicolon
+ }
+ } else {
+ *status = U_UNSUPPORTED_ERROR;
+ return -1;
+ }
+ }
+
+ return res.extract(result, resultLength, *status);
+}
+
+U_CAPI void U_EXPORT2
+unum_setTextAttribute( UNumberFormat* fmt,
+ UNumberFormatTextAttribute tag,
+ const UChar* newValue,
+ int32_t newValueLength,
+ UErrorCode *status)
+{
+ if(U_FAILURE(*status))
+ return;
+
+ int32_t len = (newValueLength == -1 ? u_strlen(newValue) : newValueLength);
+ const UnicodeString val((UChar*)newValue, len, len);
+
+ if (((NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ DecimalFormat* df = (DecimalFormat*) fmt;
+ switch(tag) {
+ case UNUM_POSITIVE_PREFIX:
+ df->setPositivePrefix(val);
+ break;
+
+ case UNUM_POSITIVE_SUFFIX:
+ df->setPositiveSuffix(val);
+ break;
+
+ case UNUM_NEGATIVE_PREFIX:
+ df->setNegativePrefix(val);
+ break;
+
+ case UNUM_NEGATIVE_SUFFIX:
+ df->setNegativeSuffix(val);
+ break;
+
+ case UNUM_PADDING_CHARACTER:
+ df->setPadCharacter(*newValue);
+ break;
+
+ case UNUM_CURRENCY_CODE:
+ df->setCurrency(newValue, *status);
+ break;
+
+ default:
+ *status = U_UNSUPPORTED_ERROR;
+ break;
+ }
+ } else {
+ U_ASSERT(((NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
+ if (tag == UNUM_DEFAULT_RULESET) {
+ ((RuleBasedNumberFormat*)fmt)->setDefaultRuleSet(newValue, *status);
+ } else {
+ *status = U_UNSUPPORTED_ERROR;
+ }
+ }
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_toPattern( const UNumberFormat* fmt,
+ UBool isPatternLocalized,
+ UChar* result,
+ int32_t resultLength,
+ UErrorCode* status)
+{
+ if(U_FAILURE(*status))
+ return -1;
+
+ UnicodeString pat;
+ if(!(result==NULL && resultLength==0)) {
+ // NULL destination for pure preflighting: empty dummy string
+ // otherwise, alias the destination buffer
+ pat.setTo(result, 0, resultLength);
+ }
+
+ if (((const NumberFormat*)fmt)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ const DecimalFormat* df = (const DecimalFormat*) fmt;
+ if(isPatternLocalized)
+ df->toLocalizedPattern(pat);
+ else
+ df->toPattern(pat);
+ } else {
+ U_ASSERT(((const NumberFormat*)fmt)->getDynamicClassID() == RuleBasedNumberFormat::getStaticClassID());
+ pat = ((const RuleBasedNumberFormat*)fmt)->getRules();
+ }
+ return pat.extract(result, resultLength, *status);
+}
+
+U_CAPI int32_t U_EXPORT2
+unum_getSymbol(const UNumberFormat *fmt,
+ UNumberFormatSymbol symbol,
+ UChar *buffer,
+ int32_t size,
+ UErrorCode *status)
+{
+ if(status==NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if(fmt==NULL || (uint16_t)symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ if (((const NumberFormat*)fmt)->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ *status = U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ return ((const DecimalFormat *)fmt)->
+ getDecimalFormatSymbols()->
+ getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
+ extract(buffer, size, *status);
+}
+
+U_CAPI void U_EXPORT2
+unum_setSymbol(UNumberFormat *fmt,
+ UNumberFormatSymbol symbol,
+ const UChar *value,
+ int32_t length,
+ UErrorCode *status)
+{
+ if(status==NULL || U_FAILURE(*status)) {
+ return;
+ }
+
+ if(fmt==NULL || (uint16_t)symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==NULL || length<-1) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ if (((NumberFormat*)fmt)->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ *status = U_UNSUPPORTED_ERROR;
+ return;
+ }
+
+ DecimalFormatSymbols symbols(*((DecimalFormat *)fmt)->getDecimalFormatSymbols());
+ symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
+ UnicodeString(value, length)); /* UnicodeString can handle the case when length = -1. */
+ ((DecimalFormat *)fmt)->setDecimalFormatSymbols(symbols);
+}
+
+U_CAPI void U_EXPORT2
+unum_applyPattern( UNumberFormat *format,
+ UBool localized,
+ const UChar *pattern,
+ int32_t patternLength,
+ UParseError *parseError,
+ UErrorCode* status)
+{
+ UErrorCode tStatus = U_ZERO_ERROR;
+ UParseError tParseError;
+
+ if(parseError == NULL){
+ parseError = &tParseError;
+ }
+
+ if(status==NULL){
+ status = &tStatus;
+ }
+
+ int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
+ const UnicodeString pat((UChar*)pattern, len, len);
+
+ // Verify if the object passed is a DecimalFormat object
+ if (((NumberFormat*)format)->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ if(localized) {
+ ((DecimalFormat*)format)->applyLocalizedPattern(pat,*parseError, *status);
+ } else {
+ ((DecimalFormat*)format)->applyPattern(pat,*parseError, *status);
+ }
+ } else {
+ *status = U_UNSUPPORTED_ERROR;
+ return;
+ }
+}
+
+U_CAPI const char* U_EXPORT2
+unum_getLocaleByType(const UNumberFormat *fmt,
+ ULocDataLocaleType type,
+ UErrorCode* status)
+{
+ if (fmt == NULL) {
+ if (U_SUCCESS(*status)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return NULL;
+ }
+ return ((const Format*)fmt)->getLocaleID(type, *status);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/uregex.cpp b/Build/source/libs/icu/icu-xetex/i18n/uregex.cpp
new file mode 100644
index 00000000000..7207b6ece8b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/uregex.cpp
@@ -0,0 +1,1105 @@
+/*
+*******************************************************************************
+* Copyright (C) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: regex.cpp
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/regex.h"
+#include "unicode/uregex.h"
+#include "unicode/unistr.h"
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "unicode/uobject.h"
+#include "umutex.h"
+#include "uassert.h"
+#include "cmemory.h"
+
+U_NAMESPACE_USE
+
+struct URegularExpression: public UMemory {
+public:
+ URegularExpression();
+ ~URegularExpression();
+ int32_t fMagic;
+ RegexPattern *fPat;
+ int32_t *fPatRefCount;
+ UChar *fPatString;
+ int32_t fPatStringLen;
+ RegexMatcher *fMatcher;
+ const UChar *fText; // Text from setText()
+ int32_t fTextLength; // Length provided by user with setText(), which
+ // may be -1.
+
+ UnicodeString fTextString; // The setText(text) is wrapped into a UnicodeString.
+ // TODO: regexp engine should not depend on UnicodeString.
+};
+
+static const int32_t REXP_MAGIC = 0x72657870; // "rexp" in ASCII
+
+URegularExpression::URegularExpression() {
+ fMagic = REXP_MAGIC;
+ fPat = NULL;
+ fPatRefCount = NULL;
+ fPatString = NULL;
+ fPatStringLen = 0;
+ fMatcher = NULL;
+ fText = NULL;
+ fTextLength = 0;
+}
+
+URegularExpression::~URegularExpression() {
+ delete fMatcher;
+ fMatcher = NULL;
+ if (fPatRefCount!=NULL && umtx_atomic_dec(fPatRefCount)==0) {
+ delete fPat;
+ uprv_free(fPatString);
+ uprv_free(fPatRefCount);
+ }
+ fMagic = 0;
+}
+
+//----------------------------------------------------------------------------------------
+//
+// validateRE Do boilerplate style checks on API function parameters.
+// Return TRUE if they look OK.
+//----------------------------------------------------------------------------------------
+static UBool validateRE(const URegularExpression *re, UErrorCode *status, UBool requiresText = TRUE) {
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+ if (re == NULL || re->fMagic != REXP_MAGIC) {
+ // U_ASSERT(FALSE);
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
+ }
+ if (requiresText && re->fText == NULL) {
+ *status = U_REGEX_INVALID_STATE;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------------------
+//
+// uregex_open
+//
+//----------------------------------------------------------------------------------------
+U_CAPI URegularExpression * U_EXPORT2
+uregex_open( const UChar *pattern,
+ int32_t patternLength,
+ uint32_t flags,
+ UParseError *pe,
+ UErrorCode *status) {
+
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ if (pattern == NULL || patternLength < -1 || patternLength == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ int32_t actualPatLen = patternLength;
+ if (actualPatLen == -1) {
+ actualPatLen = u_strlen(pattern);
+ }
+
+ URegularExpression *re = new URegularExpression;
+ int32_t *refC = (int32_t *)uprv_malloc(sizeof(int32_t));
+ UChar *patBuf = (UChar *)uprv_malloc(sizeof(UChar)*(actualPatLen+1));
+ if (re == NULL || refC == NULL || patBuf == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ delete re;
+ uprv_free(refC);
+ uprv_free(patBuf);
+ return NULL;
+ }
+ re->fPatRefCount = refC;
+ *re->fPatRefCount = 1;
+
+ //
+ // Make a copy of the pattern string, so we can return it later if asked.
+ // For compiling the pattern, we will use a read-only-aliased UnicodeString
+ // of this local copy, to avoid making even more copies.
+ //
+ re->fPatString = patBuf;
+ re->fPatStringLen = patternLength;
+ u_memcpy(patBuf, pattern, actualPatLen);
+ patBuf[actualPatLen] = 0;
+ UnicodeString patString(patternLength==-1, patBuf, patternLength);
+
+ //
+ // Compile the pattern
+ //
+ if (pe != NULL) {
+ re->fPat = RegexPattern::compile(patString, flags, *pe, *status);
+ } else {
+ re->fPat = RegexPattern::compile(patString, flags, *status);
+ }
+ if (U_FAILURE(*status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Create the matcher object
+ //
+ re->fMatcher = re->fPat->matcher(*status);
+ if (U_SUCCESS(*status)) {
+ return re;
+ }
+
+ErrorExit:
+ delete re;
+ return NULL;
+
+}
+
+//----------------------------------------------------------------------------------------
+//
+// uregex_close
+//
+//----------------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_close(URegularExpression *re) {
+ UErrorCode status = U_ZERO_ERROR;
+ if (validateRE(re, &status, FALSE) == FALSE) {
+ return;
+ }
+ delete re;
+}
+
+
+//----------------------------------------------------------------------------------------
+//
+// uregex_clone
+//
+//----------------------------------------------------------------------------------------
+U_CAPI URegularExpression * U_EXPORT2
+uregex_clone(const URegularExpression *source, UErrorCode *status) {
+ if (validateRE(source, status, FALSE) == FALSE) {
+ return NULL;
+ }
+
+ URegularExpression *clone = new URegularExpression;
+ if (clone == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ clone->fMatcher = source->fPat->matcher(*status);
+ if (U_FAILURE(*status)) {
+ delete clone;
+ return NULL;
+ }
+ if (clone == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ clone->fPat = source->fPat;
+ clone->fPatRefCount = source->fPatRefCount;
+ clone->fPatString = source->fPatString;
+ clone->fPatStringLen = source->fPatStringLen;
+ umtx_atomic_inc(source->fPatRefCount);
+ // Note: fText is not cloned.
+
+ return clone;
+}
+
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_pattern
+//
+//------------------------------------------------------------------------------
+U_CAPI const UChar * U_EXPORT2
+uregex_pattern(const URegularExpression *regexp,
+ int32_t *patLength,
+ UErrorCode *status) {
+
+ if (validateRE(regexp, status, FALSE) == FALSE) {
+ return NULL;
+ }
+ if (patLength != NULL) {
+ *patLength = regexp->fPatStringLen;
+ }
+ return regexp->fPatString;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_flags
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_flags(const URegularExpression *regexp, UErrorCode *status) {
+ if (validateRE(regexp, status, FALSE) == FALSE) {
+ return 0;
+ }
+ int32_t flags = regexp->fPat->flags();
+ return flags;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_setText
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_setText(URegularExpression *regexp,
+ const UChar *text,
+ int32_t textLength,
+ UErrorCode *status) {
+ if (validateRE(regexp, status, FALSE) == FALSE) {
+ return;
+ }
+ if (text == NULL || textLength < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ regexp->fText = text;
+ regexp->fTextLength = textLength;
+ UBool isTerminated = (textLength == -1);
+
+ regexp->fTextString.setTo(isTerminated, text, textLength);
+ regexp->fMatcher->reset(regexp->fTextString);
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_getText
+//
+//------------------------------------------------------------------------------
+U_CAPI const UChar * U_EXPORT2
+uregex_getText(URegularExpression *regexp,
+ int32_t *textLength,
+ UErrorCode *status) {
+ if (validateRE(regexp, status, FALSE) == FALSE) {
+ return NULL;
+ }
+ if (textLength != NULL) {
+ *textLength = regexp->fTextLength;
+ }
+ return regexp->fText;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_matches
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_matches(URegularExpression *regexp,
+ int32_t startIndex,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return FALSE;
+ }
+ UBool result = regexp->fMatcher->matches(startIndex, *status);
+ return result;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_lookingAt
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_lookingAt(URegularExpression *regexp,
+ int32_t startIndex,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return FALSE;
+ }
+ UBool result = regexp->fMatcher->lookingAt(startIndex, *status);
+ return result;
+}
+
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_find
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_find(URegularExpression *regexp,
+ int32_t startIndex,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return FALSE;
+ }
+ UBool result = regexp->fMatcher->find(startIndex, *status);
+ return result;
+}
+
+//------------------------------------------------------------------------------
+//
+// uregex_findNext
+//
+//------------------------------------------------------------------------------
+U_CAPI UBool U_EXPORT2
+uregex_findNext(URegularExpression *regexp,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return FALSE;
+ }
+ UBool result = regexp->fMatcher->find();
+ return result;
+}
+
+//------------------------------------------------------------------------------
+//
+// uregex_groupCount
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_groupCount(URegularExpression *regexp,
+ UErrorCode *status) {
+ if (validateRE(regexp, status, FALSE) == FALSE) {
+ return 0;
+ }
+ int32_t result = regexp->fMatcher->groupCount();
+ return result;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_group
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_group(URegularExpression *regexp,
+ int32_t groupNum,
+ UChar *dest,
+ int32_t destCapacity,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return 0;
+ }
+ if (destCapacity < 0 || (destCapacity > 0 && dest == NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ //
+ // Pick up the range of characters from the matcher
+ //
+ int32_t startIx = regexp->fMatcher->start(groupNum, *status);
+ int32_t endIx = regexp->fMatcher->end (groupNum, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ //
+ // Trim length based on buffer capacity
+ //
+ int32_t fullLength = endIx - startIx;
+ int32_t copyLength = fullLength;
+ if (copyLength < destCapacity) {
+ dest[copyLength] = 0;
+ } else if (copyLength == destCapacity) {
+ *status = U_STRING_NOT_TERMINATED_WARNING;
+ } else {
+ copyLength = destCapacity;
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+
+ //
+ // Copy capture group to user's buffer
+ //
+ if (copyLength > 0) {
+ u_memcpy(dest, &regexp->fText[startIx], copyLength);
+ }
+ return fullLength;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_start
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_start(URegularExpression *regexp,
+ int32_t groupNum,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return 0;
+ }
+ int32_t result = regexp->fMatcher->start(groupNum, *status);
+ return result;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_end
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_end(URegularExpression *regexp,
+ int32_t groupNum,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return 0;
+ }
+ int32_t result = regexp->fMatcher->end(groupNum, *status);
+ return result;
+}
+
+//------------------------------------------------------------------------------
+//
+// uregex_reset
+//
+//------------------------------------------------------------------------------
+U_CAPI void U_EXPORT2
+uregex_reset(URegularExpression *regexp,
+ int32_t index,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return;
+ }
+ regexp->fMatcher->reset(index, *status);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_replaceAll
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_replaceAll(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar *destBuf,
+ int32_t destCapacity,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return 0;
+ }
+ if (replacementText == NULL || replacementLength < -1 ||
+ destBuf == NULL && destCapacity > 0 ||
+ destCapacity < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ int32_t len = 0;
+ uregex_reset(regexp, 0, status);
+ while (uregex_findNext(regexp, status)) {
+ len += uregex_appendReplacement(regexp, replacementText, replacementLength,
+ &destBuf, &destCapacity, status);
+ }
+ len += uregex_appendTail(regexp, &destBuf, &destCapacity, status);
+
+ return len;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_replaceFirst
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_replaceFirst(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar *destBuf,
+ int32_t destCapacity,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return 0;
+ }
+ if (replacementText == NULL || replacementLength < -1 ||
+ destBuf == NULL && destCapacity > 0 ||
+ destCapacity < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ int32_t len = 0;
+ UBool findSucceeded;
+ uregex_reset(regexp, 0, status);
+ findSucceeded = uregex_find(regexp, 0, status);
+ if (findSucceeded) {
+ len = uregex_appendReplacement(regexp, replacementText, replacementLength,
+ &destBuf, &destCapacity, status);
+ }
+ len += uregex_appendTail(regexp, &destBuf, &destCapacity, status);
+
+ return len;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_appendReplacement
+//
+//------------------------------------------------------------------------------
+
+
+//
+// Dummy class, because these functions need to be friends of class RegexMatcher,
+// and stand-alone C functions don't work as friends
+//
+U_NAMESPACE_BEGIN
+class RegexCImpl {
+ public:
+ inline static int32_t appendReplacement(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status);
+
+ inline static int32_t appendTail(URegularExpression *regexp,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status);
+};
+U_NAMESPACE_END
+
+
+//
+// Call-back function for u_unescapeAt(), used when we encounter
+// \uxxxx or \Uxxxxxxxxx escapes in the replacement text.
+//
+U_CDECL_BEGIN
+static UChar U_CALLCONV
+unescape_charAt(int32_t offset, void *context) {
+ UChar c16 = ((UChar *)context)[offset];
+ return c16;
+}
+U_CDECL_END
+
+
+static const UChar BACKSLASH = 0x5c;
+static const UChar DOLLARSIGN = 0x24;
+
+//
+// Move a character to an output buffer, with bounds checking on the index.
+// Index advances even if capacity is exceeded, for preflight size computations.
+// This little sequence is used a LOT.
+//
+static inline void appendToBuf(UChar c, int32_t *idx, UChar *buf, int32_t bufCapacity) {
+ if (*idx < bufCapacity) {
+ buf[*idx] = c;
+ }
+ (*idx)++;
+}
+
+
+//
+// appendReplacement, the actual implementation.
+//
+int32_t RegexCImpl::appendReplacement(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status) {
+
+ // If we come in with a buffer overflow error, don't suppress the operation.
+ // A series of appendReplacements, appendTail need to correctly preflight
+ // the buffer size when an overflow happens somewhere in the middle.
+ UBool pendingBufferOverflow = FALSE;
+ if (*status == U_BUFFER_OVERFLOW_ERROR && destCapacity == 0) {
+ pendingBufferOverflow = TRUE;
+ *status = U_ZERO_ERROR;
+ }
+
+ //
+ // Validate all paramters
+ //
+ if (validateRE(regexp, status) == FALSE) {
+ return 0;
+ }
+ if (replacementText == NULL || replacementLength < -1 ||
+ destCapacity == NULL || destBuf == NULL ||
+ *destBuf == NULL && *destCapacity > 0 ||
+ *destCapacity < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ RegexMatcher *m = regexp->fMatcher;
+ if (m->fMatch == FALSE) {
+ *status = U_REGEX_INVALID_STATE;
+ return 0;
+ }
+
+ UChar *dest = *destBuf;
+ int32_t capacity = *destCapacity;
+ int32_t destIdx = 0;
+ int32_t i;
+
+ // If it wasn't supplied by the caller, get the length of the replacement text.
+ // TODO: slightly smarter logic in the copy loop could watch for the NUL on
+ // the fly and avoid this step.
+ if (replacementLength == -1) {
+ replacementLength = u_strlen(replacementText);
+ }
+
+ // Copy input string from the end of previous match to start of current match
+ for (i=m->fLastMatchEnd; i<m->fMatchStart; i++) {
+ appendToBuf(regexp->fText[i], &destIdx, dest, capacity);
+ }
+
+
+
+ // scan the replacement text, looking for substitutions ($n) and \escapes.
+ int32_t replIdx = 0;
+ while (replIdx < replacementLength) {
+ UChar c = replacementText[replIdx];
+ replIdx++;
+ if (c != DOLLARSIGN && c != BACKSLASH) {
+ // Common case, no substitution, no escaping,
+ // just copy the char to the dest buf.
+ appendToBuf(c, &destIdx, dest, capacity);
+ continue;
+ }
+
+ if (c == BACKSLASH) {
+ // Backslash Escape. Copy the following char out without further checks.
+ // Note: Surrogate pairs don't need any special handling
+ // The second half wont be a '$' or a '\', and
+ // will move to the dest normally on the next
+ // loop iteration.
+ if (replIdx >= replacementLength) {
+ break;
+ }
+ c = replacementText[replIdx];
+
+ if (c==0x55/*U*/ || c==0x75/*u*/) {
+ // We have a \udddd or \Udddddddd escape sequence.
+ UChar32 escapedChar =
+ u_unescapeAt(unescape_charAt,
+ &replIdx, // Index is updated by unescapeAt
+ replacementLength, // Length of replacement text
+ (void *)replacementText);
+
+ if (escapedChar != (UChar32)0xFFFFFFFF) {
+ if (escapedChar <= 0xffff) {
+ appendToBuf((UChar)escapedChar, &destIdx, dest, capacity);
+ } else {
+ appendToBuf(U16_LEAD(escapedChar), &destIdx, dest, capacity);
+ appendToBuf(U16_TRAIL(escapedChar), &destIdx, dest, capacity);
+ }
+ continue;
+ }
+ // Note: if the \u escape was invalid, just fall through and
+ // treat it as a plain \<anything> escape.
+ }
+
+ // Plain backslash escape. Just put out the escaped character.
+ appendToBuf(c, &destIdx, dest, capacity);
+
+ replIdx++;
+ continue;
+ }
+
+
+
+ // We've got a $. Pick up a capture group number if one follows.
+ // Consume at most the number of digits necessary for the largest capture
+ // number that is valid for this pattern.
+
+ int32_t numDigits = 0;
+ int32_t groupNum = 0;
+ UChar32 digitC;
+ for (;;) {
+ if (replIdx >= replacementLength) {
+ break;
+ }
+ U16_GET(replacementText, 0, replIdx, replacementLength, digitC);
+ if (u_isdigit(digitC) == FALSE) {
+ break;
+ }
+
+ U16_FWD_1(replacementText, replIdx, replacementLength);
+ groupNum=groupNum*10 + u_charDigitValue(digitC);
+ numDigits++;
+ if (numDigits >= m->fPattern->fMaxCaptureDigits) {
+ break;
+ }
+ }
+
+
+ if (numDigits == 0) {
+ // The $ didn't introduce a group number at all.
+ // Treat it as just part of the substitution text.
+ appendToBuf(DOLLARSIGN, &destIdx, dest, capacity);
+ continue;
+ }
+
+ // Finally, append the capture group data to the destination.
+ int32_t capacityRemaining = capacity - destIdx;
+ if (capacityRemaining < 0) {
+ capacityRemaining = 0;
+ }
+ destIdx += uregex_group(regexp, groupNum, dest+destIdx, capacityRemaining, status);
+ if (*status == U_BUFFER_OVERFLOW_ERROR) {
+ // Ignore buffer overflow when extracting the group. We need to
+ // continue on to get full size of the untruncated result. We will
+ // raise our own buffer overflow error at the end.
+ *status = U_ZERO_ERROR;
+ }
+
+ if (U_FAILURE(*status)) {
+ // Can fail if group number is out of range.
+ break;
+ }
+
+ }
+
+ //
+ // Nul Terminate the dest buffer if possible.
+ // Set the appropriate buffer overflow or not terminated error, if needed.
+ //
+ if (destIdx < capacity) {
+ dest[destIdx] = 0;
+ } else if (destIdx == *destCapacity) {
+ *status = U_STRING_NOT_TERMINATED_WARNING;
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+
+ //
+ // Return an updated dest buffer and capacity to the caller.
+ //
+ if (destIdx > 0 && *destCapacity > 0) {
+ if (destIdx < capacity) {
+ *destBuf += destIdx;
+ *destCapacity -= destIdx;
+ } else {
+ *destBuf += capacity;
+ *destCapacity = 0;
+ }
+ }
+
+ // If we came in with a buffer overflow, make sure we go out with one also.
+ // (A zero length match right at the end of the previous match could
+ // make this function succeed even though a previous call had overflowed the buf)
+ if (pendingBufferOverflow && U_SUCCESS(*status)) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+
+ return destIdx;
+}
+
+//
+// appendReplacement the acutal API function,
+//
+U_CAPI int32_t U_EXPORT2
+uregex_appendReplacement(URegularExpression *regexp,
+ const UChar *replacementText,
+ int32_t replacementLength,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status) {
+ return RegexCImpl::appendReplacement(
+ regexp, replacementText, replacementLength,destBuf, destCapacity, status);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_appendTail
+//
+//------------------------------------------------------------------------------
+int32_t RegexCImpl::appendTail(URegularExpression *regexp,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status) {
+
+ // If we come in with a buffer overflow error, don't suppress the operation.
+ // A series of appendReplacements, appendTail need to correctly preflight
+ // the buffer size when an overflow happens somewhere in the middle.
+ UBool pendingBufferOverflow = FALSE;
+ if (*status == U_BUFFER_OVERFLOW_ERROR && *destCapacity == 0) {
+ pendingBufferOverflow = TRUE;
+ *status = U_ZERO_ERROR;
+ }
+
+ if (validateRE(regexp, status) == FALSE) {
+ return 0;
+ }
+ if (destCapacity == NULL || destBuf == NULL ||
+ *destBuf == NULL && *destCapacity > 0 ||
+ *destCapacity < 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ RegexMatcher *m = regexp->fMatcher;
+
+ int32_t srcIdx;
+ if (m->fMatch) {
+ // The most recent call to find() succeeded.
+ srcIdx = m->fMatchEnd;
+ } else {
+ // The last call to find() on this matcher failed().
+ // Look back to the end of the last find() that succeeded for src index.
+ srcIdx = m->fLastMatchEnd;
+ if (srcIdx == -1) {
+ // There has been no successful match with this matcher.
+ // We want to copy the whole string.
+ srcIdx = 0;
+ }
+ }
+
+ int32_t destIdx = 0;
+ int32_t destCap = *destCapacity;
+ UChar *dest = *destBuf;
+
+ for (;;) {
+ if (srcIdx == regexp->fTextLength) {
+ break;
+ }
+ UChar c = regexp->fText[srcIdx];
+ if (c == 0 && regexp->fTextLength == -1) {
+ break;
+ }
+ if (destIdx < destCap) {
+ dest[destIdx] = c;
+ } else {
+ // We've overflowed the dest buffer.
+ // If the total input string length is known, we can
+ // compute the total buffer size needed without scanning through the string.
+ if (regexp->fTextLength > 0) {
+ destIdx += (regexp->fTextLength - srcIdx);
+ break;
+ }
+ }
+ srcIdx++;
+ destIdx++;
+ }
+
+ //
+ // NUL terminate the output string, if possible, otherwise issue the
+ // appropriate error or warning.
+ //
+ if (destIdx < destCap) {
+ dest[destIdx] = 0;
+ } else if (destIdx == destCap) {
+ *status = U_STRING_NOT_TERMINATED_WARNING;
+ } else {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+
+ //
+ // Update the user's buffer ptr and capacity vars to reflect the
+ // amount used.
+ //
+ if (destIdx < destCap) {
+ *destBuf += destIdx;
+ *destCapacity -= destIdx;
+ } else {
+ *destBuf += destCap;
+ *destCapacity = 0;
+ }
+
+ if (pendingBufferOverflow && U_SUCCESS(*status)) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+
+ return destIdx;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uregex_appendTail(URegularExpression *regexp,
+ UChar **destBuf,
+ int32_t *destCapacity,
+ UErrorCode *status) {
+ return RegexCImpl::appendTail(regexp, destBuf, destCapacity, status);
+}
+
+
+//------------------------------------------------------------------------------
+//
+// copyString Internal utility to copy a string to an output buffer,
+// while managing buffer overflow and preflight size
+// computation. NUL termination is added to destination,
+// and the NUL is counted in the output size.
+//
+//------------------------------------------------------------------------------
+static void copyString(UChar *destBuffer, // Destination buffer.
+ int32_t destCapacity, // Total capacity of dest buffer
+ int32_t *destIndex, // Index into dest buffer. Updated on return.
+ // Update not clipped to destCapacity.
+ const UChar *srcPtr, // Pointer to source string
+ int32_t srcLen) // Source string len.
+{
+ int32_t si;
+ int32_t di = *destIndex;
+ UChar c;
+
+ for (si=0; si<srcLen; si++) {
+ c = srcPtr[si];
+ if (di < destCapacity) {
+ destBuffer[di] = c;
+ di++;
+ } else {
+ di += srcLen - si;
+ break;
+ }
+ }
+ if (di<destCapacity) {
+ destBuffer[di] = 0;
+ }
+ di++;
+ *destIndex = di;
+}
+
+
+//------------------------------------------------------------------------------
+//
+// uregex_split
+//
+//------------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uregex_split( URegularExpression *regexp,
+ UChar *destBuf,
+ int32_t destCapacity,
+ int32_t *requiredCapacity,
+ UChar *destFields[],
+ int32_t destFieldsCapacity,
+ UErrorCode *status) {
+ if (validateRE(regexp, status) == FALSE) {
+ return 0;
+ }
+ if (destBuf == NULL && destCapacity > 0 ||
+ destCapacity < 0 ||
+ destFields == NULL ||
+ destFieldsCapacity < 1 ) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ //
+ // Reset for the input text
+ //
+ regexp->fMatcher->reset();
+ int32_t inputLen = regexp->fTextString.length();
+ int32_t nextOutputStringStart = 0;
+ if (inputLen == 0) {
+ return 0;
+ }
+
+
+ //
+ // Loop through the input text, searching for the delimiter pattern
+ //
+ int32_t i; // Index of the field being processed.
+ int32_t destIdx = 0; // Next available position in destBuf;
+ int32_t numCaptureGroups = regexp->fMatcher->groupCount();
+ for (i=0; ; i++) {
+ if (i>=destFieldsCapacity-1) {
+ // There are one or zero output string left.
+ // Fill the last output string with whatever is left from the input, then exit the loop.
+ // ( i will be == destFieldsCapacity if we filled the output array while processing
+ // capture groups of the delimiter expression, in which case we will discard the
+ // last capture group saved in favor of the unprocessed remainder of the
+ // input string.)
+ int32_t remainingLength = inputLen-nextOutputStringStart;
+ if (remainingLength > 0) {
+ }
+ if (i >= destFieldsCapacity) {
+ // No fields are left. Recycle the last one for holding the trailing part of
+ // the input string.
+ i = destFieldsCapacity-1;
+ destIdx = (int32_t)(destFields[i] - destFields[0]);
+ }
+
+ destFields[i] = &destBuf[destIdx];
+ copyString(destBuf, destCapacity, &destIdx,
+ &regexp->fText[nextOutputStringStart], remainingLength);
+ break;
+ }
+
+ if (regexp->fMatcher->find()) {
+ // We found another delimiter. Move everything from where we started looking
+ // up until the start of the delimiter into the next output string.
+ int32_t fieldLen = regexp->fMatcher->start(*status) - nextOutputStringStart;
+ destFields[i] = &destBuf[destIdx];
+ copyString(destBuf, destCapacity, &destIdx,
+ &regexp->fText[nextOutputStringStart], fieldLen);
+ nextOutputStringStart = regexp->fMatcher->end(*status);
+
+ // If the delimiter pattern has capturing parentheses, the captured
+ // text goes out into the next n destination strings.
+ int32_t groupNum;
+ for (groupNum=1; groupNum<=numCaptureGroups; groupNum++) {
+ // If we've run out of output string slots, bail out.
+ if (i==destFieldsCapacity-1) {
+ break;
+ }
+ i++;
+
+ // Set up to extract the capture group contents into the dest buffer.
+ UErrorCode tStatus = U_ZERO_ERROR; // Want to ignore any buffer overflow
+ // error while extracting this group.
+ int32_t remainingCapacity = destCapacity - destIdx;
+ if (remainingCapacity < 0) {
+ remainingCapacity = 0;
+ }
+ destFields[i] = &destBuf[destIdx];
+ int32_t t = uregex_group(regexp, groupNum, destFields[i], remainingCapacity, &tStatus);
+ destIdx += t + 1; // Record the space used in the output string buffer.
+ // +1 for the NUL that terminates the string.
+ }
+
+ if (nextOutputStringStart == inputLen) {
+ // The delimiter was at the end of the string. We're done.
+ break;
+ }
+
+ }
+ else
+ {
+ // We ran off the end of the input while looking for the next delimiter.
+ // All the remaining text goes into the current output string.
+ destFields[i] = &destBuf[destIdx];
+ copyString(destBuf, destCapacity, &destIdx,
+ &regexp->fText[nextOutputStringStart], inputLen-nextOutputStringStart);
+ break;
+ }
+ }
+
+ // Zero out any unused portion of the destFields array
+ int j;
+ for (j=i+1; j<destFieldsCapacity; j++) {
+ destFields[j] = NULL;
+ }
+
+ if (requiredCapacity != NULL) {
+ *requiredCapacity = destIdx;
+ }
+ if (destIdx > destCapacity) {
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ }
+ return i+1;
+}
+
+
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/uregexc.cpp b/Build/source/libs/icu/icu-xetex/i18n/uregexc.cpp
new file mode 100644
index 00000000000..6590020661e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/uregexc.cpp
@@ -0,0 +1,40 @@
+/*
+*******************************************************************************
+* Copyright (C) 2003-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+*******************************************************************************
+* file name: regexc.cpp
+* description: The purpose of this function is to separate the codepage
+* conversion from the rest of the uregex_ API. This can removes any
+* dependency on codepage conversion, which reduces the overhead of
+*/
+
+#include "unicode/uregex.h"
+#include "unicode/unistr.h"
+
+U_NAMESPACE_USE
+
+//----------------------------------------------------------------------------------------
+//
+// uregex_openC
+//
+//----------------------------------------------------------------------------------------
+#if !UCONFIG_NO_CONVERSION && !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+U_CAPI URegularExpression * U_EXPORT2
+uregex_openC( const char *pattern,
+ uint32_t flags,
+ UParseError *pe,
+ UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ if (pattern == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ UnicodeString patString(pattern);
+ return uregex_open(patString.getBuffer(), patString.length(), flags, pe, status);
+}
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/usearch.cpp b/Build/source/libs/icu/icu-xetex/i18n/usearch.cpp
new file mode 100644
index 00000000000..df44aa8b192
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/usearch.cpp
@@ -0,0 +1,3639 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 07/02/2001 synwee Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/usearch.h"
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "unormimp.h"
+#include "ucol_imp.h"
+#include "usrchimp.h"
+#include "cmemory.h"
+#include "ucln_in.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+// internal definition ---------------------------------------------------
+
+#define LAST_BYTE_MASK_ 0xFF
+#define SECOND_LAST_BYTE_SHIFT_ 8
+#define SUPPLEMENTARY_MIN_VALUE_ 0x10000
+
+static const uint16_t *FCD_ = NULL;
+
+// internal methods -------------------------------------------------
+
+/**
+* Fast collation element iterator setOffset.
+* This function does not check for bounds.
+* @param coleiter collation element iterator
+* @param offset to set
+*/
+static
+inline void setColEIterOffset(UCollationElements *elems,
+ int32_t offset)
+{
+ collIterate *ci = &(elems->iteratordata_);
+ ci->pos = ci->string + offset;
+ ci->CEpos = ci->toReturn = ci->CEs;
+ if (ci->flags & UCOL_ITER_INNORMBUF) {
+ ci->flags = ci->origFlags;
+ }
+ ci->fcdPosition = NULL;
+}
+
+/**
+* Getting the mask for collation strength
+* @param strength collation strength
+* @return collation element mask
+*/
+static
+inline uint32_t getMask(UCollationStrength strength)
+{
+ switch (strength)
+ {
+ case UCOL_PRIMARY:
+ return UCOL_PRIMARYORDERMASK;
+ case UCOL_SECONDARY:
+ return UCOL_SECONDARYORDERMASK | UCOL_PRIMARYORDERMASK;
+ default:
+ return UCOL_TERTIARYORDERMASK | UCOL_SECONDARYORDERMASK |
+ UCOL_PRIMARYORDERMASK;
+ }
+}
+
+/**
+* This is to squeeze the 21bit ces into a 256 table
+* @param ce collation element
+* @return collapsed version of the collation element
+*/
+static
+inline int hash(uint32_t ce)
+{
+ // the old value UCOL_PRIMARYORDER(ce) % MAX_TABLE_SIZE_ does not work
+ // well with the new collation where most of the latin 1 characters
+ // are of the value xx000xxx. their hashes will most of the time be 0
+ // to be discussed on the hash algo.
+ return UCOL_PRIMARYORDER(ce) % MAX_TABLE_SIZE_;
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+usearch_cleanup(void) {
+ FCD_ = NULL;
+ return TRUE;
+}
+U_CDECL_END
+
+/**
+* Initializing the fcd tables.
+* Internal method, status assumed to be a success.
+* @param status output error if any, caller to check status before calling
+* method, status assumed to be success when passed in.
+*/
+static
+inline void initializeFCD(UErrorCode *status)
+{
+ if (FCD_ == NULL) {
+ FCD_ = unorm_getFCDTrie(status);
+ ucln_i18n_registerCleanup(UCLN_I18N_USEARCH, usearch_cleanup);
+ }
+}
+
+/**
+* Gets the fcd value for a character at the argument index.
+* This method takes into accounts of the supplementary characters.
+* @param str UTF16 string where character for fcd retrieval resides
+* @param offset position of the character whose fcd is to be retrieved, to be
+* overwritten with the next character position, taking
+* surrogate characters into consideration.
+* @param strlength length of the argument string
+* @return fcd value
+*/
+static
+uint16_t getFCD(const UChar *str, int32_t *offset,
+ int32_t strlength)
+{
+ int32_t temp = *offset;
+ uint16_t result;
+ UChar ch = str[temp];
+ result = unorm_getFCD16(FCD_, ch);
+ temp ++;
+
+ if (result && temp != strlength && UTF_IS_FIRST_SURROGATE(ch)) {
+ ch = str[temp];
+ if (UTF_IS_SECOND_SURROGATE(ch)) {
+ result = unorm_getFCD16FromSurrogatePair(FCD_, result, ch);
+ temp ++;
+ } else {
+ result = 0;
+ }
+ }
+ *offset = temp;
+ return result;
+}
+
+/**
+* Getting the modified collation elements taking into account the collation
+* attributes
+* @param strsrch string search data
+* @param sourcece
+* @return the modified collation element
+*/
+static
+inline int32_t getCE(const UStringSearch *strsrch, uint32_t sourcece)
+{
+ // note for tertiary we can't use the collator->tertiaryMask, that
+ // is a preprocessed mask that takes into account case options. since
+ // we are only concerned with exact matches, we don't need that.
+ sourcece &= strsrch->ceMask;
+
+ if (strsrch->toShift) {
+ // alternate handling here, since only the 16 most significant digits
+ // is only used, we can safely do a compare without masking
+ // if the ce is a variable, we mask and get only the primary values
+ // no shifting to quartenary is required since all primary values
+ // less than variabletop will need to be masked off anyway.
+ if (strsrch->variableTop > sourcece) {
+ if (strsrch->strength == UCOL_QUATERNARY) {
+ sourcece &= UCOL_PRIMARYORDERMASK;
+ }
+ else {
+ sourcece = UCOL_IGNORABLE;
+ }
+ }
+ }
+
+ return sourcece;
+}
+
+/**
+* Allocate a memory and returns NULL if it failed.
+* Internal method, status assumed to be a success.
+* @param size to allocate
+* @param status output error if any, caller to check status before calling
+* method, status assumed to be success when passed in.
+* @return newly allocated array, NULL otherwise
+*/
+static
+inline void * allocateMemory(uint32_t size, UErrorCode *status)
+{
+ uint32_t *result = (uint32_t *)uprv_malloc(size);
+ if (result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return result;
+}
+
+/**
+* Adds a uint32_t value to a destination array.
+* Creates a new array if we run out of space. The caller will have to
+* manually deallocate the newly allocated array.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method. destination not to be NULL and has at least
+* size destinationlength.
+* @param destination target array
+* @param offset destination offset to add value
+* @param destinationlength target array size, return value for the new size
+* @param value to be added
+* @param increments incremental size expected
+* @param status output error if any, caller to check status before calling
+* method, status assumed to be success when passed in.
+* @return new destination array, destination if there was no new allocation
+*/
+static
+inline int32_t * addTouint32_tArray(int32_t *destination,
+ uint32_t offset,
+ uint32_t *destinationlength,
+ uint32_t value,
+ uint32_t increments,
+ UErrorCode *status)
+{
+ uint32_t newlength = *destinationlength;
+ if (offset + 1 == newlength) {
+ newlength += increments;
+ int32_t *temp = (int32_t *)allocateMemory(
+ sizeof(int32_t) * newlength, status);
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ uprv_memcpy(temp, destination, sizeof(int32_t) * offset);
+ *destinationlength = newlength;
+ destination = temp;
+ }
+ destination[offset] = value;
+ return destination;
+}
+
+/**
+* Initializing the ce table for a pattern.
+* Stores non-ignorable collation keys.
+* Table size will be estimated by the size of the pattern text. Table
+* expansion will be perform as we go along. Adding 1 to ensure that the table
+* size definitely increases.
+* Internal method, status assumed to be a success.
+* @param strsrch string search data
+* @param status output error if any, caller to check status before calling
+* method, status assumed to be success when passed in.
+* @return total number of expansions
+*/
+static
+inline uint16_t initializePatternCETable(UStringSearch *strsrch,
+ UErrorCode *status)
+{
+ UPattern *pattern = &(strsrch->pattern);
+ uint32_t cetablesize = INITIAL_ARRAY_SIZE_;
+ int32_t *cetable = pattern->CEBuffer;
+ uint32_t patternlength = pattern->textLength;
+ UCollationElements *coleiter = strsrch->utilIter;
+
+ if (coleiter == NULL) {
+ coleiter = ucol_openElements(strsrch->collator, pattern->text,
+ patternlength, status);
+ // status will be checked in ucol_next(..) later and if it is an
+ // error UCOL_NULLORDER the result of ucol_next(..) and 0 will be
+ // returned.
+ strsrch->utilIter = coleiter;
+ }
+ else {
+ uprv_init_collIterate(strsrch->collator, pattern->text,
+ pattern->textLength,
+ &coleiter->iteratordata_);
+ }
+
+ if (pattern->CE != cetable && pattern->CE) {
+ uprv_free(pattern->CE);
+ }
+
+ uint16_t offset = 0;
+ uint16_t result = 0;
+ int32_t ce;
+
+ while ((ce = ucol_next(coleiter, status)) != UCOL_NULLORDER &&
+ U_SUCCESS(*status)) {
+ uint32_t newce = getCE(strsrch, ce);
+ if (newce) {
+ int32_t *temp = addTouint32_tArray(cetable, offset, &cetablesize,
+ newce,
+ patternlength - ucol_getOffset(coleiter) + 1,
+ status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ offset ++;
+ if (cetable != temp && cetable != pattern->CEBuffer) {
+ uprv_free(cetable);
+ }
+ cetable = temp;
+ }
+ result += (uint16_t)(ucol_getMaxExpansion(coleiter, ce) - 1);
+ }
+
+ cetable[offset] = 0;
+ pattern->CE = cetable;
+ pattern->CELength = offset;
+
+ return result;
+}
+
+/**
+* Initializes the pattern struct.
+* Internal method, status assumed to be success.
+* @param strsrch UStringSearch data storage
+* @param status output error if any, caller to check status before calling
+* method, status assumed to be success when passed in.
+* @return expansionsize the total expansion size of the pattern
+*/
+static
+inline int16_t initializePattern(UStringSearch *strsrch, UErrorCode *status)
+{
+ UPattern *pattern = &(strsrch->pattern);
+ const UChar *patterntext = pattern->text;
+ int32_t length = pattern->textLength;
+ int32_t index = 0;
+
+ // Since the strength is primary, accents are ignored in the pattern.
+ if (strsrch->strength == UCOL_PRIMARY) {
+ pattern->hasPrefixAccents = 0;
+ pattern->hasSuffixAccents = 0;
+ } else {
+ pattern->hasPrefixAccents = getFCD(patterntext, &index, length) >>
+ SECOND_LAST_BYTE_SHIFT_;
+ index = length;
+ UTF_BACK_1(patterntext, 0, index);
+ pattern->hasSuffixAccents = getFCD(patterntext, &index, length) &
+ LAST_BYTE_MASK_;
+ }
+ // since intializePattern is an internal method status is a success.
+ return initializePatternCETable(strsrch, status);
+}
+
+/**
+* Initializing shift tables, with the default values.
+* If a corresponding default value is 0, the shift table is not set.
+* @param shift table for forwards shift
+* @param backshift table for backwards shift
+* @param cetable table containing pattern ce
+* @param cesize size of the pattern ces
+* @param expansionsize total size of the expansions
+* @param defaultforward the default forward value
+* @param defaultbackward the default backward value
+*/
+static
+inline void setShiftTable(int16_t shift[], int16_t backshift[],
+ int32_t *cetable, int32_t cesize,
+ int16_t expansionsize,
+ int16_t defaultforward,
+ int16_t defaultbackward)
+{
+ // estimate the value to shift. to do that we estimate the smallest
+ // number of characters to give the relevant ces, ie approximately
+ // the number of ces minus their expansion, since expansions can come
+ // from a character.
+ int32_t count;
+ for (count = 0; count < MAX_TABLE_SIZE_; count ++) {
+ shift[count] = defaultforward;
+ }
+ cesize --; // down to the last index
+ for (count = 0; count < cesize; count ++) {
+ // number of ces from right of array to the count
+ int temp = defaultforward - count - 1;
+ shift[hash(cetable[count])] = temp > 1 ? temp : 1;
+ }
+ shift[hash(cetable[cesize])] = 1;
+ // for ignorables we just shift by one. see test examples.
+ shift[hash(0)] = 1;
+
+ for (count = 0; count < MAX_TABLE_SIZE_; count ++) {
+ backshift[count] = defaultbackward;
+ }
+ for (count = cesize; count > 0; count --) {
+ // the original value count does not seem to work
+ backshift[hash(cetable[count])] = count > expansionsize ?
+ (int16_t)(count - expansionsize) : 1;
+ }
+ backshift[hash(cetable[0])] = 1;
+ backshift[hash(0)] = 1;
+}
+
+/**
+* Building of the pattern collation element list and the boyer moore strsrch
+* table.
+* The canonical match will only be performed after the default match fails.
+* For both cases we need to remember the size of the composed and decomposed
+* versions of the string. Since the Boyer-Moore shift calculations shifts by
+* a number of characters in the text and tries to match the pattern from that
+* offset, the shift value can not be too large in case we miss some
+* characters. To choose a right shift size, we estimate the NFC form of the
+* and use its size as a shift guide. The NFC form should be the small
+* possible representation of the pattern. Anyways, we'll err on the smaller
+* shift size. Hence the calculation for minlength.
+* Canonical match will be performed slightly differently. We'll split the
+* pattern into 3 parts, the prefix accents (PA), the middle string bounded by
+* the first and last base character (MS), the ending accents (EA). Matches
+* will be done on MS first, and only when we match MS then some processing
+* will be required for the prefix and end accents in order to determine if
+* they match PA and EA. Hence the default shift values
+* for the canonical match will take the size of either end's accent into
+* consideration. Forwards search will take the end accents into consideration
+* for the default shift values and the backwards search will take the prefix
+* accents into consideration.
+* If pattern has no non-ignorable ce, we return a illegal argument error.
+* Internal method, status assumed to be success.
+* @param strsrch UStringSearch data storage
+* @param status for output errors if it occurs, status is assumed to be a
+* success when it is passed in.
+*/
+static
+inline void initialize(UStringSearch *strsrch, UErrorCode *status)
+{
+ int16_t expandlength = initializePattern(strsrch, status);
+ if (U_SUCCESS(*status) && strsrch->pattern.CELength > 0) {
+ UPattern *pattern = &strsrch->pattern;
+ int32_t cesize = pattern->CELength;
+
+ int16_t minlength = cesize > expandlength
+ ? (int16_t)cesize - expandlength : 1;
+ pattern->defaultShiftSize = minlength;
+ setShiftTable(pattern->shift, pattern->backShift, pattern->CE,
+ cesize, expandlength, minlength, minlength);
+ return;
+ }
+ strsrch->pattern.defaultShiftSize = 0;
+}
+
+/**
+* Check to make sure that the match length is at the end of the character by
+* using the breakiterator.
+* @param strsrch string search data
+* @param start target text start offset
+* @param end target text end offset
+*/
+static
+void checkBreakBoundary(const UStringSearch *strsrch, int32_t *start,
+ int32_t *end)
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+ UBreakIterator *breakiterator = strsrch->search->internalBreakIter;
+ if (breakiterator) {
+ int32_t matchend = *end;
+ int32_t matchstart = *start;
+
+ if (!ubrk_isBoundary(breakiterator, matchend))
+ *end = ubrk_following(breakiterator, matchend);
+
+ /* Check the start of the matched text to make sure it doesn't have any accents
+ * before it. This code may not be necessary and so it is commented out */
+ /*if (!ubrk_isBoundary(breakiterator, matchstart) && !ubrk_isBoundary(breakiterator, matchstart-1)) {
+ *start = ubrk_preceding(breakiterator, matchstart);
+ }*/
+ }
+#endif
+}
+
+/**
+* Determine whether the target text in UStringSearch bounded by the offset
+* start and end is one or more whole units of text as
+* determined by the breakiterator in UStringSearch.
+* @param strsrch string search data
+* @param start target text start offset
+* @param end target text end offset
+*/
+static
+UBool isBreakUnit(const UStringSearch *strsrch, int32_t start,
+ int32_t end)
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+ UBreakIterator *breakiterator = strsrch->search->breakIter;
+ //TODO: Add here.
+ if (breakiterator) {
+ int32_t startindex = ubrk_first(breakiterator);
+ int32_t endindex = ubrk_last(breakiterator);
+
+ // out-of-range indexes are never boundary positions
+ if (start < startindex || start > endindex ||
+ end < startindex || end > endindex) {
+ return FALSE;
+ }
+ // otherwise, we can use following() on the position before the
+ // specified one and return true of the position we get back is the
+ // one the user specified
+ UBool result = (start == startindex ||
+ ubrk_following(breakiterator, start - 1) == start) &&
+ (end == endindex ||
+ ubrk_following(breakiterator, end - 1) == end);
+ if (result) {
+ // iterates the individual ces
+ UCollationElements *coleiter = strsrch->utilIter;
+ const UChar *text = strsrch->search->text +
+ start;
+ UErrorCode status = U_ZERO_ERROR;
+ ucol_setText(coleiter, text, end - start, &status);
+ for (int32_t count = 0; count < strsrch->pattern.CELength;
+ count ++) {
+ int32_t ce = getCE(strsrch, ucol_next(coleiter, &status));
+ if (ce == UCOL_IGNORABLE) {
+ count --;
+ continue;
+ }
+ if (U_FAILURE(status) || ce != strsrch->pattern.CE[count]) {
+ return FALSE;
+ }
+ }
+ int32_t nextce = ucol_next(coleiter, &status);
+ while (ucol_getOffset(coleiter) == (end - start)
+ && getCE(strsrch, nextce) == UCOL_IGNORABLE) {
+ nextce = ucol_next(coleiter, &status);
+ }
+ if (ucol_getOffset(coleiter) == (end - start)
+ && nextce != UCOL_NULLORDER) {
+ // extra collation elements at the end of the match
+ return FALSE;
+ }
+ }
+ return result;
+ }
+#endif
+ return TRUE;
+}
+
+/**
+* Getting the next base character offset if current offset is an accent,
+* or the current offset if the current character contains a base character.
+* accents the following base character will be returned
+* @param text string
+* @param textoffset current offset
+* @param textlength length of text string
+* @return the next base character or the current offset
+* if the current character is contains a base character.
+*/
+static
+inline int32_t getNextBaseOffset(const UChar *text,
+ int32_t textoffset,
+ int32_t textlength)
+{
+ if (textoffset < textlength) {
+ int32_t temp = textoffset;
+ if (getFCD(text, &temp, textlength) >> SECOND_LAST_BYTE_SHIFT_) {
+ while (temp < textlength) {
+ int32_t result = temp;
+ if ((getFCD(text, &temp, textlength) >>
+ SECOND_LAST_BYTE_SHIFT_) == 0) {
+ return result;
+ }
+ }
+ return textlength;
+ }
+ }
+ return textoffset;
+}
+
+/**
+* Gets the next base character offset depending on the string search pattern
+* data
+* @param strsrch string search data
+* @param textoffset current offset, one offset away from the last character
+* to search for.
+* @return start index of the next base character or the current offset
+* if the current character is contains a base character.
+*/
+static
+inline int32_t getNextUStringSearchBaseOffset(UStringSearch *strsrch,
+ int32_t textoffset)
+{
+ int32_t textlength = strsrch->search->textLength;
+ if (strsrch->pattern.hasSuffixAccents &&
+ textoffset < textlength) {
+ int32_t temp = textoffset;
+ const UChar *text = strsrch->search->text;
+ UTF_BACK_1(text, 0, temp);
+ if (getFCD(text, &temp, textlength) & LAST_BYTE_MASK_) {
+ return getNextBaseOffset(text, textoffset, textlength);
+ }
+ }
+ return textoffset;
+}
+
+/**
+* Shifting the collation element iterator position forward to prepare for
+* a following match. If the last character is a unsafe character, we'll only
+* shift by 1 to capture contractions, normalization etc.
+* Internal method, status assumed to be success.
+* @param text strsrch string search data
+* @param textoffset start text position to do search
+* @param ce the text ce which failed the match.
+* @param patternceindex index of the ce within the pattern ce buffer which
+* failed the match
+* @return final offset
+*/
+static
+inline int32_t shiftForward(UStringSearch *strsrch,
+ int32_t textoffset,
+ int32_t ce,
+ int32_t patternceindex)
+{
+ UPattern *pattern = &(strsrch->pattern);
+ if (ce != UCOL_NULLORDER) {
+ int32_t shift = pattern->shift[hash(ce)];
+ // this is to adjust for characters in the middle of the
+ // substring for matching that failed.
+ int32_t adjust = pattern->CELength - patternceindex;
+ if (adjust > 1 && shift >= adjust) {
+ shift -= adjust - 1;
+ }
+ textoffset += shift;
+ }
+ else {
+ textoffset += pattern->defaultShiftSize;
+ }
+
+ textoffset = getNextUStringSearchBaseOffset(strsrch, textoffset);
+ // check for unsafe characters
+ // * if it is the start or middle of a contraction: to be done after
+ // a initial match is found
+ // * thai or lao base consonant character: similar to contraction
+ // * high surrogate character: similar to contraction
+ // * next character is a accent: shift to the next base character
+ return textoffset;
+}
+
+/**
+* sets match not found
+* @param strsrch string search data
+*/
+static
+inline void setMatchNotFound(UStringSearch *strsrch)
+{
+ // this method resets the match result regardless of the error status.
+ strsrch->search->matchedIndex = USEARCH_DONE;
+ strsrch->search->matchedLength = 0;
+ if (strsrch->search->isForwardSearching) {
+ setColEIterOffset(strsrch->textIter, strsrch->search->textLength);
+ }
+ else {
+ setColEIterOffset(strsrch->textIter, 0);
+ }
+}
+
+/**
+* Gets the offset to the next safe point in text.
+* ie. not the middle of a contraction, swappable characters or supplementary
+* characters.
+* @param collator collation sata
+* @param text string to work with
+* @param textoffset offset in string
+* @param textlength length of text string
+* @return offset to the next safe character
+*/
+static
+inline int32_t getNextSafeOffset(const UCollator *collator,
+ const UChar *text,
+ int32_t textoffset,
+ int32_t textlength)
+{
+ int32_t result = textoffset; // first contraction character
+ while (result != textlength && ucol_unsafeCP(text[result], collator)) {
+ result ++;
+ }
+ return result;
+}
+
+/**
+* This checks for accents in the potential match started with a .
+* composite character.
+* This is really painful... we have to check that composite character do not
+* have any extra accents. We have to normalize the potential match and find
+* the immediate decomposed character before the match.
+* The first composite character would have been taken care of by the fcd
+* checks in checkForwardExactMatch.
+* This is the slow path after the fcd of the first character and
+* the last character has been checked by checkForwardExactMatch and we
+* determine that the potential match has extra non-ignorable preceding
+* ces.
+* E.g. looking for \u0301 acute in \u01FA A ring above and acute,
+* checkExtraMatchAccent should fail since there is a middle ring in \u01FA
+* Note here that accents checking are slow and cautioned in the API docs.
+* Internal method, status assumed to be a success, caller should check status
+* before calling this method
+* @param strsrch string search data
+* @param start index of the potential unfriendly composite character
+* @param end index of the potential unfriendly composite character
+* @param status output error status if any.
+* @return TRUE if there is non-ignorable accents before at the beginning
+* of the match, FALSE otherwise.
+*/
+
+static
+UBool checkExtraMatchAccents(const UStringSearch *strsrch, int32_t start,
+ int32_t end,
+ UErrorCode *status)
+{
+ UBool result = FALSE;
+ if (strsrch->pattern.hasPrefixAccents) {
+ int32_t length = end - start;
+ int32_t offset = 0;
+ const UChar *text = strsrch->search->text + start;
+
+ UTF_FWD_1(text, offset, length);
+ // we are only concerned with the first composite character
+ if (unorm_quickCheck(text, offset, UNORM_NFD, status) == UNORM_NO) {
+ int32_t safeoffset = getNextSafeOffset(strsrch->collator,
+ text, 0, length);
+ if (safeoffset != length) {
+ safeoffset ++;
+ }
+ UChar *norm = NULL;
+ UChar buffer[INITIAL_ARRAY_SIZE_];
+ int32_t size = unorm_normalize(text, safeoffset, UNORM_NFD, 0,
+ buffer, INITIAL_ARRAY_SIZE_,
+ status);
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+ if (size >= INITIAL_ARRAY_SIZE_) {
+ norm = (UChar *)allocateMemory((size + 1) * sizeof(UChar),
+ status);
+ // if allocation failed, status will be set to
+ // U_MEMORY_ALLOCATION_ERROR and unorm_normalize internally
+ // checks for it.
+ size = unorm_normalize(text, safeoffset, UNORM_NFD, 0, norm,
+ size, status);
+ if (U_FAILURE(*status) && norm != NULL) {
+ uprv_free(norm);
+ return FALSE;
+ }
+ }
+ else {
+ norm = buffer;
+ }
+
+ UCollationElements *coleiter = strsrch->utilIter;
+ ucol_setText(coleiter, norm, size, status);
+ uint32_t firstce = strsrch->pattern.CE[0];
+ UBool ignorable = TRUE;
+ uint32_t ce = UCOL_IGNORABLE;
+ while (U_SUCCESS(*status) && ce != firstce && ce != UCOL_NULLORDER) {
+ offset = ucol_getOffset(coleiter);
+ if (ce != firstce && ce != UCOL_IGNORABLE) {
+ ignorable = FALSE;
+ }
+ ce = ucol_next(coleiter, status);
+ }
+ UChar32 codepoint;
+ UTF_PREV_CHAR(norm, 0, offset, codepoint);
+ result = !ignorable && (u_getCombiningClass(codepoint) != 0);
+
+ if (norm != buffer) {
+ uprv_free(norm);
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+* Used by exact matches, checks if there are accents before the match.
+* This is really painful... we have to check that composite characters at
+* the start of the matches have to not have any extra accents.
+* We check the FCD of the character first, if it starts with an accent and
+* the first pattern ce does not match the first ce of the character, we bail.
+* Otherwise we try normalizing the first composite
+* character and find the immediate decomposed character before the match to
+* see if it is an non-ignorable accent.
+* Now normalizing the first composite character is enough because we ensure
+* that when the match is passed in here with extra beginning ces, the
+* first or last ce that match has to occur within the first character.
+* E.g. looking for \u0301 acute in \u01FA A ring above and acute,
+* checkExtraMatchAccent should fail since there is a middle ring in \u01FA
+* Note here that accents checking are slow and cautioned in the API docs.
+* @param strsrch string search data
+* @param start offset
+* @param end offset
+* @return TRUE if there are accents on either side of the match,
+* FALSE otherwise
+*/
+static
+UBool hasAccentsBeforeMatch(const UStringSearch *strsrch, int32_t start,
+ int32_t end)
+{
+ if (strsrch->pattern.hasPrefixAccents) {
+ UCollationElements *coleiter = strsrch->textIter;
+ UErrorCode status = U_ZERO_ERROR;
+ // we have been iterating forwards previously
+ uint32_t ignorable = TRUE;
+ int32_t firstce = strsrch->pattern.CE[0];
+
+ setColEIterOffset(coleiter, start);
+ int32_t ce = getCE(strsrch, ucol_next(coleiter, &status));
+ if (U_FAILURE(status)) {
+ return TRUE;
+ }
+ while (ce != firstce) {
+ if (ce != UCOL_IGNORABLE) {
+ ignorable = FALSE;
+ }
+ ce = getCE(strsrch, ucol_next(coleiter, &status));
+ if (U_FAILURE(status)) {
+ return TRUE;
+ }
+ }
+ if (!ignorable && inNormBuf(coleiter)) {
+ // within normalization buffer, discontiguous handled here
+ return TRUE;
+ }
+
+ // within text
+ int32_t temp = start;
+ // original code
+ // accent = (getFCD(strsrch->search->text, &temp,
+ // strsrch->search->textLength)
+ // >> SECOND_LAST_BYTE_SHIFT_);
+ // however this code does not work well with VC7 .net in release mode.
+ // maybe the inlines for getFCD combined with shifting has bugs in
+ // VC7. anyways this is a work around.
+ UBool accent = getFCD(strsrch->search->text, &temp,
+ strsrch->search->textLength) > 0xFF;
+ if (!accent) {
+ return checkExtraMatchAccents(strsrch, start, end, &status);
+ }
+ if (!ignorable) {
+ return TRUE;
+ }
+ if (start > 0) {
+ temp = start;
+ UTF_BACK_1(strsrch->search->text, 0, temp);
+ if (getFCD(strsrch->search->text, &temp,
+ strsrch->search->textLength) & LAST_BYTE_MASK_) {
+ setColEIterOffset(coleiter, start);
+ ce = ucol_previous(coleiter, &status);
+ if (U_FAILURE(status) ||
+ (ce != UCOL_NULLORDER && ce != UCOL_IGNORABLE)) {
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+* Used by exact matches, checks if there are accents bounding the match.
+* Note this is the initial boundary check. If the potential match
+* starts or ends with composite characters, the accents in those
+* characters will be determined later.
+* Not doing backwards iteration here, since discontiguos contraction for
+* backwards collation element iterator, use up too many characters.
+* E.g. looking for \u030A ring in \u01FA A ring above and acute,
+* should fail since there is a acute at the end of \u01FA
+* Note here that accents checking are slow and cautioned in the API docs.
+* @param strsrch string search data
+* @param start offset of match
+* @param end end offset of the match
+* @return TRUE if there are accents on either side of the match,
+* FALSE otherwise
+*/
+static
+UBool hasAccentsAfterMatch(const UStringSearch *strsrch, int32_t start,
+ int32_t end)
+{
+ if (strsrch->pattern.hasSuffixAccents) {
+ const UChar *text = strsrch->search->text;
+ int32_t temp = end;
+ int32_t textlength = strsrch->search->textLength;
+ UTF_BACK_1(text, 0, temp);
+ if (getFCD(text, &temp, textlength) & LAST_BYTE_MASK_) {
+ int32_t firstce = strsrch->pattern.CE[0];
+ UCollationElements *coleiter = strsrch->textIter;
+ UErrorCode status = U_ZERO_ERROR;
+ setColEIterOffset(coleiter, start);
+ while (getCE(strsrch, ucol_next(coleiter, &status)) != firstce) {
+ if (U_FAILURE(status)) {
+ return TRUE;
+ }
+ }
+ int32_t count = 1;
+ while (count < strsrch->pattern.CELength) {
+ if (getCE(strsrch, ucol_next(coleiter, &status))
+ == UCOL_IGNORABLE) {
+ // Thai can give an ignorable here.
+ count --;
+ }
+ if (U_FAILURE(status)) {
+ return TRUE;
+ }
+ count ++;
+ }
+ int32_t ce = ucol_next(coleiter, &status);
+ if (U_FAILURE(status)) {
+ return TRUE;
+ }
+ if (ce != UCOL_NULLORDER && ce != UCOL_IGNORABLE) {
+ ce = getCE(strsrch, ce);
+ }
+ if (ce != UCOL_NULLORDER && ce != UCOL_IGNORABLE) {
+ if (ucol_getOffset(coleiter) <= end) {
+ return TRUE;
+ }
+ if (getFCD(text, &end, textlength) >> SECOND_LAST_BYTE_SHIFT_) {
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+* Checks if the offset runs out of the text string
+* @param offset
+* @param textlength of the text string
+* @return TRUE if offset is out of bounds, FALSE otherwise
+*/
+static
+inline UBool isOutOfBounds(int32_t textlength, int32_t offset)
+{
+ return offset < 0 || offset > textlength;
+}
+
+/**
+* Checks for identical match
+* @param strsrch string search data
+* @param start offset of possible match
+* @param end offset of possible match
+* @return TRUE if identical match is found
+*/
+static
+inline UBool checkIdentical(const UStringSearch *strsrch, int32_t start,
+ int32_t end)
+{
+ UChar t2[32], p2[32];
+ int32_t length = end - start;
+ if (strsrch->strength != UCOL_IDENTICAL) {
+ return TRUE;
+ }
+
+ UErrorCode status = U_ZERO_ERROR, status2 = U_ZERO_ERROR;
+ int32_t decomplength = unorm_decompose(t2, LENGTHOF(t2),
+ strsrch->search->text + start, length,
+ FALSE, 0, &status);
+ // use separate status2 in case of buffer overflow
+ if (decomplength != unorm_decompose(p2, LENGTHOF(p2),
+ strsrch->pattern.text,
+ strsrch->pattern.textLength,
+ FALSE, 0, &status2)) {
+ return FALSE; // lengths are different
+ }
+
+ // compare contents
+ UChar *text, *pattern;
+ if(U_SUCCESS(status)) {
+ text = t2;
+ pattern = p2;
+ } else if(status==U_BUFFER_OVERFLOW_ERROR) {
+ status = U_ZERO_ERROR;
+ // allocate one buffer for both decompositions
+ text = (UChar *)uprv_malloc(decomplength * 2 * U_SIZEOF_UCHAR);
+ pattern = text + decomplength;
+ unorm_decompose(text, decomplength, strsrch->search->text + start,
+ length, FALSE, 0, &status);
+ unorm_decompose(pattern, decomplength, strsrch->pattern.text,
+ strsrch->pattern.textLength, FALSE, 0, &status);
+ } else {
+ // NFD failed, make sure that u_memcmp() does not overrun t2 & p2
+ // and that we don't uprv_free() an undefined text pointer
+ text = pattern = t2;
+ decomplength = 0;
+ }
+ UBool result = (UBool)(u_memcmp(pattern, text, decomplength) == 0);
+ if(text != t2) {
+ uprv_free(text);
+ }
+ // return FALSE if NFD failed
+ return U_SUCCESS(status) && result;
+}
+
+/**
+* Checks to see if the match is repeated
+* @param strsrch string search data
+* @param start new match start index
+* @param end new match end index
+* @return TRUE if the the match is repeated, FALSE otherwise
+*/
+static
+inline UBool checkRepeatedMatch(UStringSearch *strsrch,
+ int32_t start,
+ int32_t end)
+{
+ int32_t lastmatchindex = strsrch->search->matchedIndex;
+ UBool result;
+ if (lastmatchindex == USEARCH_DONE) {
+ return FALSE;
+ }
+ if (strsrch->search->isForwardSearching) {
+ result = start <= lastmatchindex;
+ }
+ else {
+ result = start >= lastmatchindex;
+ }
+ if (!result && !strsrch->search->isOverlap) {
+ if (strsrch->search->isForwardSearching) {
+ result = start < lastmatchindex + strsrch->search->matchedLength;
+ }
+ else {
+ result = end > lastmatchindex;
+ }
+ }
+ return result;
+}
+
+/**
+* Gets the collation element iterator's current offset.
+* @param coleiter collation element iterator
+* @param forwards flag TRUE if we are moving in th forwards direction
+* @return current offset
+*/
+static
+inline int32_t getColElemIterOffset(const UCollationElements *coleiter,
+ UBool forwards)
+{
+ int32_t result = ucol_getOffset(coleiter);
+ // intricacies of the the backwards collation element iterator
+ if (!forwards && inNormBuf(coleiter) && !isFCDPointerNull(coleiter)) {
+ result ++;
+ }
+ return result;
+}
+
+/**
+* Checks match for contraction.
+* If the match ends with a partial contraction we fail.
+* If the match starts too far off (because of backwards iteration) we try to
+* chip off the extra characters depending on whether a breakiterator has
+* been used.
+* Internal method, error assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param start offset of potential match, to be modified if necessary
+* @param end offset of potential match, to be modified if necessary
+* @param status output error status if any
+* @return TRUE if match passes the contraction test, FALSE otherwise
+*/
+
+static
+UBool checkNextExactContractionMatch(UStringSearch *strsrch,
+ int32_t *start,
+ int32_t *end, UErrorCode *status)
+{
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t textlength = strsrch->search->textLength;
+ int32_t temp = *start;
+ const UCollator *collator = strsrch->collator;
+ const UChar *text = strsrch->search->text;
+ // This part checks if either ends of the match contains potential
+ // contraction. If so we'll have to iterate through them
+ // The start contraction needs to be checked since ucol_previous dumps
+ // all characters till the first safe character into the buffer.
+ // *start + 1 is used to test for the unsafe characters instead of *start
+ // because ucol_prev takes all unsafe characters till the first safe
+ // character ie *start. so by testing *start + 1, we can estimate if
+ // excess prefix characters has been included in the potential search
+ // results.
+ if ((*end < textlength && ucol_unsafeCP(text[*end], collator)) ||
+ (*start + 1 < textlength
+ && ucol_unsafeCP(text[*start + 1], collator))) {
+ int32_t expansion = getExpansionPrefix(coleiter);
+ UBool expandflag = expansion > 0;
+ setColEIterOffset(coleiter, *start);
+ while (expansion > 0) {
+ // getting rid of the redundant ce, caused by setOffset.
+ // since backward contraction/expansion may have extra ces if we
+ // are in the normalization buffer, hasAccentsBeforeMatch would
+ // have taken care of it.
+ // E.g. the character \u01FA will have an expansion of 3, but if
+ // we are only looking for acute and ring \u030A and \u0301, we'll
+ // have to skip the first ce in the expansion buffer.
+ ucol_next(coleiter, status);
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+ if (ucol_getOffset(coleiter) != temp) {
+ *start = temp;
+ temp = ucol_getOffset(coleiter);
+ }
+ expansion --;
+ }
+
+ int32_t *patternce = strsrch->pattern.CE;
+ int32_t patterncelength = strsrch->pattern.CELength;
+ int32_t count = 0;
+ while (count < patterncelength) {
+ int32_t ce = getCE(strsrch, ucol_next(coleiter, status));
+ if (ce == UCOL_IGNORABLE) {
+ continue;
+ }
+ if (expandflag && count == 0 && ucol_getOffset(coleiter) != temp) {
+ *start = temp;
+ temp = ucol_getOffset(coleiter);
+ }
+ if (U_FAILURE(*status) || ce != patternce[count]) {
+ (*end) ++;
+ *end = getNextUStringSearchBaseOffset(strsrch, *end);
+ return FALSE;
+ }
+ count ++;
+ }
+ }
+ return TRUE;
+}
+
+/**
+* Checks and sets the match information if found.
+* Checks
+* <ul>
+* <li> the potential match does not repeat the previous match
+* <li> boundaries are correct
+* <li> exact matches has no extra accents
+* <li> identical matchesb
+* <li> potential match does not end in the middle of a contraction
+* <\ul>
+* Otherwise the offset will be shifted to the next character.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset offset in the collation element text. the returned value
+* will be the truncated end offset of the match or the new start
+* search offset.
+* @param status output error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+inline UBool checkNextExactMatch(UStringSearch *strsrch,
+ int32_t *textoffset, UErrorCode *status)
+{
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t start = getColElemIterOffset(coleiter, FALSE);
+
+ if (!checkNextExactContractionMatch(strsrch, &start, textoffset, status)) {
+ return FALSE;
+ }
+
+ // this totally matches, however we need to check if it is repeating
+ if (!isBreakUnit(strsrch, start, *textoffset) ||
+ checkRepeatedMatch(strsrch, start, *textoffset) ||
+ hasAccentsBeforeMatch(strsrch, start, *textoffset) ||
+ !checkIdentical(strsrch, start, *textoffset) ||
+ hasAccentsAfterMatch(strsrch, start, *textoffset)) {
+
+ (*textoffset) ++;
+ *textoffset = getNextUStringSearchBaseOffset(strsrch, *textoffset);
+ return FALSE;
+ }
+
+ //Add breakiterator boundary check for primary strength search.
+ if (!strsrch->search->breakIter && strsrch->strength == UCOL_PRIMARY) {
+ checkBreakBoundary(strsrch, &start, textoffset);
+ }
+
+ // totally match, we will get rid of the ending ignorables.
+ strsrch->search->matchedIndex = start;
+ strsrch->search->matchedLength = *textoffset - start;
+ return TRUE;
+}
+
+/**
+* Getting the previous base character offset, or the current offset if the
+* current character is a base character
+* @param text string
+* @param textoffset one offset after the current character
+* @return the offset of the next character after the base character or the first
+* composed character with accents
+*/
+static
+inline int32_t getPreviousBaseOffset(const UChar *text,
+ int32_t textoffset)
+{
+ if (textoffset > 0) {
+ for (;;) {
+ int32_t result = textoffset;
+ UTF_BACK_1(text, 0, textoffset);
+ int32_t temp = textoffset;
+ uint16_t fcd = getFCD(text, &temp, result);
+ if ((fcd >> SECOND_LAST_BYTE_SHIFT_) == 0) {
+ if (fcd & LAST_BYTE_MASK_) {
+ return textoffset;
+ }
+ return result;
+ }
+ if (textoffset == 0) {
+ return 0;
+ }
+ }
+ }
+ return textoffset;
+}
+
+/**
+* Getting the indexes of the accents that are not blocked in the argument
+* accent array
+* @param accents array of accents in nfd terminated by a 0.
+* @param accentsindex array of indexes of the accents that are not blocked
+*/
+static
+inline int getUnblockedAccentIndex(UChar *accents, int32_t *accentsindex)
+{
+ int32_t index = 0;
+ int32_t length = u_strlen(accents);
+ UChar32 codepoint = 0;
+ int cclass = 0;
+ int result = 0;
+ int32_t temp;
+ while (index < length) {
+ temp = index;
+ UTF_NEXT_CHAR(accents, index, length, codepoint);
+ if (u_getCombiningClass(codepoint) != cclass) {
+ cclass = u_getCombiningClass(codepoint);
+ accentsindex[result] = temp;
+ result ++;
+ }
+ }
+ accentsindex[result] = length;
+ return result;
+}
+
+/**
+* Appends 3 UChar arrays to a destination array.
+* Creates a new array if we run out of space. The caller will have to
+* manually deallocate the newly allocated array.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method. destination not to be NULL and has at least
+* size destinationlength.
+* @param destination target array
+* @param destinationlength target array size, returning the appended length
+* @param source1 null-terminated first array
+* @param source2 second array
+* @param source2length length of seond array
+* @param source3 null-terminated third array
+* @param status error status if any
+* @return new destination array, destination if there was no new allocation
+*/
+static
+inline UChar * addToUCharArray( UChar *destination,
+ int32_t *destinationlength,
+ const UChar *source1,
+ const UChar *source2,
+ int32_t source2length,
+ const UChar *source3,
+ UErrorCode *status)
+{
+ int32_t source1length = source1 ? u_strlen(source1) : 0;
+ int32_t source3length = source3 ? u_strlen(source3) : 0;
+ if (*destinationlength < source1length + source2length + source3length +
+ 1)
+ {
+ destination = (UChar *)allocateMemory(
+ (source1length + source2length + source3length + 1) * sizeof(UChar),
+ status);
+ // if error allocating memory, status will be
+ // U_MEMORY_ALLOCATION_ERROR
+ if (U_FAILURE(*status)) {
+ *destinationlength = 0;
+ return NULL;
+ }
+ }
+ if (source1length != 0) {
+ uprv_memcpy(destination, source1, sizeof(UChar) * source1length);
+ }
+ if (source2length != 0) {
+ uprv_memcpy(destination + source1length, source2,
+ sizeof(UChar) * source2length);
+ }
+ if (source3length != 0) {
+ uprv_memcpy(destination + source1length + source2length, source3,
+ sizeof(UChar) * source3length);
+ }
+ *destinationlength = source1length + source2length + source3length;
+ return destination;
+}
+
+/**
+* Running through a collation element iterator to see if the contents matches
+* pattern in string search data
+* @param strsrch string search data
+* @param coleiter collation element iterator
+* @return TRUE if a match if found, FALSE otherwise
+*/
+static
+inline UBool checkCollationMatch(const UStringSearch *strsrch,
+ UCollationElements *coleiter)
+{
+ int patternceindex = strsrch->pattern.CELength;
+ int32_t *patternce = strsrch->pattern.CE;
+ UErrorCode status = U_ZERO_ERROR;
+ while (patternceindex > 0) {
+ int32_t ce = getCE(strsrch, ucol_next(coleiter, &status));
+ if (ce == UCOL_IGNORABLE) {
+ continue;
+ }
+ if (U_FAILURE(status) || ce != *patternce) {
+ return FALSE;
+ }
+ patternce ++;
+ patternceindex --;
+ }
+ return TRUE;
+}
+
+/**
+* Rearranges the front accents to try matching.
+* Prefix accents in the text will be grouped according to their combining
+* class and the groups will be mixed and matched to try find the perfect
+* match with the pattern.
+* So for instance looking for "\u0301" in "\u030A\u0301\u0325"
+* step 1: split "\u030A\u0301" into 6 other type of potential accent substrings
+* "\u030A", "\u0301", "\u0325", "\u030A\u0301", "\u030A\u0325",
+* "\u0301\u0325".
+* step 2: check if any of the generated substrings matches the pattern.
+* Internal method, status is assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search match
+* @param start first offset of the accents to start searching
+* @param end start of the last accent set
+* @param status output error status if any
+* @return USEARCH_DONE if a match is not found, otherwise return the starting
+* offset of the match. Note this start includes all preceding accents.
+*/
+static
+int32_t doNextCanonicalPrefixMatch(UStringSearch *strsrch,
+ int32_t start,
+ int32_t end,
+ UErrorCode *status)
+{
+ const UChar *text = strsrch->search->text;
+ int32_t textlength = strsrch->search->textLength;
+ int32_t tempstart = start;
+
+ if ((getFCD(text, &tempstart, textlength) & LAST_BYTE_MASK_) == 0) {
+ // die... failed at a base character
+ return USEARCH_DONE;
+ }
+
+ int32_t offset = getNextBaseOffset(text, tempstart, textlength);
+ start = getPreviousBaseOffset(text, tempstart);
+
+ UChar accents[INITIAL_ARRAY_SIZE_];
+ // normalizing the offensive string
+ unorm_normalize(text + start, offset - start, UNORM_NFD, 0, accents,
+ INITIAL_ARRAY_SIZE_, status);
+ if (U_FAILURE(*status)) {
+ return USEARCH_DONE;
+ }
+
+ int32_t accentsindex[INITIAL_ARRAY_SIZE_];
+ int32_t accentsize = getUnblockedAccentIndex(accents,
+ accentsindex);
+ int32_t count = (2 << (accentsize - 1)) - 1;
+ UChar buffer[INITIAL_ARRAY_SIZE_];
+ UCollationElements *coleiter = strsrch->utilIter;
+ while (U_SUCCESS(*status) && count > 0) {
+ UChar *rearrange = strsrch->canonicalPrefixAccents;
+ // copy the base characters
+ for (int k = 0; k < accentsindex[0]; k ++) {
+ *rearrange ++ = accents[k];
+ }
+ // forming all possible canonical rearrangement by dropping
+ // sets of accents
+ for (int i = 0; i <= accentsize - 1; i ++) {
+ int32_t mask = 1 << (accentsize - i - 1);
+ if (count & mask) {
+ for (int j = accentsindex[i]; j < accentsindex[i + 1]; j ++) {
+ *rearrange ++ = accents[j];
+ }
+ }
+ }
+ *rearrange = 0;
+ int32_t matchsize = INITIAL_ARRAY_SIZE_;
+ UChar *match = addToUCharArray(buffer, &matchsize,
+ strsrch->canonicalPrefixAccents,
+ strsrch->search->text + offset,
+ end - offset,
+ strsrch->canonicalSuffixAccents,
+ status);
+
+ // if status is a failure, ucol_setText does nothing.
+ // run the collator iterator through this match
+ ucol_setText(coleiter, match, matchsize, status);
+ if (U_SUCCESS(*status)) {
+ if (checkCollationMatch(strsrch, coleiter)) {
+ if (match != buffer) {
+ uprv_free(match);
+ }
+ return start;
+ }
+ }
+ count --;
+ }
+ return USEARCH_DONE;
+}
+
+/**
+* Gets the offset to the safe point in text before textoffset.
+* ie. not the middle of a contraction, swappable characters or supplementary
+* characters.
+* @param collator collation sata
+* @param text string to work with
+* @param textoffset offset in string
+* @param textlength length of text string
+* @return offset to the previous safe character
+*/
+static
+inline uint32_t getPreviousSafeOffset(const UCollator *collator,
+ const UChar *text,
+ int32_t textoffset)
+{
+ int32_t result = textoffset; // first contraction character
+ while (result != 0 && ucol_unsafeCP(text[result - 1], collator)) {
+ result --;
+ }
+ if (result != 0) {
+ // the first contraction character is consider unsafe here
+ result --;
+ }
+ return result;
+}
+
+/**
+* Cleaning up after we passed the safe zone
+* @param strsrch string search data
+* @param safetext safe text array
+* @param safebuffer safe text buffer
+* @param coleiter collation element iterator for safe text
+*/
+static
+inline void cleanUpSafeText(const UStringSearch *strsrch, UChar *safetext,
+ UChar *safebuffer)
+{
+ if (safetext != safebuffer && safetext != strsrch->canonicalSuffixAccents)
+ {
+ uprv_free(safetext);
+ }
+}
+
+/**
+* Take the rearranged end accents and tries matching. If match failed at
+* a seperate preceding set of accents (seperated from the rearranged on by
+* at least a base character) then we rearrange the preceding accents and
+* tries matching again.
+* We allow skipping of the ends of the accent set if the ces do not match.
+* However if the failure is found before the accent set, it fails.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset of the start of the rearranged accent
+* @param status output error status if any
+* @return USEARCH_DONE if a match is not found, otherwise return the starting
+* offset of the match. Note this start includes all preceding accents.
+*/
+static
+int32_t doNextCanonicalSuffixMatch(UStringSearch *strsrch,
+ int32_t textoffset,
+ UErrorCode *status)
+{
+ const UChar *text = strsrch->search->text;
+ const UCollator *collator = strsrch->collator;
+ int32_t safelength = 0;
+ UChar *safetext;
+ int32_t safetextlength;
+ UChar safebuffer[INITIAL_ARRAY_SIZE_];
+ UCollationElements *coleiter = strsrch->utilIter;
+ int32_t safeoffset = textoffset;
+
+ if (textoffset != 0 && ucol_unsafeCP(strsrch->canonicalSuffixAccents[0],
+ collator)) {
+ safeoffset = getPreviousSafeOffset(collator, text, textoffset);
+ safelength = textoffset - safeoffset;
+ safetextlength = INITIAL_ARRAY_SIZE_;
+ safetext = addToUCharArray(safebuffer, &safetextlength, NULL,
+ text + safeoffset, safelength,
+ strsrch->canonicalSuffixAccents,
+ status);
+ }
+ else {
+ safetextlength = u_strlen(strsrch->canonicalSuffixAccents);
+ safetext = strsrch->canonicalSuffixAccents;
+ }
+
+ // if status is a failure, ucol_setText does nothing
+ ucol_setText(coleiter, safetext, safetextlength, status);
+ // status checked in loop below
+
+ int32_t *ce = strsrch->pattern.CE;
+ int32_t celength = strsrch->pattern.CELength;
+ int ceindex = celength - 1;
+ UBool isSafe = TRUE; // indication flag for position in safe zone
+
+ while (ceindex >= 0) {
+ int32_t textce = ucol_previous(coleiter, status);
+ if (U_FAILURE(*status)) {
+ if (isSafe) {
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ }
+ return USEARCH_DONE;
+ }
+ if (textce == UCOL_NULLORDER) {
+ // check if we have passed the safe buffer
+ if (coleiter == strsrch->textIter) {
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ return USEARCH_DONE;
+ }
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ safetext = safebuffer;
+ coleiter = strsrch->textIter;
+ setColEIterOffset(coleiter, safeoffset);
+ // status checked at the start of the loop
+ isSafe = FALSE;
+ continue;
+ }
+ textce = getCE(strsrch, textce);
+ if (textce != UCOL_IGNORABLE && textce != ce[ceindex]) {
+ // do the beginning stuff
+ int32_t failedoffset = getColElemIterOffset(coleiter, FALSE);
+ if (isSafe && failedoffset >= safelength) {
+ // alas... no hope. failed at rearranged accent set
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ return USEARCH_DONE;
+ }
+ else {
+ if (isSafe) {
+ failedoffset += safeoffset;
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ }
+
+ // try rearranging the front accents
+ int32_t result = doNextCanonicalPrefixMatch(strsrch,
+ failedoffset, textoffset, status);
+ if (result != USEARCH_DONE) {
+ // if status is a failure, ucol_setOffset does nothing
+ setColEIterOffset(strsrch->textIter, result);
+ }
+ if (U_FAILURE(*status)) {
+ return USEARCH_DONE;
+ }
+ return result;
+ }
+ }
+ if (textce == ce[ceindex]) {
+ ceindex --;
+ }
+ }
+ // set offset here
+ if (isSafe) {
+ int32_t result = getColElemIterOffset(coleiter, FALSE);
+ // sets the text iterator here with the correct expansion and offset
+ int32_t leftoverces = getExpansionPrefix(coleiter);
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ if (result >= safelength) {
+ result = textoffset;
+ }
+ else {
+ result += safeoffset;
+ }
+ setColEIterOffset(strsrch->textIter, result);
+ strsrch->textIter->iteratordata_.toReturn =
+ setExpansionPrefix(strsrch->textIter, leftoverces);
+ return result;
+ }
+
+ return ucol_getOffset(coleiter);
+}
+
+/**
+* Trying out the substring and sees if it can be a canonical match.
+* This will try normalizing the end accents and arranging them into canonical
+* equivalents and check their corresponding ces with the pattern ce.
+* Suffix accents in the text will be grouped according to their combining
+* class and the groups will be mixed and matched to try find the perfect
+* match with the pattern.
+* So for instance looking for "\u0301" in "\u030A\u0301\u0325"
+* step 1: split "\u030A\u0301" into 6 other type of potential accent substrings
+* "\u030A", "\u0301", "\u0325", "\u030A\u0301", "\u030A\u0325",
+* "\u0301\u0325".
+* step 2: check if any of the generated substrings matches the pattern.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset end offset in the collation element text that ends with
+* the accents to be rearranged
+* @param status error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+UBool doNextCanonicalMatch(UStringSearch *strsrch,
+ int32_t textoffset,
+ UErrorCode *status)
+{
+ const UChar *text = strsrch->search->text;
+ int32_t temp = textoffset;
+ UTF_BACK_1(text, 0, temp);
+ if ((getFCD(text, &temp, textoffset) & LAST_BYTE_MASK_) == 0) {
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t offset = getColElemIterOffset(coleiter, FALSE);
+ if (strsrch->pattern.hasPrefixAccents) {
+ offset = doNextCanonicalPrefixMatch(strsrch, offset, textoffset,
+ status);
+ if (U_SUCCESS(*status) && offset != USEARCH_DONE) {
+ setColEIterOffset(coleiter, offset);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ if (!strsrch->pattern.hasSuffixAccents) {
+ return FALSE;
+ }
+
+ UChar accents[INITIAL_ARRAY_SIZE_];
+ // offset to the last base character in substring to search
+ int32_t baseoffset = getPreviousBaseOffset(text, textoffset);
+ // normalizing the offensive string
+ unorm_normalize(text + baseoffset, textoffset - baseoffset, UNORM_NFD,
+ 0, accents, INITIAL_ARRAY_SIZE_, status);
+ // status checked in loop below
+
+ int32_t accentsindex[INITIAL_ARRAY_SIZE_];
+ int32_t size = getUnblockedAccentIndex(accents, accentsindex);
+
+ // 2 power n - 1 plus the full set of accents
+ int32_t count = (2 << (size - 1)) - 1;
+ while (U_SUCCESS(*status) && count > 0) {
+ UChar *rearrange = strsrch->canonicalSuffixAccents;
+ // copy the base characters
+ for (int k = 0; k < accentsindex[0]; k ++) {
+ *rearrange ++ = accents[k];
+ }
+ // forming all possible canonical rearrangement by dropping
+ // sets of accents
+ for (int i = 0; i <= size - 1; i ++) {
+ int32_t mask = 1 << (size - i - 1);
+ if (count & mask) {
+ for (int j = accentsindex[i]; j < accentsindex[i + 1]; j ++) {
+ *rearrange ++ = accents[j];
+ }
+ }
+ }
+ *rearrange = 0;
+ int32_t offset = doNextCanonicalSuffixMatch(strsrch, baseoffset,
+ status);
+ if (offset != USEARCH_DONE) {
+ return TRUE; // match found
+ }
+ count --;
+ }
+ return FALSE;
+}
+
+/**
+* Gets the previous base character offset depending on the string search
+* pattern data
+* @param strsrch string search data
+* @param textoffset current offset, current character
+* @return the offset of the next character after this base character or itself
+* if it is a composed character with accents
+*/
+static
+inline int32_t getPreviousUStringSearchBaseOffset(UStringSearch *strsrch,
+ int32_t textoffset)
+{
+ if (strsrch->pattern.hasPrefixAccents && textoffset > 0) {
+ const UChar *text = strsrch->search->text;
+ int32_t offset = textoffset;
+ if (getFCD(text, &offset, strsrch->search->textLength) >>
+ SECOND_LAST_BYTE_SHIFT_) {
+ return getPreviousBaseOffset(text, textoffset);
+ }
+ }
+ return textoffset;
+}
+
+/**
+* Checks match for contraction.
+* If the match ends with a partial contraction we fail.
+* If the match starts too far off (because of backwards iteration) we try to
+* chip off the extra characters
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param start offset of potential match, to be modified if necessary
+* @param end offset of potential match, to be modified if necessary
+* @param status output error status if any
+* @return TRUE if match passes the contraction test, FALSE otherwise
+*/
+static
+UBool checkNextCanonicalContractionMatch(UStringSearch *strsrch,
+ int32_t *start,
+ int32_t *end,
+ UErrorCode *status)
+{
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t textlength = strsrch->search->textLength;
+ int32_t temp = *start;
+ const UCollator *collator = strsrch->collator;
+ const UChar *text = strsrch->search->text;
+ // This part checks if either ends of the match contains potential
+ // contraction. If so we'll have to iterate through them
+ if ((*end < textlength && ucol_unsafeCP(text[*end], collator)) ||
+ (*start + 1 < textlength
+ && ucol_unsafeCP(text[*start + 1], collator))) {
+ int32_t expansion = getExpansionPrefix(coleiter);
+ UBool expandflag = expansion > 0;
+ setColEIterOffset(coleiter, *start);
+ while (expansion > 0) {
+ // getting rid of the redundant ce, caused by setOffset.
+ // since backward contraction/expansion may have extra ces if we
+ // are in the normalization buffer, hasAccentsBeforeMatch would
+ // have taken care of it.
+ // E.g. the character \u01FA will have an expansion of 3, but if
+ // we are only looking for acute and ring \u030A and \u0301, we'll
+ // have to skip the first ce in the expansion buffer.
+ ucol_next(coleiter, status);
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+ if (ucol_getOffset(coleiter) != temp) {
+ *start = temp;
+ temp = ucol_getOffset(coleiter);
+ }
+ expansion --;
+ }
+
+ int32_t *patternce = strsrch->pattern.CE;
+ int32_t patterncelength = strsrch->pattern.CELength;
+ int32_t count = 0;
+ int32_t textlength = strsrch->search->textLength;
+ while (count < patterncelength) {
+ int32_t ce = getCE(strsrch, ucol_next(coleiter, status));
+ // status checked below, note that if status is a failure
+ // ucol_next returns UCOL_NULLORDER
+ if (ce == UCOL_IGNORABLE) {
+ continue;
+ }
+ if (expandflag && count == 0 && ucol_getOffset(coleiter) != temp) {
+ *start = temp;
+ temp = ucol_getOffset(coleiter);
+ }
+
+ if (count == 0 && ce != patternce[0]) {
+ // accents may have extra starting ces, this occurs when a
+ // pure accent pattern is matched without rearrangement
+ // text \u0325\u0300 and looking for \u0300
+ int32_t expected = patternce[0];
+ if (getFCD(text, start, textlength) & LAST_BYTE_MASK_) {
+ ce = getCE(strsrch, ucol_next(coleiter, status));
+ while (U_SUCCESS(*status) && ce != expected &&
+ ce != UCOL_NULLORDER &&
+ ucol_getOffset(coleiter) <= *end) {
+ ce = getCE(strsrch, ucol_next(coleiter, status));
+ }
+ }
+ }
+ if (U_FAILURE(*status) || ce != patternce[count]) {
+ (*end) ++;
+ *end = getNextUStringSearchBaseOffset(strsrch, *end);
+ return FALSE;
+ }
+ count ++;
+ }
+ }
+ return TRUE;
+}
+
+/**
+* Checks and sets the match information if found.
+* Checks
+* <ul>
+* <li> the potential match does not repeat the previous match
+* <li> boundaries are correct
+* <li> potential match does not end in the middle of a contraction
+* <li> identical matches
+* <\ul>
+* Otherwise the offset will be shifted to the next character.
+* Internal method, status assumed to be success, caller has to check the
+* status before calling this method.
+* @param strsrch string search data
+* @param textoffset offset in the collation element text. the returned value
+* will be the truncated end offset of the match or the new start
+* search offset.
+* @param status output error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+inline UBool checkNextCanonicalMatch(UStringSearch *strsrch,
+ int32_t *textoffset,
+ UErrorCode *status)
+{
+ // to ensure that the start and ends are not composite characters
+ UCollationElements *coleiter = strsrch->textIter;
+ // if we have a canonical accent match
+ if ((strsrch->pattern.hasSuffixAccents &&
+ strsrch->canonicalSuffixAccents[0]) ||
+ (strsrch->pattern.hasPrefixAccents &&
+ strsrch->canonicalPrefixAccents[0])) {
+ strsrch->search->matchedIndex = getPreviousUStringSearchBaseOffset(
+ strsrch,
+ ucol_getOffset(coleiter));
+ strsrch->search->matchedLength = *textoffset -
+ strsrch->search->matchedIndex;
+ return TRUE;
+ }
+
+ int32_t start = getColElemIterOffset(coleiter, FALSE);
+ if (!checkNextCanonicalContractionMatch(strsrch, &start, textoffset,
+ status) || U_FAILURE(*status)) {
+ return FALSE;
+ }
+
+ start = getPreviousUStringSearchBaseOffset(strsrch, start);
+ // this totally matches, however we need to check if it is repeating
+ if (checkRepeatedMatch(strsrch, start, *textoffset) ||
+ !isBreakUnit(strsrch, start, *textoffset) ||
+ !checkIdentical(strsrch, start, *textoffset)) {
+ (*textoffset) ++;
+ *textoffset = getNextBaseOffset(strsrch->search->text, *textoffset,
+ strsrch->search->textLength);
+ return FALSE;
+ }
+
+ strsrch->search->matchedIndex = start;
+ strsrch->search->matchedLength = *textoffset - start;
+ return TRUE;
+}
+
+/**
+* Shifting the collation element iterator position forward to prepare for
+* a preceding match. If the first character is a unsafe character, we'll only
+* shift by 1 to capture contractions, normalization etc.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param text strsrch string search data
+* @param textoffset start text position to do search
+* @param ce the text ce which failed the match.
+* @param patternceindex index of the ce within the pattern ce buffer which
+* failed the match
+* @return final offset
+*/
+static
+inline int32_t reverseShift(UStringSearch *strsrch,
+ int32_t textoffset,
+ int32_t ce,
+ int32_t patternceindex)
+{
+ if (strsrch->search->isOverlap) {
+ if (textoffset != strsrch->search->textLength) {
+ textoffset --;
+ }
+ else {
+ textoffset -= strsrch->pattern.defaultShiftSize;
+ }
+ }
+ else {
+ if (ce != UCOL_NULLORDER) {
+ int32_t shift = strsrch->pattern.backShift[hash(ce)];
+
+ // this is to adjust for characters in the middle of the substring
+ // for matching that failed.
+ int32_t adjust = patternceindex;
+ if (adjust > 1 && shift > adjust) {
+ shift -= adjust - 1;
+ }
+ textoffset -= shift;
+ }
+ else {
+ textoffset -= strsrch->pattern.defaultShiftSize;
+ }
+ }
+ textoffset = getPreviousUStringSearchBaseOffset(strsrch, textoffset);
+ return textoffset;
+}
+
+/**
+* Checks match for contraction.
+* If the match starts with a partial contraction we fail.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param start offset of potential match, to be modified if necessary
+* @param end offset of potential match, to be modified if necessary
+* @param status output error status if any
+* @return TRUE if match passes the contraction test, FALSE otherwise
+*/
+static
+UBool checkPreviousExactContractionMatch(UStringSearch *strsrch,
+ int32_t *start,
+ int32_t *end, UErrorCode *status)
+{
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t textlength = strsrch->search->textLength;
+ int32_t temp = *end;
+ const UCollator *collator = strsrch->collator;
+ const UChar *text = strsrch->search->text;
+ // This part checks if either if the start of the match contains potential
+ // contraction. If so we'll have to iterate through them
+ // Since we used ucol_next while previously looking for the potential
+ // match, this guarantees that our end will not be a partial contraction,
+ // or a partial supplementary character.
+ if (*start < textlength && ucol_unsafeCP(text[*start], collator)) {
+ int32_t expansion = getExpansionSuffix(coleiter);
+ UBool expandflag = expansion > 0;
+ setColEIterOffset(coleiter, *end);
+ while (U_SUCCESS(*status) && expansion > 0) {
+ // getting rid of the redundant ce
+ // since forward contraction/expansion may have extra ces
+ // if we are in the normalization buffer, hasAccentsBeforeMatch
+ // would have taken care of it.
+ // E.g. the character \u01FA will have an expansion of 3, but if
+ // we are only looking for A ring A\u030A, we'll have to skip the
+ // last ce in the expansion buffer
+ ucol_previous(coleiter, status);
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+ if (ucol_getOffset(coleiter) != temp) {
+ *end = temp;
+ temp = ucol_getOffset(coleiter);
+ }
+ expansion --;
+ }
+
+ int32_t *patternce = strsrch->pattern.CE;
+ int32_t patterncelength = strsrch->pattern.CELength;
+ int32_t count = patterncelength;
+ while (count > 0) {
+ int32_t ce = getCE(strsrch, ucol_previous(coleiter, status));
+ // status checked below, note that if status is a failure
+ // ucol_previous returns UCOL_NULLORDER
+ if (ce == UCOL_IGNORABLE) {
+ continue;
+ }
+ if (expandflag && count == 0 &&
+ getColElemIterOffset(coleiter, FALSE) != temp) {
+ *end = temp;
+ temp = ucol_getOffset(coleiter);
+ }
+ if (U_FAILURE(*status) || ce != patternce[count - 1]) {
+ (*start) --;
+ *start = getPreviousBaseOffset(text, *start);
+ return FALSE;
+ }
+ count --;
+ }
+ }
+ return TRUE;
+}
+
+/**
+* Checks and sets the match information if found.
+* Checks
+* <ul>
+* <li> the current match does not repeat the last match
+* <li> boundaries are correct
+* <li> exact matches has no extra accents
+* <li> identical matches
+* <\ul>
+* Otherwise the offset will be shifted to the preceding character.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param collator
+* @param coleiter collation element iterator
+* @param text string
+* @param textoffset offset in the collation element text. the returned value
+* will be the truncated start offset of the match or the new start
+* search offset.
+* @param status output error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+inline UBool checkPreviousExactMatch(UStringSearch *strsrch,
+ int32_t *textoffset,
+ UErrorCode *status)
+{
+ // to ensure that the start and ends are not composite characters
+ int32_t end = ucol_getOffset(strsrch->textIter);
+ if (!checkPreviousExactContractionMatch(strsrch, textoffset, &end, status)
+ || U_FAILURE(*status)) {
+ return FALSE;
+ }
+
+ // this totally matches, however we need to check if it is repeating
+ // the old match
+ if (checkRepeatedMatch(strsrch, *textoffset, end) ||
+ !isBreakUnit(strsrch, *textoffset, end) ||
+ hasAccentsBeforeMatch(strsrch, *textoffset, end) ||
+ !checkIdentical(strsrch, *textoffset, end) ||
+ hasAccentsAfterMatch(strsrch, *textoffset, end)) {
+ (*textoffset) --;
+ *textoffset = getPreviousBaseOffset(strsrch->search->text,
+ *textoffset);
+ return FALSE;
+ }
+
+ //Add breakiterator boundary check for primary strength search.
+ if (!strsrch->search->breakIter && strsrch->strength == UCOL_PRIMARY) {
+ checkBreakBoundary(strsrch, textoffset, &end);
+ }
+
+ strsrch->search->matchedIndex = *textoffset;
+ strsrch->search->matchedLength = end - *textoffset;
+ return TRUE;
+}
+
+/**
+* Rearranges the end accents to try matching.
+* Suffix accents in the text will be grouped according to their combining
+* class and the groups will be mixed and matched to try find the perfect
+* match with the pattern.
+* So for instance looking for "\u0301" in "\u030A\u0301\u0325"
+* step 1: split "\u030A\u0301" into 6 other type of potential accent substrings
+* "\u030A", "\u0301", "\u0325", "\u030A\u0301", "\u030A\u0325",
+* "\u0301\u0325".
+* step 2: check if any of the generated substrings matches the pattern.
+* Internal method, status assumed to be success, user has to check status
+* before calling this method.
+* @param strsrch string search match
+* @param start offset of the first base character
+* @param end start of the last accent set
+* @param status only error status if any
+* @return USEARCH_DONE if a match is not found, otherwise return the ending
+* offset of the match. Note this start includes all following accents.
+*/
+static
+int32_t doPreviousCanonicalSuffixMatch(UStringSearch *strsrch,
+ int32_t start,
+ int32_t end,
+ UErrorCode *status)
+{
+ const UChar *text = strsrch->search->text;
+ int32_t tempend = end;
+
+ UTF_BACK_1(text, 0, tempend);
+ if (!(getFCD(text, &tempend, strsrch->search->textLength) &
+ LAST_BYTE_MASK_)) {
+ // die... failed at a base character
+ return USEARCH_DONE;
+ }
+ end = getNextBaseOffset(text, end, strsrch->search->textLength);
+
+ if (U_SUCCESS(*status)) {
+ UChar accents[INITIAL_ARRAY_SIZE_];
+ int32_t offset = getPreviousBaseOffset(text, end);
+ // normalizing the offensive string
+ unorm_normalize(text + offset, end - offset, UNORM_NFD, 0, accents,
+ INITIAL_ARRAY_SIZE_, status);
+
+ int32_t accentsindex[INITIAL_ARRAY_SIZE_];
+ int32_t accentsize = getUnblockedAccentIndex(accents,
+ accentsindex);
+ int32_t count = (2 << (accentsize - 1)) - 1;
+ UChar buffer[INITIAL_ARRAY_SIZE_];
+ UCollationElements *coleiter = strsrch->utilIter;
+ while (U_SUCCESS(*status) && count > 0) {
+ UChar *rearrange = strsrch->canonicalSuffixAccents;
+ // copy the base characters
+ for (int k = 0; k < accentsindex[0]; k ++) {
+ *rearrange ++ = accents[k];
+ }
+ // forming all possible canonical rearrangement by dropping
+ // sets of accents
+ for (int i = 0; i <= accentsize - 1; i ++) {
+ int32_t mask = 1 << (accentsize - i - 1);
+ if (count & mask) {
+ for (int j = accentsindex[i]; j < accentsindex[i + 1]; j ++) {
+ *rearrange ++ = accents[j];
+ }
+ }
+ }
+ *rearrange = 0;
+ int32_t matchsize = INITIAL_ARRAY_SIZE_;
+ UChar *match = addToUCharArray(buffer, &matchsize,
+ strsrch->canonicalPrefixAccents,
+ strsrch->search->text + start,
+ offset - start,
+ strsrch->canonicalSuffixAccents,
+ status);
+
+ // run the collator iterator through this match
+ // if status is a failure ucol_setText does nothing
+ ucol_setText(coleiter, match, matchsize, status);
+ if (U_SUCCESS(*status)) {
+ if (checkCollationMatch(strsrch, coleiter)) {
+ if (match != buffer) {
+ uprv_free(match);
+ }
+ return end;
+ }
+ }
+ count --;
+ }
+ }
+ return USEARCH_DONE;
+}
+
+/**
+* Take the rearranged start accents and tries matching. If match failed at
+* a seperate following set of accents (seperated from the rearranged on by
+* at least a base character) then we rearrange the preceding accents and
+* tries matching again.
+* We allow skipping of the ends of the accent set if the ces do not match.
+* However if the failure is found before the accent set, it fails.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset of the ends of the rearranged accent
+* @param status output error status if any
+* @return USEARCH_DONE if a match is not found, otherwise return the ending
+* offset of the match. Note this start includes all following accents.
+*/
+static
+int32_t doPreviousCanonicalPrefixMatch(UStringSearch *strsrch,
+ int32_t textoffset,
+ UErrorCode *status)
+{
+ const UChar *text = strsrch->search->text;
+ const UCollator *collator = strsrch->collator;
+ int32_t safelength = 0;
+ UChar *safetext;
+ int32_t safetextlength;
+ UChar safebuffer[INITIAL_ARRAY_SIZE_];
+ int32_t safeoffset = textoffset;
+
+ if (textoffset &&
+ ucol_unsafeCP(strsrch->canonicalPrefixAccents[
+ u_strlen(strsrch->canonicalPrefixAccents) - 1
+ ], collator)) {
+ safeoffset = getNextSafeOffset(collator, text, textoffset,
+ strsrch->search->textLength);
+ safelength = safeoffset - textoffset;
+ safetextlength = INITIAL_ARRAY_SIZE_;
+ safetext = addToUCharArray(safebuffer, &safetextlength,
+ strsrch->canonicalPrefixAccents,
+ text + textoffset, safelength,
+ NULL, status);
+ }
+ else {
+ safetextlength = u_strlen(strsrch->canonicalPrefixAccents);
+ safetext = strsrch->canonicalPrefixAccents;
+ }
+
+ UCollationElements *coleiter = strsrch->utilIter;
+ // if status is a failure, ucol_setText does nothing
+ ucol_setText(coleiter, safetext, safetextlength, status);
+ // status checked in loop below
+
+ int32_t *ce = strsrch->pattern.CE;
+ int32_t celength = strsrch->pattern.CELength;
+ int ceindex = 0;
+ UBool isSafe = TRUE; // safe zone indication flag for position
+ int32_t prefixlength = u_strlen(strsrch->canonicalPrefixAccents);
+
+ while (ceindex < celength) {
+ int32_t textce = ucol_next(coleiter, status);
+ if (U_FAILURE(*status)) {
+ if (isSafe) {
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ }
+ return USEARCH_DONE;
+ }
+ if (textce == UCOL_NULLORDER) {
+ // check if we have passed the safe buffer
+ if (coleiter == strsrch->textIter) {
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ return USEARCH_DONE;
+ }
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ safetext = safebuffer;
+ coleiter = strsrch->textIter;
+ setColEIterOffset(coleiter, safeoffset);
+ // status checked at the start of the loop
+ isSafe = FALSE;
+ continue;
+ }
+ textce = getCE(strsrch, textce);
+ if (textce != UCOL_IGNORABLE && textce != ce[ceindex]) {
+ // do the beginning stuff
+ int32_t failedoffset = ucol_getOffset(coleiter);
+ if (isSafe && failedoffset <= prefixlength) {
+ // alas... no hope. failed at rearranged accent set
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ return USEARCH_DONE;
+ }
+ else {
+ if (isSafe) {
+ failedoffset = safeoffset - failedoffset;
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ }
+
+ // try rearranging the end accents
+ int32_t result = doPreviousCanonicalSuffixMatch(strsrch,
+ textoffset, failedoffset, status);
+ if (result != USEARCH_DONE) {
+ // if status is a failure, ucol_setOffset does nothing
+ setColEIterOffset(strsrch->textIter, result);
+ }
+ if (U_FAILURE(*status)) {
+ return USEARCH_DONE;
+ }
+ return result;
+ }
+ }
+ if (textce == ce[ceindex]) {
+ ceindex ++;
+ }
+ }
+ // set offset here
+ if (isSafe) {
+ int32_t result = ucol_getOffset(coleiter);
+ // sets the text iterator here with the correct expansion and offset
+ int32_t leftoverces = getExpansionSuffix(coleiter);
+ cleanUpSafeText(strsrch, safetext, safebuffer);
+ if (result <= prefixlength) {
+ result = textoffset;
+ }
+ else {
+ result = textoffset + (safeoffset - result);
+ }
+ setColEIterOffset(strsrch->textIter, result);
+ setExpansionSuffix(strsrch->textIter, leftoverces);
+ return result;
+ }
+
+ return ucol_getOffset(coleiter);
+}
+
+/**
+* Trying out the substring and sees if it can be a canonical match.
+* This will try normalizing the starting accents and arranging them into
+* canonical equivalents and check their corresponding ces with the pattern ce.
+* Prefix accents in the text will be grouped according to their combining
+* class and the groups will be mixed and matched to try find the perfect
+* match with the pattern.
+* So for instance looking for "\u0301" in "\u030A\u0301\u0325"
+* step 1: split "\u030A\u0301" into 6 other type of potential accent substrings
+* "\u030A", "\u0301", "\u0325", "\u030A\u0301", "\u030A\u0325",
+* "\u0301\u0325".
+* step 2: check if any of the generated substrings matches the pattern.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset start offset in the collation element text that starts
+* with the accents to be rearranged
+* @param status output error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+UBool doPreviousCanonicalMatch(UStringSearch *strsrch,
+ int32_t textoffset,
+ UErrorCode *status)
+{
+ const UChar *text = strsrch->search->text;
+ int32_t temp = textoffset;
+ int32_t textlength = strsrch->search->textLength;
+ if ((getFCD(text, &temp, textlength) >> SECOND_LAST_BYTE_SHIFT_) == 0) {
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t offset = ucol_getOffset(coleiter);
+ if (strsrch->pattern.hasSuffixAccents) {
+ offset = doPreviousCanonicalSuffixMatch(strsrch, textoffset,
+ offset, status);
+ if (U_SUCCESS(*status) && offset != USEARCH_DONE) {
+ setColEIterOffset(coleiter, offset);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ if (!strsrch->pattern.hasPrefixAccents) {
+ return FALSE;
+ }
+
+ UChar accents[INITIAL_ARRAY_SIZE_];
+ // offset to the last base character in substring to search
+ int32_t baseoffset = getNextBaseOffset(text, textoffset, textlength);
+ // normalizing the offensive string
+ unorm_normalize(text + textoffset, baseoffset - textoffset, UNORM_NFD,
+ 0, accents, INITIAL_ARRAY_SIZE_, status);
+ // status checked in loop
+
+ int32_t accentsindex[INITIAL_ARRAY_SIZE_];
+ int32_t size = getUnblockedAccentIndex(accents, accentsindex);
+
+ // 2 power n - 1 plus the full set of accents
+ int32_t count = (2 << (size - 1)) - 1;
+ while (U_SUCCESS(*status) && count > 0) {
+ UChar *rearrange = strsrch->canonicalPrefixAccents;
+ // copy the base characters
+ for (int k = 0; k < accentsindex[0]; k ++) {
+ *rearrange ++ = accents[k];
+ }
+ // forming all possible canonical rearrangement by dropping
+ // sets of accents
+ for (int i = 0; i <= size - 1; i ++) {
+ int32_t mask = 1 << (size - i - 1);
+ if (count & mask) {
+ for (int j = accentsindex[i]; j < accentsindex[i + 1]; j ++) {
+ *rearrange ++ = accents[j];
+ }
+ }
+ }
+ *rearrange = 0;
+ int32_t offset = doPreviousCanonicalPrefixMatch(strsrch,
+ baseoffset, status);
+ if (offset != USEARCH_DONE) {
+ return TRUE; // match found
+ }
+ count --;
+ }
+ return FALSE;
+}
+
+/**
+* Checks match for contraction.
+* If the match starts with a partial contraction we fail.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param start offset of potential match, to be modified if necessary
+* @param end offset of potential match, to be modified if necessary
+* @param status only error status if any
+* @return TRUE if match passes the contraction test, FALSE otherwise
+*/
+static
+UBool checkPreviousCanonicalContractionMatch(UStringSearch *strsrch,
+ int32_t *start,
+ int32_t *end, UErrorCode *status)
+{
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t textlength = strsrch->search->textLength;
+ int32_t temp = *end;
+ const UCollator *collator = strsrch->collator;
+ const UChar *text = strsrch->search->text;
+ // This part checks if either if the start of the match contains potential
+ // contraction. If so we'll have to iterate through them
+ // Since we used ucol_next while previously looking for the potential
+ // match, this guarantees that our end will not be a partial contraction,
+ // or a partial supplementary character.
+ if (*start < textlength && ucol_unsafeCP(text[*start], collator)) {
+ int32_t expansion = getExpansionSuffix(coleiter);
+ UBool expandflag = expansion > 0;
+ setColEIterOffset(coleiter, *end);
+ while (expansion > 0) {
+ // getting rid of the redundant ce
+ // since forward contraction/expansion may have extra ces
+ // if we are in the normalization buffer, hasAccentsBeforeMatch
+ // would have taken care of it.
+ // E.g. the character \u01FA will have an expansion of 3, but if
+ // we are only looking for A ring A\u030A, we'll have to skip the
+ // last ce in the expansion buffer
+ ucol_previous(coleiter, status);
+ if (U_FAILURE(*status)) {
+ return FALSE;
+ }
+ if (ucol_getOffset(coleiter) != temp) {
+ *end = temp;
+ temp = ucol_getOffset(coleiter);
+ }
+ expansion --;
+ }
+
+ int32_t *patternce = strsrch->pattern.CE;
+ int32_t patterncelength = strsrch->pattern.CELength;
+ int32_t count = patterncelength;
+ while (count > 0) {
+ int32_t ce = getCE(strsrch, ucol_previous(coleiter, status));
+ // status checked below, note that if status is a failure
+ // ucol_previous returns UCOL_NULLORDER
+ if (ce == UCOL_IGNORABLE) {
+ continue;
+ }
+ if (expandflag && count == 0 &&
+ getColElemIterOffset(coleiter, FALSE) != temp) {
+ *end = temp;
+ temp = ucol_getOffset(coleiter);
+ }
+ if (count == patterncelength &&
+ ce != patternce[patterncelength - 1]) {
+ // accents may have extra starting ces, this occurs when a
+ // pure accent pattern is matched without rearrangement
+ int32_t expected = patternce[patterncelength - 1];
+ UTF_BACK_1(text, 0, *end);
+ if (getFCD(text, end, textlength) & LAST_BYTE_MASK_) {
+ ce = getCE(strsrch, ucol_previous(coleiter, status));
+ while (U_SUCCESS(*status) && ce != expected &&
+ ce != UCOL_NULLORDER &&
+ ucol_getOffset(coleiter) <= *start) {
+ ce = getCE(strsrch, ucol_previous(coleiter, status));
+ }
+ }
+ }
+ if (U_FAILURE(*status) || ce != patternce[count - 1]) {
+ (*start) --;
+ *start = getPreviousBaseOffset(text, *start);
+ return FALSE;
+ }
+ count --;
+ }
+ }
+ return TRUE;
+}
+
+/**
+* Checks and sets the match information if found.
+* Checks
+* <ul>
+* <li> the potential match does not repeat the previous match
+* <li> boundaries are correct
+* <li> potential match does not end in the middle of a contraction
+* <li> identical matches
+* <\ul>
+* Otherwise the offset will be shifted to the next character.
+* Internal method, status assumed to be success, caller has to check status
+* before calling this method.
+* @param strsrch string search data
+* @param textoffset offset in the collation element text. the returned value
+* will be the truncated start offset of the match or the new start
+* search offset.
+* @param status only error status if any
+* @return TRUE if the match is valid, FALSE otherwise
+*/
+static
+inline UBool checkPreviousCanonicalMatch(UStringSearch *strsrch,
+ int32_t *textoffset,
+ UErrorCode *status)
+{
+ // to ensure that the start and ends are not composite characters
+ UCollationElements *coleiter = strsrch->textIter;
+ // if we have a canonical accent match
+ if ((strsrch->pattern.hasSuffixAccents &&
+ strsrch->canonicalSuffixAccents[0]) ||
+ (strsrch->pattern.hasPrefixAccents &&
+ strsrch->canonicalPrefixAccents[0])) {
+ strsrch->search->matchedIndex = *textoffset;
+ strsrch->search->matchedLength =
+ getNextUStringSearchBaseOffset(strsrch,
+ getColElemIterOffset(coleiter, FALSE))
+ - *textoffset;
+ return TRUE;
+ }
+
+ int32_t end = ucol_getOffset(coleiter);
+ if (!checkPreviousCanonicalContractionMatch(strsrch, textoffset, &end,
+ status) ||
+ U_FAILURE(*status)) {
+ return FALSE;
+ }
+
+ end = getNextUStringSearchBaseOffset(strsrch, end);
+ // this totally matches, however we need to check if it is repeating
+ if (checkRepeatedMatch(strsrch, *textoffset, end) ||
+ !isBreakUnit(strsrch, *textoffset, end) ||
+ !checkIdentical(strsrch, *textoffset, end)) {
+ (*textoffset) --;
+ *textoffset = getPreviousBaseOffset(strsrch->search->text,
+ *textoffset);
+ return FALSE;
+ }
+
+ strsrch->search->matchedIndex = *textoffset;
+ strsrch->search->matchedLength = end - *textoffset;
+ return TRUE;
+}
+
+// constructors and destructor -------------------------------------------
+
+U_CAPI UStringSearch * U_EXPORT2 usearch_open(const UChar *pattern,
+ int32_t patternlength,
+ const UChar *text,
+ int32_t textlength,
+ const char *locale,
+ UBreakIterator *breakiter,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+#if UCONFIG_NO_BREAK_ITERATION
+ if (breakiter != NULL) {
+ *status = U_UNSUPPORTED_ERROR;
+ return NULL;
+ }
+#endif
+ if (locale) {
+ // ucol_open internally checks for status
+ UCollator *collator = ucol_open(locale, status);
+ // pattern, text checks are done in usearch_openFromCollator
+ UStringSearch *result = usearch_openFromCollator(pattern,
+ patternlength, text, textlength,
+ collator, breakiter, status);
+
+ if (result == NULL || U_FAILURE(*status)) {
+ if (collator) {
+ ucol_close(collator);
+ }
+ return NULL;
+ }
+ else {
+ result->ownCollator = TRUE;
+ }
+ return result;
+ }
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+}
+
+U_CAPI UStringSearch * U_EXPORT2 usearch_openFromCollator(
+ const UChar *pattern,
+ int32_t patternlength,
+ const UChar *text,
+ int32_t textlength,
+ const UCollator *collator,
+ UBreakIterator *breakiter,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+#if UCONFIG_NO_BREAK_ITERATION
+ if (breakiter != NULL) {
+ *status = U_UNSUPPORTED_ERROR;
+ return NULL;
+ }
+#endif
+ if (pattern == NULL || text == NULL || collator == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ // string search does not really work when numeric collation is turned on
+ if(ucol_getAttribute(collator, UCOL_NUMERIC_COLLATION, status) == UCOL_ON) {
+ *status = U_UNSUPPORTED_ERROR;
+ return NULL;
+ }
+
+ if (U_SUCCESS(*status)) {
+ initializeFCD(status);
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ UStringSearch *result;
+ if (textlength == -1) {
+ textlength = u_strlen(text);
+ }
+ if (patternlength == -1) {
+ patternlength = u_strlen(pattern);
+ }
+ if (textlength <= 0 || patternlength <= 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ result = (UStringSearch *)uprv_malloc(sizeof(UStringSearch));
+ if (result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ result->collator = collator;
+ result->strength = ucol_getStrength(collator);
+ result->ceMask = getMask(result->strength);
+ result->toShift =
+ ucol_getAttribute(collator, UCOL_ALTERNATE_HANDLING, status) ==
+ UCOL_SHIFTED;
+ result->variableTop = ucol_getVariableTop(collator, status);
+
+ if (U_FAILURE(*status)) {
+ uprv_free(result);
+ return NULL;
+ }
+
+ result->search = (USearch *)uprv_malloc(sizeof(USearch));
+ if (result->search == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(result);
+ return NULL;
+ }
+
+ result->search->text = text;
+ result->search->textLength = textlength;
+
+ result->pattern.text = pattern;
+ result->pattern.textLength = patternlength;
+ result->pattern.CE = NULL;
+
+ result->search->breakIter = breakiter;
+#if !UCONFIG_NO_BREAK_ITERATION
+ result->search->internalBreakIter = ubrk_open(UBRK_CHARACTER, ucol_getLocale(result->collator, ULOC_VALID_LOCALE, status), text, textlength, status);
+ if (breakiter) {
+ ubrk_setText(breakiter, text, textlength, status);
+ }
+#endif
+
+ result->ownCollator = FALSE;
+ result->search->matchedLength = 0;
+ result->search->matchedIndex = USEARCH_DONE;
+ result->textIter = ucol_openElements(collator, text,
+ textlength, status);
+ if (U_FAILURE(*status)) {
+ usearch_close(result);
+ return NULL;
+ }
+
+ result->utilIter = NULL;
+
+ result->search->isOverlap = FALSE;
+ result->search->isCanonicalMatch = FALSE;
+ result->search->isForwardSearching = TRUE;
+ result->search->reset = TRUE;
+
+ initialize(result, status);
+
+ if (U_FAILURE(*status)) {
+ usearch_close(result);
+ return NULL;
+ }
+
+ return result;
+ }
+ return NULL;
+}
+
+U_CAPI void U_EXPORT2 usearch_close(UStringSearch *strsrch)
+{
+ if (strsrch) {
+ if (strsrch->pattern.CE != strsrch->pattern.CEBuffer &&
+ strsrch->pattern.CE) {
+ uprv_free(strsrch->pattern.CE);
+ }
+ ucol_closeElements(strsrch->textIter);
+ ucol_closeElements(strsrch->utilIter);
+ if (strsrch->ownCollator && strsrch->collator) {
+ ucol_close((UCollator *)strsrch->collator);
+ }
+ if (strsrch->search->internalBreakIter) {
+ ubrk_close(strsrch->search->internalBreakIter);
+ }
+ uprv_free(strsrch->search);
+ uprv_free(strsrch);
+ }
+}
+
+// set and get methods --------------------------------------------------
+
+U_CAPI void U_EXPORT2 usearch_setOffset(UStringSearch *strsrch,
+ int32_t position,
+ UErrorCode *status)
+{
+ if (U_SUCCESS(*status) && strsrch) {
+ if (isOutOfBounds(strsrch->search->textLength, position)) {
+ *status = U_INDEX_OUTOFBOUNDS_ERROR;
+ }
+ else {
+ setColEIterOffset(strsrch->textIter, position);
+ }
+ strsrch->search->matchedIndex = USEARCH_DONE;
+ strsrch->search->matchedLength = 0;
+ strsrch->search->reset = FALSE;
+ }
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_getOffset(const UStringSearch *strsrch)
+{
+ if (strsrch) {
+ int32_t result = ucol_getOffset(strsrch->textIter);
+ if (isOutOfBounds(strsrch->search->textLength, result)) {
+ return USEARCH_DONE;
+ }
+ return result;
+ }
+ return USEARCH_DONE;
+}
+
+U_CAPI void U_EXPORT2 usearch_setAttribute(UStringSearch *strsrch,
+ USearchAttribute attribute,
+ USearchAttributeValue value,
+ UErrorCode *status)
+{
+ if (U_SUCCESS(*status) && strsrch) {
+ switch (attribute)
+ {
+ case USEARCH_OVERLAP :
+ strsrch->search->isOverlap = (value == USEARCH_ON ? TRUE : FALSE);
+ break;
+ case USEARCH_CANONICAL_MATCH :
+ strsrch->search->isCanonicalMatch = (value == USEARCH_ON ? TRUE :
+ FALSE);
+ break;
+ case USEARCH_ATTRIBUTE_COUNT :
+ default:
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ }
+ if (value == USEARCH_ATTRIBUTE_VALUE_COUNT) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+U_CAPI USearchAttributeValue U_EXPORT2 usearch_getAttribute(
+ const UStringSearch *strsrch,
+ USearchAttribute attribute)
+{
+ if (strsrch) {
+ switch (attribute) {
+ case USEARCH_OVERLAP :
+ return (strsrch->search->isOverlap == TRUE ? USEARCH_ON :
+ USEARCH_OFF);
+ case USEARCH_CANONICAL_MATCH :
+ return (strsrch->search->isCanonicalMatch == TRUE ? USEARCH_ON :
+ USEARCH_OFF);
+ case USEARCH_ATTRIBUTE_COUNT :
+ return USEARCH_DEFAULT;
+ }
+ }
+ return USEARCH_DEFAULT;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_getMatchedStart(
+ const UStringSearch *strsrch)
+{
+ if (strsrch == NULL) {
+ return USEARCH_DONE;
+ }
+ return strsrch->search->matchedIndex;
+}
+
+
+U_CAPI int32_t U_EXPORT2 usearch_getMatchedText(const UStringSearch *strsrch,
+ UChar *result,
+ int32_t resultCapacity,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ return USEARCH_DONE;
+ }
+ if (strsrch == NULL || resultCapacity < 0 || (resultCapacity > 0 &&
+ result == NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return USEARCH_DONE;
+ }
+
+ int32_t copylength = strsrch->search->matchedLength;
+ int32_t copyindex = strsrch->search->matchedIndex;
+ if (copyindex == USEARCH_DONE) {
+ u_terminateUChars(result, resultCapacity, 0, status);
+ return USEARCH_DONE;
+ }
+
+ if (resultCapacity < copylength) {
+ copylength = resultCapacity;
+ }
+ if (copylength > 0) {
+ uprv_memcpy(result, strsrch->search->text + copyindex,
+ copylength * sizeof(UChar));
+ }
+ return u_terminateUChars(result, resultCapacity,
+ strsrch->search->matchedLength, status);
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_getMatchedLength(
+ const UStringSearch *strsrch)
+{
+ if (strsrch) {
+ return strsrch->search->matchedLength;
+ }
+ return USEARCH_DONE;
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+U_CAPI void U_EXPORT2 usearch_setBreakIterator(UStringSearch *strsrch,
+ UBreakIterator *breakiter,
+ UErrorCode *status)
+{
+ if (U_SUCCESS(*status) && strsrch) {
+ strsrch->search->breakIter = breakiter;
+ if (breakiter) {
+ ubrk_setText(breakiter, strsrch->search->text,
+ strsrch->search->textLength, status);
+ }
+ }
+}
+
+U_CAPI const UBreakIterator* U_EXPORT2
+usearch_getBreakIterator(const UStringSearch *strsrch)
+{
+ if (strsrch) {
+ return strsrch->search->breakIter;
+ }
+ return NULL;
+}
+
+#endif
+
+U_CAPI void U_EXPORT2 usearch_setText( UStringSearch *strsrch,
+ const UChar *text,
+ int32_t textlength,
+ UErrorCode *status)
+{
+ if (U_SUCCESS(*status)) {
+ if (strsrch == NULL || text == NULL || textlength < -1 ||
+ textlength == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ else {
+ if (textlength == -1) {
+ textlength = u_strlen(text);
+ }
+ strsrch->search->text = text;
+ strsrch->search->textLength = textlength;
+ ucol_setText(strsrch->textIter, text, textlength, status);
+ strsrch->search->matchedIndex = USEARCH_DONE;
+ strsrch->search->matchedLength = 0;
+ strsrch->search->reset = TRUE;
+#if !UCONFIG_NO_BREAK_ITERATION
+ if (strsrch->search->breakIter != NULL) {
+ ubrk_setText(strsrch->search->breakIter, text,
+ textlength, status);
+ }
+ ubrk_setText(strsrch->search->internalBreakIter, text, textlength, status);
+#endif
+ }
+ }
+}
+
+U_CAPI const UChar * U_EXPORT2 usearch_getText(const UStringSearch *strsrch,
+ int32_t *length)
+{
+ if (strsrch) {
+ *length = strsrch->search->textLength;
+ return strsrch->search->text;
+ }
+ return NULL;
+}
+
+U_CAPI void U_EXPORT2 usearch_setCollator( UStringSearch *strsrch,
+ const UCollator *collator,
+ UErrorCode *status)
+{
+ if (U_SUCCESS(*status)) {
+ if (collator == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ if (strsrch) {
+ if (strsrch->ownCollator && (strsrch->collator != collator)) {
+ ucol_close((UCollator *)strsrch->collator);
+ strsrch->ownCollator = FALSE;
+ }
+ strsrch->collator = collator;
+ strsrch->strength = ucol_getStrength(collator);
+ strsrch->ceMask = getMask(strsrch->strength);
+#if !UCONFIG_NO_BREAK_ITERATION
+ ubrk_close(strsrch->search->internalBreakIter);
+ strsrch->search->internalBreakIter = ubrk_open(UBRK_CHARACTER, ucol_getLocale(collator, ULOC_VALID_LOCALE, status),
+ strsrch->search->text, strsrch->search->textLength, status);
+#endif
+ // if status is a failure, ucol_getAttribute returns UCOL_DEFAULT
+ strsrch->toShift =
+ ucol_getAttribute(collator, UCOL_ALTERNATE_HANDLING, status) ==
+ UCOL_SHIFTED;
+ // if status is a failure, ucol_getVariableTop returns 0
+ strsrch->variableTop = ucol_getVariableTop(collator, status);
+ if (U_SUCCESS(*status)) {
+ initialize(strsrch, status);
+ if (U_SUCCESS(*status)) {
+ uprv_init_collIterate(collator, strsrch->search->text,
+ strsrch->search->textLength,
+ &(strsrch->textIter->iteratordata_));
+ strsrch->utilIter->iteratordata_.coll = collator;
+ }
+ }
+ }
+ }
+}
+
+U_CAPI UCollator * U_EXPORT2 usearch_getCollator(const UStringSearch *strsrch)
+{
+ if (strsrch) {
+ return (UCollator *)strsrch->collator;
+ }
+ return NULL;
+}
+
+U_CAPI void U_EXPORT2 usearch_setPattern( UStringSearch *strsrch,
+ const UChar *pattern,
+ int32_t patternlength,
+ UErrorCode *status)
+{
+ if (U_SUCCESS(*status)) {
+ if (strsrch == NULL || pattern == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ else {
+ if (patternlength == -1) {
+ patternlength = u_strlen(pattern);
+ }
+ if (patternlength == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ strsrch->pattern.text = pattern;
+ strsrch->pattern.textLength = patternlength;
+ initialize(strsrch, status);
+ }
+ }
+}
+
+U_CAPI const UChar* U_EXPORT2
+usearch_getPattern(const UStringSearch *strsrch,
+ int32_t *length)
+{
+ if (strsrch) {
+ *length = strsrch->pattern.textLength;
+ return strsrch->pattern.text;
+ }
+ return NULL;
+}
+
+// miscellanous methods --------------------------------------------------
+
+U_CAPI int32_t U_EXPORT2 usearch_first(UStringSearch *strsrch,
+ UErrorCode *status)
+{
+ if (strsrch && U_SUCCESS(*status)) {
+ strsrch->search->isForwardSearching = TRUE;
+ usearch_setOffset(strsrch, 0, status);
+ if (U_SUCCESS(*status)) {
+ return usearch_next(strsrch, status);
+ }
+ }
+ return USEARCH_DONE;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_following(UStringSearch *strsrch,
+ int32_t position,
+ UErrorCode *status)
+{
+ if (strsrch && U_SUCCESS(*status)) {
+ strsrch->search->isForwardSearching = TRUE;
+ // position checked in usearch_setOffset
+ usearch_setOffset(strsrch, position, status);
+ if (U_SUCCESS(*status)) {
+ return usearch_next(strsrch, status);
+ }
+ }
+ return USEARCH_DONE;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_last(UStringSearch *strsrch,
+ UErrorCode *status)
+{
+ if (strsrch && U_SUCCESS(*status)) {
+ strsrch->search->isForwardSearching = FALSE;
+ usearch_setOffset(strsrch, strsrch->search->textLength, status);
+ if (U_SUCCESS(*status)) {
+ return usearch_previous(strsrch, status);
+ }
+ }
+ return USEARCH_DONE;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_preceding(UStringSearch *strsrch,
+ int32_t position,
+ UErrorCode *status)
+{
+ if (strsrch && U_SUCCESS(*status)) {
+ strsrch->search->isForwardSearching = FALSE;
+ // position checked in usearch_setOffset
+ usearch_setOffset(strsrch, position, status);
+ if (U_SUCCESS(*status)) {
+ return usearch_previous(strsrch, status);
+ }
+ }
+ return USEARCH_DONE;
+}
+
+/**
+* If a direction switch is required, we'll count the number of ces till the
+* beginning of the collation element iterator and iterate forwards that
+* number of times. This is so that we get to the correct point within the
+* string to continue the search in. Imagine when we are in the middle of the
+* normalization buffer when the change in direction is request. arrrgghh....
+* After searching the offset within the collation element iterator will be
+* shifted to the start of the match. If a match is not found, the offset would
+* have been set to the end of the text string in the collation element
+* iterator.
+* Okay, here's my take on normalization buffer. The only time when there can
+* be 2 matches within the same normalization is when the pattern is consists
+* of all accents. But since the offset returned is from the text string, we
+* should not confuse the caller by returning the second match within the
+* same normalization buffer. If we do, the 2 results will have the same match
+* offsets, and that'll be confusing. I'll return the next match that doesn't
+* fall within the same normalization buffer. Note this does not affect the
+* results of matches spanning the text and the normalization buffer.
+* The position to start searching is taken from the collation element
+* iterator. Callers of this API would have to set the offset in the collation
+* element iterator before using this method.
+*/
+U_CAPI int32_t U_EXPORT2 usearch_next(UStringSearch *strsrch,
+ UErrorCode *status)
+{
+ if (U_SUCCESS(*status) && strsrch) {
+ // note offset is either equivalent to the start of the previous match
+ // or is set by the user
+ int32_t offset = usearch_getOffset(strsrch);
+ USearch *search = strsrch->search;
+ search->reset = FALSE;
+ int32_t textlength = search->textLength;
+ if (search->isForwardSearching) {
+ if (offset == textlength
+ || (!search->isOverlap &&
+ (offset + strsrch->pattern.defaultShiftSize > textlength ||
+ (search->matchedIndex != USEARCH_DONE &&
+ offset + search->matchedLength >= textlength)))) {
+ // not enough characters to match
+ setMatchNotFound(strsrch);
+ return USEARCH_DONE;
+ }
+ }
+ else {
+ // switching direction.
+ // if matchedIndex == USEARCH_DONE, it means that either a
+ // setOffset has been called or that previous ran off the text
+ // string. the iterator would have been set to offset 0 if a
+ // match is not found.
+ search->isForwardSearching = TRUE;
+ if (search->matchedIndex != USEARCH_DONE) {
+ // there's no need to set the collation element iterator
+ // the next call to next will set the offset.
+ return search->matchedIndex;
+ }
+ }
+
+ if (U_SUCCESS(*status)) {
+ if (strsrch->pattern.CELength == 0) {
+ if (search->matchedIndex == USEARCH_DONE) {
+ search->matchedIndex = offset;
+ }
+ else { // moves by codepoints
+ UTF_FWD_1(search->text, search->matchedIndex, textlength);
+ }
+
+ search->matchedLength = 0;
+ setColEIterOffset(strsrch->textIter, search->matchedIndex);
+ // status checked below
+ if (search->matchedIndex == textlength) {
+ search->matchedIndex = USEARCH_DONE;
+ }
+ }
+ else {
+ if (search->matchedLength > 0) {
+ // if matchlength is 0 we are at the start of the iteration
+ if (search->isOverlap) {
+ ucol_setOffset(strsrch->textIter, offset + 1, status);
+ }
+ else {
+ ucol_setOffset(strsrch->textIter,
+ offset + search->matchedLength, status);
+ }
+ }
+ else {
+ // for boundary check purposes. this will ensure that the
+ // next match will not preceed the current offset
+ // note search->matchedIndex will always be set to something
+ // in the code
+ search->matchedIndex = offset - 1;
+ }
+
+ if (search->isCanonicalMatch) {
+ // can't use exact here since extra accents are allowed.
+ usearch_handleNextCanonical(strsrch, status);
+ }
+ else {
+ usearch_handleNextExact(strsrch, status);
+ }
+ }
+
+ if (U_FAILURE(*status)) {
+ return USEARCH_DONE;
+ }
+
+ return search->matchedIndex;
+ }
+ }
+ return USEARCH_DONE;
+}
+
+U_CAPI int32_t U_EXPORT2 usearch_previous(UStringSearch *strsrch,
+ UErrorCode *status)
+{
+ if (U_SUCCESS(*status) && strsrch) {
+ int32_t offset;
+ USearch *search = strsrch->search;
+ if (search->reset) {
+ offset = search->textLength;
+ search->isForwardSearching = FALSE;
+ search->reset = FALSE;
+ setColEIterOffset(strsrch->textIter, offset);
+ }
+ else {
+ offset = usearch_getOffset(strsrch);
+ }
+
+ int32_t matchedindex = search->matchedIndex;
+ if (search->isForwardSearching == TRUE) {
+ // switching direction.
+ // if matchedIndex == USEARCH_DONE, it means that either a
+ // setOffset has been called or that next ran off the text
+ // string. the iterator would have been set to offset textLength if
+ // a match is not found.
+ search->isForwardSearching = FALSE;
+ if (matchedindex != USEARCH_DONE) {
+ return matchedindex;
+ }
+ }
+ else {
+ if (offset == 0 || matchedindex == 0 ||
+ (!search->isOverlap &&
+ (offset < strsrch->pattern.defaultShiftSize ||
+ (matchedindex != USEARCH_DONE &&
+ matchedindex < strsrch->pattern.defaultShiftSize)))) {
+ // not enough characters to match
+ setMatchNotFound(strsrch);
+ return USEARCH_DONE;
+ }
+ }
+
+ if (U_SUCCESS(*status)) {
+ if (strsrch->pattern.CELength == 0) {
+ search->matchedIndex =
+ (matchedindex == USEARCH_DONE ? offset : matchedindex);
+ if (search->matchedIndex == 0) {
+ setMatchNotFound(strsrch);
+ // status checked below
+ }
+ else { // move by codepoints
+ UTF_BACK_1(search->text, 0, search->matchedIndex);
+ setColEIterOffset(strsrch->textIter, search->matchedIndex);
+ // status checked below
+ search->matchedLength = 0;
+ }
+ }
+ else {
+ if (strsrch->search->isCanonicalMatch) {
+ // can't use exact here since extra accents are allowed.
+ usearch_handlePreviousCanonical(strsrch, status);
+ // status checked below
+ }
+ else {
+ usearch_handlePreviousExact(strsrch, status);
+ // status checked below
+ }
+ }
+
+ if (U_FAILURE(*status)) {
+ return USEARCH_DONE;
+ }
+
+ return search->matchedIndex;
+ }
+ }
+ return USEARCH_DONE;
+}
+
+
+
+U_CAPI void U_EXPORT2 usearch_reset(UStringSearch *strsrch)
+{
+ /*
+ reset is setting the attributes that are already in
+ string search, hence all attributes in the collator should
+ be retrieved without any problems
+ */
+ if (strsrch) {
+ UErrorCode status = U_ZERO_ERROR;
+ UBool sameCollAttribute = TRUE;
+ uint32_t ceMask;
+ UBool shift;
+ uint32_t varTop;
+
+ strsrch->strength = ucol_getStrength(strsrch->collator);
+ ceMask = getMask(strsrch->strength);
+ if (strsrch->ceMask != ceMask) {
+ strsrch->ceMask = ceMask;
+ sameCollAttribute = FALSE;
+ }
+ // if status is a failure, ucol_getAttribute returns UCOL_DEFAULT
+ shift = ucol_getAttribute(strsrch->collator, UCOL_ALTERNATE_HANDLING,
+ &status) == UCOL_SHIFTED;
+ if (strsrch->toShift != shift) {
+ strsrch->toShift = shift;
+ sameCollAttribute = FALSE;
+ }
+
+ // if status is a failure, ucol_getVariableTop returns 0
+ varTop = ucol_getVariableTop(strsrch->collator, &status);
+ if (strsrch->variableTop != varTop) {
+ strsrch->variableTop = varTop;
+ sameCollAttribute = FALSE;
+ }
+ if (!sameCollAttribute) {
+ initialize(strsrch, &status);
+ }
+ uprv_init_collIterate(strsrch->collator, strsrch->search->text,
+ strsrch->search->textLength,
+ &(strsrch->textIter->iteratordata_));
+ strsrch->search->matchedLength = 0;
+ strsrch->search->matchedIndex = USEARCH_DONE;
+ strsrch->search->isOverlap = FALSE;
+ strsrch->search->isCanonicalMatch = FALSE;
+ strsrch->search->isForwardSearching = TRUE;
+ strsrch->search->reset = TRUE;
+ }
+}
+
+// internal use methods declared in usrchimp.h -----------------------------
+
+UBool usearch_handleNextExact(UStringSearch *strsrch, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t textlength = strsrch->search->textLength;
+ int32_t *patternce = strsrch->pattern.CE;
+ int32_t patterncelength = strsrch->pattern.CELength;
+ int32_t textoffset = ucol_getOffset(coleiter);
+
+ // status used in setting coleiter offset, since offset is checked in
+ // shiftForward before setting the coleiter offset, status never
+ // a failure
+ textoffset = shiftForward(strsrch, textoffset, UCOL_NULLORDER,
+ patterncelength);
+ while (textoffset <= textlength)
+ {
+ uint32_t patternceindex = patterncelength - 1;
+ int32_t targetce;
+ UBool found = FALSE;
+ int32_t lastce = UCOL_NULLORDER;
+
+ setColEIterOffset(coleiter, textoffset);
+
+ for (;;) {
+ // finding the last pattern ce match, imagine composite characters
+ // for example: search for pattern A in text \u00C0
+ // we'll have to skip \u0300 the grave first before we get to A
+ targetce = ucol_previous(coleiter, status);
+ if (U_FAILURE(*status) || targetce == UCOL_NULLORDER) {
+ found = FALSE;
+ break;
+ }
+ targetce = getCE(strsrch, targetce);
+ if (targetce == UCOL_IGNORABLE && inNormBuf(coleiter)) {
+ // this is for the text \u0315\u0300 that requires
+ // normalization and pattern \u0300, where \u0315 is ignorable
+ continue;
+ }
+ if (lastce == UCOL_NULLORDER || lastce == UCOL_IGNORABLE) {
+ lastce = targetce;
+ }
+ if (targetce == patternce[patternceindex]) {
+ // the first ce can be a contraction
+ found = TRUE;
+ break;
+ }
+ if (!hasExpansion(coleiter)) {
+ found = FALSE;
+ break;
+ }
+ }
+
+ //targetce = lastce;
+
+ while (found && patternceindex > 0) {
+ lastce = targetce;
+ targetce = ucol_previous(coleiter, status);
+ if (U_FAILURE(*status) || targetce == UCOL_NULLORDER) {
+ found = FALSE;
+ break;
+ }
+ targetce = getCE(strsrch, targetce);
+ if (targetce == UCOL_IGNORABLE) {
+ continue;
+ }
+
+ patternceindex --;
+ found = found && targetce == patternce[patternceindex];
+ }
+
+ targetce = lastce;
+
+ if (!found) {
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ textoffset = shiftForward(strsrch, textoffset, lastce,
+ patternceindex);
+ // status checked at loop.
+ patternceindex = patterncelength;
+ continue;
+ }
+
+ if (checkNextExactMatch(strsrch, &textoffset, status)) {
+ // status checked in ucol_setOffset
+ setColEIterOffset(coleiter, strsrch->search->matchedIndex);
+ return TRUE;
+ }
+ }
+ setMatchNotFound(strsrch);
+ return FALSE;
+}
+
+UBool usearch_handleNextCanonical(UStringSearch *strsrch, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t textlength = strsrch->search->textLength;
+ int32_t *patternce = strsrch->pattern.CE;
+ int32_t patterncelength = strsrch->pattern.CELength;
+ int32_t textoffset = ucol_getOffset(coleiter);
+ UBool hasPatternAccents =
+ strsrch->pattern.hasSuffixAccents || strsrch->pattern.hasPrefixAccents;
+
+ textoffset = shiftForward(strsrch, textoffset, UCOL_NULLORDER,
+ patterncelength);
+ strsrch->canonicalPrefixAccents[0] = 0;
+ strsrch->canonicalSuffixAccents[0] = 0;
+
+ while (textoffset <= textlength)
+ {
+ int32_t patternceindex = patterncelength - 1;
+ int32_t targetce;
+ UBool found = FALSE;
+ int32_t lastce = UCOL_NULLORDER;
+
+ setColEIterOffset(coleiter, textoffset);
+
+ for (;;) {
+ // finding the last pattern ce match, imagine composite characters
+ // for example: search for pattern A in text \u00C0
+ // we'll have to skip \u0300 the grave first before we get to A
+ targetce = ucol_previous(coleiter, status);
+ if (U_FAILURE(*status) || targetce == UCOL_NULLORDER) {
+ found = FALSE;
+ break;
+ }
+ targetce = getCE(strsrch, targetce);
+ if (lastce == UCOL_NULLORDER || lastce == UCOL_IGNORABLE) {
+ lastce = targetce;
+ }
+ if (targetce == patternce[patternceindex]) {
+ // the first ce can be a contraction
+ found = TRUE;
+ break;
+ }
+ if (!hasExpansion(coleiter)) {
+ found = FALSE;
+ break;
+ }
+ }
+
+ while (found && patternceindex > 0) {
+ targetce = ucol_previous(coleiter, status);
+ if (U_FAILURE(*status) || targetce == UCOL_NULLORDER) {
+ found = FALSE;
+ break;
+ }
+ targetce = getCE(strsrch, targetce);
+ if (targetce == UCOL_IGNORABLE) {
+ continue;
+ }
+
+ patternceindex --;
+ found = found && targetce == patternce[patternceindex];
+ }
+
+ // initializing the rearranged accent array
+ if (hasPatternAccents && !found) {
+ strsrch->canonicalPrefixAccents[0] = 0;
+ strsrch->canonicalSuffixAccents[0] = 0;
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ found = doNextCanonicalMatch(strsrch, textoffset, status);
+ }
+
+ if (!found) {
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ textoffset = shiftForward(strsrch, textoffset, lastce,
+ patternceindex);
+ // status checked at loop
+ patternceindex = patterncelength;
+ continue;
+ }
+
+ if (checkNextCanonicalMatch(strsrch, &textoffset, status)) {
+ setColEIterOffset(coleiter, strsrch->search->matchedIndex);
+ return TRUE;
+ }
+ }
+ setMatchNotFound(strsrch);
+ return FALSE;
+}
+
+UBool usearch_handlePreviousExact(UStringSearch *strsrch, UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t *patternce = strsrch->pattern.CE;
+ int32_t patterncelength = strsrch->pattern.CELength;
+ int32_t textoffset = ucol_getOffset(coleiter);
+
+ // shifting it check for setting offset
+ // if setOffset is called previously or there was no previous match, we
+ // leave the offset as it is.
+ if (strsrch->search->matchedIndex != USEARCH_DONE) {
+ textoffset = strsrch->search->matchedIndex;
+ }
+
+ textoffset = reverseShift(strsrch, textoffset, UCOL_NULLORDER,
+ patterncelength);
+
+ while (textoffset >= 0)
+ {
+ int32_t patternceindex = 1;
+ int32_t targetce;
+ UBool found = FALSE;
+ int32_t firstce = UCOL_NULLORDER;
+
+ // if status is a failure, ucol_setOffset does nothing
+ setColEIterOffset(coleiter, textoffset);
+
+ for (;;) {
+ // finding the first pattern ce match, imagine composite
+ // characters. for example: search for pattern \u0300 in text
+ // \u00C0, we'll have to skip A first before we get to
+ // \u0300 the grave accent
+ targetce = ucol_next(coleiter, status);
+ if (U_FAILURE(*status) || targetce == UCOL_NULLORDER) {
+ found = FALSE;
+ break;
+ }
+ targetce = getCE(strsrch, targetce);
+ if (firstce == UCOL_NULLORDER || firstce == UCOL_IGNORABLE) {
+ firstce = targetce;
+ }
+ if (targetce == UCOL_IGNORABLE && strsrch->strength != UCOL_PRIMARY) {
+ continue;
+ }
+ if (targetce == patternce[0]) {
+ found = TRUE;
+ break;
+ }
+ if (!hasExpansion(coleiter)) {
+ // checking for accents in composite character
+ found = FALSE;
+ break;
+ }
+ }
+
+ //targetce = firstce;
+
+ while (found && (patternceindex < patterncelength)) {
+ firstce = targetce;
+ targetce = ucol_next(coleiter, status);
+ if (U_FAILURE(*status) || targetce == UCOL_NULLORDER) {
+ found = FALSE;
+ break;
+ }
+ targetce = getCE(strsrch, targetce);
+ if (targetce == UCOL_IGNORABLE) {
+ continue;
+ }
+
+ found = found && targetce == patternce[patternceindex];
+ patternceindex ++;
+ }
+
+ targetce = firstce;
+
+ if (!found) {
+ if (U_FAILURE(*status)) {
+ break;
+ }
+
+ textoffset = reverseShift(strsrch, textoffset, targetce,
+ patternceindex);
+ patternceindex = 0;
+ continue;
+ }
+
+ if (checkPreviousExactMatch(strsrch, &textoffset, status)) {
+ setColEIterOffset(coleiter, textoffset);
+ return TRUE;
+ }
+ }
+ setMatchNotFound(strsrch);
+ return FALSE;
+}
+
+UBool usearch_handlePreviousCanonical(UStringSearch *strsrch,
+ UErrorCode *status)
+{
+ if (U_FAILURE(*status)) {
+ setMatchNotFound(strsrch);
+ return FALSE;
+ }
+
+ UCollationElements *coleiter = strsrch->textIter;
+ int32_t *patternce = strsrch->pattern.CE;
+ int32_t patterncelength = strsrch->pattern.CELength;
+ int32_t textoffset = ucol_getOffset(coleiter);
+ UBool hasPatternAccents =
+ strsrch->pattern.hasSuffixAccents || strsrch->pattern.hasPrefixAccents;
+
+ // shifting it check for setting offset
+ // if setOffset is called previously or there was no previous match, we
+ // leave the offset as it is.
+ if (strsrch->search->matchedIndex != USEARCH_DONE) {
+ textoffset = strsrch->search->matchedIndex;
+ }
+
+ textoffset = reverseShift(strsrch, textoffset, UCOL_NULLORDER,
+ patterncelength);
+ strsrch->canonicalPrefixAccents[0] = 0;
+ strsrch->canonicalSuffixAccents[0] = 0;
+
+ while (textoffset >= 0)
+ {
+ int32_t patternceindex = 1;
+ int32_t targetce;
+ UBool found = FALSE;
+ int32_t firstce = UCOL_NULLORDER;
+
+ setColEIterOffset(coleiter, textoffset);
+ for (;;) {
+ // finding the first pattern ce match, imagine composite
+ // characters. for example: search for pattern \u0300 in text
+ // \u00C0, we'll have to skip A first before we get to
+ // \u0300 the grave accent
+ targetce = ucol_next(coleiter, status);
+ if (U_FAILURE(*status) || targetce == UCOL_NULLORDER) {
+ found = FALSE;
+ break;
+ }
+ targetce = getCE(strsrch, targetce);
+ if (firstce == UCOL_NULLORDER || firstce == UCOL_IGNORABLE) {
+ firstce = targetce;
+ }
+
+ if (targetce == patternce[0]) {
+ // the first ce can be a contraction
+ found = TRUE;
+ break;
+ }
+ if (!hasExpansion(coleiter)) {
+ // checking for accents in composite character
+ found = FALSE;
+ break;
+ }
+ }
+
+ targetce = firstce;
+
+ while (found && patternceindex < patterncelength) {
+ targetce = ucol_next(coleiter, status);
+ if (U_FAILURE(*status) || targetce == UCOL_NULLORDER) {
+ found = FALSE;
+ break;
+ }
+ targetce = getCE(strsrch, targetce);
+ if (targetce == UCOL_IGNORABLE) {
+ continue;
+ }
+
+ found = found && targetce == patternce[patternceindex];
+ patternceindex ++;
+ }
+
+ // initializing the rearranged accent array
+ if (hasPatternAccents && !found) {
+ strsrch->canonicalPrefixAccents[0] = 0;
+ strsrch->canonicalSuffixAccents[0] = 0;
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ found = doPreviousCanonicalMatch(strsrch, textoffset, status);
+ }
+
+ if (!found) {
+ if (U_FAILURE(*status)) {
+ break;
+ }
+ textoffset = reverseShift(strsrch, textoffset, targetce,
+ patternceindex);
+ patternceindex = 0;
+ continue;
+ }
+
+ if (checkPreviousCanonicalMatch(strsrch, &textoffset, status)) {
+ setColEIterOffset(coleiter, textoffset);
+ return TRUE;
+ }
+ }
+ setMatchNotFound(strsrch);
+ return FALSE;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/usrchimp.h b/Build/source/libs/icu/icu-xetex/i18n/usrchimp.h
new file mode 100644
index 00000000000..fff52b2186e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/usrchimp.h
@@ -0,0 +1,134 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2007 IBM and others. All rights reserved.
+**********************************************************************
+* Date Name Description
+* 08/13/2001 synwee Creation.
+**********************************************************************
+*/
+#ifndef USRCHIMP_H
+#define USRCHIMP_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/ucol.h"
+#include "unicode/ucoleitr.h"
+#include "unicode/ubrk.h"
+
+#define INITIAL_ARRAY_SIZE_ 256
+#define MAX_TABLE_SIZE_ 257
+
+struct USearch {
+ // required since collation element iterator does not have a getText API
+ const UChar *text;
+ int32_t textLength; // exact length
+ UBool isOverlap;
+ UBool isCanonicalMatch;
+ UBreakIterator *internalBreakIter; //internal character breakiterator
+ UBreakIterator *breakIter;
+ // value USEARCH_DONE is the default value
+ // if we are not at the start of the text or the end of the text,
+ // depending on the iteration direction and matchedIndex is USEARCH_DONE
+ // it means that we can find any more matches in that particular direction
+ int32_t matchedIndex;
+ int32_t matchedLength;
+ UBool isForwardSearching;
+ UBool reset;
+};
+
+struct UPattern {
+ const UChar *text;
+ int32_t textLength; // exact length
+ // length required for backwards ce comparison
+ int32_t CELength;
+ int32_t *CE;
+ int32_t CEBuffer[INITIAL_ARRAY_SIZE_];
+ UBool hasPrefixAccents;
+ UBool hasSuffixAccents;
+ int16_t defaultShiftSize;
+ int16_t shift[MAX_TABLE_SIZE_];
+ int16_t backShift[MAX_TABLE_SIZE_];
+};
+
+struct UStringSearch {
+ struct USearch *search;
+ struct UPattern pattern;
+ const UCollator *collator;
+ // positions within the collation element iterator is used to determine
+ // if we are at the start of the text.
+ UCollationElements *textIter;
+ // utility collation element, used throughout program for temporary
+ // iteration.
+ UCollationElements *utilIter;
+ UBool ownCollator;
+ UCollationStrength strength;
+ uint32_t ceMask;
+ uint32_t variableTop;
+ UBool toShift;
+ UChar canonicalPrefixAccents[INITIAL_ARRAY_SIZE_];
+ UChar canonicalSuffixAccents[INITIAL_ARRAY_SIZE_];
+};
+
+/**
+* Exact matches without checking for the ends for extra accents.
+* The match after the position within the collation element iterator is to be
+* found.
+* After a match is found the offset in the collation element iterator will be
+* shifted to the start of the match.
+* Implementation note:
+* For tertiary we can't use the collator->tertiaryMask, that is a
+* preprocessed mask that takes into account case options. since we are only
+* concerned with exact matches, we don't need that.
+* Alternate handling - since only the 16 most significant digits is only used,
+* we can safely do a compare without masking if the ce is a variable, we mask
+* and get only the primary values no shifting to quartenary is required since
+* all primary values less than variabletop will need to be masked off anyway.
+* If the end character is composite and the pattern ce does not match the text
+* ce, we skip it until we find a match in the end composite character or when
+* it has passed the character. This is so that we can match pattern "a" with
+* the text "\u00e6"
+* @param strsrch string search data
+* @param status error status if any
+* @return TRUE if an exact match is found, FALSE otherwise
+*/
+U_CFUNC
+UBool usearch_handleNextExact(UStringSearch *strsrch, UErrorCode *status);
+
+/**
+* Canonical matches.
+* According to the definition, matches found here will include the whole span
+* of beginning and ending accents if it overlaps that region.
+* @param strsrch string search data
+* @param status error status if any
+* @return TRUE if a canonical match is found, FALSE otherwise
+*/
+U_CFUNC
+UBool usearch_handleNextCanonical(UStringSearch *strsrch, UErrorCode *status);
+
+/**
+* Gets the previous match.
+* Comments follows from handleNextExact
+* @param strsrch string search data
+* @param status error status if any
+* @return True if a exact math is found, FALSE otherwise.
+*/
+U_CFUNC
+UBool usearch_handlePreviousExact(UStringSearch *strsrch, UErrorCode *status);
+
+/**
+* Canonical matches.
+* According to the definition, matches found here will include the whole span
+* of beginning and ending accents if it overlaps that region.
+* @param strsrch string search data
+* @param status error status if any
+* @return TRUE if a canonical match is found, FALSE otherwise
+*/
+U_CFUNC
+UBool usearch_handlePreviousCanonical(UStringSearch *strsrch,
+ UErrorCode *status);
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/i18n/utmscale.c b/Build/source/libs/icu/icu-xetex/i18n/utmscale.c
new file mode 100644
index 00000000000..33f5d9212d0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/utmscale.c
@@ -0,0 +1,114 @@
+/*
+*******************************************************************************
+* Copyright (C) 2004-2006, International Business Machines Corporation and
+* others. All Rights Reserved.
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/utmscale.h"
+
+#define ticks INT64_C(1)
+#define microseconds (ticks * 10)
+#define milliseconds (microseconds * 1000)
+#define seconds (milliseconds * 1000)
+#define minutes (seconds * 60)
+#define hours (minutes * 60)
+#define days (hours * 24)
+
+/* Constants generated by ICU4J com.ibm.icu.dev.tool.timescale.GenerateCTimeScaleData. */
+static const int64_t timeScaleTable[UDTS_MAX_SCALE][UTSV_MAX_SCALE_VALUE] = {
+ /* units epochOffset fromMin fromMax toMin toMax epochOffsetP1 epochOffsetM1 unitsRound minRound maxRound */
+ {milliseconds, INT64_C(62135596800000), INT64_C(-984472800485477), INT64_C(860201606885477), INT64_C(-9223372036854774999), INT64_C(9223372036854774999), INT64_C(62135596800001), INT64_C(62135596799999), INT64_C(5000), INT64_C(-9223372036854770808), INT64_C(9223372036854770807)},
+ {seconds, INT64_C(62135596800), INT64_C(-984472800485), INT64_C(860201606885), U_INT64_MIN, U_INT64_MAX, INT64_C(62135596801), INT64_C(62135596799), INT64_C(5000000), INT64_C(-9223372036849775808), INT64_C(9223372036849775807)},
+ {milliseconds, INT64_C(62135596800000), INT64_C(-984472800485477), INT64_C(860201606885477), INT64_C(-9223372036854774999), INT64_C(9223372036854774999), INT64_C(62135596800001), INT64_C(62135596799999), INT64_C(5000), INT64_C(-9223372036854770808), INT64_C(9223372036854770807)},
+ {ticks, INT64_C(504911232000000000), U_INT64_MIN, INT64_C(8718460804854775807), INT64_C(-8718460804854775808), U_INT64_MAX, INT64_C(504911232000000000), INT64_C(504911232000000000), INT64_C(0), U_INT64_MIN, U_INT64_MAX},
+ {ticks, INT64_C(0), U_INT64_MIN, U_INT64_MAX, U_INT64_MIN, U_INT64_MAX, INT64_C(0), INT64_C(0), INT64_C(0), U_INT64_MIN, U_INT64_MAX},
+ {seconds, INT64_C(60052752000), INT64_C(-982389955685), INT64_C(862284451685), U_INT64_MIN, U_INT64_MAX, INT64_C(60052752001), INT64_C(60052751999), INT64_C(5000000), INT64_C(-9223372036849775808), INT64_C(9223372036849775807)},
+ {seconds, INT64_C(63113904000), INT64_C(-985451107685), INT64_C(859223299685), U_INT64_MIN, U_INT64_MAX, INT64_C(63113904001), INT64_C(63113903999), INT64_C(5000000), INT64_C(-9223372036849775808), INT64_C(9223372036849775807)},
+ {days, INT64_C(693594), INT64_C(-11368793), INT64_C(9981605), U_INT64_MIN, U_INT64_MAX, INT64_C(693595), INT64_C(693593), INT64_C(432000000000), INT64_C(-9223371604854775808), INT64_C(9223371604854775807)},
+ {days, INT64_C(693594), INT64_C(-11368793), INT64_C(9981605), U_INT64_MIN, U_INT64_MAX, INT64_C(693595), INT64_C(693593), INT64_C(432000000000), INT64_C(-9223371604854775808), INT64_C(9223371604854775807)},
+ {microseconds, INT64_C(62135596800000000), INT64_C(-984472800485477580), INT64_C(860201606885477580), INT64_C(-9223372036854775804), INT64_C(9223372036854775804), INT64_C(62135596800000001), INT64_C(62135596799999999), INT64_C(5), INT64_C(-9223372036854775803), INT64_C(9223372036854775802)},
+};
+
+U_CAPI int64_t U_EXPORT2
+utmscale_getTimeScaleValue(UDateTimeScale timeScale, UTimeScaleValue value, UErrorCode *status)
+{
+ if (status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if (timeScale < UDTS_JAVA_TIME || UDTS_MAX_SCALE <= timeScale
+ || value < UTSV_UNITS_VALUE || UTSV_MAX_SCALE_VALUE <= value)
+ {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ return timeScaleTable[timeScale][value];
+}
+
+U_CAPI int64_t U_EXPORT2
+utmscale_fromInt64(int64_t otherTime, UDateTimeScale timeScale, UErrorCode *status)
+{
+ const int64_t *data;
+
+ if (status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if (timeScale < 0 || timeScale >= UDTS_MAX_SCALE) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ data = (const int64_t *)(&timeScaleTable[timeScale]);
+
+ if (otherTime < data[UTSV_FROM_MIN_VALUE] || otherTime > data[UTSV_FROM_MAX_VALUE]) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ return (otherTime + data[UTSV_EPOCH_OFFSET_VALUE]) * data[UTSV_UNITS_VALUE];
+}
+
+U_CAPI int64_t U_EXPORT2
+utmscale_toInt64(int64_t universalTime, UDateTimeScale timeScale, UErrorCode *status)
+{
+ const int64_t *data;
+
+ if (status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+
+ if (timeScale < 0 || timeScale >= UDTS_MAX_SCALE) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ data = (const int64_t *)(&timeScaleTable[timeScale]);
+
+ if (universalTime < data[UTSV_TO_MIN_VALUE] || universalTime > data[UTSV_TO_MAX_VALUE]) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ if (universalTime < 0) {
+ if (universalTime < data[UTSV_MIN_ROUND_VALUE]) {
+ return (universalTime + data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_PLUS_1_VALUE];
+ }
+
+ return (universalTime - data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_VALUE];
+ }
+
+ if (universalTime > data[UTSV_MAX_ROUND_VALUE]) {
+ return (universalTime - data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_MINUS_1_VALUE];
+ }
+
+ return (universalTime + data[UTSV_UNITS_ROUND_VALUE]) / data[UTSV_UNITS_VALUE] - data[UTSV_EPOCH_OFFSET_VALUE];
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/utrans.cpp b/Build/source/libs/icu/icu-xetex/i18n/utrans.cpp
new file mode 100644
index 00000000000..11da9d79438
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/utrans.cpp
@@ -0,0 +1,498 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1997-2005, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *******************************************************************************
+ * Date Name Description
+ * 06/21/00 aliu Creation.
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/utrans.h"
+#include "unicode/putil.h"
+#include "unicode/rep.h"
+#include "unicode/translit.h"
+#include "unicode/unifilt.h"
+#include "unicode/uniset.h"
+#include "unicode/ustring.h"
+#include "unicode/uenum.h"
+#include "uenumimp.h"
+#include "cpputils.h"
+#include "rbt.h"
+
+// Following macro is to be followed by <return value>';' or just ';'
+#define utrans_ENTRY(s) if ((s)==NULL || U_FAILURE(*(s))) return
+
+/********************************************************************
+ * Replaceable-UReplaceableCallbacks glue
+ ********************************************************************/
+
+/**
+ * Make a UReplaceable + UReplaceableCallbacks into a Replaceable object.
+ */
+U_NAMESPACE_BEGIN
+class ReplaceableGlue : public Replaceable {
+
+ UReplaceable *rep;
+ UReplaceableCallbacks *func;
+
+public:
+
+ ReplaceableGlue(UReplaceable *replaceable,
+ UReplaceableCallbacks *funcCallback);
+
+ virtual ~ReplaceableGlue();
+
+ virtual void handleReplaceBetween(int32_t start,
+ int32_t limit,
+ const UnicodeString& text);
+
+ virtual void extractBetween(int32_t start,
+ int32_t limit,
+ UnicodeString& target) const;
+
+ virtual void copy(int32_t start, int32_t limit, int32_t dest);
+
+ // virtual Replaceable *clone() const { return NULL; } same as default
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static UClassID U_EXPORT2 getStaticClassID();
+
+protected:
+
+ virtual int32_t getLength() const;
+
+ virtual UChar getCharAt(int32_t offset) const;
+
+ virtual UChar32 getChar32At(int32_t offset) const;
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ReplaceableGlue)
+
+ReplaceableGlue::ReplaceableGlue(UReplaceable *replaceable,
+ UReplaceableCallbacks *funcCallback)
+ : Replaceable()
+{
+ this->rep = replaceable;
+ this->func = funcCallback;
+}
+
+ReplaceableGlue::~ReplaceableGlue() {}
+
+int32_t ReplaceableGlue::getLength() const {
+ return (*func->length)(rep);
+}
+
+UChar ReplaceableGlue::getCharAt(int32_t offset) const {
+ return (*func->charAt)(rep, offset);
+}
+
+UChar32 ReplaceableGlue::getChar32At(int32_t offset) const {
+ return (*func->char32At)(rep, offset);
+}
+
+void ReplaceableGlue::handleReplaceBetween(int32_t start,
+ int32_t limit,
+ const UnicodeString& text) {
+ (*func->replace)(rep, start, limit, text.getBuffer(), text.length());
+}
+
+void ReplaceableGlue::extractBetween(int32_t start,
+ int32_t limit,
+ UnicodeString& target) const {
+ (*func->extract)(rep, start, limit, target.getBuffer(limit-start));
+ target.releaseBuffer(limit-start);
+}
+
+void ReplaceableGlue::copy(int32_t start, int32_t limit, int32_t dest) {
+ (*func->copy)(rep, start, limit, dest);
+}
+U_NAMESPACE_END
+/********************************************************************
+ * General API
+ ********************************************************************/
+U_NAMESPACE_USE
+
+U_CAPI UTransliterator* U_EXPORT2
+utrans_openU(const UChar *id,
+ int32_t idLength,
+ UTransDirection dir,
+ const UChar *rules,
+ int32_t rulesLength,
+ UParseError *parseError,
+ UErrorCode *status) {
+ if(status==NULL || U_FAILURE(*status)) {
+ return NULL;
+ }
+ if (id == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+ UParseError temp;
+
+ if(parseError == NULL){
+ parseError = &temp;
+ }
+
+ UnicodeString ID(idLength<0, id, idLength); // r-o alias
+
+ if(rules==NULL){
+
+ Transliterator *trans = NULL;
+
+ trans = Transliterator::createInstance(ID, dir, *parseError, *status);
+
+ if(U_FAILURE(*status)){
+ return NULL;
+ }
+ return (UTransliterator*) trans;
+ }else{
+ UnicodeString ruleStr(rulesLength < 0,
+ rules,
+ rulesLength); // r-o alias
+
+ RuleBasedTransliterator *trans = NULL;
+ trans = new RuleBasedTransliterator(ID, ruleStr, dir,
+ NULL, *parseError, *status);
+ if (trans == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ } else if (U_FAILURE(*status)) {
+ delete trans;
+ trans = NULL;
+ }
+ return (UTransliterator*) trans;
+ }
+}
+
+U_CAPI UTransliterator* U_EXPORT2
+utrans_open(const char* id,
+ UTransDirection dir,
+ const UChar* rules, /* may be Null */
+ int32_t rulesLength, /* -1 if null-terminated */
+ UParseError* parseError, /* may be Null */
+ UErrorCode* status) {
+ UnicodeString ID(id, -1, US_INV); // use invariant converter
+ return utrans_openU(ID.getBuffer(), ID.length(), dir,
+ rules, rulesLength,
+ parseError, status);
+}
+
+U_CAPI UTransliterator* U_EXPORT2
+utrans_openInverse(const UTransliterator* trans,
+ UErrorCode* status) {
+
+ utrans_ENTRY(status) NULL;
+
+ UTransliterator* result =
+ (UTransliterator*) ((Transliterator*) trans)->createInverse(*status);
+
+ return result;
+}
+
+U_CAPI UTransliterator* U_EXPORT2
+utrans_clone(const UTransliterator* trans,
+ UErrorCode* status) {
+
+ utrans_ENTRY(status) NULL;
+
+ if (trans == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ Transliterator *t = ((Transliterator*) trans)->clone();
+ if (t == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ return (UTransliterator*) t;
+}
+
+U_CAPI void U_EXPORT2
+utrans_close(UTransliterator* trans) {
+ delete (Transliterator*) trans;
+}
+
+U_CAPI const UChar * U_EXPORT2
+utrans_getUnicodeID(const UTransliterator *trans,
+ int32_t *resultLength) {
+ // Transliterator keeps its ID NUL-terminated
+ const UnicodeString &ID=((Transliterator*) trans)->getID();
+ if(resultLength!=NULL) {
+ *resultLength=ID.length();
+ }
+ return ID.getBuffer();
+}
+
+U_CAPI int32_t U_EXPORT2
+utrans_getID(const UTransliterator* trans,
+ char* buf,
+ int32_t bufCapacity) {
+ return ((Transliterator*) trans)->getID().extract(0, 0x7fffffff, buf, bufCapacity, US_INV);
+}
+
+U_CAPI void U_EXPORT2
+utrans_register(UTransliterator* adoptedTrans,
+ UErrorCode* status) {
+ utrans_ENTRY(status);
+ // status currently ignored; may remove later
+ Transliterator::registerInstance((Transliterator*) adoptedTrans);
+}
+
+U_CAPI void U_EXPORT2
+utrans_unregisterID(const UChar* id, int32_t idLength) {
+ UnicodeString ID(idLength<0, id, idLength); // r-o alias
+ Transliterator::unregister(ID);
+}
+
+U_CAPI void U_EXPORT2
+utrans_unregister(const char* id) {
+ UnicodeString ID(id, -1, US_INV); // use invariant converter
+ Transliterator::unregister(ID);
+}
+
+U_CAPI void U_EXPORT2
+utrans_setFilter(UTransliterator* trans,
+ const UChar* filterPattern,
+ int32_t filterPatternLen,
+ UErrorCode* status) {
+
+ utrans_ENTRY(status);
+ UnicodeFilter* filter = NULL;
+ if (filterPattern != NULL && *filterPattern != 0) {
+ // Create read only alias of filterPattern:
+ UnicodeString pat(filterPatternLen < 0, filterPattern, filterPatternLen);
+ filter = new UnicodeSet(pat, *status);
+ /* test for NULL */
+ if (filter == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ if (U_FAILURE(*status)) {
+ delete filter;
+ filter = NULL;
+ }
+ }
+ ((Transliterator*) trans)->adoptFilter(filter);
+}
+
+U_CAPI int32_t U_EXPORT2
+utrans_countAvailableIDs(void) {
+ return Transliterator::countAvailableIDs();
+}
+
+U_CAPI int32_t U_EXPORT2
+utrans_getAvailableID(int32_t index,
+ char* buf, // may be NULL
+ int32_t bufCapacity) {
+ return Transliterator::getAvailableID(index).extract(0, 0x7fffffff, buf, bufCapacity, US_INV);
+}
+
+/* Transliterator UEnumeration ---------------------------------------------- */
+
+typedef struct UTransEnumeration {
+ UEnumeration uenum;
+ int32_t index, count;
+} UTransEnumeration;
+
+U_CDECL_BEGIN
+static int32_t U_CALLCONV
+utrans_enum_count(UEnumeration *uenum, UErrorCode *pErrorCode) {
+ if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+ return ((UTransEnumeration *)uenum)->count;
+}
+
+static const UChar* U_CALLCONV
+utrans_enum_unext(UEnumeration *uenum,
+ int32_t* resultLength,
+ UErrorCode *pErrorCode) {
+ if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+ return 0;
+ }
+
+ UTransEnumeration *ute=(UTransEnumeration *)uenum;
+ int32_t index=ute->index;
+ if(index<ute->count) {
+ const UnicodeString &ID=Transliterator::getAvailableID(index);
+ ute->index=index+1;
+ if(resultLength!=NULL) {
+ *resultLength=ID.length();
+ }
+ // Transliterator keeps its ID NUL-terminated
+ return ID.getBuffer();
+ }
+
+ if(resultLength!=NULL) {
+ *resultLength=0;
+ }
+ return NULL;
+}
+
+static void U_CALLCONV
+utrans_enum_reset(UEnumeration *uenum, UErrorCode *pErrorCode) {
+ if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+ return;
+ }
+
+ UTransEnumeration *ute=(UTransEnumeration *)uenum;
+ ute->index=0;
+ ute->count=Transliterator::countAvailableIDs();
+}
+
+static void U_CALLCONV
+utrans_enum_close(UEnumeration *uenum) {
+ uprv_free(uenum);
+}
+U_CDECL_END
+
+static const UEnumeration utransEnumeration={
+ NULL,
+ NULL,
+ utrans_enum_close,
+ utrans_enum_count,
+ utrans_enum_unext,
+ uenum_nextDefault,
+ utrans_enum_reset
+};
+
+U_CAPI UEnumeration * U_EXPORT2
+utrans_openIDs(UErrorCode *pErrorCode) {
+ UTransEnumeration *ute;
+
+ if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+ return NULL;
+ }
+
+ ute=(UTransEnumeration *)uprv_malloc(sizeof(UTransEnumeration));
+ if(ute==NULL) {
+ *pErrorCode=U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ ute->uenum=utransEnumeration;
+ ute->index=0;
+ ute->count=Transliterator::countAvailableIDs();
+ return (UEnumeration *)ute;
+}
+
+/********************************************************************
+ * Transliteration API
+ ********************************************************************/
+
+U_CAPI void U_EXPORT2
+utrans_trans(const UTransliterator* trans,
+ UReplaceable* rep,
+ UReplaceableCallbacks* repFunc,
+ int32_t start,
+ int32_t* limit,
+ UErrorCode* status) {
+
+ utrans_ENTRY(status);
+
+ if (trans == 0 || rep == 0 || repFunc == 0 || limit == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ ReplaceableGlue r(rep, repFunc);
+
+ *limit = ((Transliterator*) trans)->transliterate(r, start, *limit);
+}
+
+U_CAPI void U_EXPORT2
+utrans_transIncremental(const UTransliterator* trans,
+ UReplaceable* rep,
+ UReplaceableCallbacks* repFunc,
+ UTransPosition* pos,
+ UErrorCode* status) {
+
+ utrans_ENTRY(status);
+
+ if (trans == 0 || rep == 0 || repFunc == 0 || pos == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ ReplaceableGlue r(rep, repFunc);
+
+ ((Transliterator*) trans)->transliterate(r, *pos, *status);
+}
+
+U_CAPI void U_EXPORT2
+utrans_transUChars(const UTransliterator* trans,
+ UChar* text,
+ int32_t* textLength,
+ int32_t textCapacity,
+ int32_t start,
+ int32_t* limit,
+ UErrorCode* status) {
+
+ utrans_ENTRY(status);
+
+ if (trans == 0 || text == 0 || limit == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ int32_t textLen = (textLength == NULL || *textLength < 0)
+ ? u_strlen(text) : *textLength;
+ // writeable alias: for this ct, len CANNOT be -1 (why?)
+ UnicodeString str(text, textLen, textCapacity);
+
+ *limit = ((Transliterator*) trans)->transliterate(str, start, *limit);
+
+ // Copy the string buffer back to text (only if necessary)
+ // and fill in *neededCapacity (if neededCapacity != NULL).
+ textLen = str.extract(text, textCapacity, *status);
+ if(textLength != NULL) {
+ *textLength = textLen;
+ }
+}
+
+U_CAPI void U_EXPORT2
+utrans_transIncrementalUChars(const UTransliterator* trans,
+ UChar* text,
+ int32_t* textLength,
+ int32_t textCapacity,
+ UTransPosition* pos,
+ UErrorCode* status) {
+
+ utrans_ENTRY(status);
+
+ if (trans == 0 || text == 0 || pos == 0) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ int32_t textLen = (textLength == NULL || *textLength < 0)
+ ? u_strlen(text) : *textLength;
+ // writeable alias: for this ct, len CANNOT be -1 (why?)
+ UnicodeString str(text, textLen, textCapacity);
+
+ ((Transliterator*) trans)->transliterate(str, *pos, *status);
+
+ // Copy the string buffer back to text (only if necessary)
+ // and fill in *neededCapacity (if neededCapacity != NULL).
+ textLen = str.extract(text, textCapacity, *status);
+ if(textLength != NULL) {
+ *textLength = textLen;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/vtzone.cpp b/Build/source/libs/icu/icu-xetex/i18n/vtzone.cpp
new file mode 100644
index 00000000000..68c659f234f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/vtzone.cpp
@@ -0,0 +1,2469 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/vtzone.h"
+#include "unicode/rbtz.h"
+#include "unicode/ucal.h"
+#include "unicode/ures.h"
+#include "cmemory.h"
+#include "uvector.h"
+#include "gregoimp.h"
+#include "uhash.h"
+
+U_NAMESPACE_BEGIN
+
+// Smybol characters used by RFC2445 VTIMEZONE
+static const UChar COLON = 0x3A; /* : */
+static const UChar SEMICOLON = 0x3B; /* ; */
+static const UChar EQUALS_SIGN = 0x3D; /* = */
+static const UChar COMMA = 0x2C; /* , */
+static const UChar PLUS = 0x2B; /* + */
+static const UChar MINUS = 0x2D; /* - */
+
+// RFC2445 VTIMEZONE tokens
+static const UChar ICAL_BEGIN_VTIMEZONE[] = {0x42, 0x45, 0x47, 0x49, 0x4E, 0x3A, 0x56, 0x54, 0x49, 0x4D, 0x45, 0x5A, 0x4F, 0x4E, 0x45, 0}; /* "BEGIN:VTIMEZONE" */
+static const UChar ICAL_END_VTIMEZONE[] = {0x45, 0x4E, 0x44, 0x3A, 0x56, 0x54, 0x49, 0x4D, 0x45, 0x5A, 0x4F, 0x4E, 0x45, 0}; /* "END:VTIMEZONE" */
+static const UChar ICAL_BEGIN[] = {0x42, 0x45, 0x47, 0x49, 0x4E, 0}; /* "BEGIN" */
+static const UChar ICAL_END[] = {0x45, 0x4E, 0x44, 0}; /* "END" */
+static const UChar ICAL_VTIMEZONE[] = {0x56, 0x54, 0x49, 0x4D, 0x45, 0x5A, 0x4F, 0x4E, 0x45, 0}; /* "VTIMEZONE" */
+static const UChar ICAL_TZID[] = {0x54, 0x5A, 0x49, 0x44, 0}; /* "TZID" */
+static const UChar ICAL_STANDARD[] = {0x53, 0x54, 0x41, 0x4E, 0x44, 0x41, 0x52, 0x44, 0}; /* "STANDARD" */
+static const UChar ICAL_DAYLIGHT[] = {0x44, 0x41, 0x59, 0x4C, 0x49, 0x47, 0x48, 0x54, 0}; /* "DAYLIGHT" */
+static const UChar ICAL_DTSTART[] = {0x44, 0x54, 0x53, 0x54, 0x41, 0x52, 0x54, 0}; /* "DTSTART" */
+static const UChar ICAL_TZOFFSETFROM[] = {0x54, 0x5A, 0x4F, 0x46, 0x46, 0x53, 0x45, 0x54, 0x46, 0x52, 0x4F, 0x4D, 0}; /* "TZOFFSETFROM" */
+static const UChar ICAL_TZOFFSETTO[] = {0x54, 0x5A, 0x4F, 0x46, 0x46, 0x53, 0x45, 0x54, 0x54, 0x4F, 0}; /* "TZOFFSETTO" */
+static const UChar ICAL_RDATE[] = {0x52, 0x44, 0x41, 0x54, 0x45, 0}; /* "RDATE" */
+static const UChar ICAL_RRULE[] = {0x52, 0x52, 0x55, 0x4C, 0x45, 0}; /* "RRULE" */
+static const UChar ICAL_TZNAME[] = {0x54, 0x5A, 0x4E, 0x41, 0x4D, 0x45, 0}; /* "TZNAME" */
+static const UChar ICAL_TZURL[] = {0x54, 0x5A, 0x55, 0x52, 0x4C, 0}; /* "TZURL" */
+static const UChar ICAL_LASTMOD[] = {0x4C, 0x41, 0x53, 0x54, 0x2D, 0x4D, 0x4F, 0x44, 0x49, 0x46, 0x49, 0x45, 0x44, 0}; /* "LAST-MODIFIED" */
+
+static const UChar ICAL_FREQ[] = {0x46, 0x52, 0x45, 0x51, 0}; /* "FREQ" */
+static const UChar ICAL_UNTIL[] = {0x55, 0x4E, 0x54, 0x49, 0x4C, 0}; /* "UNTIL" */
+static const UChar ICAL_YEARLY[] = {0x59, 0x45, 0x41, 0x52, 0x4C, 0x59, 0}; /* "YEARLY" */
+static const UChar ICAL_BYMONTH[] = {0x42, 0x59, 0x4D, 0x4F, 0x4E, 0x54, 0x48, 0}; /* "BYMONTH" */
+static const UChar ICAL_BYDAY[] = {0x42, 0x59, 0x44, 0x41, 0x59, 0}; /* "BYDAY" */
+static const UChar ICAL_BYMONTHDAY[] = {0x42, 0x59, 0x4D, 0x4F, 0x4E, 0x54, 0x48, 0x44, 0x41, 0x59, 0}; /* "BYMONTHDAY" */
+
+static const UChar ICAL_NEWLINE[] = {0x0D, 0x0A, 0}; /* CRLF */
+
+static const UChar ICAL_DOW_NAMES[7][3] = {
+ {0x53, 0x55, 0}, /* "SU" */
+ {0x4D, 0x4F, 0}, /* "MO" */
+ {0x54, 0x55, 0}, /* "TU" */
+ {0x57, 0x45, 0}, /* "WE" */
+ {0x54, 0x48, 0}, /* "TH" */
+ {0x46, 0x52, 0}, /* "FR" */
+ {0x53, 0x41, 0} /* "SA" */};
+
+// Month length for non-leap year
+static const int32_t MONTHLENGTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+// ICU custom property
+static const UChar ICU_TZINFO_PROP[] = {0x58, 0x2D, 0x54, 0x5A, 0x49, 0x4E, 0x46, 0x4F, 0x3A, 0}; /* "X-TZINFO:" */
+static const UChar ICU_TZINFO_PARTIAL[] = {0x2F, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6C, 0x40, 0}; /* "/Partial@" */
+static const UChar ICU_TZINFO_SIMPLE[] = {0x2F, 0x53, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x40, 0}; /* "/Simple@" */
+
+
+/*
+ * Simple fixed digit ASCII number to integer converter
+ */
+static int32_t parseAsciiDigits(const UnicodeString& str, int32_t start, int32_t length, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ if (length <= 0 || str.length() < start || (start + length) > str.length()) {
+ status = U_INVALID_FORMAT_ERROR;
+ return 0;
+ }
+ int32_t sign = 1;
+ if (str.charAt(start) == PLUS) {
+ start++;
+ length--;
+ } else if (str.charAt(start) == MINUS) {
+ sign = -1;
+ start++;
+ length--;
+ }
+ int32_t num = 0;
+ for (int32_t i = 0; i < length; i++) {
+ int32_t digit = str.charAt(start + i) - 0x0030;
+ if (digit < 0 || digit > 9) {
+ status = U_INVALID_FORMAT_ERROR;
+ return 0;
+ }
+ num = 10 * num + digit;
+ }
+ return sign * num;
+}
+
+static UnicodeString& appendAsciiDigits(int32_t number, uint8_t length, UnicodeString& str) {
+ UBool negative = FALSE;
+ int32_t digits[10]; // max int32_t is 10 decimal digits
+ int32_t i;
+
+ if (number < 0) {
+ negative = TRUE;
+ number *= -1;
+ }
+
+ length = length > 10 ? 10 : length;
+ if (length == 0) {
+ // variable length
+ i = 0;
+ do {
+ digits[i++] = number % 10;
+ number /= 10;
+ } while (number != 0);
+ length = i;
+ } else {
+ // fixed digits
+ for (i = 0; i < length; i++) {
+ digits[i] = number % 10;
+ number /= 10;
+ }
+ }
+ if (negative) {
+ str.append(MINUS);
+ }
+ for (i = length - 1; i >= 0; i--) {
+ str.append((UChar)(digits[i] + 0x0030));
+ }
+ return str;
+}
+
+static UnicodeString& appendMillis(UDate date, UnicodeString& str) {
+ UBool negative = FALSE;
+ int32_t digits[20]; // max int64_t is 20 decimal digits
+ int32_t i;
+ int64_t number;
+
+ if (date < MIN_MILLIS) {
+ number = (int64_t)MIN_MILLIS;
+ } else if (date > MAX_MILLIS) {
+ number = (int64_t)MAX_MILLIS;
+ } else {
+ number = (int64_t)date;
+ }
+ if (number < 0) {
+ negative = TRUE;
+ number *= -1;
+ }
+ i = 0;
+ do {
+ digits[i++] = (int32_t)(number % 10);
+ number /= 10;
+ } while (number != 0);
+
+ if (negative) {
+ str.append(MINUS);
+ }
+ i--;
+ while (i >= 0) {
+ str.append((UChar)(digits[i--] + 0x0030));
+ }
+ return str;
+}
+
+/*
+ * Convert date/time to RFC2445 Date-Time form #1 DATE WITH LOCAL TIME
+ */
+static UnicodeString& getDateTimeString(UDate time, UnicodeString& str) {
+ int32_t year, month, dom, dow, doy, mid;
+ Grego::timeToFields(time, year, month, dom, dow, doy, mid);
+
+ str.remove();
+ appendAsciiDigits(year, 4, str);
+ appendAsciiDigits(month + 1, 2, str);
+ appendAsciiDigits(dom, 2, str);
+ str.append((UChar)0x0054 /*'T'*/);
+
+ int32_t t = mid;
+ int32_t hour = t / U_MILLIS_PER_HOUR;
+ t %= U_MILLIS_PER_HOUR;
+ int32_t min = t / U_MILLIS_PER_MINUTE;
+ t %= U_MILLIS_PER_MINUTE;
+ int32_t sec = t / U_MILLIS_PER_SECOND;
+
+ appendAsciiDigits(hour, 2, str);
+ appendAsciiDigits(min, 2, str);
+ appendAsciiDigits(sec, 2, str);
+ return str;
+}
+
+/*
+ * Convert date/time to RFC2445 Date-Time form #2 DATE WITH UTC TIME
+ */
+static UnicodeString& getUTCDateTimeString(UDate time, UnicodeString& str) {
+ getDateTimeString(time, str);
+ str.append((UChar)0x005A /*'Z'*/);
+ return str;
+}
+
+/*
+ * Parse RFC2445 Date-Time form #1 DATE WITH LOCAL TIME and
+ * #2 DATE WITH UTC TIME
+ */
+static UDate parseDateTimeString(const UnicodeString& str, int32_t offset, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return 0.0;
+ }
+
+ int32_t year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
+ UBool isUTC = FALSE;
+ UBool isValid = FALSE;
+ do {
+ int length = str.length();
+ if (length != 15 && length != 16) {
+ // FORM#1 15 characters, such as "20060317T142115"
+ // FORM#2 16 characters, such as "20060317T142115Z"
+ break;
+ }
+ if (str.charAt(8) != 0x0054) {
+ // charcter "T" must be used for separating date and time
+ break;
+ }
+ if (length == 16) {
+ if (str.charAt(15) != 0x005A) {
+ // invalid format
+ break;
+ }
+ isUTC = TRUE;
+ }
+
+ year = parseAsciiDigits(str, 0, 4, status);
+ month = parseAsciiDigits(str, 4, 2, status) - 1; // 0-based
+ day = parseAsciiDigits(str, 6, 2, status);
+ hour = parseAsciiDigits(str, 9, 2, status);
+ min = parseAsciiDigits(str, 11, 2, status);
+ sec = parseAsciiDigits(str, 13, 2, status);
+
+ if (U_FAILURE(status)) {
+ break;
+ }
+
+ // check valid range
+ int32_t maxDayOfMonth = Grego::monthLength(year, month);
+ if (year < 0 || month < 0 || month > 11 || day < 1 || day > maxDayOfMonth ||
+ hour < 0 || hour >= 24 || min < 0 || min >= 60 || sec < 0 || sec >= 60) {
+ break;
+ }
+
+ isValid = TRUE;
+ } while(false);
+
+ if (!isValid) {
+ status = U_INVALID_FORMAT_ERROR;
+ return 0.0;
+ }
+ // Calculate the time
+ UDate time = Grego::fieldsToDay(year, month, day) * U_MILLIS_PER_DAY;
+ time += (hour * U_MILLIS_PER_HOUR + min * U_MILLIS_PER_MINUTE + sec * U_MILLIS_PER_SECOND);
+ if (!isUTC) {
+ time -= offset;
+ }
+ return time;
+}
+
+/*
+ * Convert RFC2445 utc-offset string to milliseconds
+ */
+static int32_t offsetStrToMillis(const UnicodeString& str, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+
+ UBool isValid = FALSE;
+ int32_t sign = 0, hour = 0, min = 0, sec = 0;
+
+ do {
+ int length = str.length();
+ if (length != 5 && length != 7) {
+ // utf-offset must be 5 or 7 characters
+ break;
+ }
+ // sign
+ UChar s = str.charAt(0);
+ if (s == PLUS) {
+ sign = 1;
+ } else if (s == MINUS) {
+ sign = -1;
+ } else {
+ // utf-offset must start with "+" or "-"
+ break;
+ }
+ hour = parseAsciiDigits(str, 1, 2, status);
+ min = parseAsciiDigits(str, 3, 2, status);
+ if (length == 7) {
+ sec = parseAsciiDigits(str, 5, 2, status);
+ }
+ if (U_FAILURE(status)) {
+ break;
+ }
+ isValid = true;
+ } while(false);
+
+ if (!isValid) {
+ status = U_INVALID_FORMAT_ERROR;
+ return 0;
+ }
+ int32_t millis = sign * ((hour * 60 + min) * 60 + sec) * 1000;
+ return millis;
+}
+
+/*
+ * Convert milliseconds to RFC2445 utc-offset string
+ */
+static void millisToOffset(int32_t millis, UnicodeString& str) {
+ str.remove();
+ if (millis >= 0) {
+ str.append(PLUS);
+ } else {
+ str.append(MINUS);
+ millis = -millis;
+ }
+ int32_t hour, min, sec;
+ int32_t t = millis / 1000;
+
+ sec = t % 60;
+ t = (t - sec) / 60;
+ min = t % 60;
+ hour = t / 60;
+
+ appendAsciiDigits(hour, 2, str);
+ appendAsciiDigits(min, 2, str);
+ appendAsciiDigits(sec, 2, str);
+}
+
+/*
+ * Create a default TZNAME from TZID
+ */
+static void getDefaultTZName(const UnicodeString tzid, UBool isDST, UnicodeString& tzname) {
+ tzname = tzid;
+ if (isDST) {
+ tzname += UNICODE_STRING_SIMPLE("(DST)");
+ } else {
+ tzname += UNICODE_STRING_SIMPLE("(STD)");
+ }
+}
+
+/*
+ * Parse individual RRULE
+ *
+ * On return -
+ *
+ * month calculated by BYMONTH-1, or -1 when not found
+ * dow day of week in BYDAY, or 0 when not found
+ * wim day of week ordinal number in BYDAY, or 0 when not found
+ * dom an array of day of month
+ * domCount number of availble days in dom (domCount is specifying the size of dom on input)
+ * until time defined by UNTIL attribute or MIN_MILLIS if not available
+ */
+static void parseRRULE(const UnicodeString& rrule, int32_t& month, int32_t& dow, int32_t& wim,
+ int32_t* dom, int32_t& domCount, UDate& until, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ int32_t numDom = 0;
+
+ month = -1;
+ dow = 0;
+ wim = 0;
+ until = MIN_MILLIS;
+
+ UBool yearly = FALSE;
+ //UBool parseError = FALSE;
+
+ int32_t prop_start = 0;
+ int32_t prop_end;
+ UnicodeString prop, attr, value;
+ UBool nextProp = TRUE;
+
+ while (nextProp) {
+ prop_end = rrule.indexOf(SEMICOLON, prop_start);
+ if (prop_end == -1) {
+ prop.setTo(rrule, prop_start);
+ nextProp = FALSE;
+ } else {
+ prop.setTo(rrule, prop_start, prop_end - prop_start);
+ prop_start = prop_end + 1;
+ }
+ int32_t eql = prop.indexOf(EQUALS_SIGN);
+ if (eql != -1) {
+ attr.setTo(prop, 0, eql);
+ value.setTo(prop, eql + 1);
+ } else {
+ goto rruleParseError;
+ }
+
+ if (attr.compare(ICAL_FREQ) == 0) {
+ // only support YEARLY frequency type
+ if (value.compare(ICAL_YEARLY) == 0) {
+ yearly = TRUE;
+ } else {
+ goto rruleParseError;
+ }
+ } else if (attr.compare(ICAL_UNTIL) == 0) {
+ // ISO8601 UTC format, for example, "20060315T020000Z"
+ until = parseDateTimeString(value, 0, status);
+ if (U_FAILURE(status)) {
+ goto rruleParseError;
+ }
+ } else if (attr.compare(ICAL_BYMONTH) == 0) {
+ // Note: BYMONTH may contain multiple months, but only single month make sense for
+ // VTIMEZONE property.
+ if (value.length() > 2) {
+ goto rruleParseError;
+ }
+ month = parseAsciiDigits(value, 0, value.length(), status) - 1;
+ if (U_FAILURE(status) || month < 0 || month >= 12) {
+ goto rruleParseError;
+ }
+ } else if (attr.compare(ICAL_BYDAY) == 0) {
+ // Note: BYDAY may contain multiple day of week separated by comma. It is unlikely used for
+ // VTIMEZONE property. We do not support the case.
+
+ // 2-letter format is used just for representing a day of week, for example, "SU" for Sunday
+ // 3 or 4-letter format is used for represeinging Nth day of week, for example, "-1SA" for last Saturday
+ int32_t length = value.length();
+ if (length < 2 || length > 4) {
+ goto rruleParseError;
+ }
+ if (length > 2) {
+ // Nth day of week
+ int32_t sign = 1;
+ if (value.charAt(0) == PLUS) {
+ sign = 1;
+ } else if (value.charAt(0) == MINUS) {
+ sign = -1;
+ } else if (length == 4) {
+ goto rruleParseError;
+ }
+ int32_t n = parseAsciiDigits(value, length - 3, 1, status);
+ if (U_FAILURE(status) || n == 0 || n > 4) {
+ goto rruleParseError;
+ }
+ wim = n * sign;
+ value.remove(0, length - 2);
+ }
+ int32_t wday;
+ for (wday = 0; wday < 7; wday++) {
+ if (value.compare(ICAL_DOW_NAMES[wday], 2) == 0) {
+ break;
+ }
+ }
+ if (wday < 7) {
+ // Sunday(1) - Saturday(7)
+ dow = wday + 1;
+ } else {
+ goto rruleParseError;
+ }
+ } else if (attr.compare(ICAL_BYMONTHDAY) == 0) {
+ // Note: BYMONTHDAY may contain multiple days delimitted by comma
+ //
+ // A value of BYMONTHDAY could be negative, for example, -1 means
+ // the last day in a month
+ int32_t dom_idx = 0;
+ int32_t dom_start = 0;
+ int32_t dom_end;
+ UBool nextDOM = TRUE;
+ while (nextDOM) {
+ dom_end = value.indexOf(COMMA, dom_start);
+ if (dom_end == -1) {
+ dom_end = value.length();
+ nextDOM = FALSE;
+ }
+ if (dom_idx < domCount) {
+ dom[dom_idx] = parseAsciiDigits(value, dom_start, dom_end - dom_start, status);
+ if (U_FAILURE(status)) {
+ goto rruleParseError;
+ }
+ dom_idx++;
+ } else {
+ status = U_BUFFER_OVERFLOW_ERROR;
+ goto rruleParseError;
+ }
+ dom_start = dom_end + 1;
+ }
+ numDom = dom_idx;
+ }
+ }
+ if (!yearly) {
+ // FREQ=YEARLY must be set
+ goto rruleParseError;
+ }
+ // Set actual number of parsed DOM (ICAL_BYMONTHDAY)
+ domCount = numDom;
+ return;
+
+rruleParseError:
+ if (U_SUCCESS(status)) {
+ // Set error status
+ status = U_INVALID_FORMAT_ERROR;
+ }
+}
+
+static TimeZoneRule* createRuleByRRULE(const UnicodeString& tzname, int rawOffset, int dstSavings, UDate start,
+ UVector* dates, int fromOffset, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (dates == NULL || dates->size() == 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ int32_t i, j;
+ DateTimeRule *adtr = NULL;
+
+ // Parse the first rule
+ UnicodeString rrule = *((UnicodeString*)dates->elementAt(0));
+ int32_t month, dayOfWeek, nthDayOfWeek, dayOfMonth = 0;
+ int32_t days[7];
+ int32_t daysCount = sizeof(days)/sizeof(days[0]);
+ UDate until;
+
+ parseRRULE(rrule, month, dayOfWeek, nthDayOfWeek, days, daysCount, until, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+
+ if (dates->size() == 1) {
+ // No more rules
+ if (daysCount > 1) {
+ // Multiple BYMONTHDAY values
+ if (daysCount != 7 || month == -1 || dayOfWeek == 0) {
+ // Only support the rule using 7 continuous days
+ // BYMONTH and BYDAY must be set at the same time
+ goto unsupportedRRule;
+ }
+ int32_t firstDay = 31; // max possible number of dates in a month
+ for (i = 0; i < 7; i++) {
+ // Resolve negative day numbers. A negative day number should
+ // not be used in February, but if we see such case, we use 28
+ // as the base.
+ if (days[i] < 0) {
+ days[i] = MONTHLENGTH[month] + days[i] + 1;
+ }
+ if (days[i] < firstDay) {
+ firstDay = days[i];
+ }
+ }
+ // Make sure days are continuous
+ for (i = 1; i < 7; i++) {
+ UBool found = FALSE;
+ for (j = 0; j < 7; j++) {
+ if (days[j] == firstDay + i) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found) {
+ // days are not continuous
+ goto unsupportedRRule;
+ }
+ }
+ // Use DOW_GEQ_DOM rule with firstDay as the start date
+ dayOfMonth = firstDay;
+ }
+ } else {
+ // Check if BYMONTH + BYMONTHDAY + BYDAY rule with multiple RRULE lines.
+ // Otherwise, not supported.
+ if (month == -1 || dayOfWeek == 0 || daysCount == 0) {
+ // This is not the case
+ goto unsupportedRRule;
+ }
+ // Parse the rest of rules if number of rules is not exceeding 7.
+ // We can only support 7 continuous days starting from a day of month.
+ if (dates->size() > 7) {
+ goto unsupportedRRule;
+ }
+
+ // Note: To check valid date range across multiple rule is a little
+ // bit complicated. For now, this code is not doing strict range
+ // checking across month boundary
+
+ int32_t earliestMonth = month;
+ int32_t earliestDay = 31;
+ for (i = 0; i < daysCount; i++) {
+ int32_t dom = days[i];
+ dom = dom > 0 ? dom : MONTHLENGTH[month] + dom + 1;
+ earliestDay = dom < earliestDay ? dom : earliestDay;
+ }
+
+ int32_t anotherMonth = -1;
+ for (i = 1; i < dates->size(); i++) {
+ rrule = *((UnicodeString*)dates->elementAt(i));
+ UDate tmp_until;
+ int32_t tmp_month, tmp_dayOfWeek, tmp_nthDayOfWeek;
+ int32_t tmp_days[7];
+ int32_t tmp_daysCount = sizeof(tmp_days)/sizeof(tmp_days[0]);
+ parseRRULE(rrule, tmp_month, tmp_dayOfWeek, tmp_nthDayOfWeek, tmp_days, tmp_daysCount, tmp_until, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ // If UNTIL is newer than previous one, use the one
+ if (tmp_until > until) {
+ until = tmp_until;
+ }
+
+ // Check if BYMONTH + BYMONTHDAY + BYDAY rule
+ if (tmp_month == -1 || tmp_dayOfWeek == 0 || tmp_daysCount == 0) {
+ goto unsupportedRRule;
+ }
+ // Count number of BYMONTHDAY
+ if (daysCount + tmp_daysCount > 7) {
+ // We cannot support BYMONTHDAY more than 7
+ goto unsupportedRRule;
+ }
+ // Check if the same BYDAY is used. Otherwise, we cannot
+ // support the rule
+ if (tmp_dayOfWeek != dayOfWeek) {
+ goto unsupportedRRule;
+ }
+ // Check if the month is same or right next to the primary month
+ if (tmp_month != month) {
+ if (anotherMonth == -1) {
+ int32_t diff = tmp_month - month;
+ if (diff == -11 || diff == -1) {
+ // Previous month
+ anotherMonth = tmp_month;
+ earliestMonth = anotherMonth;
+ // Reset earliest day
+ earliestDay = 31;
+ } else if (diff == 11 || diff == 1) {
+ // Next month
+ anotherMonth = tmp_month;
+ } else {
+ // The day range cannot exceed more than 2 months
+ goto unsupportedRRule;
+ }
+ } else if (tmp_month != month && tmp_month != anotherMonth) {
+ // The day range cannot exceed more than 2 months
+ goto unsupportedRRule;
+ }
+ }
+ // If ealier month, go through days to find the earliest day
+ if (tmp_month == earliestMonth) {
+ for (j = 0; j < tmp_daysCount; j++) {
+ tmp_days[j] = tmp_days[j] > 0 ? tmp_days[j] : MONTHLENGTH[tmp_month] + tmp_days[j] + 1;
+ earliestDay = tmp_days[j] < earliestDay ? tmp_days[j] : earliestDay;
+ }
+ }
+ daysCount += tmp_daysCount;
+ }
+ if (daysCount != 7) {
+ // Number of BYMONTHDAY entries must be 7
+ goto unsupportedRRule;
+ }
+ month = earliestMonth;
+ dayOfMonth = earliestDay;
+ }
+
+ // Calculate start/end year and missing fields
+ int32_t startYear, startMonth, startDOM, startDOW, startDOY, startMID;
+ Grego::timeToFields(start + fromOffset, startYear, startMonth, startDOM,
+ startDOW, startDOY, startMID);
+ if (month == -1) {
+ // If BYMONTH is not set, use the month of DTSTART
+ month = startMonth;
+ }
+ if (dayOfWeek == 0 && nthDayOfWeek == 0 && dayOfMonth == 0) {
+ // If only YEARLY is set, use the day of DTSTART as BYMONTHDAY
+ dayOfMonth = startDOM;
+ }
+
+ int32_t endYear;
+ if (until != MIN_MILLIS) {
+ int32_t endMonth, endDOM, endDOW, endDOY, endMID;
+ Grego::timeToFields(until, endYear, endMonth, endDOM, endDOW, endDOY, endMID);
+ } else {
+ endYear = AnnualTimeZoneRule::MAX_YEAR;
+ }
+
+ // Create the AnnualDateTimeRule
+ if (dayOfWeek == 0 && nthDayOfWeek == 0 && dayOfMonth != 0) {
+ // Day in month rule, for example, 15th day in the month
+ adtr = new DateTimeRule(month, dayOfMonth, startMID, DateTimeRule::WALL_TIME);
+ } else if (dayOfWeek != 0 && nthDayOfWeek != 0 && dayOfMonth == 0) {
+ // Nth day of week rule, for example, last Sunday
+ adtr = new DateTimeRule(month, nthDayOfWeek, dayOfWeek, startMID, DateTimeRule::WALL_TIME);
+ } else if (dayOfWeek != 0 && nthDayOfWeek == 0 && dayOfMonth != 0) {
+ // First day of week after day of month rule, for example,
+ // first Sunday after 15th day in the month
+ adtr = new DateTimeRule(month, dayOfMonth, dayOfWeek, TRUE, startMID, DateTimeRule::WALL_TIME);
+ }
+ if (adtr == NULL) {
+ goto unsupportedRRule;
+ }
+ return new AnnualTimeZoneRule(tzname, rawOffset, dstSavings, adtr, startYear, endYear);
+
+unsupportedRRule:
+ status = U_INVALID_STATE_ERROR;
+ return NULL;
+}
+
+/*
+ * Create a TimeZoneRule by the RDATE definition
+ */
+static TimeZoneRule* createRuleByRDATE(const UnicodeString& tzname, int32_t rawOffset, int32_t dstSavings,
+ UDate start, UVector* dates, int32_t fromOffset, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ TimeArrayTimeZoneRule *retVal = NULL;
+ if (dates == NULL || dates->size() == 0) {
+ // When no RDATE line is provided, use start (DTSTART)
+ // as the transition time
+ retVal = new TimeArrayTimeZoneRule(tzname, rawOffset, dstSavings,
+ &start, 1, DateTimeRule::UTC_TIME);
+ } else {
+ // Create an array of transition times
+ int32_t size = dates->size();
+ UDate* times = (UDate*)uprv_malloc(sizeof(UDate) * size);
+ if (times == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ for (int32_t i = 0; i < size; i++) {
+ UnicodeString *datestr = (UnicodeString*)dates->elementAt(i);
+ times[i] = parseDateTimeString(*datestr, fromOffset, status);
+ if (U_FAILURE(status)) {
+ uprv_free(times);
+ return NULL;
+ }
+ }
+ retVal = new TimeArrayTimeZoneRule(tzname, rawOffset, dstSavings,
+ times, size, DateTimeRule::UTC_TIME);
+ uprv_free(times);
+ }
+ return retVal;
+}
+
+/*
+ * Check if the DOW rule specified by month, weekInMonth and dayOfWeek is equivalent
+ * to the DateTimerule.
+ */
+static UBool isEquivalentDateRule(int32_t month, int32_t weekInMonth, int32_t dayOfWeek, const DateTimeRule *dtrule) {
+ if (month != dtrule->getRuleMonth() || dayOfWeek != dtrule->getRuleDayOfWeek()) {
+ return FALSE;
+ }
+ if (dtrule->getTimeRuleType() != DateTimeRule::WALL_TIME) {
+ // Do not try to do more intelligent comparison for now.
+ return FALSE;
+ }
+ if (dtrule->getDateRuleType() == DateTimeRule::DOW
+ && dtrule->getRuleWeekInMonth() == weekInMonth) {
+ return TRUE;
+ }
+ int32_t ruleDOM = dtrule->getRuleDayOfMonth();
+ if (dtrule->getDateRuleType() == DateTimeRule::DOW_GEQ_DOM) {
+ if (ruleDOM%7 == 1 && (ruleDOM + 6)/7 == weekInMonth) {
+ return TRUE;
+ }
+ if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - ruleDOM)%7 == 6
+ && weekInMonth == -1*((MONTHLENGTH[month]-ruleDOM+1)/7)) {
+ return TRUE;
+ }
+ }
+ if (dtrule->getDateRuleType() == DateTimeRule::DOW_LEQ_DOM) {
+ if (ruleDOM%7 == 0 && ruleDOM/7 == weekInMonth) {
+ return TRUE;
+ }
+ if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - ruleDOM)%7 == 0
+ && weekInMonth == -1*((MONTHLENGTH[month] - ruleDOM)/7 + 1)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Convert the rule to its equivalent rule using WALL_TIME mode.
+ * This function returns NULL when the specified DateTimeRule is already
+ * using WALL_TIME mode.
+ */
+static DateTimeRule* toWallTimeRule(const DateTimeRule* rule, int32_t rawOffset, int32_t dstSavings) {
+ if (rule->getTimeRuleType() == DateTimeRule::WALL_TIME) {
+ return NULL;
+ }
+ int32_t wallt = rule->getRuleMillisInDay();
+ if (rule->getTimeRuleType() == DateTimeRule::UTC_TIME) {
+ wallt += (rawOffset + dstSavings);
+ } else if (rule->getTimeRuleType() == DateTimeRule::STANDARD_TIME) {
+ wallt += dstSavings;
+ }
+
+ int32_t month = -1, dom = 0, dow = 0;
+ DateTimeRule::DateRuleType dtype;
+ int32_t dshift = 0;
+ if (wallt < 0) {
+ dshift = -1;
+ wallt += U_MILLIS_PER_DAY;
+ } else if (wallt >= U_MILLIS_PER_DAY) {
+ dshift = 1;
+ wallt -= U_MILLIS_PER_DAY;
+ }
+
+ month = rule->getRuleMonth();
+ dom = rule->getRuleDayOfMonth();
+ dow = rule->getRuleDayOfWeek();
+ dtype = rule->getDateRuleType();
+
+ if (dshift != 0) {
+ if (dtype == DateTimeRule::DOW) {
+ // Convert to DOW_GEW_DOM or DOW_LEQ_DOM rule first
+ int32_t wim = rule->getRuleWeekInMonth();
+ if (wim > 0) {
+ dtype = DateTimeRule::DOW_GEQ_DOM;
+ dom = 7 * (wim - 1) + 1;
+ } else {
+ dtype = DateTimeRule::DOW_LEQ_DOM;
+ dom = MONTHLENGTH[month] + 7 * (wim + 1);
+ }
+ }
+ // Shift one day before or after
+ dom += dshift;
+ if (dom == 0) {
+ month--;
+ month = month < UCAL_JANUARY ? UCAL_DECEMBER : month;
+ dom = MONTHLENGTH[month];
+ } else if (dom > MONTHLENGTH[month]) {
+ month++;
+ month = month > UCAL_DECEMBER ? UCAL_JANUARY : month;
+ dom = 1;
+ }
+ if (dtype != DateTimeRule::DOM) {
+ // Adjust day of week
+ dow += dshift;
+ if (dow < UCAL_SUNDAY) {
+ dow = UCAL_SATURDAY;
+ } else if (dow > UCAL_SATURDAY) {
+ dow = UCAL_SUNDAY;
+ }
+ }
+ }
+ // Create a new rule
+ DateTimeRule *modifiedRule;
+ if (dtype == DateTimeRule::DOM) {
+ modifiedRule = new DateTimeRule(month, dom, wallt, DateTimeRule::WALL_TIME);
+ } else {
+ modifiedRule = new DateTimeRule(month, dom, dow,
+ (dtype == DateTimeRule::DOW_GEQ_DOM), wallt, DateTimeRule::WALL_TIME);
+ }
+ return modifiedRule;
+}
+
+/*
+ * Minumum implementations of stream writer/reader, writing/reading
+ * UnicodeString. For now, we do not want to introduce the dependency
+ * on the ICU I/O stream in this module. But we want to keep the code
+ * equivalent to the ICU4J implementation, which utilizes java.io.Writer/
+ * Reader.
+ */
+class VTZWriter {
+public:
+ VTZWriter(UnicodeString& out);
+ ~VTZWriter();
+
+ void write(const UnicodeString& str);
+ void write(UChar ch);
+ //void write(const UChar* str, int32_t length);
+private:
+ UnicodeString* out;
+};
+
+VTZWriter::VTZWriter(UnicodeString& output) {
+ out = &output;
+}
+
+VTZWriter::~VTZWriter() {
+}
+
+void
+VTZWriter::write(const UnicodeString& str) {
+ out->append(str);
+}
+
+void
+VTZWriter::write(UChar ch) {
+ out->append(ch);
+}
+
+/*
+void
+VTZWriter::write(const UChar* str, int32_t length) {
+ out->append(str, length);
+}
+*/
+
+class VTZReader {
+public:
+ VTZReader(const UnicodeString& input);
+ ~VTZReader();
+
+ UChar read(void);
+private:
+ const UnicodeString* in;
+ int32_t index;
+};
+
+VTZReader::VTZReader(const UnicodeString& input) {
+ in = &input;
+ index = 0;
+}
+
+VTZReader::~VTZReader() {
+}
+
+UChar
+VTZReader::read(void) {
+ UChar ch = 0xFFFF;
+ if (index < in->length()) {
+ ch = in->charAt(index);
+ }
+ index++;
+ return ch;
+}
+
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(VTimeZone)
+
+VTimeZone::VTimeZone()
+: BasicTimeZone(), tz(NULL), vtzlines(NULL),
+ lastmod(MAX_MILLIS) {
+}
+
+VTimeZone::VTimeZone(const VTimeZone& source)
+: BasicTimeZone(source), tz(NULL), vtzlines(NULL),
+ tzurl(source.tzurl), lastmod(source.lastmod),
+ olsonzid(source.olsonzid), icutzver(source.icutzver) {
+ if (source.tz != NULL) {
+ tz = (BasicTimeZone*)source.tz->clone();
+ }
+ if (source.vtzlines != NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t size = source.vtzlines->size();
+ vtzlines = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, size, status);
+ if (U_SUCCESS(status)) {
+ for (int32_t i = 0; i < size; i++) {
+ UnicodeString *line = (UnicodeString*)source.vtzlines->elementAt(i);
+ vtzlines->addElement(line->clone(), status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ }
+ }
+ if (U_FAILURE(status) && vtzlines != NULL) {
+ delete vtzlines;
+ }
+ }
+}
+
+VTimeZone::~VTimeZone() {
+ if (tz != NULL) {
+ delete tz;
+ }
+ if (vtzlines != NULL) {
+ delete vtzlines;
+ }
+}
+
+VTimeZone&
+VTimeZone::operator=(const VTimeZone& right) {
+ if (this == &right) {
+ return *this;
+ }
+ if (*this != right) {
+ BasicTimeZone::operator=(right);
+ if (tz != NULL) {
+ delete tz;
+ tz = NULL;
+ }
+ if (right.tz != NULL) {
+ tz = (BasicTimeZone*)right.tz->clone();
+ }
+ if (vtzlines != NULL) {
+ delete vtzlines;
+ }
+ if (right.vtzlines != NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t size = right.vtzlines->size();
+ vtzlines = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, size, status);
+ if (U_SUCCESS(status)) {
+ for (int32_t i = 0; i < size; i++) {
+ UnicodeString *line = (UnicodeString*)right.vtzlines->elementAt(i);
+ vtzlines->addElement(line->clone(), status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ }
+ }
+ if (U_FAILURE(status) && vtzlines != NULL) {
+ delete vtzlines;
+ vtzlines = NULL;
+ }
+ }
+ tzurl = right.tzurl;
+ lastmod = right.lastmod;
+ olsonzid = right.olsonzid;
+ icutzver = right.icutzver;
+ }
+ return *this;
+}
+
+UBool
+VTimeZone::operator==(const TimeZone& that) const {
+ if (this == &that) {
+ return TRUE;
+ }
+ if (getDynamicClassID() != that.getDynamicClassID()
+ || !BasicTimeZone::operator==(that)) {
+ return FALSE;
+ }
+ VTimeZone *vtz = (VTimeZone*)&that;
+ if (*tz == *(vtz->tz)
+ && tzurl == vtz->tzurl
+ && lastmod == vtz->lastmod
+ /* && olsonzid = that.olsonzid */
+ /* && icutzver = that.icutzver */) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+VTimeZone::operator!=(const TimeZone& that) const {
+ return !operator==(that);
+}
+
+VTimeZone*
+VTimeZone::createVTimeZoneByID(const UnicodeString& ID) {
+ VTimeZone *vtz = new VTimeZone();
+ vtz->tz = (BasicTimeZone*)TimeZone::createTimeZone(ID);
+ vtz->tz->getID(vtz->olsonzid);
+
+ // Set ICU tzdata version
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *bundle = NULL;
+ const UChar* versionStr = NULL;
+ int32_t len;
+ bundle = ures_openDirect(NULL, "zoneinfo", &status);
+ versionStr = ures_getStringByKey(bundle, "TZVersion", &len, &status);
+ if (U_SUCCESS(status)) {
+ vtz->icutzver.setTo(versionStr, len);
+ }
+ ures_close(bundle);
+ return vtz;
+}
+
+VTimeZone*
+VTimeZone::createVTimeZone(const UnicodeString& vtzdata, UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ VTZReader reader(vtzdata);
+ VTimeZone *vtz = new VTimeZone();
+ vtz->load(reader, status);
+ if (U_FAILURE(status)) {
+ delete vtz;
+ return NULL;
+ }
+ return vtz;
+}
+
+UBool
+VTimeZone::getTZURL(UnicodeString& url) const {
+ if (tzurl.length() > 0) {
+ url = tzurl;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+VTimeZone::setTZURL(const UnicodeString& url) {
+ tzurl = url;
+}
+
+UBool
+VTimeZone::getLastModified(UDate& lastModified) const {
+ if (lastmod != MAX_MILLIS) {
+ lastModified = lastmod;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+VTimeZone::setLastModified(UDate lastModified) {
+ lastmod = lastModified;
+}
+
+void
+VTimeZone::write(UnicodeString& result, UErrorCode& status) const {
+ result.remove();
+ VTZWriter writer(result);
+ write(writer, status);
+}
+
+void
+VTimeZone::write(UDate start, UnicodeString& result, UErrorCode& status) /*const*/ {
+ result.remove();
+ VTZWriter writer(result);
+ write(start, writer, status);
+}
+
+void
+VTimeZone::writeSimple(UDate time, UnicodeString& result, UErrorCode& status) /*const*/ {
+ result.remove();
+ VTZWriter writer(result);
+ writeSimple(time, writer, status);
+}
+
+TimeZone*
+VTimeZone::clone(void) const {
+ return new VTimeZone(*this);
+}
+
+int32_t
+VTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const {
+ return tz->getOffset(era, year, month, day, dayOfWeek, millis, status);
+}
+
+int32_t
+VTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ uint8_t dayOfWeek, int32_t millis,
+ int32_t monthLength, UErrorCode& status) const {
+ return tz->getOffset(era, year, month, day, dayOfWeek, millis, monthLength, status);
+}
+
+void
+VTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
+ int32_t& dstOffset, UErrorCode& status) const {
+ return tz->getOffset(date, local, rawOffset, dstOffset, status);
+}
+
+void
+VTimeZone::setRawOffset(int32_t offsetMillis) {
+ tz->setRawOffset(offsetMillis);
+}
+
+int32_t
+VTimeZone::getRawOffset(void) const {
+ return tz->getRawOffset();
+}
+
+UBool
+VTimeZone::useDaylightTime(void) const {
+ return tz->useDaylightTime();
+}
+
+UBool
+VTimeZone::inDaylightTime(UDate date, UErrorCode& status) const {
+ return tz->inDaylightTime(date, status);
+}
+
+UBool
+VTimeZone::hasSameRules(const TimeZone& other) const {
+ return tz->hasSameRules(other);
+}
+
+UBool
+VTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+ return tz->getNextTransition(base, inclusive, result);
+}
+
+UBool
+VTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+ return tz->getPreviousTransition(base, inclusive, result);
+}
+
+int32_t
+VTimeZone::countTransitionRules(UErrorCode& status) /*const*/ {
+ return tz->countTransitionRules(status);
+}
+
+void
+VTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[], int32_t& trscount,
+ UErrorCode& status) /*const*/ {
+ tz->getTimeZoneRules(initial, trsrules, trscount, status);
+}
+
+void
+VTimeZone::load(VTZReader& reader, UErrorCode& status) {
+ vtzlines = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, DEFAULT_VTIMEZONE_LINES, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UBool eol = FALSE;
+ UBool start = FALSE;
+ UBool success = FALSE;
+ UnicodeString line;
+
+ while (TRUE) {
+ UChar ch = reader.read();
+ if (ch == 0xFFFF) {
+ // end of file
+ if (start && line.startsWith(ICAL_END_VTIMEZONE)) {
+ vtzlines->addElement(new UnicodeString(line), status);
+ if (U_FAILURE(status)) {
+ goto cleanupVtzlines;
+ }
+ success = TRUE;
+ }
+ break;
+ }
+ if (ch == 0x000D) {
+ // CR, must be followed by LF according to the definition in RFC2445
+ continue;
+ }
+ if (eol) {
+ if (ch != 0x0009 && ch != 0x0020) {
+ // NOT followed by TAB/SP -> new line
+ if (start) {
+ if (line.length() > 0) {
+ vtzlines->addElement(new UnicodeString(line), status);
+ if (U_FAILURE(status)) {
+ goto cleanupVtzlines;
+ }
+ }
+ }
+ line.remove();
+ if (ch != 0x000A) {
+ line.append(ch);
+ }
+ }
+ eol = FALSE;
+ } else {
+ if (ch == 0x000A) {
+ // LF
+ eol = TRUE;
+ if (start) {
+ if (line.startsWith(ICAL_END_VTIMEZONE)) {
+ vtzlines->addElement(new UnicodeString(line), status);
+ if (U_FAILURE(status)) {
+ goto cleanupVtzlines;
+ }
+ success = TRUE;
+ break;
+ }
+ } else {
+ if (line.startsWith(ICAL_BEGIN_VTIMEZONE)) {
+ vtzlines->addElement(new UnicodeString(line), status);
+ if (U_FAILURE(status)) {
+ goto cleanupVtzlines;
+ }
+ line.remove();
+ start = TRUE;
+ eol = FALSE;
+ }
+ }
+ } else {
+ line.append(ch);
+ }
+ }
+ }
+ if (!success) {
+ if (U_SUCCESS(status)) {
+ status = U_INVALID_STATE_ERROR;
+ }
+ goto cleanupVtzlines;
+ }
+ parse(status);
+ return;
+
+cleanupVtzlines:
+ delete vtzlines;
+ vtzlines = NULL;
+}
+
+// parser state
+#define INI 0 // Initial state
+#define VTZ 1 // In VTIMEZONE
+#define TZI 2 // In STANDARD or DAYLIGHT
+
+#define DEF_DSTSAVINGS (60*60*1000)
+#define DEF_TZSTARTTIME (0.0)
+
+void
+VTimeZone::parse(UErrorCode& status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (vtzlines == NULL || vtzlines->size() == 0) {
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ InitialTimeZoneRule *initialRule = NULL;
+ RuleBasedTimeZone *rbtz = NULL;
+
+ // timezone ID
+ UnicodeString tzid;
+
+ int32_t state = INI;
+ int32_t n = 0;
+ UBool dst = FALSE; // current zone type
+ UnicodeString from; // current zone from offset
+ UnicodeString to; // current zone offset
+ UnicodeString tzname; // current zone name
+ UnicodeString dtstart; // current zone starts
+ UBool isRRULE = FALSE; // true if the rule is described by RRULE
+ int32_t initialRawOffset = 0; // initial offset
+ int32_t initialDSTSavings = 0; // initial offset
+ UDate firstStart = MAX_MILLIS; // the earliest rule start time
+ UnicodeString name; // RFC2445 prop name
+ UnicodeString value; // RFC2445 prop value
+
+ UVector *dates = NULL; // list of RDATE or RRULE strings
+ UVector *rules = NULL; // list of TimeZoneRule instances
+
+ rules = new UVector(status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ dates = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+
+ for (n = 0; n < vtzlines->size(); n++) {
+ UnicodeString *line = (UnicodeString*)vtzlines->elementAt(n);
+ int32_t valueSep = line->indexOf(COLON);
+ if (valueSep < 0) {
+ continue;
+ }
+ name.setTo(*line, 0, valueSep);
+ value.setTo(*line, valueSep + 1);
+
+ switch (state) {
+ case INI:
+ if (name.compare(ICAL_BEGIN) == 0
+ && value.compare(ICAL_VTIMEZONE) == 0) {
+ state = VTZ;
+ }
+ break;
+
+ case VTZ:
+ if (name.compare(ICAL_TZID) == 0) {
+ tzid = value;
+ } else if (name.compare(ICAL_TZURL) == 0) {
+ tzurl = value;
+ } else if (name.compare(ICAL_LASTMOD) == 0) {
+ // Always in 'Z' format, so the offset argument for the parse method
+ // can be any value.
+ lastmod = parseDateTimeString(value, 0, status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ } else if (name.compare(ICAL_BEGIN) == 0) {
+ UBool isDST = (value.compare(ICAL_DAYLIGHT) == 0);
+ if (value.compare(ICAL_STANDARD) == 0 || isDST) {
+ // tzid must be ready at this point
+ if (tzid.length() == 0) {
+ goto cleanupParse;
+ }
+ // initialize current zone properties
+ if (dates->size() != 0) {
+ dates->removeAllElements();
+ }
+ isRRULE = FALSE;
+ from.remove();
+ to.remove();
+ tzname.remove();
+ dst = isDST;
+ state = TZI;
+ } else {
+ // BEGIN property other than STANDARD/DAYLIGHT
+ // must not be there.
+ goto cleanupParse;
+ }
+ } else if (name.compare(ICAL_END) == 0) {
+ break;
+ }
+ break;
+ case TZI:
+ if (name.compare(ICAL_DTSTART) == 0) {
+ dtstart = value;
+ } else if (name.compare(ICAL_TZNAME) == 0) {
+ tzname = value;
+ } else if (name.compare(ICAL_TZOFFSETFROM) == 0) {
+ from = value;
+ } else if (name.compare(ICAL_TZOFFSETTO) == 0) {
+ to = value;
+ } else if (name.compare(ICAL_RDATE) == 0) {
+ // RDATE mixed with RRULE is not supported
+ if (isRRULE) {
+ goto cleanupParse;
+ }
+ // RDATE value may contain multiple date delimited
+ // by comma
+ UBool nextDate = TRUE;
+ int32_t dstart = 0;
+ UnicodeString *dstr;
+ while (nextDate) {
+ int32_t dend = value.indexOf(COMMA, dstart);
+ if (dend == -1) {
+ dstr = new UnicodeString(value, dstart);
+ nextDate = FALSE;
+ } else {
+ dstr = new UnicodeString(value, dstart, dend - dstart);
+ }
+ dates->addElement(dstr, status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ dstart = dend + 1;
+ }
+ } else if (name.compare(ICAL_RRULE) == 0) {
+ // RRULE mixed with RDATE is not supported
+ if (!isRRULE && dates->size() != 0) {
+ goto cleanupParse;
+ }
+ isRRULE = true;
+ dates->addElement(new UnicodeString(value), status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ } else if (name.compare(ICAL_END) == 0) {
+ // Mandatory properties
+ if (dtstart.length() == 0 || from.length() == 0 || to.length() == 0) {
+ goto cleanupParse;
+ }
+ // if tzname is not available, create one from tzid
+ if (tzname.length() == 0) {
+ getDefaultTZName(tzid, dst, tzname);
+ }
+
+ // create a time zone rule
+ TimeZoneRule *rule = NULL;
+ int32_t fromOffset = 0;
+ int32_t toOffset = 0;
+ int32_t rawOffset = 0;
+ int32_t dstSavings = 0;
+ UDate start = 0;
+
+ // Parse TZOFFSETFROM/TZOFFSETTO
+ fromOffset = offsetStrToMillis(from, status);
+ toOffset = offsetStrToMillis(to, status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+
+ if (dst) {
+ // If daylight, use the previous offset as rawoffset if positive
+ if (toOffset - fromOffset > 0) {
+ rawOffset = fromOffset;
+ dstSavings = toOffset - fromOffset;
+ } else {
+ // This is rare case.. just use 1 hour DST savings
+ rawOffset = toOffset - DEF_DSTSAVINGS;
+ dstSavings = DEF_DSTSAVINGS;
+ }
+ } else {
+ rawOffset = toOffset;
+ dstSavings = 0;
+ }
+
+ // start time
+ start = parseDateTimeString(dtstart, fromOffset, status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+
+ // Create the rule
+ UDate actualStart = MAX_MILLIS;
+ if (isRRULE) {
+ rule = createRuleByRRULE(tzname, rawOffset, dstSavings, start, dates, fromOffset, status);
+ } else {
+ rule = createRuleByRDATE(tzname, rawOffset, dstSavings, start, dates, fromOffset, status);
+ }
+ if (U_FAILURE(status) || rule == NULL) {
+ goto cleanupParse;
+ } else {
+ UBool startAvail = rule->getFirstStart(fromOffset, 0, actualStart);
+ if (startAvail && actualStart < firstStart) {
+ // save from offset information for the earliest rule
+ firstStart = actualStart;
+ // If this is STD, assume the time before this transtion
+ // is DST when the difference is 1 hour. This might not be
+ // accurate, but VTIMEZONE data does not have such info.
+ if (dstSavings > 0) {
+ initialRawOffset = fromOffset;
+ initialDSTSavings = 0;
+ } else {
+ if (fromOffset - toOffset == DEF_DSTSAVINGS) {
+ initialRawOffset = fromOffset - DEF_DSTSAVINGS;
+ initialDSTSavings = DEF_DSTSAVINGS;
+ } else {
+ initialRawOffset = fromOffset;
+ initialDSTSavings = 0;
+ }
+ }
+ }
+ }
+ rules->addElement(rule, status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ state = VTZ;
+ }
+ break;
+ }
+ }
+ // Must have at least one rule
+ if (rules->size() == 0) {
+ goto cleanupParse;
+ }
+
+ // Create a initial rule
+ getDefaultTZName(tzid, FALSE, tzname);
+ initialRule = new InitialTimeZoneRule(tzname,
+ initialRawOffset, initialDSTSavings);
+
+ // Finally, create the RuleBasedTimeZone
+ rbtz = new RuleBasedTimeZone(tzid, initialRule);
+ while (!rules->isEmpty()) {
+ TimeZoneRule *tzr = (TimeZoneRule*)rules->orphanElementAt(0);
+ rbtz->addTransitionRule(tzr, status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ }
+ rbtz->complete(status);
+ if (U_FAILURE(status)) {
+ goto cleanupParse;
+ }
+ delete rules;
+ delete dates;
+
+ tz = rbtz;
+ setID(tzid);
+ return;
+
+cleanupParse:
+ if (rules != NULL) {
+ while (!rules->isEmpty()) {
+ TimeZoneRule *r = (TimeZoneRule*)rules->orphanElementAt(0);
+ delete r;
+ }
+ delete rules;
+ }
+ if (dates != NULL) {
+ delete dates;
+ }
+ if (initialRule != NULL) {
+ delete initialRule;
+ }
+ if (rbtz != NULL) {
+ delete rbtz;
+ }
+ return;
+}
+
+void
+VTimeZone::write(VTZWriter& writer, UErrorCode& status) const {
+ if (vtzlines != NULL) {
+ for (int32_t i = 0; i < vtzlines->size(); i++) {
+ UnicodeString *line = (UnicodeString*)vtzlines->elementAt(i);
+ if (line->startsWith(ICAL_TZURL)
+ && line->charAt(u_strlen(ICAL_TZURL)) == COLON) {
+ writer.write(ICAL_TZURL);
+ writer.write(COLON);
+ writer.write(tzurl);
+ writer.write(ICAL_NEWLINE);
+ } else if (line->startsWith(ICAL_LASTMOD)
+ && line->charAt(u_strlen(ICAL_LASTMOD)) == COLON) {
+ UnicodeString utcString;
+ writer.write(ICAL_LASTMOD);
+ writer.write(COLON);
+ writer.write(getUTCDateTimeString(lastmod, utcString));
+ writer.write(ICAL_NEWLINE);
+ } else {
+ writer.write(*line);
+ writer.write(ICAL_NEWLINE);
+ }
+ }
+ } else {
+ UVector *customProps = NULL;
+ if (olsonzid.length() > 0 && icutzver.length() > 0) {
+ customProps = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
+ icutzprop->append(olsonzid);
+ icutzprop->append((UChar)0x005B/*'['*/);
+ icutzprop->append(icutzver);
+ icutzprop->append((UChar)0x005D/*']'*/);
+ customProps->addElement(icutzprop, status);
+ if (U_FAILURE(status)) {
+ delete icutzprop;
+ delete customProps;
+ return;
+ }
+ }
+ writeZone(writer, *tz, customProps, status);
+ delete customProps;
+ }
+}
+
+void
+VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ InitialTimeZoneRule *initial = NULL;
+ UVector *transitionRules = NULL;
+ UVector customProps(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ UnicodeString tzid;
+
+ // Extract rules applicable to dates after the start time
+ getTimeZoneRulesAfter(start, initial, transitionRules, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Create a RuleBasedTimeZone with the subset rule
+ getID(tzid);
+ RuleBasedTimeZone rbtz(tzid, initial);
+ if (transitionRules != NULL) {
+ while (!transitionRules->isEmpty()) {
+ TimeZoneRule *tr = (TimeZoneRule*)transitionRules->orphanElementAt(0);
+ rbtz.addTransitionRule(tr, status);
+ if (U_FAILURE(status)) {
+ goto cleanupWritePartial;
+ }
+ }
+ delete transitionRules;
+ transitionRules = NULL;
+ }
+ rbtz.complete(status);
+ if (U_FAILURE(status)) {
+ goto cleanupWritePartial;
+ }
+
+ if (olsonzid.length() > 0 && icutzver.length() > 0) {
+ UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
+ icutzprop->append(olsonzid);
+ icutzprop->append((UChar)0x005B/*'['*/);
+ icutzprop->append(icutzver);
+ icutzprop->append(ICU_TZINFO_PARTIAL);
+ appendMillis(start, *icutzprop);
+ icutzprop->append((UChar)0x005D/*']'*/);
+ customProps.addElement(icutzprop, status);
+ if (U_FAILURE(status)) {
+ delete icutzprop;
+ goto cleanupWritePartial;
+ }
+ }
+ writeZone(writer, rbtz, &customProps, status);
+ return;
+
+cleanupWritePartial:
+ if (initial != NULL) {
+ delete initial;
+ }
+ if (transitionRules != NULL) {
+ while (!transitionRules->isEmpty()) {
+ TimeZoneRule *tr = (TimeZoneRule*)transitionRules->orphanElementAt(0);
+ delete tr;
+ }
+ delete transitionRules;
+ }
+}
+
+void
+VTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) /*const*/ {
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ UVector customProps(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ UnicodeString tzid;
+
+ // Extract simple rules
+ InitialTimeZoneRule *initial = NULL;
+ AnnualTimeZoneRule *std = NULL, *dst = NULL;
+ getSimpleRulesNear(time, initial, std, dst, status);
+ if (U_SUCCESS(status)) {
+ // Create a RuleBasedTimeZone with the subset rule
+ getID(tzid);
+ RuleBasedTimeZone rbtz(tzid, initial);
+ if (std != NULL && dst != NULL) {
+ rbtz.addTransitionRule(std, status);
+ rbtz.addTransitionRule(dst, status);
+ }
+ if (U_FAILURE(status)) {
+ goto cleanupWriteSimple;
+ }
+
+ if (olsonzid.length() > 0 && icutzver.length() > 0) {
+ UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
+ icutzprop->append(olsonzid);
+ icutzprop->append((UChar)0x005B/*'['*/);
+ icutzprop->append(icutzver);
+ icutzprop->append(ICU_TZINFO_SIMPLE);
+ appendMillis(time, *icutzprop);
+ icutzprop->append((UChar)0x005D/*']'*/);
+ customProps.addElement(icutzprop, status);
+ if (U_FAILURE(status)) {
+ delete icutzprop;
+ goto cleanupWriteSimple;
+ }
+ }
+ writeZone(writer, rbtz, &customProps, status);
+ }
+ return;
+
+cleanupWriteSimple:
+ if (initial != NULL) {
+ delete initial;
+ }
+ if (std != NULL) {
+ delete std;
+ }
+ if (dst != NULL) {
+ delete dst;
+ }
+}
+
+void
+VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
+ UVector* customProps, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ writeHeaders(w, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ if (customProps != NULL) {
+ for (int32_t i = 0; i < customProps->size(); i++) {
+ UnicodeString *custprop = (UnicodeString*)customProps->elementAt(i);
+ w.write(*custprop);
+ w.write(ICAL_NEWLINE);
+ }
+ }
+
+ UDate t = MIN_MILLIS;
+ UnicodeString dstName;
+ int32_t dstFromOffset = 0;
+ int32_t dstFromDSTSavings = 0;
+ int32_t dstToOffset = 0;
+ int32_t dstStartYear = 0;
+ int32_t dstMonth = 0;
+ int32_t dstDayOfWeek = 0;
+ int32_t dstWeekInMonth = 0;
+ int32_t dstMillisInDay = 0;
+ UDate dstStartTime = 0.0;
+ UDate dstUntilTime = 0.0;
+ int32_t dstCount = 0;
+ AnnualTimeZoneRule *finalDstRule = NULL;
+
+ UnicodeString stdName;
+ int32_t stdFromOffset = 0;
+ int32_t stdFromDSTSavings = 0;
+ int32_t stdToOffset = 0;
+ int32_t stdStartYear = 0;
+ int32_t stdMonth = 0;
+ int32_t stdDayOfWeek = 0;
+ int32_t stdWeekInMonth = 0;
+ int32_t stdMillisInDay = 0;
+ UDate stdStartTime = 0.0;
+ UDate stdUntilTime = 0.0;
+ int32_t stdCount = 0;
+ AnnualTimeZoneRule *finalStdRule = NULL;
+
+ int32_t year, month, dom, dow, doy, mid;
+ UBool hasTransitions = FALSE;
+ TimeZoneTransition tzt;
+ UBool tztAvail;
+ UnicodeString name;
+ UBool isDst;
+
+ // Going through all transitions
+ while (TRUE) {
+ tztAvail = basictz.getNextTransition(t, FALSE, tzt);
+ if (!tztAvail) {
+ break;
+ }
+ hasTransitions = TRUE;
+ t = tzt.getTime();
+ tzt.getTo()->getName(name);
+ isDst = (tzt.getTo()->getDSTSavings() != 0);
+ int32_t fromOffset = tzt.getFrom()->getRawOffset() + tzt.getFrom()->getDSTSavings();
+ int32_t fromDSTSavings = tzt.getFrom()->getDSTSavings();
+ int32_t toOffset = tzt.getTo()->getRawOffset() + tzt.getTo()->getDSTSavings();
+ Grego::timeToFields(tzt.getTime() + fromOffset, year, month, dom, dow, doy, mid);
+ int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
+ UBool sameRule = FALSE;
+ if (isDst) {
+ if (finalDstRule == NULL
+ && tzt.getTo()->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()) {
+ if (((AnnualTimeZoneRule*)tzt.getTo())->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
+ finalDstRule = (AnnualTimeZoneRule*)tzt.getTo()->clone();
+ }
+ }
+ if (dstCount > 0) {
+ if (year == dstStartYear + dstCount
+ && name.compare(dstName) == 0
+ && dstFromOffset == fromOffset
+ && dstToOffset == toOffset
+ && dstMonth == month
+ && dstDayOfWeek == dow
+ && dstWeekInMonth == weekInMonth
+ && dstMillisInDay == mid) {
+ // Update until time
+ dstUntilTime = t;
+ dstCount++;
+ sameRule = TRUE;
+ }
+ if (!sameRule) {
+ if (dstCount == 1) {
+ writeZonePropsByTime(w, TRUE, dstName, dstFromOffset, dstToOffset, dstStartTime,
+ TRUE, status);
+ } else {
+ writeZonePropsByDOW(w, TRUE, dstName, dstFromOffset, dstToOffset,
+ dstMonth, dstWeekInMonth, dstDayOfWeek, dstStartTime, dstUntilTime, status);
+ }
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ }
+ }
+ if (!sameRule) {
+ // Reset this DST information
+ dstName = name;
+ dstFromOffset = fromOffset;
+ dstFromDSTSavings = fromDSTSavings;
+ dstToOffset = toOffset;
+ dstStartYear = year;
+ dstMonth = month;
+ dstDayOfWeek = dow;
+ dstWeekInMonth = weekInMonth;
+ dstMillisInDay = mid;
+ dstStartTime = dstUntilTime = t;
+ dstCount = 1;
+ }
+ if (finalStdRule != NULL && finalDstRule != NULL) {
+ break;
+ }
+ } else {
+ if (finalStdRule == NULL
+ && tzt.getTo()->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()) {
+ if (((AnnualTimeZoneRule*)tzt.getTo())->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
+ finalStdRule = (AnnualTimeZoneRule*)tzt.getTo()->clone();
+ }
+ }
+ if (stdCount > 0) {
+ if (year == stdStartYear + stdCount
+ && name.compare(stdName) == 0
+ && stdFromOffset == fromOffset
+ && stdToOffset == toOffset
+ && stdMonth == month
+ && stdDayOfWeek == dow
+ && stdWeekInMonth == weekInMonth
+ && stdMillisInDay == mid) {
+ // Update until time
+ stdUntilTime = t;
+ stdCount++;
+ sameRule = TRUE;
+ }
+ if (!sameRule) {
+ if (stdCount == 1) {
+ writeZonePropsByTime(w, FALSE, stdName, stdFromOffset, stdToOffset, stdStartTime,
+ TRUE, status);
+ } else {
+ writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
+ stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, stdUntilTime, status);
+ }
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ }
+ }
+ if (!sameRule) {
+ // Reset this STD information
+ stdName = name;
+ stdFromOffset = fromOffset;
+ stdFromDSTSavings = fromDSTSavings;
+ stdToOffset = toOffset;
+ stdStartYear = year;
+ stdMonth = month;
+ stdDayOfWeek = dow;
+ stdWeekInMonth = weekInMonth;
+ stdMillisInDay = mid;
+ stdStartTime = stdUntilTime = t;
+ stdCount = 1;
+ }
+ if (finalStdRule != NULL && finalDstRule != NULL) {
+ break;
+ }
+ }
+ }
+ if (!hasTransitions) {
+ // No transition - put a single non transition RDATE
+ int32_t raw, dst, offset;
+ basictz.getOffset(0.0/*any time*/, FALSE, raw, dst, status);
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ offset = raw + dst;
+ isDst = (dst != 0);
+ UnicodeString tzid;
+ basictz.getID(tzid);
+ getDefaultTZName(tzid, isDst, name);
+ writeZonePropsByTime(w, isDst, name,
+ offset, offset, DEF_TZSTARTTIME - offset, FALSE, status);
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ } else {
+ if (dstCount > 0) {
+ if (finalDstRule == NULL) {
+ if (dstCount == 1) {
+ writeZonePropsByTime(w, TRUE, dstName, dstFromOffset, dstToOffset, dstStartTime,
+ TRUE, status);
+ } else {
+ writeZonePropsByDOW(w, TRUE, dstName, dstFromOffset, dstToOffset,
+ dstMonth, dstWeekInMonth, dstDayOfWeek, dstStartTime, dstUntilTime, status);
+ }
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ } else {
+ if (dstCount == 1) {
+ writeFinalRule(w, TRUE, finalDstRule,
+ dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, dstStartTime, status);
+ } else {
+ // Use a single rule if possible
+ if (isEquivalentDateRule(dstMonth, dstWeekInMonth, dstDayOfWeek, finalDstRule->getRule())) {
+ writeZonePropsByDOW(w, TRUE, dstName, dstFromOffset, dstToOffset,
+ dstMonth, dstWeekInMonth, dstDayOfWeek, dstStartTime, MAX_MILLIS, status);
+ } else {
+ // Not equivalent rule - write out two different rules
+ writeZonePropsByDOW(w, TRUE, dstName, dstFromOffset, dstToOffset,
+ dstMonth, dstWeekInMonth, dstDayOfWeek, dstStartTime, dstUntilTime, status);
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ writeFinalRule(w, TRUE, finalDstRule,
+ dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, dstStartTime, status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ }
+ }
+ if (stdCount > 0) {
+ if (finalStdRule == NULL) {
+ if (stdCount == 1) {
+ writeZonePropsByTime(w, FALSE, stdName, stdFromOffset, stdToOffset, stdStartTime,
+ TRUE, status);
+ } else {
+ writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
+ stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, stdUntilTime, status);
+ }
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ } else {
+ if (stdCount == 1) {
+ writeFinalRule(w, FALSE, finalStdRule,
+ stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, stdStartTime, status);
+ } else {
+ // Use a single rule if possible
+ if (isEquivalentDateRule(stdMonth, stdWeekInMonth, stdDayOfWeek, finalStdRule->getRule())) {
+ writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
+ stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, MAX_MILLIS, status);
+ } else {
+ // Not equivalent rule - write out two different rules
+ writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
+ stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, stdUntilTime, status);
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ writeFinalRule(w, FALSE, finalStdRule,
+ stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, stdStartTime, status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ goto cleanupWriteZone;
+ }
+ }
+ }
+ }
+ writeFooter(w, status);
+
+cleanupWriteZone:
+
+ if (finalStdRule != NULL) {
+ delete finalStdRule;
+ }
+ if (finalDstRule != NULL) {
+ delete finalDstRule;
+ }
+}
+
+void
+VTimeZone::writeHeaders(VTZWriter& writer, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UnicodeString tzid;
+ tz->getID(tzid);
+
+ writer.write(ICAL_BEGIN);
+ writer.write(COLON);
+ writer.write(ICAL_VTIMEZONE);
+ writer.write(ICAL_NEWLINE);
+ writer.write(ICAL_TZID);
+ writer.write(COLON);
+ writer.write(tzid);
+ writer.write(ICAL_NEWLINE);
+ if (tzurl.length() != 0) {
+ writer.write(ICAL_TZURL);
+ writer.write(COLON);
+ writer.write(tzurl);
+ writer.write(ICAL_NEWLINE);
+ }
+ if (lastmod != MAX_MILLIS) {
+ UnicodeString lastmodStr;
+ writer.write(ICAL_LASTMOD);
+ writer.write(COLON);
+ writer.write(getUTCDateTimeString(lastmod, lastmodStr));
+ writer.write(ICAL_NEWLINE);
+ }
+}
+
+/*
+ * Write the closing section of the VTIMEZONE definition block
+ */
+void
+VTimeZone::writeFooter(VTZWriter& writer, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ writer.write(ICAL_END);
+ writer.write(COLON);
+ writer.write(ICAL_VTIMEZONE);
+ writer.write(ICAL_NEWLINE);
+}
+
+/*
+ * Write a single start time
+ */
+void
+VTimeZone::writeZonePropsByTime(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset, UDate time, UBool withRDATE,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ beginZoneProps(writer, isDst, tzname, fromOffset, toOffset, time, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (withRDATE) {
+ writer.write(ICAL_RDATE);
+ writer.write(COLON);
+ UnicodeString timestr;
+ writer.write(getDateTimeString(time + fromOffset, timestr));
+ writer.write(ICAL_NEWLINE);
+ }
+ endZoneProps(writer, isDst, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+}
+
+/*
+ * Write start times defined by a DOM rule using VTIMEZONE RRULE
+ */
+void
+VTimeZone::writeZonePropsByDOM(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset,
+ int32_t month, int32_t dayOfMonth, UDate startTime, UDate untilTime,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ beginZoneProps(writer, isDst, tzname, fromOffset, toOffset, startTime, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ beginRRULE(writer, month, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ writer.write(ICAL_BYMONTHDAY);
+ writer.write(EQUALS_SIGN);
+ UnicodeString dstr;
+ appendAsciiDigits(dayOfMonth, 0, dstr);
+ writer.write(dstr);
+ if (untilTime != MAX_MILLIS) {
+ appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ writer.write(ICAL_NEWLINE);
+ endZoneProps(writer, isDst, status);
+}
+
+/*
+ * Write start times defined by a DOW rule using VTIMEZONE RRULE
+ */
+void
+VTimeZone::writeZonePropsByDOW(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset,
+ int32_t month, int32_t weekInMonth, int32_t dayOfWeek,
+ UDate startTime, UDate untilTime, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ beginZoneProps(writer, isDst, tzname, fromOffset, toOffset, startTime, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ beginRRULE(writer, month, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ writer.write(ICAL_BYDAY);
+ writer.write(EQUALS_SIGN);
+ UnicodeString dstr;
+ appendAsciiDigits(weekInMonth, 0, dstr);
+ writer.write(dstr); // -4, -3, -2, -1, 1, 2, 3, 4
+ writer.write(ICAL_DOW_NAMES[dayOfWeek - 1]); // SU, MO, TU...
+
+ if (untilTime != MAX_MILLIS) {
+ appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ writer.write(ICAL_NEWLINE);
+ endZoneProps(writer, isDst, status);
+}
+
+/*
+ * Write start times defined by a DOW_GEQ_DOM rule using VTIMEZONE RRULE
+ */
+void
+VTimeZone::writeZonePropsByDOW_GEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset,
+ int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ UDate startTime, UDate untilTime, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // Check if this rule can be converted to DOW rule
+ if (dayOfMonth%7 == 1) {
+ // Can be represented by DOW rule
+ writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+ month, (dayOfMonth + 6)/7, dayOfWeek, startTime, untilTime, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ } else if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - dayOfMonth)%7 == 6) {
+ // Can be represented by DOW rule with negative week number
+ writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+ month, -1*((MONTHLENGTH[month] - dayOfMonth + 1)/7), dayOfWeek, startTime, untilTime, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ } else {
+ // Otherwise, use BYMONTHDAY to include all possible dates
+ beginZoneProps(writer, isDst, tzname, fromOffset, toOffset, startTime, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // Check if all days are in the same month
+ int32_t startDay = dayOfMonth;
+ int32_t currentMonthDays = 7;
+
+ if (dayOfMonth <= 0) {
+ // The start day is in previous month
+ int32_t prevMonthDays = 1 - dayOfMonth;
+ currentMonthDays -= prevMonthDays;
+
+ int32_t prevMonth = (month - 1) < 0 ? 11 : month - 1;
+
+ // Note: When a rule is separated into two, UNTIL attribute needs to be
+ // calculated for each of them. For now, we skip this, because we basically use this method
+ // only for final rules, which does not have the UNTIL attribute
+ writeZonePropsByDOW_GEQ_DOM_sub(writer, prevMonth, -prevMonthDays, dayOfWeek, prevMonthDays,
+ MAX_MILLIS /* Do not use UNTIL */, fromOffset, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Start from 1 for the rest
+ startDay = 1;
+ } else if (dayOfMonth + 6 > MONTHLENGTH[month]) {
+ // Note: This code does not actually work well in February. For now, days in month in
+ // non-leap year.
+ int32_t nextMonthDays = dayOfMonth + 6 - MONTHLENGTH[month];
+ currentMonthDays -= nextMonthDays;
+
+ int32_t nextMonth = (month + 1) > 11 ? 0 : month + 1;
+
+ writeZonePropsByDOW_GEQ_DOM_sub(writer, nextMonth, 1, dayOfWeek, nextMonthDays,
+ MAX_MILLIS /* Do not use UNTIL */, fromOffset, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ writeZonePropsByDOW_GEQ_DOM_sub(writer, month, startDay, dayOfWeek, currentMonthDays,
+ untilTime, fromOffset, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ endZoneProps(writer, isDst, status);
+ }
+}
+
+/*
+ * Called from writeZonePropsByDOW_GEQ_DOM
+ */
+void
+VTimeZone::writeZonePropsByDOW_GEQ_DOM_sub(VTZWriter& writer, int32_t month, int32_t dayOfMonth,
+ int32_t dayOfWeek, int32_t numDays,
+ UDate untilTime, int32_t fromOffset, UErrorCode& status) const {
+
+ if (U_FAILURE(status)) {
+ return;
+ }
+ int32_t startDayNum = dayOfMonth;
+ UBool isFeb = (month == UCAL_FEBRUARY);
+ if (dayOfMonth < 0 && !isFeb) {
+ // Use positive number if possible
+ startDayNum = MONTHLENGTH[month] + dayOfMonth + 1;
+ }
+ beginRRULE(writer, month, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ writer.write(ICAL_BYDAY);
+ writer.write(EQUALS_SIGN);
+ writer.write(ICAL_DOW_NAMES[dayOfWeek - 1]); // SU, MO, TU...
+ writer.write(SEMICOLON);
+ writer.write(ICAL_BYMONTHDAY);
+ writer.write(EQUALS_SIGN);
+
+ UnicodeString dstr;
+ appendAsciiDigits(startDayNum, 0, dstr);
+ writer.write(dstr);
+ for (int32_t i = 1; i < numDays; i++) {
+ writer.write(COMMA);
+ dstr.remove();
+ appendAsciiDigits(startDayNum + i, 0, dstr);
+ writer.write(dstr);
+ }
+
+ if (untilTime != MAX_MILLIS) {
+ appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr), status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ writer.write(ICAL_NEWLINE);
+}
+
+/*
+ * Write start times defined by a DOW_LEQ_DOM rule using VTIMEZONE RRULE
+ */
+void
+VTimeZone::writeZonePropsByDOW_LEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset,
+ int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
+ UDate startTime, UDate untilTime, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // Check if this rule can be converted to DOW rule
+ if (dayOfMonth%7 == 0) {
+ // Can be represented by DOW rule
+ writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+ month, dayOfMonth/7, dayOfWeek, startTime, untilTime, status);
+ } else if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - dayOfMonth)%7 == 0){
+ // Can be represented by DOW rule with negative week number
+ writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+ month, -1*((MONTHLENGTH[month] - dayOfMonth)/7 + 1), dayOfWeek, startTime, untilTime, status);
+ } else if (month == UCAL_FEBRUARY && dayOfMonth == 29) {
+ // Specical case for February
+ writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+ UCAL_FEBRUARY, -1, dayOfWeek, startTime, untilTime, status);
+ } else {
+ // Otherwise, convert this to DOW_GEQ_DOM rule
+ writeZonePropsByDOW_GEQ_DOM(writer, isDst, tzname, fromOffset, toOffset,
+ month, dayOfMonth - 6, dayOfWeek, startTime, untilTime, status);
+ }
+}
+
+/*
+ * Write the final time zone rule using RRULE, with no UNTIL attribute
+ */
+void
+VTimeZone::writeFinalRule(VTZWriter& writer, UBool isDst, const AnnualTimeZoneRule* rule,
+ int32_t fromRawOffset, int32_t fromDSTSavings,
+ UDate startTime, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UBool modifiedRule = TRUE;
+ const DateTimeRule *dtrule = toWallTimeRule(rule->getRule(), fromRawOffset, fromDSTSavings);
+ if (dtrule == NULL) {
+ modifiedRule = FALSE;
+ dtrule = rule->getRule();
+ }
+ int32_t toOffset = rule->getRawOffset() + rule->getDSTSavings();
+ UnicodeString name;
+ rule->getName(name);
+ switch (dtrule->getDateRuleType()) {
+ case DateTimeRule::DOM:
+ writeZonePropsByDOM(writer, isDst, name, fromRawOffset + fromDSTSavings, toOffset,
+ dtrule->getRuleMonth(), dtrule->getRuleDayOfMonth(), startTime, MAX_MILLIS, status);
+ break;
+ case DateTimeRule::DOW:
+ writeZonePropsByDOW(writer, isDst, name, fromRawOffset + fromDSTSavings, toOffset,
+ dtrule->getRuleMonth(), dtrule->getRuleWeekInMonth(), dtrule->getRuleDayOfWeek(), startTime, MAX_MILLIS, status);
+ break;
+ case DateTimeRule::DOW_GEQ_DOM:
+ writeZonePropsByDOW_GEQ_DOM(writer, isDst, name, fromRawOffset + fromDSTSavings, toOffset,
+ dtrule->getRuleMonth(), dtrule->getRuleDayOfMonth(), dtrule->getRuleDayOfWeek(), startTime, MAX_MILLIS, status);
+ break;
+ case DateTimeRule::DOW_LEQ_DOM:
+ writeZonePropsByDOW_LEQ_DOM(writer, isDst, name, fromRawOffset + fromDSTSavings, toOffset,
+ dtrule->getRuleMonth(), dtrule->getRuleDayOfMonth(), dtrule->getRuleDayOfWeek(), startTime, MAX_MILLIS, status);
+ break;
+ }
+ if (modifiedRule) {
+ delete dtrule;
+ }
+}
+
+/*
+ * Write the opening section of zone properties
+ */
+void
+VTimeZone::beginZoneProps(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+ int32_t fromOffset, int32_t toOffset, UDate startTime, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ writer.write(ICAL_BEGIN);
+ writer.write(COLON);
+ if (isDst) {
+ writer.write(ICAL_DAYLIGHT);
+ } else {
+ writer.write(ICAL_STANDARD);
+ }
+ writer.write(ICAL_NEWLINE);
+
+ UnicodeString dstr;
+
+ // TZOFFSETTO
+ writer.write(ICAL_TZOFFSETTO);
+ writer.write(COLON);
+ millisToOffset(toOffset, dstr);
+ writer.write(dstr);
+ writer.write(ICAL_NEWLINE);
+
+ // TZOFFSETFROM
+ writer.write(ICAL_TZOFFSETFROM);
+ writer.write(COLON);
+ millisToOffset(fromOffset, dstr);
+ writer.write(dstr);
+ writer.write(ICAL_NEWLINE);
+
+ // TZNAME
+ writer.write(ICAL_TZNAME);
+ writer.write(COLON);
+ writer.write(tzname);
+ writer.write(ICAL_NEWLINE);
+
+ // DTSTART
+ writer.write(ICAL_DTSTART);
+ writer.write(COLON);
+ writer.write(getDateTimeString(startTime + fromOffset, dstr));
+ writer.write(ICAL_NEWLINE);
+}
+
+/*
+ * Writes the closing section of zone properties
+ */
+void
+VTimeZone::endZoneProps(VTZWriter& writer, UBool isDst, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ // END:STANDARD or END:DAYLIGHT
+ writer.write(ICAL_END);
+ writer.write(COLON);
+ if (isDst) {
+ writer.write(ICAL_DAYLIGHT);
+ } else {
+ writer.write(ICAL_STANDARD);
+ }
+ writer.write(ICAL_NEWLINE);
+}
+
+/*
+ * Write the beggining part of RRULE line
+ */
+void
+VTimeZone::beginRRULE(VTZWriter& writer, int32_t month, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UnicodeString dstr;
+ writer.write(ICAL_RRULE);
+ writer.write(COLON);
+ writer.write(ICAL_FREQ);
+ writer.write(EQUALS_SIGN);
+ writer.write(ICAL_YEARLY);
+ writer.write(SEMICOLON);
+ writer.write(ICAL_BYMONTH);
+ writer.write(EQUALS_SIGN);
+ appendAsciiDigits(month + 1, 0, dstr);
+ writer.write(dstr);
+ writer.write(SEMICOLON);
+}
+
+/*
+ * Append the UNTIL attribute after RRULE line
+ */
+void
+VTimeZone::appendUNTIL(VTZWriter& writer, const UnicodeString& until, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (until.length() > 0) {
+ writer.write(SEMICOLON);
+ writer.write(ICAL_UNTIL);
+ writer.write(EQUALS_SIGN);
+ writer.write(until);
+ }
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/windtfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/windtfmt.cpp
new file mode 100644
index 00000000000..5e37e4156bc
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/windtfmt.cpp
@@ -0,0 +1,315 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINDTFMT.CPP
+*
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/ures.h"
+#include "unicode/format.h"
+#include "unicode/fmtable.h"
+#include "unicode/datefmt.h"
+#include "unicode/msgfmt.h"
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "unicode/locid.h"
+#include "unicode/unistr.h"
+#include "unicode/ustring.h"
+#include "unicode/timezone.h"
+#include "unicode/utmscale.h"
+
+#include "cmemory.h"
+#include "uresimp.h"
+#include "windtfmt.h"
+#include "wintz.h"
+
+# define WIN32_LEAN_AND_MEAN
+# define VC_EXTRALEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+#include <windows.h>
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32DateFormat)
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
+#define DELETE_ARRAY(array) uprv_free((void *) (array))
+
+#define STACK_BUFFER_SIZE 64
+
+UnicodeString *getTimeDateFormat(const Calendar *cal, const Locale *locale, UErrorCode &status)
+{
+ UnicodeString *result = NULL;
+ const char *type = cal->getType();
+ const char *base = locale->getBaseName();
+ UResourceBundle *topBundle = ures_open((char *) 0, base, &status);
+ UResourceBundle *calBundle = ures_getByKey(topBundle, "calendar", NULL, &status);
+ UResourceBundle *typBundle = ures_getByKeyWithFallback(calBundle, type, NULL, &status);
+ UResourceBundle *patBundle = ures_getByKeyWithFallback(typBundle, "DateTimePatterns", NULL, &status);
+
+ if (status == U_MISSING_RESOURCE_ERROR) {
+ status = U_ZERO_ERROR;
+ typBundle = ures_getByKeyWithFallback(calBundle, "gregorian", typBundle, &status);
+ patBundle = ures_getByKeyWithFallback(typBundle, "DateTimePatterns", patBundle, &status);
+ }
+
+ if (U_FAILURE(status)) {
+ static const UChar defaultPattern[] = {0x007B, 0x0031, 0x007D, 0x0020, 0x007B, 0x0030, 0x007D, 0x0000}; // "{1} {0}"
+ return new UnicodeString(defaultPattern, ARRAY_SIZE(defaultPattern));
+ }
+
+ int32_t resStrLen = 0;
+ const UChar *resStr = ures_getStringByIndex(patBundle, (int32_t)DateFormat::kDateTime, &resStrLen, &status);
+
+ result = new UnicodeString(TRUE, resStr, resStrLen);
+
+ ures_close(patBundle);
+ ures_close(typBundle);
+ ures_close(calBundle);
+ ures_close(topBundle);
+
+ return result;
+}
+
+// TODO: Range-check timeStyle, dateStyle
+Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status)
+ : DateFormat(), fDateTimeMsg(NULL), fTimeStyle(timeStyle), fDateStyle(dateStyle), fLocale(&locale), fZoneID()
+{
+ if (U_SUCCESS(status)) {
+ fLCID = locale.getLCID();
+ fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1);
+ uprv_memset(fTZI, 0, sizeof(TIME_ZONE_INFORMATION));
+ adoptCalendar(Calendar::createInstance(locale, status));
+ }
+}
+
+Win32DateFormat::Win32DateFormat(const Win32DateFormat &other)
+ : DateFormat(other)
+{
+ *this = other;
+}
+
+Win32DateFormat::~Win32DateFormat()
+{
+// delete fCalendar;
+ uprv_free(fTZI);
+ delete fDateTimeMsg;
+}
+
+Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other)
+{
+ // The following handles fCalendar
+ DateFormat::operator=(other);
+
+// delete fCalendar;
+
+ this->fDateTimeMsg = other.fDateTimeMsg;
+ this->fTimeStyle = other.fTimeStyle;
+ this->fDateStyle = other.fDateStyle;
+ this->fLCID = other.fLCID;
+// this->fCalendar = other.fCalendar->clone();
+ this->fZoneID = other.fZoneID;
+
+ this->fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1);
+ *this->fTZI = *other.fTZI;
+
+ return *this;
+}
+
+Format *Win32DateFormat::clone(void) const
+{
+ return new Win32DateFormat(*this);
+}
+
+// TODO: Is just ignoring pos the right thing?
+UnicodeString &Win32DateFormat::format(Calendar &cal, UnicodeString &appendTo, FieldPosition &pos) const
+{
+ FILETIME ft;
+ SYSTEMTIME st_gmt;
+ SYSTEMTIME st_local;
+ TIME_ZONE_INFORMATION tzi = *fTZI;
+ UErrorCode status = U_ZERO_ERROR;
+ const TimeZone &tz = cal.getTimeZone();
+ int64_t uct, uft;
+
+ setTimeZoneInfo(&tzi, tz);
+
+ uct = utmscale_fromInt64((int64_t) cal.getTime(status), UDTS_ICU4C_TIME, &status);
+ uft = utmscale_toInt64(uct, UDTS_WINDOWS_FILE_TIME, &status);
+
+ ft.dwLowDateTime = (DWORD) (uft & 0xFFFFFFFF);
+ ft.dwHighDateTime = (DWORD) ((uft >> 32) & 0xFFFFFFFF);
+
+ FileTimeToSystemTime(&ft, &st_gmt);
+ SystemTimeToTzSpecificLocalTime(&tzi, &st_gmt, &st_local);
+
+
+ if (fDateStyle != DateFormat::kNone && fTimeStyle != DateFormat::kNone) {
+ UnicodeString *date = new UnicodeString();
+ UnicodeString *time = new UnicodeString();
+ UnicodeString *pattern = fDateTimeMsg;
+ Formattable timeDateArray[2];
+
+ formatDate(&st_local, *date);
+ formatTime(&st_local, *time);
+
+ timeDateArray[0].adoptString(time);
+ timeDateArray[1].adoptString(date);
+
+ if (strcmp(fCalendar->getType(), cal.getType()) != 0) {
+ pattern = getTimeDateFormat(&cal, fLocale, status);
+ }
+
+ MessageFormat::format(*pattern, timeDateArray, 2, appendTo, status);
+ } else if (fDateStyle != DateFormat::kNone) {
+ formatDate(&st_local, appendTo);
+ } else if (fTimeStyle != DateFormat::kNone) {
+ formatTime(&st_local, appendTo);
+ }
+
+ return appendTo;
+}
+
+void Win32DateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& pos) const
+{
+ pos.setErrorIndex(pos.getIndex());
+}
+
+void Win32DateFormat::adoptCalendar(Calendar *newCalendar)
+{
+ if (fCalendar == NULL || strcmp(fCalendar->getType(), newCalendar->getType()) != 0) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ if (fDateStyle != DateFormat::kNone && fTimeStyle != DateFormat::kNone) {
+ delete fDateTimeMsg;
+ fDateTimeMsg = getTimeDateFormat(newCalendar, fLocale, status);
+ }
+ }
+
+ delete fCalendar;
+ fCalendar = newCalendar;
+
+ fZoneID = setTimeZoneInfo(fTZI, fCalendar->getTimeZone());
+}
+
+void Win32DateFormat::setCalendar(const Calendar &newCalendar)
+{
+ adoptCalendar(newCalendar.clone());
+}
+
+void Win32DateFormat::adoptTimeZone(TimeZone *zoneToAdopt)
+{
+ fZoneID = setTimeZoneInfo(fTZI, *zoneToAdopt);
+ fCalendar->adoptTimeZone(zoneToAdopt);
+}
+
+void Win32DateFormat::setTimeZone(const TimeZone& zone)
+{
+ fZoneID = setTimeZoneInfo(fTZI, zone);
+ fCalendar->setTimeZone(zone);
+}
+
+static const DWORD dfFlags[] = {DATE_LONGDATE, DATE_LONGDATE, DATE_SHORTDATE, DATE_SHORTDATE};
+
+void Win32DateFormat::formatDate(const SYSTEMTIME *st, UnicodeString &appendTo) const
+{
+ int result;
+ UChar stackBuffer[STACK_BUFFER_SIZE];
+ UChar *buffer = stackBuffer;
+
+ result = GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, STACK_BUFFER_SIZE);
+
+ if (result == 0) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ int newLength = GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, NULL, 0);
+
+ buffer = NEW_ARRAY(UChar, newLength);
+ GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, newLength);
+ }
+ }
+
+ appendTo.append(buffer, (int32_t) wcslen(buffer));
+
+ if (buffer != stackBuffer) {
+ DELETE_ARRAY(buffer);
+ }
+}
+
+static const DWORD tfFlags[] = {0, 0, 0, TIME_NOSECONDS};
+
+void Win32DateFormat::formatTime(const SYSTEMTIME *st, UnicodeString &appendTo) const
+{
+ int result;
+ UChar stackBuffer[STACK_BUFFER_SIZE];
+ UChar *buffer = stackBuffer;
+
+ result = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE);
+
+ if (result == 0) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ int newLength = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, NULL, 0);
+
+ buffer = NEW_ARRAY(UChar, newLength);
+ GetDateFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, newLength);
+ }
+ }
+
+ appendTo.append(buffer, (int32_t) wcslen(buffer));
+
+ if (buffer != stackBuffer) {
+ DELETE_ARRAY(buffer);
+ }
+}
+
+UnicodeString Win32DateFormat::setTimeZoneInfo(TIME_ZONE_INFORMATION *tzi, const TimeZone &zone) const
+{
+ UnicodeString zoneID;
+
+ zone.getID(zoneID);
+
+ if (zoneID.compare(fZoneID) != 0) {
+ UnicodeString icuid;
+
+ zone.getID(icuid);
+ if (! uprv_getWindowsTimeZoneInfo(tzi, icuid.getBuffer(), icuid.length())) {
+ UBool found = FALSE;
+ int32_t ec = TimeZone::countEquivalentIDs(icuid);
+
+ for (int z = 0; z < ec; z += 1) {
+ UnicodeString equiv = TimeZone::getEquivalentID(icuid, z);
+
+ if (found = uprv_getWindowsTimeZoneInfo(tzi, equiv.getBuffer(), equiv.length())) {
+ break;
+ }
+ }
+
+ if (! found) {
+ GetTimeZoneInformation(tzi);
+ }
+ }
+ }
+
+ return zoneID;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // #ifdef U_WINDOWS
+
diff --git a/Build/source/libs/icu/icu-xetex/i18n/windtfmt.h b/Build/source/libs/icu/icu-xetex/i18n/windtfmt.h
new file mode 100644
index 00000000000..869044e04bc
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/windtfmt.h
@@ -0,0 +1,148 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINDTFMT.H
+*
+********************************************************************************
+*/
+
+#ifndef __WINDTFMT
+#define __WINDTFMT
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+#include "unicode/datefmt.h"
+#include "unicode/calendar.h"
+#include "unicode/ustring.h"
+#include "unicode/locid.h"
+
+/**
+ * \file
+ * \brief C++ API: Format dates using Windows API.
+ */
+
+U_CDECL_BEGIN
+// Forward declarations for Windows types...
+typedef struct _SYSTEMTIME SYSTEMTIME;
+typedef struct _TIME_ZONE_INFORMATION TIME_ZONE_INFORMATION;
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+class Win32DateFormat : public DateFormat
+{
+public:
+ Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status);
+
+ Win32DateFormat(const Win32DateFormat &other);
+
+ virtual ~Win32DateFormat();
+
+ virtual Format *clone(void) const;
+
+ Win32DateFormat &operator=(const Win32DateFormat &other);
+
+ UnicodeString &format(Calendar &cal, UnicodeString &appendTo, FieldPosition &pos) const;
+
+ UnicodeString& format(UDate date, UnicodeString& appendTo) const;
+
+ void parse(const UnicodeString& text, Calendar& cal, ParsePosition& pos) const;
+
+ /**
+ * Set the calendar to be used by this date format. Initially, the default
+ * calendar for the specified or default locale is used. The caller should
+ * not delete the Calendar object after it is adopted by this call.
+ *
+ * @param calendarToAdopt Calendar object to be adopted.
+ * @draft ICU 3.6
+ */
+ virtual void adoptCalendar(Calendar* calendarToAdopt);
+
+ /**
+ * Set the calendar to be used by this date format. Initially, the default
+ * calendar for the specified or default locale is used.
+ *
+ * @param newCalendar Calendar object to be set.
+ *
+ * @draft ICU 3.6
+ */
+ virtual void setCalendar(const Calendar& newCalendar);
+
+ /**
+ * Sets the time zone for the calendar of this DateFormat object. The caller
+ * no longer owns the TimeZone object and should not delete it after this call.
+ *
+ * @param zoneToAdopt the TimeZone to be adopted.
+ *
+ * @draft ICU 3.6
+ */
+ virtual void adoptTimeZone(TimeZone* zoneToAdopt);
+
+ /**
+ * Sets the time zone for the calendar of this DateFormat object.
+ * @param zone the new time zone.
+ *
+ * @draft ICU 3.6
+ */
+ virtual void setTimeZone(const TimeZone& zone);
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @draft ICU 3.6
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @draft ICU 3.6
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+private:
+ void formatDate(const SYSTEMTIME *st, UnicodeString &appendTo) const;
+ void formatTime(const SYSTEMTIME *st, UnicodeString &appendTo) const;
+
+ UnicodeString setTimeZoneInfo(TIME_ZONE_INFORMATION *tzi, const TimeZone &zone) const;
+
+ UnicodeString *fDateTimeMsg;
+ DateFormat::EStyle fTimeStyle;
+ DateFormat::EStyle fDateStyle;
+ const Locale *fLocale;
+ int32_t fLCID;
+ UnicodeString fZoneID;
+ TIME_ZONE_INFORMATION *fTZI;
+};
+
+inline UnicodeString &Win32DateFormat::format(UDate date, UnicodeString& appendTo) const {
+ return DateFormat::format(date, appendTo);
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // #ifdef U_WINDOWS
+
+#endif // __WINDTFMT
diff --git a/Build/source/libs/icu/icu-xetex/i18n/winnmfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/winnmfmt.cpp
new file mode 100644
index 00000000000..4207c52e7e9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/winnmfmt.cpp
@@ -0,0 +1,354 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINNMFMT.CPP
+*
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "winnmfmt.h"
+
+#include "unicode/format.h"
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+#include "unicode/ustring.h"
+
+#include "cmemory.h"
+#include "uassert.h"
+#include "locmap.h"
+
+# define WIN32_LEAN_AND_MEAN
+# define VC_EXTRALEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+#include <windows.h>
+#include <stdio.h>
+
+U_NAMESPACE_BEGIN
+
+union FormatInfo
+{
+ NUMBERFMTW number;
+ CURRENCYFMTW currency;
+};
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32NumberFormat)
+
+#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
+#define DELETE_ARRAY(array) uprv_free((void *) (array))
+
+#define STACK_BUFFER_SIZE 32
+
+/*
+ * Turns a string of the form "3;2;0" into the grouping UINT
+ * needed for NUMBERFMT and CURRENCYFMT. If the string does not
+ * end in ";0" then the return value should be multiplied by 10.
+ * (e.g. "3" => 30, "3;2" => 320)
+ */
+static UINT getGrouping(const char *grouping)
+{
+ UINT g = 0;
+ const char *s;
+
+ for (s = grouping; *s != '\0'; s += 1) {
+ if (*s > '0' && *s < '9') {
+ g = g * 10 + (*s - '0');
+ } else if (*s != ';') {
+ break;
+ }
+ }
+
+ if (*s != '0') {
+ g *= 10;
+ }
+
+ return g;
+}
+
+static void getNumberFormat(NUMBERFMTW *fmt, int32_t lcid)
+{
+ char buf[10];
+
+ GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_IDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT));
+ GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT));
+
+ GetLocaleInfoA(lcid, LOCALE_SGROUPING, buf, 10);
+ fmt->Grouping = getGrouping(buf);
+
+ fmt->lpDecimalSep = NEW_ARRAY(UChar, 6);
+ GetLocaleInfoW(lcid, LOCALE_SDECIMAL, fmt->lpDecimalSep, 6);
+
+ fmt->lpThousandSep = NEW_ARRAY(UChar, 6);
+ GetLocaleInfoW(lcid, LOCALE_STHOUSAND, fmt->lpThousandSep, 6);
+
+ GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_INEGNUMBER, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT));
+}
+
+static void freeNumberFormat(NUMBERFMTW *fmt)
+{
+ if (fmt != NULL) {
+ DELETE_ARRAY(fmt->lpThousandSep);
+ DELETE_ARRAY(fmt->lpDecimalSep);
+ }
+}
+
+static void getCurrencyFormat(CURRENCYFMTW *fmt, int32_t lcid)
+{
+ char buf[10];
+
+ GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ICURRDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT));
+ GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT));
+
+ GetLocaleInfoA(lcid, LOCALE_SMONGROUPING, buf, sizeof(buf));
+ fmt->Grouping = getGrouping(buf);
+
+ fmt->lpDecimalSep = NEW_ARRAY(UChar, 6);
+ GetLocaleInfoW(lcid, LOCALE_SMONDECIMALSEP, fmt->lpDecimalSep, 6);
+
+ fmt->lpThousandSep = NEW_ARRAY(UChar, 6);
+ GetLocaleInfoW(lcid, LOCALE_SMONTHOUSANDSEP, fmt->lpThousandSep, 6);
+
+ GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_INEGCURR, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT));
+ GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ICURRENCY, (LPWSTR) &fmt->PositiveOrder, sizeof(UINT));
+
+ fmt->lpCurrencySymbol = NEW_ARRAY(UChar, 8);
+ GetLocaleInfoW(lcid, LOCALE_SCURRENCY, (LPWSTR) fmt->lpCurrencySymbol, 8);
+}
+
+static void freeCurrencyFormat(CURRENCYFMTW *fmt)
+{
+ if (fmt != NULL) {
+ DELETE_ARRAY(fmt->lpCurrencySymbol);
+ DELETE_ARRAY(fmt->lpThousandSep);
+ DELETE_ARRAY(fmt->lpDecimalSep);
+ }
+}
+
+// TODO: keep locale too?
+Win32NumberFormat::Win32NumberFormat(const Locale &locale, UBool currency, UErrorCode &status)
+ : NumberFormat(), fCurrency(currency), fFractionDigitsSet(FALSE), fFormatInfo(NULL)
+{
+ if (!U_FAILURE(status)) {
+ fLCID = locale.getLCID();
+
+ fFormatInfo = (FormatInfo*)uprv_malloc(sizeof(FormatInfo));
+
+ if (fCurrency) {
+ getCurrencyFormat(&fFormatInfo->currency, fLCID);
+ } else {
+ getNumberFormat(&fFormatInfo->number, fLCID);
+ }
+ }
+}
+
+Win32NumberFormat::Win32NumberFormat(const Win32NumberFormat &other)
+ : NumberFormat(other), fFormatInfo((FormatInfo*)uprv_malloc(sizeof(FormatInfo)))
+{
+ if (fFormatInfo != NULL) {
+ uprv_memset(fFormatInfo, 0, sizeof(*fFormatInfo));
+ }
+ *this = other;
+}
+
+Win32NumberFormat::~Win32NumberFormat()
+{
+ if (fFormatInfo != NULL) {
+ if (fCurrency) {
+ freeCurrencyFormat(&fFormatInfo->currency);
+ } else {
+ freeNumberFormat(&fFormatInfo->number);
+ }
+
+ uprv_free(fFormatInfo);
+ }
+}
+
+Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other)
+{
+ NumberFormat::operator=(other);
+
+ this->fCurrency = other.fCurrency;
+ this->fLCID = other.fLCID;
+ this->fFractionDigitsSet = other.fFractionDigitsSet;
+
+ if (fCurrency) {
+ freeCurrencyFormat(&fFormatInfo->currency);
+ getCurrencyFormat(&fFormatInfo->currency, fLCID);
+ } else {
+ freeNumberFormat(&fFormatInfo->number);
+ getNumberFormat(&fFormatInfo->number, fLCID);
+ }
+
+ return *this;
+}
+
+Format *Win32NumberFormat::clone(void) const
+{
+ return new Win32NumberFormat(*this);
+}
+
+UnicodeString& Win32NumberFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const
+{
+ return format(getMaximumFractionDigits(), appendTo, L"%.16f", number);
+}
+
+UnicodeString& Win32NumberFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const
+{
+ return format(getMinimumFractionDigits(), appendTo, L"%I32d", number);
+}
+
+UnicodeString& Win32NumberFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const
+{
+ return format(getMinimumFractionDigits(), appendTo, L"%I64d", number);
+}
+
+// TODO: cache Locale and NumberFormat? Could keep locale passed to constructor...
+void Win32NumberFormat::parse(const UnicodeString& text, Formattable& result, ParsePosition& parsePosition) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Locale loc(uprv_convertToPosix(fLCID, &status));
+ NumberFormat *nf = fCurrency? NumberFormat::createCurrencyInstance(loc, status) : NumberFormat::createInstance(loc, status);
+
+ nf->parse(text, result, parsePosition);
+ delete nf;
+}
+void Win32NumberFormat::setMaximumFractionDigits(int32_t newValue)
+{
+ fFractionDigitsSet = TRUE;
+ NumberFormat::setMaximumFractionDigits(newValue);
+}
+
+void Win32NumberFormat::setMinimumFractionDigits(int32_t newValue)
+{
+ fFractionDigitsSet = TRUE;
+ NumberFormat::setMinimumFractionDigits(newValue);
+}
+
+UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appendTo, wchar_t *fmt, ...) const
+{
+ wchar_t nStackBuffer[STACK_BUFFER_SIZE];
+ wchar_t *nBuffer = nStackBuffer;
+ va_list args;
+ int result;
+
+ nBuffer[0] = 0x0000;
+
+ /* Due to the arguments causing a result to be <= 23 characters (+2 for NULL and minus),
+ we don't need to reallocate the buffer. */
+ va_start(args, fmt);
+ result = _vsnwprintf(nBuffer, STACK_BUFFER_SIZE, fmt, args);
+ va_end(args);
+
+ /* Just to make sure of the above statement, we add this assert */
+ U_ASSERT(result >=0);
+ // The following code is not used because _vscwprintf isn't available on MinGW at the moment.
+ /*if (result < 0) {
+ int newLength;
+
+ va_start(args, fmt);
+ newLength = _vscwprintf(fmt, args);
+ va_end(args);
+
+ nBuffer = NEW_ARRAY(UChar, newLength + 1);
+
+ va_start(args, fmt);
+ result = _vsnwprintf(nBuffer, newLength + 1, fmt, args);
+ va_end(args);
+ }*/
+
+ // vswprintf is sensitive to the locale set by setlocale. For some locales
+ // it doesn't use "." as the decimal separator, which is what GetNumberFormatW
+ // and GetCurrencyFormatW both expect to see.
+ //
+ // To fix this, we scan over the string and replace the first non-digits, except
+ // for a leading "-", with a "."
+ //
+ // Note: (nBuffer[0] == L'-') will evaluate to 1 if there is a leading '-' in the
+ // number, and 0 otherwise.
+ for (wchar_t *p = &nBuffer[nBuffer[0] == L'-']; *p != L'\0'; p += 1) {
+ if (*p < L'0' || *p > L'9') {
+ *p = L'.';
+ break;
+ }
+ }
+
+ UChar stackBuffer[STACK_BUFFER_SIZE];
+ UChar *buffer = stackBuffer;
+ FormatInfo formatInfo;
+
+ formatInfo = *fFormatInfo;
+ buffer[0] = 0x0000;
+
+ if (fCurrency) {
+ if (fFractionDigitsSet) {
+ formatInfo.currency.NumDigits = (UINT) numDigits;
+ }
+
+ if (!isGroupingUsed()) {
+ formatInfo.currency.Grouping = 0;
+ }
+
+ result = GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, buffer, STACK_BUFFER_SIZE);
+
+ if (result == 0) {
+ DWORD lastError = GetLastError();
+
+ if (lastError == ERROR_INSUFFICIENT_BUFFER) {
+ int newLength = GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, NULL, 0);
+
+ buffer = NEW_ARRAY(UChar, newLength);
+ buffer[0] = 0x0000;
+ GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, buffer, newLength);
+ }
+ }
+ } else {
+ if (fFractionDigitsSet) {
+ formatInfo.number.NumDigits = (UINT) numDigits;
+ }
+
+ if (!isGroupingUsed()) {
+ formatInfo.number.Grouping = 0;
+ }
+
+ result = GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, buffer, STACK_BUFFER_SIZE);
+
+ if (result == 0) {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ int newLength = GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, NULL, 0);
+
+ buffer = NEW_ARRAY(UChar, newLength);
+ buffer[0] = 0x0000;
+ GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, buffer, newLength);
+ }
+ }
+ }
+
+ appendTo.append(buffer, (int32_t) wcslen(buffer));
+
+ if (buffer != stackBuffer) {
+ DELETE_ARRAY(buffer);
+ }
+
+ /*if (nBuffer != nStackBuffer) {
+ DELETE_ARRAY(nBuffer);
+ }*/
+
+ return appendTo;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // #ifdef U_WINDOWS
diff --git a/Build/source/libs/icu/icu-xetex/i18n/winnmfmt.h b/Build/source/libs/icu/icu-xetex/i18n/winnmfmt.h
new file mode 100644
index 00000000000..9b737f8ab79
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/winnmfmt.h
@@ -0,0 +1,168 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINNMFMT.H
+*
+********************************************************************************
+*/
+
+#ifndef __WINNMFMT
+#define __WINNMFMT
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#include "unicode/format.h"
+#include "unicode/datefmt.h"
+#include "unicode/calendar.h"
+#include "unicode/ustring.h"
+#include "unicode/locid.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * \file
+ * \brief C++ API: Format numbers using Windows API.
+ */
+
+U_NAMESPACE_BEGIN
+
+union FormatInfo;
+
+class Win32NumberFormat : public NumberFormat
+{
+public:
+ Win32NumberFormat(const Locale &locale, UBool currency, UErrorCode &status);
+
+ Win32NumberFormat(const Win32NumberFormat &other);
+
+ virtual ~Win32NumberFormat();
+
+ virtual Format *clone(void) const;
+
+ Win32NumberFormat &operator=(const Win32NumberFormat &other);
+
+ /**
+ * Format a double number. Concrete subclasses must implement
+ * these pure virtual methods.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @draft ICU 3.6
+ */
+ virtual UnicodeString& format(double number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+ /**
+ * Format a long number. Concrete subclasses must implement
+ * these pure virtual methods.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @draft ICU 3.6
+ */
+ virtual UnicodeString& format(int32_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+ /**
+ * Format an int64 number.
+ *
+ * @param number The value to be formatted.
+ * @param appendTo Output parameter to receive result.
+ * Result is appended to existing contents.
+ * @param pos On input: an alignment field, if desired.
+ * On output: the offsets of the alignment field.
+ * @return Reference to 'appendTo' parameter.
+ * @draft ICU 3.6
+ */
+ virtual UnicodeString& format(int64_t number,
+ UnicodeString& appendTo,
+ FieldPosition& pos) const;
+
+// Use the default behavior for the following.
+// virtual UnicodeString &format(double number, UnicodeString &appendTo) const;
+// virtual UnicodeString &format(int32_t number, UnicodeString &appendTo) const;
+// virtual UnicodeString &format(int64_t number, UnicodeString &appendTo) const;
+
+ virtual void parse(const UnicodeString& text, Formattable& result, ParsePosition& parsePosition) const;
+
+ /**
+ * Sets the maximum number of digits allowed in the fraction portion of a
+ * number. maximumFractionDigits must be >= minimumFractionDigits. If the
+ * new value for maximumFractionDigits is less than the current value
+ * of minimumFractionDigits, then minimumFractionDigits will also be set to
+ * the new value.
+ * @param newValue the new value to be set.
+ * @see getMaximumFractionDigits
+ * @draft ICU 3.6
+ */
+ virtual void setMaximumFractionDigits(int32_t newValue);
+
+ /**
+ * Sets the minimum number of digits allowed in the fraction portion of a
+ * number. minimumFractionDigits must be &lt;= maximumFractionDigits. If the
+ * new value for minimumFractionDigits exceeds the current value
+ * of maximumFractionDigits, then maximumIntegerDigits will also be set to
+ * the new value
+ * @param newValue the new value to be set.
+ * @see getMinimumFractionDigits
+ * @draft ICU 3.6
+ */
+ virtual void setMinimumFractionDigits(int32_t newValue);
+
+ /**
+ * Return the class ID for this class. This is useful only for comparing to
+ * a return value from getDynamicClassID(). For example:
+ * <pre>
+ * . Base* polymorphic_pointer = createPolymorphicObject();
+ * . if (polymorphic_pointer->getDynamicClassID() ==
+ * . erived::getStaticClassID()) ...
+ * </pre>
+ * @return The class ID for all objects of this class.
+ * @stable ICU 2.0
+ */
+ U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+ /**
+ * Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
+ * method is to implement a simple version of RTTI, since not all C++
+ * compilers support genuine RTTI. Polymorphic operator==() and clone()
+ * methods call this method.
+ *
+ * @return The class ID for this object. All objects of a
+ * given class have the same class ID. Objects of
+ * other classes have different class IDs.
+ * @stable ICU 2.0
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+private:
+ UnicodeString &format(int32_t numDigits, UnicodeString &appendTo, wchar_t *format, ...) const;
+
+ UBool fCurrency;
+ int32_t fLCID;
+ FormatInfo *fFormatInfo;
+ UBool fFractionDigitsSet;
+
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // #ifdef U_WINDOWS
+
+#endif // __WINNMFMT
diff --git a/Build/source/libs/icu/icu-xetex/i18n/zonemeta.cpp b/Build/source/libs/icu/icu-xetex/i18n/zonemeta.cpp
new file mode 100644
index 00000000000..0e67c687c28
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/zonemeta.cpp
@@ -0,0 +1,873 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "zonemeta.h"
+
+#include "unicode/timezone.h"
+#include "unicode/ustring.h"
+#include "unicode/putil.h"
+
+#include "umutex.h"
+#include "uvector.h"
+#include "cmemory.h"
+#include "gregoimp.h"
+#include "cstring.h"
+#include "ucln_in.h"
+
+static UBool gZoneMetaInitialized = FALSE;
+
+// Metazone mapping tables
+static UMTX gZoneMetaLock = NULL;
+static U_NAMESPACE_QUALIFIER Hashtable *gCanonicalMap = NULL;
+static U_NAMESPACE_QUALIFIER Hashtable *gOlsonToMeta = NULL;
+static U_NAMESPACE_QUALIFIER Hashtable *gMetaToOlson = NULL;
+
+U_CDECL_BEGIN
+/**
+ * Cleanup callback func
+ */
+static UBool U_CALLCONV zoneMeta_cleanup(void)
+{
+ umtx_destroy(&gZoneMetaLock);
+
+ if (gCanonicalMap != NULL) {
+ delete gCanonicalMap;
+ gCanonicalMap = NULL;
+ }
+
+ if (gOlsonToMeta != NULL) {
+ delete gOlsonToMeta;
+ gOlsonToMeta = NULL;
+ }
+
+ if (gMetaToOlson != NULL) {
+ delete gMetaToOlson;
+ gMetaToOlson = NULL;
+ }
+
+ gZoneMetaInitialized = FALSE;
+
+ return TRUE;
+}
+
+/**
+ * Deleter for UVector
+ */
+static void U_CALLCONV
+deleteUVector(void *obj) {
+ delete (U_NAMESPACE_QUALIFIER UVector*) obj;
+}
+
+/**
+ * Deleter for CanonicalMapEntry
+ */
+static void U_CALLCONV
+deleteCanonicalMapEntry(void *obj) {
+ U_NAMESPACE_QUALIFIER CanonicalMapEntry *entry = (U_NAMESPACE_QUALIFIER CanonicalMapEntry*)obj;
+ uprv_free(entry->id);
+ uprv_free(entry);
+}
+
+/**
+ * Deleter for OlsonToMetaMappingEntry
+ */
+static void U_CALLCONV
+deleteOlsonToMetaMappingEntry(void *obj) {
+ U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry *entry = (U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry*)obj;
+ uprv_free(entry);
+}
+
+/**
+ * Deleter for MetaToOlsonMappingEntry
+ */
+static void U_CALLCONV
+deleteMetaToOlsonMappingEntry(void *obj) {
+ U_NAMESPACE_QUALIFIER MetaToOlsonMappingEntry *entry = (U_NAMESPACE_QUALIFIER MetaToOlsonMappingEntry*)obj;
+ uprv_free(entry->territory);
+ uprv_free(entry);
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+#define ZID_KEY_MAX 128
+static const char gZoneStringsTag[] = "zoneStrings";
+static const char gUseMetazoneTag[] = "um";
+
+static const char gSupplementalData[] = "supplementalData";
+static const char gMapTimezonesTag[] = "mapTimezones";
+static const char gMetazonesTag[] = "metazones";
+static const char gZoneFormattingTag[] = "zoneFormatting";
+static const char gTerritoryTag[] = "territory";
+static const char gAliasesTag[] = "aliases";
+static const char gMultizoneTag[] = "multizone";
+
+static const char gMetazoneInfo[] = "metazoneInfo";
+static const char gMetazoneMappings[] = "metazoneMappings";
+
+#define MZID_PREFIX_LEN 5
+static const char gMetazoneIdPrefix[] = "meta:";
+
+static const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001"
+
+#define ASCII_DIGIT(c) (((c)>=0x30 && (c)<=0x39) ? (c)-0x30 : -1)
+
+/*
+ * Convert a date string used by metazone mappings to UDate.
+ * The format used by CLDR metazone mapping is "yyyy-MM-dd HH:mm".
+ */
+ static UDate parseDate (const UChar *text, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ int32_t len = u_strlen(text);
+ if (len != 16 && len != 10) {
+ // It must be yyyy-MM-dd HH:mm (length 16) or yyyy-MM-dd (length 10)
+ status = U_INVALID_FORMAT_ERROR;
+ return 0;
+ }
+
+ int32_t year = 0, month = 0, day = 0, hour = 0, min = 0, n;
+ int32_t idx;
+
+ // "yyyy" (0 - 3)
+ for (idx = 0; idx <= 3 && U_SUCCESS(status); idx++) {
+ n = ASCII_DIGIT(text[idx]);
+ if (n >= 0) {
+ year = 10*year + n;
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ // "MM" (5 - 6)
+ for (idx = 5; idx <= 6 && U_SUCCESS(status); idx++) {
+ n = ASCII_DIGIT(text[idx]);
+ if (n >= 0) {
+ month = 10*month + n;
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ // "dd" (8 - 9)
+ for (idx = 8; idx <= 9 && U_SUCCESS(status); idx++) {
+ n = ASCII_DIGIT(text[idx]);
+ if (n >= 0) {
+ day = 10*day + n;
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ if (len == 16) {
+ // "HH" (11 - 12)
+ for (idx = 11; idx <= 12 && U_SUCCESS(status); idx++) {
+ n = ASCII_DIGIT(text[idx]);
+ if (n >= 0) {
+ hour = 10*hour + n;
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ // "mm" (14 - 15)
+ for (idx = 14; idx <= 15 && U_SUCCESS(status); idx++) {
+ n = ASCII_DIGIT(text[idx]);
+ if (n >= 0) {
+ min = 10*min + n;
+ } else {
+ status = U_INVALID_FORMAT_ERROR;
+ }
+ }
+ }
+
+ if (U_SUCCESS(status)) {
+ UDate date = Grego::fieldsToDay(year, month - 1, day) * U_MILLIS_PER_DAY
+ + hour * U_MILLIS_PER_HOUR + min * U_MILLIS_PER_MINUTE;
+ return date;
+ }
+ return 0;
+}
+
+ /*
+ * Initialize global objects
+ */
+void
+ZoneMeta::initialize(void) {
+ UBool initialized;
+ UMTX_CHECK(&gZoneMetaLock, gZoneMetaInitialized, initialized);
+ if (initialized) {
+ return;
+ }
+
+ // Initialize hash tables
+ Hashtable *tmpCanonicalMap = createCanonicalMap();
+ Hashtable *tmpOlsonToMeta = createOlsonToMetaMap();
+ if (tmpOlsonToMeta == NULL) {
+ // With ICU 3.8 data
+ tmpOlsonToMeta = createOlsonToMetaMapOld();
+ }
+ Hashtable *tmpMetaToOlson = createMetaToOlsonMap();
+
+ umtx_lock(&gZoneMetaLock);
+ if (gZoneMetaInitialized) {
+ // Another thread already created mappings
+ delete tmpCanonicalMap;
+ delete tmpOlsonToMeta;
+ delete tmpMetaToOlson;
+ } else {
+ gZoneMetaInitialized = TRUE;
+ gCanonicalMap = tmpCanonicalMap;
+ gOlsonToMeta = tmpOlsonToMeta;
+ gMetaToOlson = tmpMetaToOlson;
+ ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
+ }
+ umtx_unlock(&gZoneMetaLock);
+}
+
+Hashtable*
+ZoneMeta::createCanonicalMap(void) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ Hashtable *canonicalMap = NULL;
+ UResourceBundle *zoneFormatting = NULL;
+ UResourceBundle *tzitem = NULL;
+ UResourceBundle *aliases = NULL;
+
+ canonicalMap = new Hashtable(uhash_compareUnicodeString, NULL, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ canonicalMap->setValueDeleter(deleteCanonicalMapEntry);
+
+ zoneFormatting = ures_openDirect(NULL, gSupplementalData, &status);
+ zoneFormatting = ures_getByKey(zoneFormatting, gZoneFormattingTag, zoneFormatting, &status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+
+ while (ures_hasNext(zoneFormatting)) {
+ tzitem = ures_getNextResource(zoneFormatting, tzitem, &status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ if (ures_getType(tzitem) != URES_TABLE) {
+ continue;
+ }
+
+ int32_t territoryLen;
+ const UChar *territory = ures_getStringByKey(tzitem, gTerritoryTag, &territoryLen, &status);
+ if (U_FAILURE(status)) {
+ territory = NULL;
+ status = U_ZERO_ERROR;
+ }
+
+ int32_t tzidLen = 0;
+ char tzid[ZID_KEY_MAX];
+ const char *tzkey = ures_getKey(tzitem);
+ uprv_strcpy(tzid, tzkey);
+ // Replace ':' with '/'
+ char *p = tzid;
+ while (*p) {
+ if (*p == ':') {
+ *p = '/';
+ }
+ p++;
+ tzidLen++;
+ }
+
+ // Create canonical map entry
+ CanonicalMapEntry *entry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry));
+ if (entry == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto error_cleanup;
+ }
+ entry->id = (UChar*)uprv_malloc((tzidLen + 1) * sizeof(UChar));
+ if (entry->id == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(entry);
+ goto error_cleanup;
+ }
+ u_charsToUChars(tzid, entry->id, tzidLen + 1);
+
+ if (territory == NULL || u_strcmp(territory, gWorld) == 0) {
+ entry->country = NULL;
+ } else {
+ entry->country = territory;
+ }
+
+ // Put this entry to the table
+ canonicalMap->put(UnicodeString(entry->id), entry, status);
+ if (U_FAILURE(status)) {
+ deleteCanonicalMapEntry(entry);
+ goto error_cleanup;
+ }
+
+ // Get aliases
+ aliases = ures_getByKey(tzitem, gAliasesTag, aliases, &status);
+ if (U_FAILURE(status)) {
+ // No aliases
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ while (ures_hasNext(aliases)) {
+ const UChar* alias = ures_getNextString(aliases, NULL, NULL, &status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ // Create canonical map entry for this alias
+ entry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry));
+ if (entry == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto error_cleanup;
+ }
+ entry->id = (UChar*)uprv_malloc((tzidLen + 1) * sizeof(UChar));
+ if (entry->id == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(entry);
+ goto error_cleanup;
+ }
+ u_charsToUChars(tzid, entry->id, tzidLen + 1);
+
+ if (territory == NULL || u_strcmp(territory, gWorld) == 0) {
+ entry->country = NULL;
+ } else {
+ entry->country = territory;
+ }
+ canonicalMap->put(UnicodeString(alias), entry, status);
+ if (U_FAILURE(status)) {
+ deleteCanonicalMapEntry(entry);
+ goto error_cleanup;
+ }
+ }
+ }
+
+normal_cleanup:
+ ures_close(aliases);
+ ures_close(tzitem);
+ ures_close(zoneFormatting);
+ return canonicalMap;
+
+error_cleanup:
+ delete canonicalMap;
+ canonicalMap = NULL;
+
+ goto normal_cleanup;
+}
+
+/*
+ * Creating Olson tzid to metazone mappings from resource (3.8.1 and beyond)
+ */
+Hashtable*
+ZoneMeta::createOlsonToMetaMap(void) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ Hashtable *olsonToMeta = NULL;
+ UResourceBundle *metazoneMappings = NULL;
+ UResourceBundle *zoneItem = NULL;
+ UResourceBundle *mz = NULL;
+ StringEnumeration *tzids = NULL;
+
+ olsonToMeta = new Hashtable(uhash_compareUnicodeString, NULL, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ olsonToMeta->setValueDeleter(deleteUVector);
+
+ // Read metazone mappings from metazoneInfo bundle
+ metazoneMappings = ures_openDirect(NULL, gMetazoneInfo, &status);
+ metazoneMappings = ures_getByKey(metazoneMappings, gMetazoneMappings, metazoneMappings, &status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+
+ // Walk through all canonical tzids
+ char zidkey[ZID_KEY_MAX];
+
+ tzids = TimeZone::createEnumeration();
+ const UnicodeString *tzid;
+ while ((tzid = tzids->snext(status))) {
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ // We may skip aliases, because the bundle
+ // contains only canonical IDs. For now, try
+ // all of them.
+ tzid->extract(0, tzid->length(), zidkey, sizeof(zidkey), US_INV);
+ zidkey[sizeof(zidkey)-1] = 0; // NULL terminate just in case.
+
+ // Replace '/' with ':'
+ UBool foundSep = FALSE;
+ char *p = zidkey;
+ while (*p) {
+ if (*p == '/') {
+ *p = ':';
+ foundSep = TRUE;
+ }
+ p++;
+ }
+ if (!foundSep) {
+ // A valid time zone key has at least one separator
+ continue;
+ }
+
+ zoneItem = ures_getByKey(metazoneMappings, zidkey, zoneItem, &status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ UVector *mzMappings = NULL;
+ while (ures_hasNext(zoneItem)) {
+ mz = ures_getNextResource(zoneItem, mz, &status);
+ const UChar *mz_name = ures_getStringByIndex(mz, 0, NULL, &status);
+ const UChar *mz_from = ures_getStringByIndex(mz, 1, NULL, &status);
+ const UChar *mz_to = ures_getStringByIndex(mz, 2, NULL, &status);
+
+ if(U_FAILURE(status)){
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ // We do not want to use SimpleDateformat to parse boundary dates,
+ // because this code could be triggered by the initialization code
+ // used by SimpleDateFormat.
+ UDate from = parseDate(mz_from, status);
+ UDate to = parseDate(mz_to, status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ OlsonToMetaMappingEntry *entry = (OlsonToMetaMappingEntry*)uprv_malloc(sizeof(OlsonToMetaMappingEntry));
+ if (entry == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ entry->mzid = mz_name;
+ entry->from = from;
+ entry->to = to;
+
+ if (mzMappings == NULL) {
+ mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
+ if (U_FAILURE(status)) {
+ delete mzMappings;
+ deleteOlsonToMetaMappingEntry(entry);
+ uprv_free(entry);
+ break;
+ }
+ }
+
+ mzMappings->addElement(entry, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ }
+
+ if (U_FAILURE(status)) {
+ if (mzMappings != NULL) {
+ delete mzMappings;
+ }
+ goto error_cleanup;
+ }
+ if (mzMappings != NULL) {
+ olsonToMeta->put(*tzid, mzMappings, status);
+ if (U_FAILURE(status)) {
+ delete mzMappings;
+ goto error_cleanup;
+ }
+ }
+ }
+
+normal_cleanup:
+ if (tzids != NULL) {
+ delete tzids;
+ }
+ ures_close(zoneItem);
+ ures_close(mz);
+ ures_close(metazoneMappings);
+ return olsonToMeta;
+
+error_cleanup:
+ if (olsonToMeta != NULL) {
+ delete olsonToMeta;
+ olsonToMeta = NULL;
+ }
+ goto normal_cleanup;
+}
+
+/*
+ * Creating Olson tzid to metazone mappings from ICU resource (3.8)
+ */
+Hashtable*
+ZoneMeta::createOlsonToMetaMapOld(void) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ Hashtable *olsonToMeta = NULL;
+ UResourceBundle *zoneStringsArray = NULL;
+ UResourceBundle *mz = NULL;
+ UResourceBundle *zoneItem = NULL;
+ UResourceBundle *useMZ = NULL;
+ StringEnumeration *tzids = NULL;
+
+ olsonToMeta = new Hashtable(uhash_compareUnicodeString, NULL, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ olsonToMeta->setValueDeleter(deleteUVector);
+
+ // Read metazone mappings from root bundle
+ zoneStringsArray = ures_openDirect(NULL, "", &status);
+ zoneStringsArray = ures_getByKey(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+
+ // Walk through all canonical tzids
+ char zidkey[ZID_KEY_MAX];
+
+ tzids = TimeZone::createEnumeration();
+ const UnicodeString *tzid;
+ while ((tzid = tzids->snext(status))) {
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ // We may skip aliases, because the bundle
+ // contains only canonical IDs. For now, try
+ // all of them.
+ tzid->extract(0, tzid->length(), zidkey, sizeof(zidkey), US_INV);
+ zidkey[sizeof(zidkey)-1] = 0; // NULL terminate just in case.
+
+ // Replace '/' with ':'
+ UBool foundSep = FALSE;
+ char *p = zidkey;
+ while (*p) {
+ if (*p == '/') {
+ *p = ':';
+ foundSep = TRUE;
+ }
+ p++;
+ }
+ if (!foundSep) {
+ // A valid time zone key has at least one separator
+ continue;
+ }
+
+ zoneItem = ures_getByKey(zoneStringsArray, zidkey, zoneItem, &status);
+ useMZ = ures_getByKey(zoneItem, gUseMetazoneTag, useMZ, &status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ UVector *mzMappings = NULL;
+ while (ures_hasNext(useMZ)) {
+ mz = ures_getNextResource(useMZ, mz, &status);
+ const UChar *mz_name = ures_getStringByIndex(mz, 0, NULL, &status);
+ const UChar *mz_from = ures_getStringByIndex(mz, 1, NULL, &status);
+ const UChar *mz_to = ures_getStringByIndex(mz, 2, NULL, &status);
+
+ if(U_FAILURE(status)){
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ // We do not want to use SimpleDateformat to parse boundary dates,
+ // because this code could be triggered by the initialization code
+ // used by SimpleDateFormat.
+ UDate from = parseDate(mz_from, status);
+ UDate to = parseDate(mz_to, status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ OlsonToMetaMappingEntry *entry = (OlsonToMetaMappingEntry*)uprv_malloc(sizeof(OlsonToMetaMappingEntry));
+ if (entry == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ entry->mzid = mz_name;
+ entry->from = from;
+ entry->to = to;
+
+ if (mzMappings == NULL) {
+ mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
+ if (U_FAILURE(status)) {
+ delete mzMappings;
+ deleteOlsonToMetaMappingEntry(entry);
+ uprv_free(entry);
+ break;
+ }
+ }
+
+ mzMappings->addElement(entry, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ }
+
+ if (U_FAILURE(status)) {
+ if (mzMappings != NULL) {
+ delete mzMappings;
+ }
+ goto error_cleanup;
+ }
+ if (mzMappings != NULL) {
+ olsonToMeta->put(*tzid, mzMappings, status);
+ if (U_FAILURE(status)) {
+ delete mzMappings;
+ goto error_cleanup;
+ }
+ }
+ }
+
+normal_cleanup:
+ if (tzids != NULL) {
+ delete tzids;
+ }
+ ures_close(zoneItem);
+ ures_close(useMZ);
+ ures_close(mz);
+ ures_close(zoneStringsArray);
+ return olsonToMeta;
+
+error_cleanup:
+ if (olsonToMeta != NULL) {
+ delete olsonToMeta;
+ }
+ goto normal_cleanup;
+}
+
+Hashtable*
+ZoneMeta::createMetaToOlsonMap(void) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ Hashtable *metaToOlson = NULL;
+ UResourceBundle *metazones = NULL;
+ UResourceBundle *mz = NULL;
+
+ metaToOlson = new Hashtable(uhash_compareUnicodeString, NULL, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ metaToOlson->setValueDeleter(deleteUVector);
+
+ metazones = ures_openDirect(NULL, gSupplementalData, &status);
+ metazones = ures_getByKey(metazones, gMapTimezonesTag, metazones, &status);
+ metazones = ures_getByKey(metazones, gMetazonesTag, metazones, &status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+
+ while (ures_hasNext(metazones)) {
+ mz = ures_getNextResource(metazones, mz, &status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ const char *mzkey = ures_getKey(mz);
+ if (uprv_strncmp(mzkey, gMetazoneIdPrefix, MZID_PREFIX_LEN) == 0) {
+ const char *mzid = mzkey + MZID_PREFIX_LEN;
+ const char *territory = uprv_strrchr(mzid, '_');
+ int32_t mzidLen = 0;
+ int32_t territoryLen = 0;
+ if (territory) {
+ mzidLen = territory - mzid;
+ territory++;
+ territoryLen = uprv_strlen(territory);
+ }
+ if (mzidLen > 0 && territoryLen > 0) {
+ int32_t tzidLen;
+ const UChar *tzid = ures_getStringByIndex(mz, 0, &tzidLen, &status);
+ if (U_SUCCESS(status)) {
+ // Create MetaToOlsonMappingEntry
+ MetaToOlsonMappingEntry *entry = (MetaToOlsonMappingEntry*)uprv_malloc(sizeof(MetaToOlsonMappingEntry));
+ if (entry == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto error_cleanup;
+ }
+ entry->id = tzid;
+ entry->territory = (UChar*)uprv_malloc((territoryLen + 1) * sizeof(UChar));
+ if (entry->territory == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ uprv_free(entry);
+ goto error_cleanup;
+ }
+ u_charsToUChars(territory, entry->territory, territoryLen + 1);
+
+ // Check if mapping entries for metazone is already available
+ UnicodeString mzidStr(mzid, mzidLen, US_INV);
+ UVector *tzMappings = (UVector*)metaToOlson->get(mzidStr);
+ if (tzMappings == NULL) {
+ // Create new UVector and put it into the hashtable
+ tzMappings = new UVector(deleteMetaToOlsonMappingEntry, NULL, status);
+ metaToOlson->put(mzidStr, tzMappings, status);
+ if (U_FAILURE(status)) {
+ if (tzMappings != NULL) {
+ delete tzMappings;
+ }
+ deleteMetaToOlsonMappingEntry(entry);
+ goto error_cleanup;
+ }
+ }
+ tzMappings->addElement(entry, status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ } else {
+ status = U_ZERO_ERROR;
+ }
+ }
+ }
+ }
+
+normal_cleanup:
+ ures_close(mz);
+ ures_close(metazones);
+ return metaToOlson;
+
+error_cleanup:
+ if (metaToOlson != NULL) {
+ delete metaToOlson;
+ }
+ goto normal_cleanup;
+}
+
+UnicodeString&
+ZoneMeta::getCanonicalID(const UnicodeString &tzid, UnicodeString &canonicalID) {
+ const CanonicalMapEntry *entry = getCanonicalInfo(tzid);
+ if (entry != NULL) {
+ canonicalID.setTo(entry->id);
+ } else {
+ // Use the input tzid
+ canonicalID.setTo(tzid);
+ }
+ return canonicalID;
+}
+
+UnicodeString&
+ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry) {
+ const CanonicalMapEntry *entry = getCanonicalInfo(tzid);
+ if (entry != NULL && entry->country != NULL) {
+ canonicalCountry.setTo(entry->country);
+ } else {
+ // Use the input tzid
+ canonicalCountry.remove();
+ }
+ return canonicalCountry;
+}
+
+const CanonicalMapEntry*
+ZoneMeta::getCanonicalInfo(const UnicodeString &tzid) {
+ initialize();
+ CanonicalMapEntry *entry = NULL;
+ UnicodeString canonicalOlsonId;
+ TimeZone::getOlsonCanonicalID(tzid, canonicalOlsonId);
+ if (!canonicalOlsonId.isEmpty()) {
+ if (gCanonicalMap != NULL) {
+ entry = (CanonicalMapEntry*)gCanonicalMap->get(tzid);
+ }
+ }
+ return entry;
+}
+
+UnicodeString&
+ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Get canonical country for the zone
+ getCanonicalCountry(tzid, country);
+
+ if (!country.isEmpty()) {
+ UResourceBundle *supplementalDataBundle = ures_openDirect(NULL, gSupplementalData, &status);
+ UResourceBundle *zoneFormatting = ures_getByKey(supplementalDataBundle, gZoneFormattingTag, NULL, &status);
+ UResourceBundle *multizone = ures_getByKey(zoneFormatting, gMultizoneTag, NULL, &status);
+
+ if (U_SUCCESS(status)) {
+ while (ures_hasNext(multizone)) {
+ int32_t len;
+ const UChar* multizoneCountry = ures_getNextString(multizone, &len, NULL, &status);
+ if (country.compare(multizoneCountry, len) == 0) {
+ // Included in the multizone country list
+ country.remove();
+ break;
+ }
+ }
+ }
+
+ ures_close(multizone);
+ ures_close(zoneFormatting);
+ ures_close(supplementalDataBundle);
+ }
+
+ return country;
+}
+
+UnicodeString&
+ZoneMeta::getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &result) {
+ UBool isSet = FALSE;
+ const UVector *mappings = getMetazoneMappings(tzid);
+ if (mappings != NULL) {
+ for (int32_t i = 0; i < mappings->size(); i++) {
+ OlsonToMetaMappingEntry *mzm = (OlsonToMetaMappingEntry*)mappings->elementAt(i);
+ if (mzm->from <= date && mzm->to > date) {
+ result.setTo(mzm->mzid, -1);
+ isSet = TRUE;
+ break;
+ }
+ }
+ }
+ if (!isSet) {
+ result.remove();
+ }
+ return result;
+}
+
+const UVector*
+ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) {
+ initialize();
+ const UVector *result = NULL;
+ if (gOlsonToMeta != NULL) {
+ result = (UVector*)gOlsonToMeta->get(tzid);
+ }
+ return result;
+}
+
+UnicodeString&
+ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &region, UnicodeString &result) {
+ initialize();
+ UBool isSet = FALSE;
+ if (gMetaToOlson != NULL) {
+ UVector *mappings = (UVector*)gMetaToOlson->get(mzid);
+ if (mappings != NULL) {
+ // Find a preferred time zone for the given region.
+ for (int32_t i = 0; i < mappings->size(); i++) {
+ MetaToOlsonMappingEntry *olsonmap = (MetaToOlsonMappingEntry*)mappings->elementAt(i);
+ if (region.compare(olsonmap->territory, -1) == 0) {
+ result.setTo(olsonmap->id);
+ isSet = TRUE;
+ break;
+ } else if (u_strcmp(olsonmap->territory, gWorld) == 0) {
+ result.setTo(olsonmap->id);
+ isSet = TRUE;
+ }
+ }
+ }
+ }
+ if (!isSet) {
+ result.remove();
+ }
+ return result;
+}
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/zonemeta.h b/Build/source/libs/icu/icu-xetex/i18n/zonemeta.h
new file mode 100644
index 00000000000..d7cb1a48bb0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/zonemeta.h
@@ -0,0 +1,84 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef ZONEMETA_H
+#define ZONEMETA_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "hash.h"
+
+U_NAMESPACE_BEGIN
+
+typedef struct CanonicalMapEntry {
+ UChar *id;
+ const UChar *country; // const because it's a reference to a resource bundle string.
+} CanonicalMapEntry;
+
+typedef struct OlsonToMetaMappingEntry {
+ const UChar *mzid; // const because it's a reference to a resource bundle string.
+ UDate from;
+ UDate to;
+} OlsonToMetaMappingEntry;
+
+typedef struct MetaToOlsonMappingEntry {
+ const UChar *id; // const because it's a reference to a resource bundle string.
+ UChar *territory;
+} MetaToOlsonMappingEntry;
+
+class UVector;
+
+class U_I18N_API ZoneMeta {
+public:
+ /**
+ * Return the canonical id for this tzid, which might be the id itself.
+ * If there is no canonical id for it, return the passed-in id.
+ */
+ static UnicodeString& getCanonicalID(const UnicodeString &tzid, UnicodeString &canonicalID);
+
+ /**
+ * Return the canonical country code for this tzid. If we have none, or if the time zone
+ * is not associated with a country, return null.
+ */
+ static UnicodeString& getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry);
+
+ /**
+ * Return the country code if this is a 'single' time zone that can fallback to just
+ * the country, otherwise return empty string. (Note, one must also check the locale data
+ * to see that there is a localization for the country in order to implement
+ * tr#35 appendix J step 5.)
+ */
+ static UnicodeString& getSingleCountry(const UnicodeString &tzid, UnicodeString &country);
+
+ /**
+ * Returns a CLDR metazone ID for the given Olson tzid and time.
+ */
+ static UnicodeString& getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &result);
+ /**
+ * Returns an Olson ID for the ginve metazone and region
+ */
+ static UnicodeString& getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &region, UnicodeString &result);
+
+ static const UVector* getMetazoneMappings(const UnicodeString &tzid);
+
+private:
+ static void initialize(void);
+
+ static const CanonicalMapEntry* getCanonicalInfo(const UnicodeString &tzid);
+
+ static Hashtable* createCanonicalMap(void);
+ static Hashtable* createOlsonToMetaMapOld(void);
+ static Hashtable* createOlsonToMetaMap(void);
+ static Hashtable* createMetaToOlsonMap(void);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+#endif // ZONEMETA_H
diff --git a/Build/source/libs/icu/icu-xetex/i18n/zstrfmt.cpp b/Build/source/libs/icu/icu-xetex/i18n/zstrfmt.cpp
new file mode 100644
index 00000000000..b42bbfb25a5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/zstrfmt.cpp
@@ -0,0 +1,1604 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "zstrfmt.h"
+
+#include "unicode/ustring.h"
+#include "unicode/putil.h"
+#include "unicode/msgfmt.h"
+#include "unicode/basictz.h"
+#include "unicode/simpletz.h"
+#include "unicode/rbtz.h"
+#include "unicode/vtzone.h"
+
+#include "uvector.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include "uresimp.h"
+#include "zonemeta.h"
+#include "olsontz.h"
+#include "umutex.h"
+#include "ucln_in.h"
+
+/**
+ * global ZoneStringFormatCache stuffs
+ */
+static UMTX gZSFCacheLock = NULL;
+static U_NAMESPACE_QUALIFIER ZSFCache *gZoneStringFormatCache = NULL;
+
+U_CDECL_BEGIN
+/**
+ * ZoneStringFormatCache cleanup callback func
+ */
+static UBool U_CALLCONV zoneStringFormat_cleanup(void)
+{
+ umtx_destroy(&gZSFCacheLock);
+ if (gZoneStringFormatCache != NULL) {
+ delete gZoneStringFormatCache;
+ gZoneStringFormatCache = NULL;
+ }
+ gZoneStringFormatCache = NULL;
+ return TRUE;
+}
+
+/**
+ * Deleter for ZoneStringInfo
+ */
+static void U_CALLCONV
+deleteZoneStringInfo(void *obj) {
+ delete (U_NAMESPACE_QUALIFIER ZoneStringInfo*)obj;
+}
+
+/**
+ * Deleter for ZoneStrings
+ */
+static void U_CALLCONV
+deleteZoneStrings(void *obj) {
+ delete (U_NAMESPACE_QUALIFIER ZoneStrings*)obj;
+}
+U_CDECL_END
+
+U_NAMESPACE_BEGIN
+
+#define ZID_KEY_MAX 128
+
+static const char gCountriesTag[] = "Countries";
+static const char gZoneStringsTag[] = "zoneStrings";
+static const char gShortGenericTag[] = "sg";
+static const char gShortStandardTag[] = "ss";
+static const char gShortDaylightTag[] = "sd";
+static const char gLongGenericTag[] = "lg";
+static const char gLongStandardTag[] = "ls";
+static const char gLongDaylightTag[] = "ld";
+static const char gExemplarCityTag[] = "ec";
+static const char gCommonlyUsedTag[] = "cu";
+static const char gFallbackFormatTag[] = "fallbackFormat";
+static const char gRegionFormatTag[] = "regionFormat";
+
+#define MZID_PREFIX_LEN 5
+static const char gMetazoneIdPrefix[] = "meta:";
+
+#define MAX_METAZONES_PER_ZONE 10
+
+static const UChar gDefFallbackPattern[] = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
+static const UChar gDefRegionPattern[] = {0x7B, 0x30, 0x7D, 0x00}; // "{0}"
+static const UChar gCommonlyUsedTrue[] = {0x31, 0x00}; // "1"
+
+static const double kDstCheckRange = (double)184*U_MILLIS_PER_DAY;
+
+static int32_t
+getTimeZoneTranslationTypeIndex(TimeZoneTranslationType type) {
+ int32_t typeIdx = 0;
+ switch (type) {
+ case LOCATION:
+ typeIdx = ZSIDX_LOCATION;
+ break;
+ case GENERIC_LONG:
+ typeIdx = ZSIDX_LONG_GENERIC;
+ break;
+ case GENERIC_SHORT:
+ typeIdx = ZSIDX_SHORT_GENERIC;
+ break;
+ case STANDARD_LONG:
+ typeIdx = ZSIDX_LONG_STANDARD;
+ break;
+ case STANDARD_SHORT:
+ typeIdx = ZSIDX_SHORT_STANDARD;
+ break;
+ case DAYLIGHT_LONG:
+ typeIdx = ZSIDX_LONG_DAYLIGHT;
+ break;
+ case DAYLIGHT_SHORT:
+ typeIdx = ZSIDX_SHORT_DAYLIGHT;
+ break;
+ }
+ return typeIdx;
+}
+
+static int32_t
+getTimeZoneTranslationType(TimeZoneTranslationTypeIndex typeIdx) {
+ int32_t type = 0;
+ switch (typeIdx) {
+ case ZSIDX_LOCATION:
+ type = LOCATION;
+ break;
+ case ZSIDX_LONG_GENERIC:
+ type = GENERIC_LONG;
+ break;
+ case ZSIDX_SHORT_GENERIC:
+ type = GENERIC_SHORT;
+ break;
+ case ZSIDX_LONG_STANDARD:
+ type = STANDARD_LONG;
+ break;
+ case ZSIDX_SHORT_STANDARD:
+ type = STANDARD_SHORT;
+ break;
+ case ZSIDX_LONG_DAYLIGHT:
+ type = DAYLIGHT_LONG;
+ break;
+ case ZSIDX_SHORT_DAYLIGHT:
+ type = DAYLIGHT_SHORT;
+ break;
+ }
+ return type;
+}
+
+#define DEFAULT_CHARACTERNODE_CAPACITY 1
+
+// ----------------------------------------------------------------------------
+CharacterNode::CharacterNode(UChar32 c, UObjectDeleter *valueDeleterFunc, UErrorCode &status)
+: UMemory(),
+ fChildren(valueDeleterFunc, NULL, DEFAULT_CHARACTERNODE_CAPACITY, status),
+ fValues(valueDeleterFunc, NULL, DEFAULT_CHARACTERNODE_CAPACITY, status),
+ fValueDeleter(valueDeleterFunc),
+ fCharacter(c)
+{
+}
+
+CharacterNode::~CharacterNode() {
+ while (!fChildren.isEmpty()) {
+ CharacterNode *node = (CharacterNode*)fChildren.orphanElementAt(0);
+ delete node;
+ }
+}
+
+void
+CharacterNode::addValue(void *value, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fValues.addElement(value, status);
+}
+
+CharacterNode*
+CharacterNode::addChildNode(UChar32 c, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ CharacterNode *result = NULL;
+ for (int32_t i = 0; i < fChildren.size(); i++) {
+ CharacterNode *node = (CharacterNode*)fChildren.elementAt(i);
+ if (node->getCharacter() == c) {
+ result = node;
+ break;
+ }
+ }
+ if (result == NULL) {
+ result = new CharacterNode(c, fValueDeleter, status);
+ fChildren.addElement(result, status);
+ }
+
+ return result;
+}
+
+CharacterNode*
+CharacterNode::getChildNode(UChar32 c) const {
+ CharacterNode *result = NULL;
+ for (int32_t i = 0; i < fChildren.size(); i++) {
+ CharacterNode *node = (CharacterNode*)fChildren.elementAt(i);
+ if (node->getCharacter() == c) {
+ result = node;
+ break;
+ }
+ }
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+TextTrieMap::TextTrieMap(UBool ignoreCase, UObjectDeleter *valueDeleterFunc)
+: UMemory(), fIgnoreCase(ignoreCase), fValueDeleter(valueDeleterFunc), fRoot(NULL) {
+}
+
+TextTrieMap::~TextTrieMap() {
+ if (fRoot != NULL) {
+ delete fRoot;
+ }
+}
+
+void
+TextTrieMap::put(const UnicodeString &key, void *value, UErrorCode &status) {
+ if (fRoot == NULL) {
+ fRoot = new CharacterNode(0, fValueDeleter, status);
+ }
+
+ UnicodeString keyString(key);
+ if (fIgnoreCase) {
+ keyString.foldCase();
+ }
+
+ CharacterNode *node = fRoot;
+ int32_t index = 0;
+ while (index < keyString.length()) {
+ UChar32 c = keyString.char32At(index);
+ node = node->addChildNode(c, status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ index = keyString.moveIndex32(index, 1);
+ }
+ node->addValue(value, status);
+}
+
+void
+TextTrieMap::search(const UnicodeString &text, int32_t start,
+ TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
+ if (fRoot == NULL) {
+ return;
+ }
+ search(fRoot, text, start, start, handler, status);
+}
+
+void
+TextTrieMap::search(CharacterNode *node, const UnicodeString &text, int32_t start,
+ int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ const UVector *values = node->getValues();
+ if (values != NULL) {
+ if (!handler->handleMatch(index - start, values, status)) {
+ return;
+ }
+ if (U_FAILURE(status)) {
+ return;
+ }
+ }
+ UChar32 c = text.char32At(index);
+ if (fIgnoreCase) {
+ // size of character may grow after fold operation
+ UnicodeString tmp(c);
+ tmp.foldCase();
+ int32_t tmpidx = 0;
+ while (tmpidx < tmp.length()) {
+ c = tmp.char32At(tmpidx);
+ node = node->getChildNode(c);
+ if (node == NULL) {
+ break;
+ }
+ tmpidx = tmp.moveIndex32(tmpidx, 1);
+ }
+ } else {
+ node = node->getChildNode(c);
+ }
+ if (node != NULL) {
+ search(node, text, start, index+1, handler, status);
+ }
+}
+
+// ----------------------------------------------------------------------------
+ZoneStringInfo::ZoneStringInfo(const UnicodeString &id, const UnicodeString &str,
+ TimeZoneTranslationType type)
+: UMemory(), fId(id), fStr(str), fType(type) {
+}
+
+ZoneStringInfo::~ZoneStringInfo() {
+}
+// ----------------------------------------------------------------------------
+ZoneStringSearchResultHandler::ZoneStringSearchResultHandler(UErrorCode &status)
+: UMemory(), fResults(status)
+{
+ clear();
+}
+
+ZoneStringSearchResultHandler::~ZoneStringSearchResultHandler() {
+ clear();
+}
+
+UBool
+ZoneStringSearchResultHandler::handleMatch(int32_t matchLength, const UVector *values, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (values != NULL) {
+ for (int32_t i = 0; values->size(); i++) {
+ ZoneStringInfo *zsinfo = (ZoneStringInfo*)values->elementAt(i);
+ if (zsinfo == NULL) {
+ break;
+ }
+ // Update the results
+ UBool foundType = FALSE;
+ for (int32_t j = 0; j < fResults.size(); j++) {
+ ZoneStringInfo *tmp = (ZoneStringInfo*)fResults.elementAt(j);
+ if (zsinfo->fType == tmp->fType) {
+ int32_t lenidx = getTimeZoneTranslationTypeIndex(tmp->fType);
+ if (matchLength > fMatchLen[lenidx]) {
+ // Same type, longer match
+ fResults.setElementAt(zsinfo, j);
+ fMatchLen[lenidx] = matchLength;
+ }
+ foundType = TRUE;
+ break;
+ }
+ }
+ if (!foundType) {
+ // not found in the current list
+ fResults.addElement(zsinfo, status);
+ fMatchLen[getTimeZoneTranslationTypeIndex(zsinfo->fType)] = matchLength;
+ }
+ }
+ }
+ return TRUE;
+}
+
+int32_t
+ZoneStringSearchResultHandler::countMatches(void) {
+ return fResults.size();
+}
+
+const ZoneStringInfo*
+ZoneStringSearchResultHandler::getMatch(int32_t index, int32_t &matchLength) {
+ ZoneStringInfo *zsinfo = NULL;
+ if (index < fResults.size()) {
+ zsinfo = (ZoneStringInfo*)fResults.elementAt(index);
+ matchLength = fMatchLen[getTimeZoneTranslationTypeIndex(zsinfo->fType)];
+ }
+ return zsinfo;
+}
+
+void
+ZoneStringSearchResultHandler::clear(void) {
+ fResults.removeAllElements();
+ for (int32_t i = 0; i < (int32_t)(sizeof(fMatchLen)/sizeof(fMatchLen[0])); i++) {
+ fMatchLen[i] = 0;
+ }
+}
+// ----------------------------------------------------------------------------
+ZoneStringFormat::ZoneStringFormat(const UnicodeString* const* strings,
+ int32_t rowCount, int32_t columnCount, UErrorCode &status)
+: UMemory(),
+ fLocale(""),
+ fTzidToStrings(uhash_compareUnicodeString, NULL, status),
+ fMzidToStrings(uhash_compareUnicodeString, NULL, status),
+ fZoneStringsTrie(TRUE, deleteZoneStringInfo)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fLocale.setToBogus();
+ if (strings == NULL || columnCount <= 0 || rowCount <= 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ fTzidToStrings.setValueDeleter(deleteZoneStrings);
+
+ for (int32_t row = 0; row < rowCount; row++) {
+ if (strings[row][0].isEmpty()) {
+ continue;
+ }
+ UnicodeString *names = new UnicodeString[ZSIDX_COUNT];
+ for (int32_t col = 1; col < columnCount; col++) {
+ if (!strings[row][col].isEmpty()) {
+ int32_t typeIdx = -1;
+ switch (col) {
+ case 1:
+ typeIdx = ZSIDX_LONG_STANDARD;
+ break;
+ case 2:
+ typeIdx = ZSIDX_SHORT_STANDARD;
+ break;
+ case 3:
+ typeIdx = ZSIDX_LONG_DAYLIGHT;
+ break;
+ case 4:
+ typeIdx = ZSIDX_SHORT_DAYLIGHT;
+ break;
+ case 5:
+ typeIdx = ZSIDX_LOCATION;
+ break;
+ case 6:
+ typeIdx = ZSIDX_LONG_GENERIC;
+ break;
+ case 7:
+ typeIdx = ZSIDX_SHORT_GENERIC;
+ break;
+ }
+ if (typeIdx != -1) {
+ names[typeIdx].setTo(strings[row][col]);
+
+ // Put the name into the trie
+ int32_t type = getTimeZoneTranslationType((TimeZoneTranslationTypeIndex)typeIdx);
+ ZoneStringInfo *zsinf = new ZoneStringInfo(strings[row][0], strings[row][col], (TimeZoneTranslationType)type);
+ fZoneStringsTrie.put(strings[row][col], zsinf, status);
+ if (U_FAILURE(status)) {
+ delete zsinf;
+ goto error_cleanup;
+ }
+ }
+ }
+ }
+ ZoneStrings *zstrings = new ZoneStrings(names, ZSIDX_COUNT, TRUE, NULL, 0, 0);
+ fTzidToStrings.put(strings[row][0], zstrings, status);
+ if (U_FAILURE(status)) {
+ delete zstrings;
+ goto error_cleanup;
+ }
+ }
+ return;
+
+error_cleanup:
+ return;
+}
+
+ZoneStringFormat::ZoneStringFormat(const Locale &locale, UErrorCode &status)
+: UMemory(),
+ fLocale(locale),
+ fTzidToStrings(uhash_compareUnicodeString, NULL, status),
+ fMzidToStrings(uhash_compareUnicodeString, NULL, status),
+ fZoneStringsTrie(TRUE, deleteZoneStringInfo)
+{
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fTzidToStrings.setValueDeleter(deleteZoneStrings);
+ fMzidToStrings.setValueDeleter(deleteZoneStrings);
+
+ UResourceBundle *zoneStringsArray = ures_open(NULL, locale.getName(), &status);
+ zoneStringsArray = ures_getByKeyWithFallback(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status);
+ if (U_FAILURE(status)) {
+ // If no locale bundles are available, zoneStrings will be null.
+ // We still want to go through the rest of zone strings initialization,
+ // because generic location format is generated from tzid for the case.
+ // The rest of code should work even zoneStrings is null.
+ status = U_ZERO_ERROR;
+ ures_close(zoneStringsArray);
+ zoneStringsArray = NULL;
+ }
+
+ StringEnumeration *tzids = NULL;
+ MessageFormat *fallbackFmt = NULL;
+ MessageFormat *regionFmt = NULL;
+
+ UResourceBundle *zoneItem = NULL;
+ UResourceBundle *metazoneItem = NULL;
+
+ char zidkey[ZID_KEY_MAX];
+ const UChar *zstrarray[ZSIDX_COUNT];
+ const UChar *mzstrarray[ZSIDX_COUNT];
+ UnicodeString mzPartialLoc[MAX_METAZONES_PER_ZONE][4];
+
+ UnicodeString region;
+ getRegion(region);
+
+ fallbackFmt = getFallbackFormat(locale, status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ regionFmt = getRegionFormat(locale, status);
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+
+ tzids = TimeZone::createEnumeration();
+ const char *tzid;
+ while ((tzid = tzids->next(NULL, status))) {
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ // Skip non-canonical IDs
+ UnicodeString utzid(tzid, -1, US_INV);
+ UnicodeString canonicalID;
+ ZoneMeta::getCanonicalID(utzid, canonicalID);
+ if (utzid != canonicalID) {
+ continue;
+ }
+
+ uprv_strcpy(zidkey, tzid);
+
+ // Replace '/' with ':'
+ char *pCity = NULL;
+ char *p = zidkey;
+ while (*p) {
+ if (*p == '/') {
+ *p = ':';
+ pCity = p + 1;
+ }
+ p++;
+ }
+
+ if (zoneStringsArray != NULL) {
+ zoneItem = ures_getByKeyWithFallback(zoneStringsArray, zidkey, zoneItem, &status);
+ if (U_FAILURE(status)) {
+ // If failed to open the zone item, create only location string
+ ures_close(zoneItem);
+ zoneItem = NULL;
+ status = U_ZERO_ERROR;
+ }
+ }
+ zstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(zoneItem, gLongStandardTag);
+ zstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(zoneItem, gShortStandardTag);
+ zstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(zoneItem, gLongDaylightTag);
+ zstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(zoneItem, gShortDaylightTag);
+ zstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(zoneItem, gLongGenericTag);
+ zstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(zoneItem, gShortGenericTag);
+
+ // Compose location format string
+ UnicodeString location;
+ UnicodeString country;
+ UnicodeString city;
+ UnicodeString countryCode;
+ ZoneMeta::getCanonicalCountry(utzid, countryCode);
+ if (countryCode.isEmpty()) {
+ zstrarray[ZSIDX_LOCATION] = NULL;
+ } else {
+ const UChar* tmpCity = getZoneStringFromBundle(zoneItem, gExemplarCityTag);
+ if (tmpCity != NULL) {
+ city.setTo(TRUE, tmpCity, -1);
+ } else {
+ city.setTo(UnicodeString(pCity, -1, US_INV));
+ // Replace '_' with ' '
+ for (int32_t i = 0; i < city.length(); i++) {
+ if (city.charAt(i) == (UChar)0x5F /*'_'*/) {
+ city.setCharAt(i, (UChar)0x20 /*' '*/);
+ }
+ }
+ }
+ getLocalizedCountry(countryCode, locale, country);
+ UnicodeString singleCountry;
+ ZoneMeta::getSingleCountry(utzid, singleCountry);
+ FieldPosition fpos;
+ if (singleCountry.isEmpty()) {
+ Formattable params [] = {
+ Formattable(city),
+ Formattable(country)
+ };
+ fallbackFmt->format(params, 2, location, fpos, status);
+ } else {
+ // If the zone is only one zone in the country, do not add city
+ Formattable params [] = {
+ Formattable(country)
+ };
+ regionFmt->format(params, 1, location, fpos, status);
+ }
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+
+ // Workaround for reducing UMR warning in Purify.
+ // Append NULL before calling getTerminatedBuffer()
+ int32_t locLen = location.length();
+ location.append((UChar)0).truncate(locLen);
+
+ zstrarray[ZSIDX_LOCATION] = location.getTerminatedBuffer();
+ }
+
+ UBool commonlyUsed = isCommonlyUsed(zoneItem);
+
+ // Resolve metazones used by this zone
+ int32_t mzPartialLocIdx = 0;
+ const UVector *metazoneMappings = ZoneMeta::getMetazoneMappings(utzid);
+ if (metazoneMappings != NULL) {
+ for (int32_t i = 0; i < metazoneMappings->size(); i++) {
+ const OlsonToMetaMappingEntry *mzmap = (const OlsonToMetaMappingEntry*)metazoneMappings->elementAt(i);
+ UnicodeString mzid(mzmap->mzid);
+ const ZoneStrings *mzStrings = (const ZoneStrings*)fMzidToStrings.get(mzid);
+ if (mzStrings == NULL) {
+ // If the metazone strings are not yet processed, do it now.
+ char mzidkey[ZID_KEY_MAX];
+ uprv_strcpy(mzidkey, gMetazoneIdPrefix);
+ u_UCharsToChars(mzmap->mzid, mzidkey + MZID_PREFIX_LEN, u_strlen(mzmap->mzid) + 1);
+ metazoneItem = ures_getByKeyWithFallback(zoneStringsArray, mzidkey, metazoneItem, &status);
+ if (U_FAILURE(status)) {
+ // No resources available for this metazone
+ // Resource bundle will be cleaned up after end of the loop.
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ UBool mzCommonlyUsed = isCommonlyUsed(metazoneItem);
+ mzstrarray[ZSIDX_LONG_STANDARD] = getZoneStringFromBundle(metazoneItem, gLongStandardTag);
+ mzstrarray[ZSIDX_SHORT_STANDARD] = getZoneStringFromBundle(metazoneItem, gShortStandardTag);
+ mzstrarray[ZSIDX_LONG_DAYLIGHT] = getZoneStringFromBundle(metazoneItem, gLongDaylightTag);
+ mzstrarray[ZSIDX_SHORT_DAYLIGHT] = getZoneStringFromBundle(metazoneItem, gShortDaylightTag);
+ mzstrarray[ZSIDX_LONG_GENERIC] = getZoneStringFromBundle(metazoneItem, gLongGenericTag);
+ mzstrarray[ZSIDX_SHORT_GENERIC] = getZoneStringFromBundle(metazoneItem, gShortGenericTag);
+ mzstrarray[ZSIDX_LOCATION] = NULL;
+
+ int32_t lastNonNullIdx = ZSIDX_COUNT - 1;
+ while (lastNonNullIdx >= 0) {
+ if (mzstrarray[lastNonNullIdx] != NULL) {
+ break;
+ }
+ lastNonNullIdx--;
+ }
+ UnicodeString *strings_mz = NULL;
+ ZoneStrings *tmp_mzStrings = NULL;
+ if (lastNonNullIdx >= 0) {
+ // Create UnicodeString array and put strings to the zone string trie
+ strings_mz = new UnicodeString[lastNonNullIdx + 1];
+
+ UnicodeString preferredIdForLocale;
+ ZoneMeta::getZoneIdByMetazone(mzid, region, preferredIdForLocale);
+
+ for (int32_t typeidx = 0; typeidx <= lastNonNullIdx; typeidx++) {
+ if (mzstrarray[typeidx] != NULL) {
+ strings_mz[typeidx].setTo(TRUE, mzstrarray[typeidx], -1);
+
+ // Add a metazone string to the zone string trie
+ int32_t type = getTimeZoneTranslationType((TimeZoneTranslationTypeIndex)typeidx);
+ ZoneStringInfo *zsinfo = new ZoneStringInfo(preferredIdForLocale, strings_mz[typeidx], (TimeZoneTranslationType)type);
+ fZoneStringsTrie.put(strings_mz[typeidx], zsinfo, status);
+ if (U_FAILURE(status)) {
+ delete zsinfo;
+ delete strings_mz;
+ goto error_cleanup;
+ }
+ }
+ }
+ tmp_mzStrings = new ZoneStrings(strings_mz, lastNonNullIdx + 1, mzCommonlyUsed, NULL, 0, 0);
+ } else {
+ // Create ZoneStrings with empty contents
+ tmp_mzStrings = new ZoneStrings(NULL, 0, FALSE, NULL, 0, 0);
+ }
+
+ fMzidToStrings.put(mzid, tmp_mzStrings, status);
+ if (U_FAILURE(status)) {
+ delete tmp_mzStrings;
+ goto error_cleanup;
+ }
+
+ mzStrings = tmp_mzStrings;
+ }
+
+ // Compose generic partial location format
+ UnicodeString lg;
+ UnicodeString sg;
+
+ mzStrings->getString(ZSIDX_LONG_GENERIC, lg);
+ mzStrings->getString(ZSIDX_SHORT_GENERIC, sg);
+
+ if (!lg.isEmpty() || !sg.isEmpty()) {
+ UBool addMzPartialLocationNames = TRUE;
+ for (int32_t j = 0; j < mzPartialLocIdx; j++) {
+ if (mzPartialLoc[j][0] == mzid) {
+ // already processed
+ addMzPartialLocationNames = FALSE;
+ break;
+ }
+ }
+ if (addMzPartialLocationNames) {
+ UnicodeString *locationPart = NULL;
+ // Check if the zone is the preferred zone for the territory associated with the zone
+ UnicodeString preferredID;
+ ZoneMeta::getZoneIdByMetazone(mzid, countryCode, preferredID);
+ if (utzid == preferredID) {
+ // Use country for the location
+ locationPart = &country;
+ } else {
+ // Use city for the location
+ locationPart = &city;
+ }
+ // Reset the partial location string array
+ mzPartialLoc[mzPartialLocIdx][0].setTo(mzid);
+ mzPartialLoc[mzPartialLocIdx][1].remove();
+ mzPartialLoc[mzPartialLocIdx][2].remove();
+ mzPartialLoc[mzPartialLocIdx][3].remove();
+
+ if (locationPart != NULL) {
+ FieldPosition fpos;
+ if (!lg.isEmpty()) {
+ Formattable params [] = {
+ Formattable(*locationPart),
+ Formattable(lg)
+ };
+ fallbackFmt->format(params, 2, mzPartialLoc[mzPartialLocIdx][1], fpos, status);
+ }
+ if (!sg.isEmpty()) {
+ Formattable params [] = {
+ Formattable(*locationPart),
+ Formattable(sg)
+ };
+ fallbackFmt->format(params, 2, mzPartialLoc[mzPartialLocIdx][2], fpos, status);
+ if (mzStrings->isShortFormatCommonlyUsed()) {
+ mzPartialLoc[mzPartialLocIdx][3].setTo(TRUE, gCommonlyUsedTrue, -1);
+ }
+ }
+ if (U_FAILURE(status)) {
+ goto error_cleanup;
+ }
+ }
+ mzPartialLocIdx++;
+ }
+ }
+ }
+ }
+ // Collected names for a zone
+
+ // Create UnicodeString array for localized zone strings
+ int32_t lastIdx = ZSIDX_COUNT - 1;
+ while (lastIdx >= 0) {
+ if (zstrarray[lastIdx] != NULL) {
+ break;
+ }
+ lastIdx--;
+ }
+ UnicodeString *strings = NULL;
+ int32_t stringsCount = lastIdx + 1;
+
+ if (stringsCount > 0) {
+ strings = new UnicodeString[stringsCount];
+ for (int32_t i = 0; i < stringsCount; i++) {
+ if (zstrarray[i] != NULL) {
+ strings[i].setTo(zstrarray[i], -1);
+
+ // Add names to the trie
+ int32_t type = getTimeZoneTranslationType((TimeZoneTranslationTypeIndex)i);
+ ZoneStringInfo *zsinfo = new ZoneStringInfo(utzid, strings[i], (TimeZoneTranslationType)type);
+ fZoneStringsTrie.put(strings[i], zsinfo, status);
+ if (U_FAILURE(status)) {
+ delete zsinfo;
+ delete[] strings;
+ goto error_cleanup;
+ }
+ }
+ }
+ }
+
+ // Create UnicodeString array for generic partial location strings
+ UnicodeString **genericPartialLocationNames = NULL;
+ int32_t genericPartialRowCount = mzPartialLocIdx;
+ int32_t genericPartialColCount = 4;
+
+ if (genericPartialRowCount != 0) {
+ genericPartialLocationNames = (UnicodeString**)uprv_malloc(genericPartialRowCount * sizeof(UnicodeString*));
+ if (genericPartialLocationNames == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete[] strings;
+ goto error_cleanup;
+ }
+ for (int32_t i = 0; i < genericPartialRowCount; i++) {
+ genericPartialLocationNames[i] = new UnicodeString[genericPartialColCount];
+ for (int32_t j = 0; j < genericPartialColCount; j++) {
+ genericPartialLocationNames[i][j].setTo(mzPartialLoc[i][j]);
+ // Add names to the trie
+ if ((j == 1 || j == 2) &&!genericPartialLocationNames[i][j].isEmpty()) {
+ ZoneStringInfo *zsinfo;
+ TimeZoneTranslationType type = (j == 1) ? GENERIC_LONG : GENERIC_SHORT;
+ zsinfo = new ZoneStringInfo(utzid, genericPartialLocationNames[i][j], type);
+ fZoneStringsTrie.put(genericPartialLocationNames[i][j], zsinfo, status);
+ if (U_FAILURE(status)) {
+ delete[] genericPartialLocationNames[i];
+ uprv_free(genericPartialLocationNames);
+ delete[] strings;
+ goto error_cleanup;
+ }
+ }
+ }
+ }
+ }
+
+ // Finally, create ZoneStrings instance and put it into the tzidToStinrgs map
+ ZoneStrings *zstrings = new ZoneStrings(strings, stringsCount, commonlyUsed,
+ genericPartialLocationNames, genericPartialRowCount, genericPartialColCount);
+
+ fTzidToStrings.put(utzid, zstrings, status);
+ if (U_FAILURE(status)) {
+ delete zstrings;
+ goto error_cleanup;
+ }
+ }
+
+error_cleanup:
+ if (fallbackFmt != NULL) {
+ delete fallbackFmt;
+ }
+ if (regionFmt != NULL) {
+ delete regionFmt;
+ }
+ if (tzids != NULL) {
+ delete tzids;
+ }
+ ures_close(zoneItem);
+ ures_close(metazoneItem);
+ ures_close(zoneStringsArray);
+}
+
+ZoneStringFormat::~ZoneStringFormat() {
+}
+
+SafeZoneStringFormatPtr*
+ZoneStringFormat::getZoneStringFormat(const Locale& locale, UErrorCode &status) {
+ umtx_lock(&gZSFCacheLock);
+ if (gZoneStringFormatCache == NULL) {
+ gZoneStringFormatCache = new ZSFCache(10 /* capacity */);
+ ucln_i18n_registerCleanup(UCLN_I18N_ZSFORMAT, zoneStringFormat_cleanup);
+ }
+ umtx_unlock(&gZSFCacheLock);
+
+ return gZoneStringFormatCache->get(locale, status);
+}
+
+
+UnicodeString**
+ZoneStringFormat::createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ UnicodeString **result = NULL;
+ rowCount = 0;
+ colCount = 0;
+
+ // Collect canonical time zone IDs
+ UVector canonicalIDs(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ StringEnumeration *tzids = TimeZone::createEnumeration();
+ const UChar *tzid;
+ while ((tzid = tzids->unext(NULL, status))) {
+ if (U_FAILURE(status)) {
+ delete tzids;
+ return NULL;
+ }
+ UnicodeString utzid(tzid);
+ UnicodeString canonicalID;
+ ZoneMeta::getCanonicalID(UnicodeString(tzid), canonicalID);
+ if (utzid == canonicalID) {
+ canonicalIDs.addElement(new UnicodeString(utzid), status);
+ if (U_FAILURE(status)) {
+ delete tzids;
+ return NULL;
+ }
+ }
+ }
+ delete tzids;
+
+ // Allocate array
+ result = (UnicodeString**)uprv_malloc(canonicalIDs.size() * sizeof(UnicodeString*));
+ if (result == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ for (int32_t i = 0; i < canonicalIDs.size(); i++) {
+ result[i] = new UnicodeString[8];
+ UnicodeString *id = (UnicodeString*)canonicalIDs.elementAt(i);
+ result[i][0].setTo(*id);
+ getLongStandard(*id, date, result[i][1]);
+ getShortStandard(*id, date, FALSE, result[i][2]);
+ getLongDaylight(*id, date, result[i][3]);
+ getShortDaylight(*id, date, FALSE, result[i][4]);
+ getGenericLocation(*id, result[i][5]);
+ getLongGenericNonLocation(*id, date, result[i][6]);
+ getShortGenericNonLocation(*id, date, FALSE, result[i][7]);
+ }
+
+ rowCount = canonicalIDs.size();
+ colCount = 8;
+ return result;
+}
+
+UnicodeString&
+ZoneStringFormat::getSpecificLongString(const Calendar &cal, UnicodeString &result,
+ UErrorCode &status) const {
+ result.remove();
+ if (U_FAILURE(status)) {
+ return result;
+ }
+ UnicodeString tzid;
+ cal.getTimeZone().getID(tzid);
+ UDate date = cal.getTime(status);
+ if (cal.get(UCAL_DST_OFFSET, status) == 0) {
+ return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /*not used*/, result);
+ } else {
+ return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /*not used*/, result);
+ }
+}
+
+UnicodeString&
+ZoneStringFormat::getSpecificShortString(const Calendar &cal, UBool commonlyUsedOnly,
+ UnicodeString &result, UErrorCode &status) const {
+ result.remove();
+ if (U_FAILURE(status)) {
+ return result;
+ }
+ UnicodeString tzid;
+ cal.getTimeZone().getID(tzid);
+ UDate date = cal.getTime(status);
+ if (cal.get(UCAL_DST_OFFSET, status) == 0) {
+ return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result);
+ } else {
+ return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result);
+ }
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericLongString(const Calendar &cal, UnicodeString &result,
+ UErrorCode &status) const {
+ return getGenericString(cal, FALSE /*long*/, FALSE /* not used */, result, status);
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericShortString(const Calendar &cal, UBool commonlyUsedOnly,
+ UnicodeString &result, UErrorCode &status) const {
+ return getGenericString(cal, TRUE /*short*/, commonlyUsedOnly, result, status);
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericLocationString(const Calendar &cal, UnicodeString &result,
+ UErrorCode &status) const {
+ UnicodeString tzid;
+ cal.getTimeZone().getID(tzid);
+ UDate date = cal.getTime(status);
+ return getString(tzid, ZSIDX_LOCATION, date, FALSE /*not used*/, result);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findSpecificLong(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, STANDARD_LONG | DAYLIGHT_LONG, matchLength, status);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findSpecificShort(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, STANDARD_SHORT | DAYLIGHT_SHORT, matchLength, status);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findGenericLong(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, GENERIC_LONG | STANDARD_LONG | LOCATION, matchLength, status);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findGenericShort(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, GENERIC_SHORT | STANDARD_SHORT | LOCATION, matchLength, status);
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::findGenericLocation(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const {
+ return find(text, start, LOCATION, matchLength, status);
+}
+
+UnicodeString&
+ZoneStringFormat::getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date,
+ UBool commonlyUsedOnly, UnicodeString& result) const {
+ result.remove();
+
+ // ICU's own array does not have entries for aliases
+ UnicodeString canonicalID;
+ ZoneMeta::getCanonicalID(tzid, canonicalID);
+
+ if (fTzidToStrings.count() > 0) {
+ ZoneStrings *zstrings = (ZoneStrings*)fTzidToStrings.get(canonicalID);
+ if (zstrings != NULL) {
+ switch (typeIdx) {
+ case ZSIDX_LONG_STANDARD:
+ case ZSIDX_LONG_DAYLIGHT:
+ case ZSIDX_LONG_GENERIC:
+ case ZSIDX_LOCATION:
+ zstrings->getString(typeIdx, result);
+ break;
+ case ZSIDX_SHORT_STANDARD:
+ case ZSIDX_SHORT_DAYLIGHT:
+ case ZSIDX_SHORT_GENERIC:
+ if (!commonlyUsedOnly || zstrings->isShortFormatCommonlyUsed()) {
+ zstrings->getString(typeIdx, result);
+ }
+ break;
+ }
+ }
+ }
+ if (result.isEmpty() && fMzidToStrings.count() > 0 && typeIdx != ZSIDX_LOCATION) {
+ // Try metazone
+ UnicodeString mzid;
+ ZoneMeta::getMetazoneID(canonicalID, date, mzid);
+ if (!mzid.isEmpty()) {
+ ZoneStrings *mzstrings = (ZoneStrings*)fMzidToStrings.get(mzid);
+ if (mzstrings != NULL) {
+ switch (typeIdx) {
+ case ZSIDX_LONG_STANDARD:
+ case ZSIDX_LONG_DAYLIGHT:
+ case ZSIDX_LONG_GENERIC:
+ case ZSIDX_LOCATION:
+ mzstrings->getString(typeIdx, result);
+ break;
+ case ZSIDX_SHORT_STANDARD:
+ case ZSIDX_SHORT_DAYLIGHT:
+ case ZSIDX_SHORT_GENERIC:
+ if (!commonlyUsedOnly || mzstrings->isShortFormatCommonlyUsed()) {
+ mzstrings->getString(typeIdx, result);
+ }
+ break;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly,
+ UnicodeString &result, UErrorCode &status) const {
+ result.remove();
+ UDate time = cal.getTime(status);
+ if (U_FAILURE(status)) {
+ return result;
+ }
+ const TimeZone &tz = cal.getTimeZone();
+ UnicodeString tzid;
+ tz.getID(tzid);
+
+ // ICU's own array does not have entries for aliases
+ UnicodeString canonicalID;
+ ZoneMeta::getCanonicalID(tzid, canonicalID);
+
+ ZoneStrings *zstrings;
+ if (fTzidToStrings.count() > 0) {
+ zstrings = (ZoneStrings*)fTzidToStrings.get(canonicalID);
+ if (zstrings != NULL) {
+ if (isShort) {
+ if (!commonlyUsedOnly || zstrings->isShortFormatCommonlyUsed()) {
+ zstrings->getString(ZSIDX_SHORT_GENERIC, result);
+ }
+ } else {
+ zstrings->getString(ZSIDX_LONG_GENERIC, result);
+ }
+ }
+ }
+ if (result.isEmpty() && fMzidToStrings.count() > 0) {
+ // try metazone
+ int32_t raw, sav;
+ UnicodeString mzid;
+ ZoneMeta::getMetazoneID(canonicalID, time, mzid);
+ if (!mzid.isEmpty()) {
+ UBool useStandard = FALSE;
+ sav = cal.get(UCAL_DST_OFFSET, status);
+ if (U_FAILURE(status)) {
+ return result;
+ }
+ if (sav == 0) {
+ useStandard = TRUE;
+ // Check if the zone actually uses daylight saving time around the time
+ TimeZone *tmptz = tz.clone();
+ BasicTimeZone *btz = NULL;
+ if (tmptz->getDynamicClassID() == OlsonTimeZone::getStaticClassID()
+ || tmptz->getDynamicClassID() == SimpleTimeZone::getStaticClassID()
+ || tmptz->getDynamicClassID() == RuleBasedTimeZone::getStaticClassID()
+ || tmptz->getDynamicClassID() == VTimeZone::getStaticClassID()) {
+ btz = (BasicTimeZone*)tmptz;
+ }
+
+ if (btz != NULL) {
+ TimeZoneTransition before;
+ UBool beforTrs = btz->getPreviousTransition(time, TRUE, before);
+ if (beforTrs
+ && (time - before.getTime() < kDstCheckRange)
+ && before.getFrom()->getDSTSavings() != 0) {
+ useStandard = FALSE;
+ } else {
+ TimeZoneTransition after;
+ UBool afterTrs = btz->getNextTransition(time, FALSE, after);
+ if (afterTrs
+ && (after.getTime() - time < kDstCheckRange)
+ && after.getTo()->getDSTSavings() != 0) {
+ useStandard = FALSE;
+ }
+ }
+ } else {
+ // If not BasicTimeZone... only if the instance is not an ICU's implementation.
+ // We may get a wrong answer in edge case, but it should practically work OK.
+ tmptz->getOffset(time - kDstCheckRange, FALSE, raw, sav, status);
+ if (sav != 0) {
+ useStandard = FALSE;
+ } else {
+ tmptz->getOffset(time + kDstCheckRange, FALSE, raw, sav, status);
+ if (sav != 0){
+ useStandard = FALSE;
+ }
+ }
+ if (U_FAILURE(status)) {
+ delete tmptz;
+ result.remove();
+ return result;
+ }
+ }
+ delete tmptz;
+ }
+ if (useStandard) {
+ getString(canonicalID, (isShort ? ZSIDX_SHORT_STANDARD : ZSIDX_LONG_STANDARD),
+ time, commonlyUsedOnly, result);
+
+ // Note:
+ // In CLDR 1.5.1, a same localization is used for both generic and standard
+ // for some metazones in some locales. This is actually data bugs and should
+ // be resolved in later versions of CLDR. For now, we check if the standard
+ // name is different from its generic name below.
+ if (!result.isEmpty()) {
+ UnicodeString genericNonLocation;
+ getString(canonicalID, (isShort ? ZSIDX_SHORT_GENERIC : ZSIDX_LONG_GENERIC),
+ time, commonlyUsedOnly, genericNonLocation);
+ if (!genericNonLocation.isEmpty() && result == genericNonLocation) {
+ result.remove();
+ }
+ }
+ }
+ if (result.isEmpty()) {
+ ZoneStrings *mzstrings = (ZoneStrings*)fMzidToStrings.get(mzid);
+ if (mzstrings != NULL) {
+ if (isShort) {
+ if (!commonlyUsedOnly || mzstrings->isShortFormatCommonlyUsed()) {
+ mzstrings->getString(ZSIDX_SHORT_GENERIC, result);
+ }
+ } else {
+ mzstrings->getString(ZSIDX_LONG_GENERIC, result);
+ }
+ }
+ if (!result.isEmpty()) {
+ // Check if the offsets at the given time matches the preferred zone's offsets
+ UnicodeString preferredId;
+ UnicodeString region;
+ ZoneMeta::getZoneIdByMetazone(mzid, getRegion(region), preferredId);
+ if (canonicalID != preferredId) {
+ // Check if the offsets at the given time are identical with the preferred zone
+ raw = cal.get(UCAL_ZONE_OFFSET, status);
+ if (U_FAILURE(status)) {
+ result.remove();
+ return result;
+ }
+ TimeZone *preferredZone = TimeZone::createTimeZone(preferredId);
+ int32_t prfRaw, prfSav;
+ // Check offset in preferred time zone with wall time.
+ // With getOffset(time, false, preferredOffsets),
+ // you may get incorrect results because of time overlap at DST->STD
+ // transition.
+ preferredZone->getOffset(time + raw + sav, TRUE, prfRaw, prfSav, status);
+ delete preferredZone;
+
+ if (U_FAILURE(status)) {
+ result.remove();
+ return result;
+ }
+ if ((raw != prfRaw || sav != prfSav) && zstrings != NULL) {
+ // Use generic partial location string as fallback
+ zstrings->getGenericPartialLocationString(mzid, isShort, commonlyUsedOnly, result);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (result.isEmpty()) {
+ // Use location format as the final fallback
+ getString(canonicalID, ZSIDX_LOCATION, time, FALSE /*not used*/, result);
+ }
+
+ return result;
+}
+
+UnicodeString&
+ZoneStringFormat::getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort,
+ UDate date, UBool commonlyUsedOnly, UnicodeString &result) const {
+ result.remove();
+ if (fTzidToStrings.count() <= 0) {
+ return result;
+ }
+
+ UnicodeString canonicalID;
+ ZoneMeta::getCanonicalID(tzid, canonicalID);
+
+ UnicodeString mzid;
+ ZoneMeta::getMetazoneID(canonicalID, date, mzid);
+
+ if (!mzid.isEmpty()) {
+ ZoneStrings *zstrings = (ZoneStrings*)fTzidToStrings.get(canonicalID);
+ if (zstrings != NULL) {
+ zstrings->getGenericPartialLocationString(mzid, isShort, commonlyUsedOnly, result);
+ }
+ }
+ return result;
+}
+
+const ZoneStringInfo*
+ZoneStringFormat::find(const UnicodeString &text, int32_t start, int32_t types,
+ int32_t &matchLength, UErrorCode &status) const {
+ matchLength = 0;
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (fZoneStringsTrie.isEmpty()) {
+ return NULL;
+ }
+ const ZoneStringInfo *result = NULL;
+ const ZoneStringInfo *fallback = NULL;
+ int32_t fallbackMatchLen = 0;
+
+ ZoneStringSearchResultHandler handler(status);
+ fZoneStringsTrie.search(text, start, (TextTrieMapSearchResultHandler*)&handler, status);
+ if (U_SUCCESS(status)) {
+ int32_t numMatches = handler.countMatches();
+ for (int32_t i = 0; i < numMatches; i++) {
+ int32_t tmpMatchLen;
+ const ZoneStringInfo *tmp = handler.getMatch(i, tmpMatchLen);
+ if ((types & tmp->fType) != 0) {
+ if (result == NULL || matchLength < tmpMatchLen) {
+ result = tmp;
+ matchLength = tmpMatchLen;
+ } else if (matchLength == tmpMatchLen) {
+ // Tie breaker - there are some examples that a
+ // long standard name is identical with a location
+ // name - for example, "Uruguay Time". In this case,
+ // we interpret it as generic, not specific.
+ if (tmp->isGeneric() && !result->isGeneric()) {
+ result = tmp;
+ }
+ }
+ } else if (result == NULL) {
+ if (fallback == NULL || fallbackMatchLen < tmpMatchLen) {
+ fallback = tmp;
+ fallbackMatchLen = tmpMatchLen;
+ } else if (fallbackMatchLen == tmpMatchLen) {
+ if (tmp->isGeneric() && !fallback->isGeneric()) {
+ fallback = tmp;
+ }
+ }
+ }
+ }
+ if (result == NULL && fallback != NULL) {
+ result = fallback;
+ matchLength = fallbackMatchLen;
+ }
+ }
+ return result;
+}
+
+
+UnicodeString&
+ZoneStringFormat::getRegion(UnicodeString &region) const {
+ const char* country = fLocale.getCountry();
+ // TODO: Utilize addLikelySubtag in Locale to resolve default region
+ // when the implementation is ready.
+ region.setTo(UnicodeString(country, -1, US_INV));
+ return region;
+}
+
+MessageFormat*
+ZoneStringFormat::getFallbackFormat(const Locale &locale, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ UnicodeString pattern(TRUE, gDefFallbackPattern, -1);
+ UResourceBundle *zoneStringsArray = ures_open(NULL, locale.getName(), &status);
+ zoneStringsArray = ures_getByKeyWithFallback(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status);
+ int32_t len;
+ const UChar *flbkfmt = ures_getStringByKeyWithFallback(zoneStringsArray, gFallbackFormatTag, &len, &status);
+ if (U_SUCCESS(status)) {
+ pattern.setTo(flbkfmt);
+ } else {
+ status = U_ZERO_ERROR;
+ }
+ ures_close(zoneStringsArray);
+
+ MessageFormat *fallbackFmt = new MessageFormat(pattern, status);
+ return fallbackFmt;
+}
+
+MessageFormat*
+ZoneStringFormat::getRegionFormat(const Locale& locale, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ UnicodeString pattern(TRUE, gDefRegionPattern, -1);
+ UResourceBundle *zoneStringsArray = ures_open(NULL, locale.getName(), &status);
+ zoneStringsArray = ures_getByKeyWithFallback(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status);
+ int32_t len;
+ const UChar *regionfmt = ures_getStringByKeyWithFallback(zoneStringsArray, gRegionFormatTag, &len, &status);
+ if (U_SUCCESS(status)) {
+ pattern.setTo(regionfmt);
+ } else {
+ status = U_ZERO_ERROR;
+ }
+ ures_close(zoneStringsArray);
+
+ MessageFormat *regionFmt = new MessageFormat(pattern, status);
+ return regionFmt;
+}
+
+const UChar*
+ZoneStringFormat::getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key) {
+ const UChar *str = NULL;
+ if (zoneitem != NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len;
+ str = ures_getStringByKeyWithFallback(zoneitem, key, &len, &status);
+ if (U_FAILURE(status)) {
+ str = NULL;
+ }
+ }
+ return str;
+}
+
+UBool
+ZoneStringFormat::isCommonlyUsed(const UResourceBundle *zoneitem) {
+ if (zoneitem == NULL) {
+ return TRUE;
+ }
+
+ UBool commonlyUsed = FALSE;
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *cuRes = ures_getByKey(zoneitem, gCommonlyUsedTag, NULL, &status);
+ int32_t cuValue = ures_getInt(cuRes, &status);
+ if (U_SUCCESS(status)) {
+ if (cuValue == 1) {
+ commonlyUsed = TRUE;
+ }
+ }
+ ures_close(cuRes);
+ return commonlyUsed;
+}
+
+UnicodeString&
+ZoneStringFormat::getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale, UnicodeString &displayCountry) {
+ // We do not want to use display country names only from the target language bundle
+ // Note: we should do this in better way.
+ displayCountry.remove();
+ int32_t ccLen = countryCode.length();
+ if (ccLen > 0 && ccLen < ULOC_COUNTRY_CAPACITY) {
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status);
+ if (U_SUCCESS(status)) {
+ const char *bundleLocStr = ures_getLocale(localeBundle, &status);
+ if (U_SUCCESS(status) && uprv_strlen(bundleLocStr) > 0) {
+ Locale bundleLoc(bundleLocStr);
+ if (uprv_strcmp(bundleLocStr, "root") != 0 && uprv_strcmp(bundleLoc.getLanguage(), locale.getLanguage()) == 0) {
+ // Create a fake locale strings
+ char tmpLocStr[ULOC_COUNTRY_CAPACITY + 3];
+ uprv_strcpy(tmpLocStr, "xx_");
+ u_UCharsToChars(countryCode.getBuffer(), &tmpLocStr[3], ccLen);
+ tmpLocStr[3 + ccLen] = 0;
+
+ Locale tmpLoc(tmpLocStr);
+ tmpLoc.getDisplayCountry(locale, displayCountry);
+ }
+ }
+ }
+ ures_close(localeBundle);
+ }
+ if (displayCountry.isEmpty()) {
+ // Use the country code as the fallback
+ displayCountry.setTo(countryCode);
+ }
+ return displayCountry;
+}
+
+// ----------------------------------------------------------------------------
+/*
+ * This constructor adopts the input UnicodeString arrays.
+ */
+ZoneStrings::ZoneStrings(UnicodeString *strings, int32_t stringsCount, UBool commonlyUsed,
+ UnicodeString **genericPartialLocationStrings, int32_t genericRowCount, int32_t genericColCount)
+: UMemory(), fStrings(strings), fStringsCount(stringsCount), fIsCommonlyUsed(commonlyUsed),
+ fGenericPartialLocationStrings(genericPartialLocationStrings),
+ fGenericPartialLocationRowCount(genericRowCount), fGenericPartialLocationColCount(genericColCount) {
+}
+
+ZoneStrings::~ZoneStrings() {
+ if (fStrings != NULL) {
+ delete[] fStrings;
+ }
+ if (fGenericPartialLocationStrings != NULL) {
+ for (int32_t i = 0; i < fGenericPartialLocationRowCount; i++) {
+ delete[] fGenericPartialLocationStrings[i];
+ }
+ uprv_free(fGenericPartialLocationStrings);
+ }
+}
+
+
+UnicodeString&
+ZoneStrings::getString(int32_t typeIdx, UnicodeString &result) const {
+ if (typeIdx >= 0 && typeIdx < fStringsCount) {
+ result.setTo(fStrings[typeIdx]);
+ } else {
+ result.remove();
+ }
+ return result;
+}
+
+UnicodeString&
+ZoneStrings::getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort,
+ UBool commonlyUsedOnly, UnicodeString &result) const {
+ UBool isSet = FALSE;
+ if (fGenericPartialLocationColCount >= 2) {
+ for (int32_t i = 0; i < fGenericPartialLocationRowCount; i++) {
+ if (fGenericPartialLocationStrings[i][0] == mzid) {
+ if (isShort) {
+ if (fGenericPartialLocationColCount >= 3) {
+ if (!commonlyUsedOnly ||
+ fGenericPartialLocationColCount == 3 || fGenericPartialLocationStrings[i][3].length() != 0) {
+ result.setTo(fGenericPartialLocationStrings[i][2]);
+ isSet = TRUE;
+ }
+ }
+ } else {
+ result.setTo(fGenericPartialLocationStrings[i][1]);
+ isSet = TRUE;
+ }
+ break;
+ }
+ }
+ }
+ if (!isSet) {
+ result.remove();
+ }
+ return result;
+}
+
+// --------------------------------------------------------------
+SafeZoneStringFormatPtr::SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry)
+: UMemory(), fCacheEntry(cacheEntry) {
+}
+
+SafeZoneStringFormatPtr::~SafeZoneStringFormatPtr() {
+ fCacheEntry->delRef();
+}
+
+const ZoneStringFormat*
+SafeZoneStringFormatPtr::get() const {
+ return fCacheEntry->getZoneStringFormat();
+}
+
+ZSFCacheEntry::ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next)
+: UMemory(), fLocale(locale), fZoneStringFormat(zsf),
+ fNext(next), fRefCount(1)
+{
+}
+
+ZSFCacheEntry::~ZSFCacheEntry () {
+ delete fZoneStringFormat;
+}
+
+const ZoneStringFormat*
+ZSFCacheEntry::getZoneStringFormat(void) {
+ return (const ZoneStringFormat*)fZoneStringFormat;
+}
+
+void
+ZSFCacheEntry::delRef(void) {
+ umtx_lock(&gZSFCacheLock);
+ --fRefCount;
+ umtx_unlock(&gZSFCacheLock);
+}
+
+ZSFCache::ZSFCache(int32_t capacity)
+: UMemory(), fCapacity(capacity), fFirst(NULL) {
+}
+
+ZSFCache::~ZSFCache() {
+ ZSFCacheEntry *entry = fFirst;
+ while (entry) {
+ ZSFCacheEntry *next = entry->fNext;
+ delete entry;
+ entry = next;
+ }
+}
+
+SafeZoneStringFormatPtr*
+ZSFCache::get(const Locale &locale, UErrorCode &status) {
+ SafeZoneStringFormatPtr *result = NULL;
+
+ // Search the cache entry list
+ ZSFCacheEntry *entry = NULL;
+ ZSFCacheEntry *next, *prev;
+
+ umtx_lock(&gZSFCacheLock);
+ entry = fFirst;
+ prev = NULL;
+ while (entry) {
+ next = entry->fNext;
+ if (entry->fLocale == locale) {
+ // Add reference count
+ entry->fRefCount++;
+
+ // move the entry to the top
+ if (entry != fFirst) {
+ prev->fNext = next;
+ entry->fNext = fFirst;
+ fFirst = entry;
+ }
+ break;
+ }
+ prev = entry;
+ entry = next;
+ }
+ umtx_unlock(&gZSFCacheLock);
+
+ // Create a new ZoneStringFormat
+ if (entry == NULL) {
+ ZoneStringFormat *zsf = new ZoneStringFormat(locale, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ // Now add the new entry
+ umtx_lock(&gZSFCacheLock);
+ // Make sure no other threads already created the one for the same locale
+ entry = fFirst;
+ prev = NULL;
+ while (entry) {
+ next = entry->fNext;
+ if (entry->fLocale == locale) {
+ // Add reference count
+ entry->fRefCount++;
+
+ // move the entry to the top
+ if (entry != fFirst) {
+ prev->fNext = next;
+ entry->fNext = fFirst;
+ fFirst = entry;
+ }
+ break;
+ }
+ prev = entry;
+ entry = next;
+ }
+ if (entry == NULL) {
+ // Add the new one to the top
+ next = fFirst;
+ entry = new ZSFCacheEntry(locale, zsf, next);
+ fFirst = entry;
+ } else {
+ delete zsf;
+ }
+ umtx_unlock(&gZSFCacheLock);
+ }
+
+ result = new SafeZoneStringFormatPtr(entry);
+
+ // Now, delete unused cache entries beyond the capacity
+ umtx_lock(&gZSFCacheLock);
+ entry = fFirst;
+ prev = NULL;
+ int32_t idx = 1;
+ while (entry) {
+ next = entry->fNext;
+ if (idx >= fCapacity && entry->fRefCount == 0) {
+ if (entry == fFirst) {
+ fFirst = next;
+ } else {
+ prev->fNext = next;
+ }
+ delete entry;
+ } else {
+ prev = entry;
+ }
+ entry = next;
+ idx++;
+ }
+ umtx_unlock(&gZSFCacheLock);
+
+ return result;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/i18n/zstrfmt.h b/Build/source/libs/icu/icu-xetex/i18n/zstrfmt.h
new file mode 100644
index 00000000000..6765d6dd7b9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/i18n/zstrfmt.h
@@ -0,0 +1,442 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#ifndef ZSTRFMT_H
+#define ZSTRFMT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/calendar.h"
+#include "hash.h"
+#include "uvector.h"
+
+U_NAMESPACE_BEGIN
+
+/*
+ * Character node used by TextTrieMap
+ */
+class CharacterNode : public UMemory {
+public:
+ CharacterNode(UChar32 c, UObjectDeleter *fn, UErrorCode &status);
+ virtual ~CharacterNode();
+
+ inline UChar32 getCharacter(void) const;
+ inline const UVector* getValues(void) const;
+ inline const UVector* getChildNodes(void) const;
+
+ void addValue(void *value, UErrorCode &status);
+ CharacterNode* addChildNode(UChar32 c, UErrorCode &status);
+ CharacterNode* getChildNode(UChar32 c) const;
+
+private:
+ UVector fChildren;
+ UVector fValues;
+ UObjectDeleter *fValueDeleter;
+ UChar32 fCharacter;
+};
+
+inline UChar32 CharacterNode::getCharacter(void) const {
+ return fCharacter;
+}
+
+inline const UVector* CharacterNode::getValues(void) const {
+ return &fValues;
+}
+
+inline const UVector* CharacterNode::getChildNodes(void) const {
+ return &fChildren;
+}
+
+/*
+ * Search result handler callback interface used by TextTrieMap search.
+ */
+class TextTrieMapSearchResultHandler {
+public:
+ virtual UBool handleMatch(int32_t matchLength,
+ const UVector *values, UErrorCode& status) = 0;
+};
+
+/**
+ * TextTrieMap is a trie implementation for supporting
+ * fast prefix match for the string key.
+ */
+class TextTrieMap : public UMemory {
+public:
+ TextTrieMap(UBool ignoreCase, UObjectDeleter *valueDeleterFunc);
+ virtual ~TextTrieMap();
+
+ void put(const UnicodeString &key, void *value, UErrorCode &status);
+ void search(const UnicodeString &text, int32_t start,
+ TextTrieMapSearchResultHandler *handler, UErrorCode& status) const;
+ inline int32_t isEmpty() const;
+
+private:
+ UBool fIgnoreCase;
+ UObjectDeleter *fValueDeleter;
+ CharacterNode *fRoot;
+
+ void search(CharacterNode *node, const UnicodeString &text, int32_t start,
+ int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const;
+};
+
+inline UChar32 TextTrieMap::isEmpty(void) const {
+ return fRoot == NULL;
+}
+
+// Name types, these bit flag are used for zone string lookup
+enum TimeZoneTranslationType {
+ LOCATION = 0x0001,
+ GENERIC_LONG = 0x0002,
+ GENERIC_SHORT = 0x0004,
+ STANDARD_LONG = 0x0008,
+ STANDARD_SHORT = 0x0010,
+ DAYLIGHT_LONG = 0x0020,
+ DAYLIGHT_SHORT = 0x0040
+};
+
+// Name type index, these constants are used for index in the zone strings array.
+enum TimeZoneTranslationTypeIndex {
+ ZSIDX_LOCATION = 0,
+ ZSIDX_LONG_STANDARD,
+ ZSIDX_SHORT_STANDARD,
+ ZSIDX_LONG_DAYLIGHT,
+ ZSIDX_SHORT_DAYLIGHT,
+ ZSIDX_LONG_GENERIC,
+ ZSIDX_SHORT_GENERIC,
+
+ ZSIDX_COUNT
+};
+
+class MessageFormat;
+
+/*
+ * ZoneStringInfo is a class holding a localized zone string
+ * information.
+ */
+class ZoneStringInfo : public UMemory {
+public:
+ virtual ~ZoneStringInfo();
+
+ inline UnicodeString& getID(UnicodeString &result) const;
+ inline UnicodeString& getString(UnicodeString &result) const;
+ inline UBool isStandard(void) const;
+ inline UBool isDaylight(void) const;
+ inline UBool isGeneric(void) const;
+
+private:
+ friend class ZoneStringFormat;
+ friend class ZoneStringSearchResultHandler;
+
+ ZoneStringInfo(const UnicodeString &id, const UnicodeString &str, TimeZoneTranslationType type);
+
+ UnicodeString fId;
+ UnicodeString fStr;
+ TimeZoneTranslationType fType;
+};
+
+inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const {
+ return result.setTo(fId);
+}
+
+inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const {
+ return result.setTo(fStr);
+}
+
+inline UBool ZoneStringInfo::isStandard(void) const {
+ return (fType == STANDARD_LONG || fType == STANDARD_SHORT);
+}
+
+inline UBool ZoneStringInfo::isDaylight(void) const {
+ return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT);
+}
+
+inline UBool ZoneStringInfo::isGeneric(void) const {
+ return (fType == LOCATION || fType == GENERIC_LONG || fType == GENERIC_SHORT);
+}
+
+class SafeZoneStringFormatPtr;
+
+class ZoneStringFormat : public UMemory {
+public:
+ ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status);
+ ZoneStringFormat(const Locale& locale, UErrorCode &status);
+ virtual ~ZoneStringFormat();
+
+ static SafeZoneStringFormatPtr* getZoneStringFormat(const Locale& locale, UErrorCode &status);
+
+ /*
+ * Create a snapshot of old zone strings array for the given date
+ */
+ UnicodeString** createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const;
+
+ const UnicodeString** getZoneStrings(int32_t &rowCount, int32_t &columnCount) const;
+
+ UnicodeString& getSpecificLongString(const Calendar &cal,
+ UnicodeString &result, UErrorCode &status) const;
+
+ UnicodeString& getSpecificShortString(const Calendar &cal,
+ UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
+
+ UnicodeString& getGenericLongString(const Calendar &cal,
+ UnicodeString &result, UErrorCode &status) const;
+
+ UnicodeString& getGenericShortString(const Calendar &cal,
+ UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
+
+ UnicodeString& getGenericLocationString(const Calendar &cal,
+ UnicodeString &result, UErrorCode &status) const;
+
+ const ZoneStringInfo* findSpecificLong(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+ const ZoneStringInfo* findSpecificShort(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+ const ZoneStringInfo* findGenericLong(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+ const ZoneStringInfo* findGenericShort(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+ const ZoneStringInfo* findGenericLocation(const UnicodeString &text, int32_t start,
+ int32_t &matchLength, UErrorCode &status) const;
+
+ // Following APIs are not used by SimpleDateFormat, but public for testing purpose
+ inline UnicodeString& getLongStandard(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const;
+ inline UnicodeString& getLongDaylight(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const;
+ inline UnicodeString& getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const;
+ inline UnicodeString& getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const;
+ inline UnicodeString& getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const;
+ inline UnicodeString& getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const;
+ inline UnicodeString& getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const;
+ inline UnicodeString& getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const;
+ inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const;
+
+private:
+ Locale fLocale;
+ Hashtable fTzidToStrings;
+ Hashtable fMzidToStrings;
+ TextTrieMap fZoneStringsTrie;
+
+ /*
+ * Private method to get a zone string except generic partial location types.
+ */
+ UnicodeString& getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date,
+ UBool commonlyUsedOnly, UnicodeString& result) const;
+
+ /*
+ * Private method to get a generic string, with fallback logic involved,
+ * that is,
+ *
+ * 1. If a generic non-location string is avaiable for the zone, return it.
+ * 2. If a generic non-location string is associated with a metazone and
+ * the zone never use daylight time around the given date, use the standard
+ * string (if available).
+ *
+ * Note: In CLDR1.5.1, the same localization is used for generic and standard.
+ * In this case, we do not use the standard string and do the rest.
+ *
+ * 3. If a generic non-location string is associated with a metazone and
+ * the offset at the given time is different from the preferred zone for the
+ * current locale, then return the generic partial location string (if avaiable)
+ * 4. If a generic non-location string is not available, use generic location
+ * string.
+ */
+ UnicodeString& getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly,
+ UnicodeString &result, UErrorCode &status) const;
+
+ /*
+ * Private method to get a generic partial location string
+ */
+ UnicodeString& getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort,
+ UDate date, UBool commonlyUsedOnly, UnicodeString &result) const;
+
+ /*
+ * Find a prefix matching time zone for the given zone string types.
+ * @param text The text contains a time zone string
+ * @param start The start index within the text
+ * @param types The bit mask representing a set of requested types
+ * @param matchLength Receives the match length
+ * @param status
+ * @return If any zone string matched for the requested types, returns a
+ * ZoneStringInfo for the longest match. If no matches are found for
+ * the requested types, returns a ZoneStringInfo for the longest match
+ * for any other types. If nothing matches at all, returns null.
+ */
+ const ZoneStringInfo* find(const UnicodeString &text, int32_t start, int32_t types,
+ int32_t &matchLength, UErrorCode &status) const;
+
+ UnicodeString& getRegion(UnicodeString &region) const;
+
+ static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status);
+ static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status);
+ static const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key);
+ static UBool isCommonlyUsed(const UResourceBundle *zoneitem);
+ static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale,
+ UnicodeString &displayCountry);
+};
+
+inline UnicodeString&
+ZoneStringFormat::getLongStandard(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /* not used */, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getLongDaylight(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /* not used */, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_LONG_GENERIC, date, FALSE /* not used */, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
+ UnicodeString &result) const {
+ return getGenericPartialLocationString(tzid, FALSE, date, FALSE /* not used */, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const {
+ return getString(tzid, ZSIDX_SHORT_GENERIC, date, commonlyUsedOnly, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
+ UnicodeString &result) const {
+ return getGenericPartialLocationString(tzid, TRUE, date, commonlyUsedOnly, result);
+}
+
+inline UnicodeString&
+ZoneStringFormat::getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const {
+ return getString(tzid, ZSIDX_LOCATION, 0 /*not used*/, FALSE /*not used*/, result);
+}
+
+
+/*
+ * ZooneStrings is a container of localized zone strings used by ZoneStringFormat
+ */
+class ZoneStrings : public UMemory {
+public:
+ ZoneStrings(UnicodeString *strings, int32_t stringsCount, UBool commonlyUsed,
+ UnicodeString **genericPartialLocationStrings, int32_t genericRowCount, int32_t genericColCount);
+ virtual ~ZoneStrings();
+
+ UnicodeString& getString(int32_t typeIdx, UnicodeString &result) const;
+ inline UBool isShortFormatCommonlyUsed(void) const;
+ UnicodeString& getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort,
+ UBool commonlyUsedOnly, UnicodeString &result) const;
+
+private:
+ UnicodeString *fStrings;
+ int32_t fStringsCount;
+ UBool fIsCommonlyUsed;
+ UnicodeString **fGenericPartialLocationStrings;
+ int32_t fGenericPartialLocationRowCount;
+ int32_t fGenericPartialLocationColCount;
+};
+
+inline UBool
+ZoneStrings::isShortFormatCommonlyUsed(void) const {
+ return fIsCommonlyUsed;
+}
+
+/*
+ * ZoneStringSearchResultHandler is an implementation of
+ * TextTrieMapSearchHandler. This class is used by ZoneStringFormat
+ * for collecting search results for localized zone strings.
+ */
+class ZoneStringSearchResultHandler : public UMemory, TextTrieMapSearchResultHandler {
+public:
+ ZoneStringSearchResultHandler(UErrorCode &status);
+ virtual ~ZoneStringSearchResultHandler();
+
+ virtual UBool handleMatch(int32_t matchLength, const UVector *values, UErrorCode &status);
+ int32_t countMatches(void);
+ const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength);
+ void clear(void);
+
+private:
+ UVector fResults;
+ int32_t fMatchLen[ZSIDX_COUNT];
+};
+
+
+/*
+ * ZoneStringFormat cache implementation
+ */
+class ZSFCacheEntry : public UMemory {
+public:
+ ~ZSFCacheEntry();
+
+ void delRef(void);
+ const ZoneStringFormat* getZoneStringFormat(void);
+
+private:
+ friend class ZSFCache;
+
+ ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next);
+
+ Locale fLocale;
+ ZoneStringFormat *fZoneStringFormat;
+ ZSFCacheEntry *fNext;
+ int32_t fRefCount;
+};
+
+class SafeZoneStringFormatPtr : public UMemory {
+public:
+ ~SafeZoneStringFormatPtr();
+ const ZoneStringFormat* get() const;
+
+private:
+ friend class ZSFCache;
+
+ SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry);
+
+ ZSFCacheEntry *fCacheEntry;
+};
+
+class ZSFCache : public UMemory {
+public:
+ ZSFCache(int32_t capacity);
+ ~ZSFCache();
+
+ SafeZoneStringFormatPtr* get(const Locale &locale, UErrorCode &status);
+
+private:
+ int32_t fCapacity;
+ ZSFCacheEntry *fFirst;
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // ZSTRFMT_H